mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
implement TokensIterator::peek
This commit is contained in:
parent
a949117017
commit
92fcb0af8f
7 changed files with 196 additions and 198 deletions
|
|
@ -5,7 +5,6 @@ use konst::string::{split_at, str_range, char_indices};
|
||||||
use itertools::join;
|
use itertools::join;
|
||||||
use self::ParseError::*;
|
use self::ParseError::*;
|
||||||
use self::TokenKind::*;
|
use self::TokenKind::*;
|
||||||
type TokenResult<'a> = Result<Token<'a>, ParseError>;
|
|
||||||
#[derive(Debug)] pub enum ParseError {
|
#[derive(Debug)] pub enum ParseError {
|
||||||
Unimplemented, Empty, Incomplete, Unexpected(char), Code(u8),
|
Unimplemented, Empty, Incomplete, Unexpected(char), Code(u8),
|
||||||
}
|
}
|
||||||
|
|
@ -31,6 +30,7 @@ macro_rules! iterate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Copy, Clone, PartialEq)] pub struct TokensIterator<'a>(&'a str);
|
#[derive(Copy, Clone, PartialEq)] pub struct TokensIterator<'a>(&'a str);
|
||||||
|
type TokenResult<'a> = Result<Token<'a>, ParseError>;
|
||||||
impl<'a> Iterator for TokensIterator<'a> {
|
impl<'a> Iterator for TokensIterator<'a> {
|
||||||
type Item = TokenResult<'a>;
|
type Item = TokenResult<'a>;
|
||||||
fn next (&mut self) -> Option<TokenResult<'a>> { self.next_mut().map(|(result, _)|result) }
|
fn next (&mut self) -> Option<TokenResult<'a>> { self.next_mut().map(|(result, _)|result) }
|
||||||
|
|
@ -47,6 +47,13 @@ impl<'a> TokensIterator<'a> {
|
||||||
Self::next_mut(&mut self)
|
Self::next_mut(&mut self)
|
||||||
}
|
}
|
||||||
pub const fn next_mut (&mut self) -> Option<(TokenResult<'a>, Self)> {
|
pub const fn next_mut (&mut self) -> Option<(TokenResult<'a>, Self)> {
|
||||||
|
match self.peek() {
|
||||||
|
Some(Ok(token)) => Some((Ok(token), self.split(token.end()))),
|
||||||
|
Some(Err((l, e))) => Some((Err(e), self.split(l))),
|
||||||
|
None => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const fn peek (&self) -> Option<Result<Token<'a>, (usize, ParseError)>> {
|
||||||
let mut token: Token<'a> = Token::new(self.0, Nil, 0, 0, 0);
|
let mut token: Token<'a> = Token::new(self.0, Nil, 0, 0, 0);
|
||||||
iterate!(char_indices(self.0) => (index, c) => token = match token.kind() {
|
iterate!(char_indices(self.0) => (index, c) => token = match token.kind() {
|
||||||
Nil => match c {
|
Nil => match c {
|
||||||
|
|
@ -55,36 +62,39 @@ impl<'a> TokensIterator<'a> {
|
||||||
'0'..='9' => Token::new(self.0, Num, index, 1, 0),
|
'0'..='9' => Token::new(self.0, Num, index, 1, 0),
|
||||||
'/'|'a'..='z' => Token::new(self.0, Key, index, 1, 0),
|
'/'|'a'..='z' => Token::new(self.0, Key, index, 1, 0),
|
||||||
' '|'\n'|'\r'|'\t' => token.grow(),
|
' '|'\n'|'\r'|'\t' => token.grow(),
|
||||||
_ => return Some((Err(Unexpected(c)), self.split(token.end())))
|
_ => return Some(Err((token.end(), Unexpected(c))))
|
||||||
},
|
},
|
||||||
Num => match c {
|
Num => match c {
|
||||||
'0'..='9' => token.grow(),
|
'0'..='9' => token.grow(),
|
||||||
' '|'\n'|'\r'|'\t' => return Some((Ok(token), self.split(token.end()))),
|
' '|'\n'|'\r'|'\t' => return Some(Ok(token)),
|
||||||
_ => return Some((Err(Unexpected(c)), self.split(token.end())))
|
_ => return Some(Err((token.end(), Unexpected(c))))
|
||||||
},
|
},
|
||||||
Sym => match c {
|
Sym => match c {
|
||||||
'a'..='z'|'0'..='9'|'-' => token.grow(),
|
'a'..='z'|'0'..='9'|'-' => token.grow(),
|
||||||
' '|'\n'|'\r'|'\t' => return Some((Ok(token), self.split(token.end()))),
|
' '|'\n'|'\r'|'\t' => return Some(Ok(token)),
|
||||||
_ => return Some((Err(Unexpected(c)), self.split(token.end())))
|
_ => return Some(Err((token.end(), Unexpected(c))))
|
||||||
},
|
},
|
||||||
Key => match c {
|
Key => match c {
|
||||||
'a'..='z'|'0'..='9'|'-'|'/' => token.grow(),
|
'a'..='z'|'0'..='9'|'-'|'/' => token.grow(),
|
||||||
' '|'\n'|'\r'|'\t' => return Some((Ok(token), self.split(token.end()))),
|
' '|'\n'|'\r'|'\t' => return Some(Ok(token)),
|
||||||
_ => return Some((Err(Unexpected(c)), self.split(token.end())))
|
_ => return Some(Err((token.end(), Unexpected(c))))
|
||||||
},
|
},
|
||||||
Exp => match token.depth {
|
Exp => match token.depth {
|
||||||
0 => return Some((Ok(token), Self(split_at(self.0, token.end()).1))),
|
0 => return Some(Ok(token)),
|
||||||
_ => match c {
|
_ => match c {
|
||||||
')' => match token.grow_out() {
|
')' => match token.grow_out() {
|
||||||
Ok(token) => token,
|
Ok(token) => token,
|
||||||
Err(e) => return Some((Err(e), self.split(token.end())))
|
Err(e) => return Some(Err((token.end(), e)))
|
||||||
},
|
},
|
||||||
'(' => token.grow_in(),
|
'(' => token.grow_in(),
|
||||||
_ => token.grow(),
|
_ => token.grow(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
match token.kind() { Nil => None, _ => Some((Err(ParseError::Incomplete), self.split(token.end()))) }
|
match token.kind() {
|
||||||
|
Nil => None,
|
||||||
|
_ => Some(Err((token.end(), ParseError::Incomplete)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Debug, Copy, Clone, Default, PartialEq)] pub enum TokenKind {
|
#[derive(Debug, Copy, Clone, Default, PartialEq)] pub enum TokenKind {
|
||||||
|
|
@ -154,7 +164,7 @@ const fn to_digit (c: char) -> Result<usize, ParseError> {
|
||||||
_ => return Err(Unexpected(c))
|
_ => return Err(Unexpected(c))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub trait Atom: Sized {
|
pub trait Atom: Sized + Send + Sync {
|
||||||
fn kind (&self) -> TokenKind;
|
fn kind (&self) -> TokenKind;
|
||||||
fn text (&self) -> &str;
|
fn text (&self) -> &str;
|
||||||
fn num (&self) -> usize;
|
fn num (&self) -> usize;
|
||||||
|
|
@ -296,27 +306,27 @@ impl<'a> Display for ArcAtom {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Map EDN tokens to parameters of a given type for a given context
|
/// Map EDN tokens to parameters of a given type for a given context
|
||||||
pub trait Context<'a, U>: Sized {
|
pub trait Context<U>: Sized {
|
||||||
fn get (&'a self, _atom: &'a impl Atom) -> Option<U> {
|
fn get (&self, _atom: &impl Atom) -> Option<U> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
fn get_or_fail (&'a self, atom: &'a impl Atom) -> U {
|
fn get_or_fail (&self, atom: &impl Atom) -> U {
|
||||||
self.get(atom).expect("no value")
|
self.get(atom).expect("no value")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a, T: Context<'a, U>, U> Context<'a, U> for &T {
|
impl<T: Context<U>, U> Context<U> for &T {
|
||||||
fn get (&'a self, atom: &'a impl Atom) -> Option<U> {
|
fn get (&self, atom: &impl Atom) -> Option<U> {
|
||||||
(*self).get(atom)
|
(*self).get(atom)
|
||||||
}
|
}
|
||||||
fn get_or_fail (&'a self, atom: &'a impl Atom) -> U {
|
fn get_or_fail (&self, atom: &impl Atom) -> U {
|
||||||
(*self).get_or_fail(atom)
|
(*self).get_or_fail(atom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a, T: Context<'a, U>, U> Context<'a, U> for Option<T> {
|
impl<T: Context<U>, U> Context<U> for Option<T> {
|
||||||
fn get (&'a self, atom: &'a impl Atom) -> Option<U> {
|
fn get (&self, atom: &impl Atom) -> Option<U> {
|
||||||
self.as_ref().map(|s|s.get(atom)).flatten()
|
self.as_ref().map(|s|s.get(atom)).flatten()
|
||||||
}
|
}
|
||||||
fn get_or_fail (&'a self, atom: &'a impl Atom) -> U {
|
fn get_or_fail (&self, atom: &impl Atom) -> U {
|
||||||
self.as_ref().map(|s|s.get_or_fail(atom)).expect("no provider")
|
self.as_ref().map(|s|s.get_or_fail(atom)).expect("no provider")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -324,8 +334,8 @@ impl<'a, T: Context<'a, U>, U> Context<'a, U> for Option<T> {
|
||||||
#[macro_export] macro_rules! provide {
|
#[macro_export] macro_rules! provide {
|
||||||
// Provide a value to the EDN template
|
// Provide a value to the EDN template
|
||||||
($type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => {
|
($type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => {
|
||||||
impl<'a> Context<'a, $type> for $State {
|
impl Context<$type> for $State {
|
||||||
fn get (&'a $self, atom: &'a impl Atom) -> Option<$type> {
|
fn get (&$self, atom: &impl Atom) -> Option<$type> {
|
||||||
Some(match (atom.kind(), atom.text()) {
|
Some(match (atom.kind(), atom.text()) {
|
||||||
$((TokenKind::Sym, $pat) => $expr,)*
|
$((TokenKind::Sym, $pat) => $expr,)*
|
||||||
_ => return None
|
_ => return None
|
||||||
|
|
@ -336,7 +346,7 @@ impl<'a, T: Context<'a, U>, U> Context<'a, U> for Option<T> {
|
||||||
// Provide a value more generically
|
// Provide a value more generically
|
||||||
($lt:lifetime: $type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => {
|
($lt:lifetime: $type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => {
|
||||||
impl<$lt> Context<$lt, $type> for $State {
|
impl<$lt> Context<$lt, $type> for $State {
|
||||||
fn get (&$lt $self, atom: &$lt impl Atom) -> Option<$type> {
|
fn get (&$lt $self, atom: &impl Atom) -> Option<$type> {
|
||||||
Some(match (atom.kind(), atom.text()) {
|
Some(match (atom.kind(), atom.text()) {
|
||||||
$((TokenKind::Sym, $pat) => $expr,)*
|
$((TokenKind::Sym, $pat) => $expr,)*
|
||||||
_ => return None
|
_ => return None
|
||||||
|
|
@ -351,8 +361,8 @@ impl<'a, T: Context<'a, U>, U> Context<'a, U> for Option<T> {
|
||||||
#[macro_export] macro_rules! provide_num {
|
#[macro_export] macro_rules! provide_num {
|
||||||
// Provide a value that may also be a numeric literal in the EDN, to a generic implementation.
|
// Provide a value that may also be a numeric literal in the EDN, to a generic implementation.
|
||||||
($type:ty:|$self:ident:<$T:ident:$Trait:path>|{ $($pat:pat => $expr:expr),* $(,)? }) => {
|
($type:ty:|$self:ident:<$T:ident:$Trait:path>|{ $($pat:pat => $expr:expr),* $(,)? }) => {
|
||||||
impl<'a, $T: $Trait> Context<'a, $type> for $T {
|
impl<$T: $Trait> Context<$type> for $T {
|
||||||
fn get (&'a $self, atom: &'a impl Atom) -> Option<$type> {
|
fn get (&$self, atom: &impl Atom) -> Option<$type> {
|
||||||
Some(match (atom.kind(), atom.text()) {
|
Some(match (atom.kind(), atom.text()) {
|
||||||
$((TokenKind::Sym, $pat) => $expr,)*
|
$((TokenKind::Sym, $pat) => $expr,)*
|
||||||
(TokenKind::Num, _) => atom.num() as $type,
|
(TokenKind::Num, _) => atom.num() as $type,
|
||||||
|
|
@ -363,8 +373,8 @@ impl<'a, T: Context<'a, U>, U> Context<'a, U> for Option<T> {
|
||||||
};
|
};
|
||||||
// Provide a value that may also be a numeric literal in the EDN, to a concrete implementation.
|
// Provide a value that may also be a numeric literal in the EDN, to a concrete implementation.
|
||||||
($type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => {
|
($type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => {
|
||||||
impl<'a> Context<'a, $type> for $State {
|
impl Context<$type> for $State {
|
||||||
fn get (&'a $self, atom: &'a impl Atom) -> Option<$type> {
|
fn get (&$self, atom: &impl Atom) -> Option<$type> {
|
||||||
Some(match (atom.kind(), atom.text()) {
|
Some(match (atom.kind(), atom.text()) {
|
||||||
$((TokenKind::Sym, $pat) => $expr,)*
|
$((TokenKind::Sym, $pat) => $expr,)*
|
||||||
(TokenKind::Num, _) => atom.num() as $type,
|
(TokenKind::Num, _) => atom.num() as $type,
|
||||||
|
|
@ -395,12 +405,3 @@ impl<'a, T: Context<'a, U>, U> Context<'a, U> for Option<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[macro_export] macro_rules! try_delegate {
|
|
||||||
($s:ident, $atom:expr, $T:ty) => {
|
|
||||||
if let [head, tail @ ..] = $atom.as_slice() {
|
|
||||||
if let Some(value) = <$T>::try_from_atoms($s, head, tail) {
|
|
||||||
return Some(value.boxed())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ pub trait AtomCommand<C>: Command<C> {
|
||||||
fn from_atom <'a> (
|
fn from_atom <'a> (
|
||||||
$state: &$T, head: &impl Atom, tail: &'a [impl Atom]
|
$state: &$T, head: &impl Atom, tail: &'a [impl Atom]
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
$(if let (TokenType::Key, $key, [ // if the identifier matches
|
$(if let (TokenKind::Key, $key, [ // if the identifier matches
|
||||||
// bind argument ids
|
// bind argument ids
|
||||||
$($arg),*
|
$($arg),*
|
||||||
// bind rest parameters
|
// bind rest parameters
|
||||||
|
|
@ -153,7 +153,7 @@ pub trait AtomCommand<C>: Command<C> {
|
||||||
head: &impl Atom,
|
head: &impl Atom,
|
||||||
tail: &'a [impl Atom],
|
tail: &'a [impl Atom],
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
$(if let (TokenType::Key, $key, [ // if the identifier matches
|
$(if let (TokenKind::Key, $key, [ // if the identifier matches
|
||||||
// bind argument ids
|
// bind argument ids
|
||||||
$($arg),*
|
$($arg),*
|
||||||
// bind rest parameters
|
// bind rest parameters
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,17 @@ try_from_atoms!(<'a, E>: Align<RenderBox<'a, E>>: |state, atoms| {
|
||||||
let head = atoms.next()?;
|
let head = atoms.next()?;
|
||||||
if head.kind() != TokenKind::Key { return None }
|
if head.kind() != TokenKind::Key { return None }
|
||||||
match head.text() {
|
match head.text() {
|
||||||
"align/c" => return Some(Self::c(state.get_content(atoms.next()?).expect("no content"))),
|
"align/c" => return Some(Self::c(state.get_content(&atoms.next()?).expect("no content"))),
|
||||||
"align/x" => return Some(Self::x(state.get_content(atoms.next()?).expect("no content"))),
|
"align/x" => return Some(Self::x(state.get_content(&atoms.next()?).expect("no content"))),
|
||||||
"align/y" => return Some(Self::y(state.get_content(atoms.next()?).expect("no content"))),
|
"align/y" => return Some(Self::y(state.get_content(&atoms.next()?).expect("no content"))),
|
||||||
"align/n" => return Some(Self::n(state.get_content(atoms.next()?).expect("no content"))),
|
"align/n" => return Some(Self::n(state.get_content(&atoms.next()?).expect("no content"))),
|
||||||
"align/s" => return Some(Self::s(state.get_content(atoms.next()?).expect("no content"))),
|
"align/s" => return Some(Self::s(state.get_content(&atoms.next()?).expect("no content"))),
|
||||||
"align/e" => return Some(Self::e(state.get_content(atoms.next()?).expect("no content"))),
|
"align/e" => return Some(Self::e(state.get_content(&atoms.next()?).expect("no content"))),
|
||||||
"align/w" => return Some(Self::w(state.get_content(atoms.next()?).expect("no content"))),
|
"align/w" => return Some(Self::w(state.get_content(&atoms.next()?).expect("no content"))),
|
||||||
"align/nw" => return Some(Self::nw(state.get_content(atoms.next()?).expect("no content"))),
|
"align/nw" => return Some(Self::nw(state.get_content(&atoms.next()?).expect("no content"))),
|
||||||
"align/ne" => return Some(Self::ne(state.get_content(atoms.next()?).expect("no content"))),
|
"align/ne" => return Some(Self::ne(state.get_content(&atoms.next()?).expect("no content"))),
|
||||||
"align/sw" => return Some(Self::sw(state.get_content(atoms.next()?).expect("no content"))),
|
"align/sw" => return Some(Self::sw(state.get_content(&atoms.next()?).expect("no content"))),
|
||||||
"align/se" => return Some(Self::se(state.get_content(atoms.next()?).expect("no content"))),
|
"align/se" => return Some(Self::se(state.get_content(&atoms.next()?).expect("no content"))),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use RefAtom::*;
|
|
||||||
pub use self::Direction::*;
|
pub use self::Direction::*;
|
||||||
/// A cardinal direction.
|
/// A cardinal direction.
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
|
@ -37,28 +36,28 @@ try_from_atoms!(<'a, E>: Bsp<RenderBox<'a, E>, RenderBox<'a, E>>: |state, atoms|
|
||||||
if head.kind() != TokenKind::Key { return None }
|
if head.kind() != TokenKind::Key { return None }
|
||||||
match head.text() {
|
match head.text() {
|
||||||
"bsp/n" => return Some(Self::n(
|
"bsp/n" => return Some(Self::n(
|
||||||
state.get_content(atoms.next()?).expect("no south"),
|
state.get_content(&atoms.next()?).expect("no south"),
|
||||||
state.get_content(atoms.next()?).expect("no north")
|
state.get_content(&atoms.next()?).expect("no north")
|
||||||
)),
|
)),
|
||||||
"bsp/s" => return Some(Self::s(
|
"bsp/s" => return Some(Self::s(
|
||||||
state.get_content(atoms.next()?).expect("no north"),
|
state.get_content(&atoms.next()?).expect("no north"),
|
||||||
state.get_content(atoms.next()?).expect("no south")
|
state.get_content(&atoms.next()?).expect("no south")
|
||||||
)),
|
)),
|
||||||
"bsp/e" => return Some(Self::e(
|
"bsp/e" => return Some(Self::e(
|
||||||
state.get_content(atoms.next()?).expect("no west"),
|
state.get_content(&atoms.next()?).expect("no west"),
|
||||||
state.get_content(atoms.next()?).expect("no east")
|
state.get_content(&atoms.next()?).expect("no east")
|
||||||
)),
|
)),
|
||||||
"bsp/w" => return Some(Self::w(
|
"bsp/w" => return Some(Self::w(
|
||||||
state.get_content(atoms.next()?).expect("no east"),
|
state.get_content(&atoms.next()?).expect("no east"),
|
||||||
state.get_content(atoms.next()?).expect("no west")
|
state.get_content(&atoms.next()?).expect("no west")
|
||||||
)),
|
)),
|
||||||
"bsp/a" => return Some(Self::a(
|
"bsp/a" => return Some(Self::a(
|
||||||
state.get_content(atoms.next()?).expect("no above"),
|
state.get_content(&atoms.next()?).expect("no above"),
|
||||||
state.get_content(atoms.next()?).expect("no below")
|
state.get_content(&atoms.next()?).expect("no below")
|
||||||
)),
|
)),
|
||||||
"bsp/b" => return Some(Self::b(
|
"bsp/b" => return Some(Self::b(
|
||||||
state.get_content(atoms.next()?).expect("no above"),
|
state.get_content(&atoms.next()?).expect("no above"),
|
||||||
state.get_content(atoms.next()?).expect("no below")
|
state.get_content(&atoms.next()?).expect("no below")
|
||||||
)),
|
)),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
@ -124,22 +123,18 @@ impl<E: Output, A: Content<E>, B: Content<E>> BspAreas<E, A, B> for Bsp<A, B> {
|
||||||
fn direction (&self) -> Direction { self.0 }
|
fn direction (&self) -> Direction { self.0 }
|
||||||
fn contents (&self) -> (&A, &B) { (&self.1, &self.2) }
|
fn contents (&self) -> (&A, &B) { (&self.1, &self.2) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Renders multiple things on top of each other,
|
/// Renders multiple things on top of each other,
|
||||||
#[macro_export] macro_rules! lay {
|
#[macro_export] macro_rules! lay {
|
||||||
($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::b(bsp, $expr);)*; bsp }}
|
($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::b(bsp, $expr);)*; bsp }}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stack southward.
|
/// Stack southward.
|
||||||
#[macro_export] macro_rules! col {
|
#[macro_export] macro_rules! col {
|
||||||
($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::s(bsp, $expr);)*; bsp }};
|
($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::s(bsp, $expr);)*; bsp }};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stack northward.
|
/// Stack northward.
|
||||||
#[macro_export] macro_rules! col_up {
|
#[macro_export] macro_rules! col_up {
|
||||||
($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::n(bsp, $expr);)*; bsp }}
|
($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::n(bsp, $expr);)*; bsp }}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stack eastward.
|
/// Stack eastward.
|
||||||
#[macro_export] macro_rules! row {
|
#[macro_export] macro_rules! row {
|
||||||
($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::e(bsp, $expr);)*; bsp }};
|
($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::e(bsp, $expr);)*; bsp }};
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,9 @@ try_from_atoms!(<'a, E>: When<RenderBox<'a, E>>: |state, atoms| {
|
||||||
let head = atoms.next()?;
|
let head = atoms.next()?;
|
||||||
if (head.kind(), head.text()) == (TokenKind::Key, "when") {
|
if (head.kind(), head.text()) == (TokenKind::Key, "when") {
|
||||||
let condition = atoms.next();
|
let condition = atoms.next();
|
||||||
if let Some(condition) = condition {
|
if let Some(ref condition) = condition {
|
||||||
let condition = state.get_bool(condition).expect("no condition");
|
let condition = state.get_bool(condition).expect("no condition");
|
||||||
if let Some(content) = atoms.next() {
|
if let Some(ref content) = atoms.next() {
|
||||||
let content = state.get_content(content).expect("no atom");
|
let content = state.get_content(content).expect("no atom");
|
||||||
return Some(Self(condition, content))
|
return Some(Self(condition, content))
|
||||||
}
|
}
|
||||||
|
|
@ -22,11 +22,11 @@ try_from_atoms!(<'a, E>: Either<RenderBox<'a, E>, RenderBox<'a, E>>: |state, ato
|
||||||
let head = atoms.next()?;
|
let head = atoms.next()?;
|
||||||
if (head.kind(), head.text()) == (TokenKind::Key, "either") {
|
if (head.kind(), head.text()) == (TokenKind::Key, "either") {
|
||||||
let condition = atoms.next();
|
let condition = atoms.next();
|
||||||
if let Some(condition) = condition {
|
if let Some(ref condition) = condition {
|
||||||
let condition = state.get_bool(condition).expect("no condition");
|
let condition = state.get_bool(condition).expect("no condition");
|
||||||
if let Some(content1) = atoms.next() {
|
if let Some(ref content1) = atoms.next() {
|
||||||
let content1 = state.get_content(content1).expect("no content1");
|
let content1 = state.get_content(content1).expect("no content1");
|
||||||
if let Some(content2) = atoms.next() {
|
if let Some(ref content2) = atoms.next() {
|
||||||
let content2 = state.get_content(content2).expect("no content2");
|
let content2 = state.get_content(content2).expect("no content2");
|
||||||
return Some(Self(condition, content1, content2))
|
return Some(Self(condition, content1, content2))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,24 @@ macro_rules! transform_xy {
|
||||||
pub fn y (item: T) -> Self { Self::Y(item) }
|
pub fn y (item: T) -> Self { Self::Y(item) }
|
||||||
pub fn xy (item: T) -> Self { Self::XY(item) }
|
pub fn xy (item: T) -> Self { Self::XY(item) }
|
||||||
}
|
}
|
||||||
|
impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromAtom<'a, T> for $Enum<RenderBox<'a, E>> {
|
||||||
|
fn try_from_atoms (state: &'a T, mut atoms: impl Iterator<Item = RefAtom<'a>> + 'a) -> Option<Self> {
|
||||||
|
let head = atoms.next()?;
|
||||||
|
if head.kind() != TokenKind::Key { return None }
|
||||||
|
Some(match head.text() {
|
||||||
|
$x => Self::x(
|
||||||
|
state.get_content(&atoms.next().expect("no content")).expect("no content")
|
||||||
|
),
|
||||||
|
$y => Self::y(
|
||||||
|
state.get_content(&atoms.next().expect("no content")).expect("no content")
|
||||||
|
),
|
||||||
|
$xy => Self::xy(
|
||||||
|
state.get_content(&atoms.next().expect("no content")).expect("no content")
|
||||||
|
),
|
||||||
|
_ => return None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
impl<E: Output, T: Content<E>> Content<E> for $Enum<T> {
|
impl<E: Output, T: Content<E>> Content<E> for $Enum<T> {
|
||||||
fn content (&self) -> impl Render<E> {
|
fn content (&self) -> impl Render<E> {
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -26,24 +44,6 @@ macro_rules! transform_xy {
|
||||||
$area
|
$area
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromAtom<'a, T> for $Enum<RenderBox<'a, E>> {
|
|
||||||
fn try_from_atoms (state: &'a T, mut atoms: impl Iterator<Item = RefAtom<'a>> + 'a) -> Option<Self> {
|
|
||||||
let head = atoms.next()?;
|
|
||||||
if head.kind() != TokenKind::Key { return None }
|
|
||||||
Some(match head.text() {
|
|
||||||
$x => Self::x(
|
|
||||||
state.get_content(atoms.next().expect("no content")).expect("no content")
|
|
||||||
),
|
|
||||||
$y => Self::y(
|
|
||||||
state.get_content(atoms.next().expect("no content")).expect("no content")
|
|
||||||
),
|
|
||||||
$xy => Self::xy(
|
|
||||||
state.get_content(atoms.next().expect("no content")).expect("no content")
|
|
||||||
),
|
|
||||||
_ => return None
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Defines an enum that parametrically transforms its content
|
/// Defines an enum that parametrically transforms its content
|
||||||
|
|
@ -56,16 +56,26 @@ macro_rules! transform_xy_unit {
|
||||||
pub fn y (y: U, item: T) -> Self { Self::Y(y, item) }
|
pub fn y (y: U, item: T) -> Self { Self::Y(y, item) }
|
||||||
pub fn xy (x: U, y: U, item: T) -> Self { Self::XY(x, y, item) }
|
pub fn xy (x: U, y: U, item: T) -> Self { Self::XY(x, y, item) }
|
||||||
}
|
}
|
||||||
impl<U: Copy + Coordinate, T> $Enum<U, T> {
|
impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromAtom<'a, T> for $Enum<E::Unit, RenderBox<'a, E>> {
|
||||||
pub fn dx (&self) -> U {
|
fn try_from_atoms (state: &'a T, mut atoms: impl Iterator<Item = RefAtom<'a>> + 'a) -> Option<Self> {
|
||||||
match self {
|
let head = atoms.next()?;
|
||||||
Self::X(x, _) => *x, Self::Y(_, _) => 0.into(), Self::XY(x, _, _) => *x,
|
if head.kind() != TokenKind::Key { return None }
|
||||||
}
|
Some(match head.text() {
|
||||||
}
|
$x => Self::x(
|
||||||
pub fn dy (&self) -> U {
|
state.get_unit(&atoms.next().expect("no x")).expect("no x"),
|
||||||
match self {
|
state.get_content(&atoms.next().expect("no content")).expect("no content")
|
||||||
Self::X(_, _) => 0.into(), Self::Y(y, _) => *y, Self::XY(_, y, _) => *y,
|
),
|
||||||
}
|
$y => Self::y(
|
||||||
|
state.get_unit(&atoms.next().expect("no y")).expect("no y"),
|
||||||
|
state.get_content(&atoms.next().expect("no content")).expect("no content")
|
||||||
|
),
|
||||||
|
$xy => Self::xy(
|
||||||
|
state.get_unit(&atoms.next().expect("no x")).expect("no x"),
|
||||||
|
state.get_unit(&atoms.next().expect("no y")).expect("no y"),
|
||||||
|
state.get_content(&atoms.next().expect("no content")).expect("no content"),
|
||||||
|
),
|
||||||
|
_ => return None
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<E: Output, T: Content<E>> Content<E> for $Enum<E::Unit, T> {
|
impl<E: Output, T: Content<E>> Content<E> for $Enum<E::Unit, T> {
|
||||||
|
|
@ -80,26 +90,16 @@ macro_rules! transform_xy_unit {
|
||||||
$layout.into()
|
$layout.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromAtom<'a, T> for $Enum<E::Unit, RenderBox<'a, E>> {
|
impl<U: Copy + Coordinate, T> $Enum<U, T> {
|
||||||
fn try_from_atoms (state: &'a T, mut atoms: impl Iterator<Item = RefAtom<'a>> + 'a) -> Option<Self> {
|
pub fn dx (&self) -> U {
|
||||||
let head = atoms.next()?;
|
match self {
|
||||||
if head.kind() != TokenKind::Key { return None }
|
Self::X(x, _) => *x, Self::Y(_, _) => 0.into(), Self::XY(x, _, _) => *x,
|
||||||
Some(match head.text() {
|
}
|
||||||
$x => Self::x(
|
}
|
||||||
state.get_unit(atoms.next().expect("no x")).expect("no x"),
|
pub fn dy (&self) -> U {
|
||||||
state.get_content(atoms.next().expect("no content")).expect("no content")
|
match self {
|
||||||
),
|
Self::X(_, _) => 0.into(), Self::Y(y, _) => *y, Self::XY(_, y, _) => *y,
|
||||||
$y => Self::y(
|
}
|
||||||
state.get_unit(atoms.next().expect("no y")).expect("no y"),
|
|
||||||
state.get_content(atoms.next().expect("no content")).expect("no content")
|
|
||||||
),
|
|
||||||
$xy => Self::xy(
|
|
||||||
state.get_unit(atoms.next().expect("no x")).expect("no x"),
|
|
||||||
state.get_unit(atoms.next().expect("no y")).expect("no y"),
|
|
||||||
state.get_content(atoms.next().expect("no content")).expect("no content"),
|
|
||||||
),
|
|
||||||
_ => return None
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -111,7 +111,6 @@ transform_xy!("fill/x" "fill/y" "fill/xy" |self: Fill, to|{
|
||||||
X(_) => [x0, y, wmax, h],
|
X(_) => [x0, y, wmax, h],
|
||||||
Y(_) => [x, y0, w, hmax],
|
Y(_) => [x, y0, w, hmax],
|
||||||
XY(_) => [x0, y0, wmax, hmax],
|
XY(_) => [x0, y0, wmax, hmax],
|
||||||
_ => unreachable!()
|
|
||||||
}.into()
|
}.into()
|
||||||
});
|
});
|
||||||
transform_xy_unit!("fixed/x" "fixed/y" "fixed/xy"|self: Fixed, area|{
|
transform_xy_unit!("fixed/x" "fixed/y" "fixed/xy"|self: Fixed, area|{
|
||||||
|
|
@ -120,14 +119,12 @@ transform_xy_unit!("fixed/x" "fixed/y" "fixed/xy"|self: Fixed, area|{
|
||||||
Self::X(fw, _) => [x, y, *fw, h],
|
Self::X(fw, _) => [x, y, *fw, h],
|
||||||
Self::Y(fh, _) => [x, y, w, *fh],
|
Self::Y(fh, _) => [x, y, w, *fh],
|
||||||
Self::XY(fw, fh, _) => [x, y, *fw, *fh],
|
Self::XY(fw, fh, _) => [x, y, *fw, *fh],
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
};
|
||||||
let [x, y, w, h] = Render::layout(&self.content(), fixed_area.into()).xywh();
|
let [x, y, w, h] = Render::layout(&self.content(), fixed_area.into()).xywh();
|
||||||
let fixed_area = match self {
|
let fixed_area = match self {
|
||||||
Self::X(fw, _) => [x, y, *fw, h],
|
Self::X(fw, _) => [x, y, *fw, h],
|
||||||
Self::Y(fh, _) => [x, y, w, *fh],
|
Self::Y(fh, _) => [x, y, w, *fh],
|
||||||
Self::XY(fw, fh, _) => [x, y, *fw, *fh],
|
Self::XY(fw, fh, _) => [x, y, *fw, *fh],
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
};
|
||||||
fixed_area
|
fixed_area
|
||||||
});
|
});
|
||||||
|
|
@ -137,7 +134,6 @@ transform_xy_unit!("min/x" "min/y" "min/xy"|self: Min, area|{
|
||||||
Self::X(mw, _) => [area.x(), area.y(), area.w().max(*mw), area.h()],
|
Self::X(mw, _) => [area.x(), area.y(), area.w().max(*mw), area.h()],
|
||||||
Self::Y(mh, _) => [area.x(), area.y(), area.w(), area.h().max(*mh)],
|
Self::Y(mh, _) => [area.x(), area.y(), area.w(), area.h().max(*mh)],
|
||||||
Self::XY(mw, mh, _) => [area.x(), area.y(), area.w().max(*mw), area.h().max(*mh)],
|
Self::XY(mw, mh, _) => [area.x(), area.y(), area.w().max(*mw), area.h().max(*mh)],
|
||||||
_ => unreachable!(),
|
|
||||||
}});
|
}});
|
||||||
transform_xy_unit!("max/x" "max/y" "max/xy"|self: Max, area|{
|
transform_xy_unit!("max/x" "max/y" "max/xy"|self: Max, area|{
|
||||||
let [x, y, w, h] = area.xywh();
|
let [x, y, w, h] = area.xywh();
|
||||||
|
|
@ -145,15 +141,13 @@ transform_xy_unit!("max/x" "max/y" "max/xy"|self: Max, area|{
|
||||||
Self::X(fw, _) => [x, y, *fw, h],
|
Self::X(fw, _) => [x, y, *fw, h],
|
||||||
Self::Y(fh, _) => [x, y, w, *fh],
|
Self::Y(fh, _) => [x, y, w, *fh],
|
||||||
Self::XY(fw, fh, _) => [x, y, *fw, *fh],
|
Self::XY(fw, fh, _) => [x, y, *fw, *fh],
|
||||||
_ => unreachable!(),
|
|
||||||
}.into())});
|
}.into())});
|
||||||
|
transform_xy_unit!("shrink/x" "shrink/y" "shrink/xy"|self: Shrink, area|Render::layout(
|
||||||
transform_xy_unit!("shrink/x" "shrink/y" "shrink/xy"|self: Shrink, area|Render::layout(&self.content(), [
|
&self.content(),
|
||||||
area.x(), area.y(), area.w().minus(self.dx()), area.h().minus(self.dy())
|
[area.x(), area.y(), area.w().minus(self.dx()), area.h().minus(self.dy())].into()));
|
||||||
].into()));
|
transform_xy_unit!("expand/x" "expand/y" "expand/xy"|self: Expand, area|Render::layout(
|
||||||
transform_xy_unit!("expand/x" "expand/y" "expand/xy"|self: Expand, area|Render::layout(&self.content(), [
|
&self.content(),
|
||||||
area.x(), area.y(), area.w() + self.dx(), area.h() + self.dy()
|
[area.x(), area.y(), area.w() + self.dx(), area.h() + self.dy()].into()));
|
||||||
].into()));
|
|
||||||
transform_xy_unit!("push/x" "push/y" "push/xy"|self: Push, area|{
|
transform_xy_unit!("push/x" "push/y" "push/xy"|self: Push, area|{
|
||||||
let area = Render::layout(&self.content(), area);
|
let area = Render::layout(&self.content(), area);
|
||||||
[area.x() + self.dx(), area.y() + self.dy(), area.w(), area.h()]
|
[area.x() + self.dx(), area.y() + self.dy(), area.w(), area.h()]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use std::{sync::Arc, marker::PhantomData};
|
use std::{sync::Arc, fmt::Debug};
|
||||||
use TokenKind::*;
|
use TokenKind::*;
|
||||||
/// Define an EDN-backed view.
|
/// Define an EDN-backed view.
|
||||||
///
|
///
|
||||||
|
|
@ -46,104 +46,112 @@ use TokenKind::*;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Renders from EDN source and context.
|
/// Renders from EDN source and context.
|
||||||
#[derive(Default)] pub enum AtomView<'a, E: Output, T: ViewContext<'a, E> + std::fmt::Debug> {
|
///
|
||||||
|
/// Generic over:
|
||||||
|
///
|
||||||
|
/// * `O` - Output target.
|
||||||
|
/// * `S` - State provider.
|
||||||
|
/// * `A` - Atom storage type.
|
||||||
|
#[derive(Default, Clone)] pub enum AtomView<'a, O, S, A> {
|
||||||
|
_Unused(std::marker::PhantomData<&'a O>),
|
||||||
#[default] Inert,
|
#[default] Inert,
|
||||||
Ok(T, Atom<Arc<str>>),
|
Src(S, &'a str),
|
||||||
//render: Box<dyn Fn(&'a T)->Box<dyn Render<E> + Send + Sync + 'a> + Send + Sync + 'a>
|
Ref(S, &'a A),
|
||||||
Err(String),
|
Own(S, A),
|
||||||
_Unused(PhantomData<&'a E>),
|
Err(Arc<str>)
|
||||||
}
|
}
|
||||||
impl<'a, E: Output, T: ViewContext<'a, E> + std::fmt::Debug> std::fmt::Debug for AtomView<'a, E, T> {
|
impl<'a, O, S, A> Debug for AtomView<'a, O, S, A>
|
||||||
|
where S: Debug, A: Debug {
|
||||||
fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||||
match self {
|
match self {
|
||||||
Self::Inert | Self::_Unused(_) =>
|
Self::Inert =>
|
||||||
write!(f, "AtomView::Inert"),
|
write!(f, "AtomView::Inert"),
|
||||||
Self::Ok(state, view) =>
|
Self::Src(state, view) =>
|
||||||
write!(f, "AtomView::Ok(state={state:?} view={view:?}"),
|
write!(f, "AtomView::Src(state={state:?} view={view:?}"),
|
||||||
|
Self::Ref(state, view) =>
|
||||||
|
write!(f, "AtomView::Ref(state={state:?} view={view:?}"),
|
||||||
|
Self::Own(state, view) =>
|
||||||
|
write!(f, "AtomView::Arc(state={state:?} view={view:?}"),
|
||||||
Self::Err(error) =>
|
Self::Err(error) =>
|
||||||
write!(f, "AtomView::Err({error})"),
|
write!(f, "AtomView::Err({error})"),
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a, E: Output, T> ViewContext<'a, E> for T where T:
|
impl<'a, O, S, A> Content<O> for AtomView<'a, O, S, A>
|
||||||
Context<'a, bool> +
|
where O: Output, S: ViewContext<'a, O>, A: Atom {
|
||||||
Context<'a, usize> +
|
fn content (&self) -> impl Render<O> {
|
||||||
Context<'a, E::Unit> +
|
|
||||||
Context<'a, Box<dyn Render<E> + 'a>>
|
|
||||||
{}
|
|
||||||
impl<'a, E: Output, T: ViewContext<'a, E> + std::fmt::Debug> AtomView<'a, E, T> {
|
|
||||||
pub fn from_source (state: T, source: &'a str) -> Self {
|
|
||||||
match RefAtom::read_one(&source) {
|
|
||||||
Ok((layout, _)) => Self::Ok(state, layout),
|
|
||||||
Err(error) => Self::Err(format!("{error} in {source}"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn from_atoms (state: T, atoms: Vec<impl Atom>) -> Self {
|
|
||||||
Self::Ok(state, Atom::Exp(atoms).to_arc())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<E: Output, T: for<'a>ViewContext<'a, E> + Send + Sync + std::fmt::Debug> Content<E> for AtomView<'_, E, T> {
|
|
||||||
fn content (&self) -> impl Render<E> {
|
|
||||||
match self {
|
match self {
|
||||||
Self::Ok(state, layout) => state.get_content(layout),
|
Self::Inert => { panic!("inert rendered") },
|
||||||
Self::Err(_error) => {
|
Self::Err(e) => { panic!("render error: {e}") },
|
||||||
panic!("{self:?}");
|
Self::Src(state, source) => {},
|
||||||
//TODO:&format!("AtomView error: {error:?}")) // FIXME: String is not Render
|
Self::Ref(state, atom) => {},
|
||||||
},
|
Self::Own(state, atom) => {},
|
||||||
_ => todo!()
|
_ => unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<'a, E: Output, T> ViewContext<'a, E> for T where T: Sized + Send + Sync
|
||||||
|
+ Context<bool>
|
||||||
|
+ Context<usize>
|
||||||
|
+ Context<E::Unit>
|
||||||
|
+ Context<Box<dyn Render<E> + 'a>> {}
|
||||||
/// Provides values to the template
|
/// Provides values to the template
|
||||||
pub trait ViewContext<'a, E: Output>:
|
pub trait ViewContext<'a, E: Output>: Sized + Send + Sync
|
||||||
Context<'a, bool> +
|
+ Context<bool>
|
||||||
Context<'a, usize> +
|
+ Context<usize>
|
||||||
Context<'a, E::Unit> +
|
+ Context<E::Unit>
|
||||||
Context<'a, Box<dyn Render<E> + 'a>>
|
+ Context<Box<dyn Render<E> + 'a>>
|
||||||
{
|
{
|
||||||
fn get_bool (&'a self, atom: RefAtom<'a>) -> Option<bool> {
|
fn get_bool (&self, atom: &impl Atom) -> Option<bool> {
|
||||||
Some(match atom.kind() {
|
Some(match atom.kind() {
|
||||||
Sym => match atom.text().as_ref() {
|
Num => match atom.num() { 0 => false, _ => true },
|
||||||
":false" | ":f" => false,
|
Sym => match atom.text() {
|
||||||
":true" | ":t" => true,
|
":false" | ":f" => false, ":true" | ":t" => true,
|
||||||
_ => return Context::get(self, atom)
|
_ => return Context::get(self, atom)
|
||||||
},
|
},
|
||||||
Num => match atom.num() {
|
|
||||||
0 => false,
|
|
||||||
_ => true
|
|
||||||
},
|
|
||||||
_ => return Context::get(self, atom)
|
_ => return Context::get(self, atom)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn get_usize (&'a self, atom: RefAtom<'a>) -> Option<usize> {
|
fn get_usize (&self, atom: &impl Atom) -> Option<usize> {
|
||||||
Some(match atom.kind() {
|
Some(match atom.kind() {
|
||||||
Num => atom.num(),
|
Num => atom.num(),
|
||||||
_ => return Context::get(self, atom)
|
_ => return Context::get(self, atom)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn get_unit (&'a self, atom: RefAtom<'a>) -> Option<E::Unit> {
|
fn get_unit (&self, atom: &impl Atom) -> Option<E::Unit> {
|
||||||
Some(match atom.kind() {
|
Some(match atom.kind() {
|
||||||
Num => E::Unit::from(atom.num() as u16),
|
Num => E::Unit::from(atom.num() as u16),
|
||||||
_ => return Context::get(self, atom)
|
_ => return Context::get(self, atom)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn get_content (&'a self, atom: RefAtom<'a>) -> Option<Box<dyn Render<E> + 'a>> where E: 'a {
|
fn get_content (&self, atom: &impl Atom) -> Option<Box<dyn Render<E> + 'a>> where E: 'a {
|
||||||
try_delegate!(self, atom, When::<_, RenderBox<'a, E>>);
|
try_delegate!(self, atom, When::<RenderBox<'a, E>>);
|
||||||
try_delegate!(self, atom, Either::<_, RenderBox<'a, E>, RenderBox<'a, E>>);
|
try_delegate!(self, atom, Either::<RenderBox<'a, E>, RenderBox<'a, E>>);
|
||||||
try_delegate!(self, atom, Align::<_, RenderBox<'a, E>>);
|
try_delegate!(self, atom, Align::<RenderBox<'a, E>>);
|
||||||
try_delegate!(self, atom, Bsp::<_, RenderBox<'a, E>, RenderBox<'a, E>>);
|
try_delegate!(self, atom, Bsp::<RenderBox<'a, E>, RenderBox<'a, E>>);
|
||||||
try_delegate!(self, atom, Fill::<_, RenderBox<'a, E>>);
|
try_delegate!(self, atom, Fill::<RenderBox<'a, E>>);
|
||||||
try_delegate!(self, atom, Fixed::<_, _, RenderBox<'a, E>>);
|
try_delegate!(self, atom, Fixed::<_, RenderBox<'a, E>>);
|
||||||
try_delegate!(self, atom, Min::<_, _, RenderBox<'a, E>>);
|
try_delegate!(self, atom, Min::<_, RenderBox<'a, E>>);
|
||||||
try_delegate!(self, atom, Max::<_, _, RenderBox<'a, E>>);
|
try_delegate!(self, atom, Max::<_, RenderBox<'a, E>>);
|
||||||
try_delegate!(self, atom, Shrink::<_, _, RenderBox<'a, E>>);
|
try_delegate!(self, atom, Shrink::<_, RenderBox<'a, E>>);
|
||||||
try_delegate!(self, atom, Expand::<_, _, RenderBox<'a, E>>);
|
try_delegate!(self, atom, Expand::<_, RenderBox<'a, E>>);
|
||||||
try_delegate!(self, atom, Push::<_, _, RenderBox<'a, E>>);
|
try_delegate!(self, atom, Push::<_, RenderBox<'a, E>>);
|
||||||
try_delegate!(self, atom, Pull::<_, _, RenderBox<'a, E>>);
|
try_delegate!(self, atom, Pull::<_, RenderBox<'a, E>>);
|
||||||
try_delegate!(self, atom, Margin::<_, _, RenderBox<'a, E>>);
|
try_delegate!(self, atom, Margin::<_, RenderBox<'a, E>>);
|
||||||
try_delegate!(self, atom, Padding::<_, _, RenderBox<'a, E>>);
|
try_delegate!(self, atom, Padding::<_, RenderBox<'a, E>>);
|
||||||
Context::get_or_fail(self, atom)
|
Some(Context::get_or_fail(self, atom))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[macro_export] macro_rules! try_delegate {
|
||||||
|
($s:ident, $atom:expr, $T:ty) => {
|
||||||
|
if $atom.kind() == TokenKind::Exp {
|
||||||
|
if let [head, tail @ ..] = $atom.as_slice() {
|
||||||
|
if let Some(value) = <$T>::try_from_atoms($s, head, tail) {
|
||||||
|
return Some(value.boxed())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// A function that returns a `RenderBox.
|
// A function that returns a `RenderBox.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue