diff --git a/dsl/src/dsl_provide.rs b/dsl/src/dsl_provide.rs index 85e622d..d63426e 100644 --- a/dsl/src/dsl_provide.rs +++ b/dsl/src/dsl_provide.rs @@ -3,117 +3,144 @@ use crate::*; // maybe their names should be switched around? /// [Take]s instances of [Type] given [TokenIter]. -pub trait Give { +pub trait Give<'state, Type> { /// Implement this to be able to [Give] [Type] from the [TokenIter]. - fn give <'source> (&self, words: &mut TokenIter<'source>) -> Perhaps; + fn give <'source: 'state> (&self, words: TokenIter<'source>) -> Perhaps; /// Return custom error on [None]. - fn give_or_fail <'source, E: Into>, F: Fn()->E> ( - &self, words: &mut TokenIter<'source>, error: F + fn give_or_fail <'source: 'state, E: Into>, F: Fn()->E> ( + &self, mut words: TokenIter<'source>, error: F ) -> Usually { + let next = words.peek().map(|x|x.value).clone(); if let Some(value) = Give::::give(self, words)? { Ok(value) } else { - Result::Err(format!("give: {}: {:?}", error().into(), words.peek().map(|x|x.value)).into()) + Result::Err(format!("give: {}: {next:?}", error().into()).into()) } } } -/// [Give]s instances of [Self] given [TokenIter]. -pub trait Take<'n, State>: Sized + 'n { - fn take <'source> (state: &State, words: &mut TokenIter<'source>) -> Perhaps; - /// Return custom error on [None]. - fn take_or_fail <'source, E: Into>, F: Fn()->E> ( - state: &State, words: &mut TokenIter<'source>, error: F - ) -> Usually { - if let Some(value) = Take::::take(state, words)? { - Ok(value) - } else { - Result::Err(format!("take: {}: {:?}", error().into(), words.peek().map(|x|x.value)).into()) - } - } -} - -#[macro_export] macro_rules! take { - () => { - impl<'n, Type: 'n, State: Give + 'n> Take<'n, State> for Type { - fn take <'source> (state: &State, words: &mut TokenIter<'source>) -> Perhaps { - state.give(words) - } - } - }; - (box) => { - impl<'n, T, State: Give> + 'n> Take<'n, State> for Box { - fn take <'source> (state: &State, words: &mut TokenIter<'source>) -> Perhaps { - state.give(words) - } - } - }; - ($Type:ty:$State:ty) => { - impl<'n> Take<'n, $State> for $Type { - fn take <'source> (state: &$State, words: &mut TokenIter<'source>) -> Perhaps { - state.give(words) - } - } - }; - ($Type:path$(,$Arg:ident)*|$state:ident:$State:path,$words:ident|$expr:expr) => { - impl<'n, State: $State + 'n $(, $Arg: 'n)*> Take<'n, State> for $Type { - fn take <'source> ($state: &State, $words: &mut TokenIter<'source>) -> Perhaps { - $expr - } - } - }; -} #[macro_export] macro_rules! give { () => { - impl<'n, Type: Take<'n, State>, State> Give for State { - fn give <'source> (&self, words: &mut TokenIter<'source>) -> Perhaps { + impl<'state, Type: Take<'state, State>, State> Give<'state, Type> for State { + fn give <'source: 'state> (&self, mut words:TokenIter<'source>) -> Perhaps { Type::take(self, words) } } }; (box) => { - //impl<'n, T, Type: Take<'n, Box>> Give> for Box { - //fn give <'source> (&self, words: &mut TokenIter<'source>) -> Perhaps> { + //impl<'state, T, Type: Take<'state, Box>> Give<'state, Box> for Box { + //fn give (&self, mut words:TokenIter<'source>) -> Perhaps> { //Type::take(self, words) //} //} }; ($Type:ty: $State:ty) => { - impl<'n, $Type: Take<'n, $State>> Give<$Type> for $State { - fn give <'source> (&self, words: &mut TokenIter<'source>) -> Perhaps<$Type> { + impl<'state, $Type: Take<'state, $State>> Give<'state, $Type> for $State { + fn give <'source: 'state> (&self, mut words:TokenIter<'source>) -> Perhaps<$Type> { $Type::take(self, words) } } }; ($Type:ty|$state:ident:$State:ident,$words:ident|$expr:expr) => { - impl Give<$Type> for $State { - fn give <'source> (&self, $words: &mut TokenIter<'source>) -> Perhaps<$Type> { + impl<'state> Give<'state, $Type> for $State { + fn give <'source: 'state> (&self, mut $words:TokenIter<'source>) -> Perhaps<$Type> { let $state = self; $expr } } }; + ($Type:path$(,$Arg:ident)*|$state:ident,$words:ident|$expr:expr) => { + impl<'state, State: $(Give<'state, $Arg> +)* 'state $(, $Arg)*> Give<'state, $Type> for State { + fn give <'source: 'state> (&self, mut $words:TokenIter<'source>) -> Perhaps<$Type> { + let $state = self; + $expr + } + } + } +} +/// [Give]s instances of [Self] given [TokenIter]. +pub trait Take<'state, State>: Sized { + fn take <'source: 'state> (state: &State, words: TokenIter<'source>) -> Perhaps; + /// Return custom error on [None]. + fn take_or_fail <'source: 'state, E: Into>, F: Fn()->E> ( + state: &State, mut words:TokenIter<'source>, error: F + ) -> Usually { + let next = words.peek().map(|x|x.value).clone(); + if let Some(value) = Take::::take(state, words)? { + Ok(value) + } else { + Result::Err(format!("take: {}: {next:?}", error().into()).into()) + } + } +} +#[macro_export] macro_rules! take { + () => { + impl<'state, Type: 'state, State: Give<'state, Type> + 'state> Take<'state, State> for Type { + fn take <'source: 'state> (state: &State, mut words:TokenIter<'source>) -> Perhaps { + state.give(words) + } + } + }; + (box) => { + impl<'state, T, State: Give<'state, Box> + 'state> Take<'state, State> for Box { + fn take <'source: 'state> (state: &State, mut words:TokenIter<'source>) -> Perhaps { + state.give(words) + } + } + }; + ($Type:ty:$State:ty) => { + impl<'state> Take<'state, $State> for $Type { + fn take <'source: 'state> (state: &$State, mut words:TokenIter<'source>) -> Perhaps { + state.give(words) + } + } + }; + ($Type:path$(,$Arg:ident)*|$state:ident,$words:ident|$expr:expr) => { + impl<'state, + State: Give<'state, bool> + $(Give<'state, $Arg> + )* 'state + $(, $Arg: Take<'state, State> + 'state)* + > Take<'state, State> for $Type { + fn take <'source: 'state> ($state: &State, mut $words:TokenIter<'source>) -> Perhaps { + $expr + } + } + }; + ($Type:path$(,$Arg:ident)*|$state:ident:$State:path,$words:ident|$expr:expr) => { + impl<'state $(, $Arg: 'state)*> Take<'state, $State> for $Type { + fn take <'source: 'state> ($state: &$State, mut $words:TokenIter<'source>) -> Perhaps { + $expr + } + } + }; +} + +#[cfg(feature="dsl")] +impl<'state, E: 'state, State: Give<'state, Box + 'state>>> +Take<'state, State> for Box + 'state> { + fn take <'source: 'state> (state: &State, words: TokenIter<'source>) -> Perhaps { + state.give(words) + } } /// Implement the [Give] trait, which boils down to /// specifying two types and providing an expression. #[macro_export] macro_rules! from_dsl { (@a: $T:ty: |$state:ident, $words:ident|$expr:expr) => { - impl<'n, State, A: Take<'n, State>> Take<'n, State> for $T { - fn take <'source> ($state: &State, $words: &mut TokenIter<'source>) -> Perhaps<$T> { + impl<'state, State, A: Take<'state, State>> Take<'state, State> for $T { + fn take <'source: 'state> ($state: &State, mut $words:TokenIter<'source>) -> Perhaps<$T> { $expr } } }; (@ab: $T:ty: |$state:ident, $words:ident|$expr:expr) => { - impl<'n, State, A: Take<'n, State>, B: Take<'n, State>> Take<'n, State> for $T { - fn take <'source> ($state: &State, $words: &mut TokenIter<'source>) -> Perhaps<$T> { + impl<'state, State, A: Take<'state, State>, B: Take<'state, State>> Take<'state, State> for $T { + fn take <'source: 'state> ($state: &State, mut $words:TokenIter<'source>) -> Perhaps<$T> { $expr } } }; ($T:ty: |$state:ident:$S:ty, $words:ident|$expr:expr) => { - impl<'n> Take<'n, $S> for $T { - fn take <'source> ($state: &$S, $words: &mut TokenIter<'source>) -> Perhaps<$T> { + impl<'state> Take<'state, $S> for $T { + fn take <'source: 'state> ($state: &$S, mut $words:TokenIter<'source>) -> Perhaps<$T> { $expr } } @@ -122,16 +149,16 @@ pub trait Take<'n, State>: Sized + 'n { // auto impl graveyard: -//impl<'n, State: Give, Type: 'n> Take<'n, State> for Type { - //fn take <'source> (state: &State, words: &mut TokenIter<'source>) +//impl<'state, State: Give, Type: 'state> Take<'state, State> for Type { + //fn take <'state> (state: &State, mut words:TokenIter<'source>) //-> Perhaps //{ //state.take(words) //} //} -//impl<'n, Type: Take<'n, State>, State> Give for State { - //fn take <'source> (&self, words: &mut TokenIter<'source>) -> Perhaps { +//impl<'state, Type: Take<'state, State>, State> Give for State { + //fn take <'state> (&self, mut words:TokenIter<'source>) -> Perhaps { //Type::take(self, words) //} //} diff --git a/input/src/input_dsl.rs b/input/src/input_dsl.rs index 79334f4..9c08545 100644 --- a/input/src/input_dsl.rs +++ b/input/src/input_dsl.rs @@ -22,7 +22,7 @@ impl<'k, S, C: Take<'k, S> + Command, I: DslInput> KeyMap<'k, S, C, I> for So match exp_iter.next() { Some(Token { value: Value::Sym(binding), .. }) => { if input.matches_dsl(binding) { - if let Some(command) = Take::take(state, &mut exp_iter)? { + if let Some(command) = Take::take(state, exp_iter)? { return Ok(Some(command)) } } @@ -48,7 +48,7 @@ impl<'k, S, C: Take<'k, S> + Command, I: DslInput> KeyMap<'k, S, C, I> for To match e.next() { Some(Token { value: Value::Sym(binding), .. }) => { if input.matches_dsl(binding) { - if let Some(command) = Take::take(state, &mut e)? { + if let Some(command) = Take::take(state, e)? { return Ok(Some(command)) } } diff --git a/output/src/ops/align.rs b/output/src/ops/align.rs index 1626da5..ffd5b48 100644 --- a/output/src/ops/align.rs +++ b/output/src/ops/align.rs @@ -31,32 +31,38 @@ use crate::*; #[derive(Debug, Copy, Clone, Default)] pub enum Alignment { #[default] Center, X, Y, NW, N, NE, E, SE, S, SW, W } pub struct Align(Alignment, A); -#[cfg(feature = "dsl")]take!(Align, A|state: Give, words|Ok(Some(match words.peek() { - Some(Token { value: Value::Key(key), .. }) => match key { - "align/c"|"align/x"|"align/y"| - "align/n"|"align/s"|"align/e"|"al;qign/w"| - "align/nw"|"align/sw"|"align/ne"|"align/se" => { - let _ = words.next().unwrap(); - let content = state.give_or_fail(&mut words.clone(), ||"expected content")?; - match key { - "align/c" => Self::c(content), - "align/x" => Self::x(content), - "align/y" => Self::y(content), - "align/n" => Self::n(content), - "align/s" => Self::s(content), - "align/e" => Self::e(content), - "align/w" => Self::w(content), - "align/nw" => Self::nw(content), - "align/ne" => Self::ne(content), - "align/sw" => Self::sw(content), - "align/se" => Self::se(content), - _ => unreachable!() - } - }, - _ => return Ok(None) - }, - _ => return Ok(None) -}))); +#[cfg(feature = "dsl")] +impl<'state, State: Give<'state, A>, A: 'state> Take<'state, State> for Align { + fn take <'source: 'state> (state: &State, words: TokenIter<'source>) -> Perhaps { + todo!() + } +} +//give!(Align, A|state, words|Ok(Some(match words.peek() { + //Some(Token { value: Value::Key(key), .. }) => match key { + //"align/c"|"align/x"|"align/y"| + //"align/n"|"align/s"|"align/e"|"al;qign/w"| + //"align/nw"|"align/sw"|"align/ne"|"align/se" => { + //let _ = words.next().unwrap(); + //let content = Take::take_or_fail(state, &mut words.clone(), ||"expected content")?; + //match key { + //"align/c" => Self::c(content), + //"align/x" => Self::x(content), + //"align/y" => Self::y(content), + //"align/n" => Self::n(content), + //"align/s" => Self::s(content), + //"align/e" => Self::e(content), + //"align/w" => Self::w(content), + //"align/nw" => Self::nw(content), + //"align/ne" => Self::ne(content), + //"align/sw" => Self::sw(content), + //"align/se" => Self::se(content), + //_ => unreachable!() + //} + //}, + //_ => return Ok(None) + //}, + //_ => return Ok(None) +//}))); impl Align { #[inline] pub const fn c (a: A) -> Self { Self(Alignment::Center, a) } diff --git a/output/src/ops/bsp.rs b/output/src/ops/bsp.rs index 9ecd6d7..e714f8e 100644 --- a/output/src/ops/bsp.rs +++ b/output/src/ops/bsp.rs @@ -20,34 +20,29 @@ impl, B: Content> Content for Bsp { } } } -#[cfg(feature = "dsl")] -impl<'n, State: Give + Give, A: 'n, B: 'n> Take<'n, State> for Bsp { - fn take <'source> (state: &State, words: &mut TokenIter<'source>) -> Perhaps { - Ok(if let Some(Token { - value: Value::Key("bsp/n"|"bsp/s"|"bsp/e"|"bsp/w"|"bsp/a"|"bsp/b"), - .. - }) = words.peek() { - if let Value::Key(key) = words.next().unwrap().value() { - let base = words.clone(); - let a: A = state.give_or_fail(words, ||"bsp: expected content 1")?; - let b: B = state.give_or_fail(words, ||"bsp: expected content 2")?; - return Ok(Some(match key { - "bsp/n" => Self::n(a, b), - "bsp/s" => Self::s(a, b), - "bsp/e" => Self::e(a, b), - "bsp/w" => Self::w(a, b), - "bsp/a" => Self::a(a, b), - "bsp/b" => Self::b(a, b), - _ => unreachable!(), - })) - } else { - unreachable!() - } - } else { - None - }) +#[cfg(feature = "dsl")] take!(Bsp, A, B|state, words|Ok(if let Some(Token { + value: Value::Key("bsp/n"|"bsp/s"|"bsp/e"|"bsp/w"|"bsp/a"|"bsp/b"), + .. +}) = words.peek() { + if let Value::Key(key) = words.next().unwrap().value() { + let base = words.clone(); + let a: A = state.give_or_fail(words, ||"bsp: expected content 1")?; + let b: B = state.give_or_fail(words, ||"bsp: expected content 2")?; + return Ok(Some(match key { + "bsp/n" => Self::n(a, b), + "bsp/s" => Self::s(a, b), + "bsp/e" => Self::e(a, b), + "bsp/w" => Self::w(a, b), + "bsp/a" => Self::a(a, b), + "bsp/b" => Self::b(a, b), + _ => unreachable!(), + })) + } else { + unreachable!() } -} +} else { + None +})); impl Bsp { #[inline] pub const fn n (a: A, b: B) -> Self { Self(North, a, b) } #[inline] pub const fn s (a: A, b: B) -> Self { Self(South, a, b) } diff --git a/output/src/ops/either.rs b/output/src/ops/either.rs index a35d555..29ab0e8 100644 --- a/output/src/ops/either.rs +++ b/output/src/ops/either.rs @@ -8,21 +8,18 @@ impl Either { Self(c, a, b) } } -#[cfg(feature = "dsl")] -impl<'n, State: Give + Give + Give, A: 'n, B: 'n> Take<'n, State> for Either { - fn take <'source> (state: &State, token: &mut TokenIter<'source>) -> Perhaps { - if let Some(Token { value: Value::Key("either"), .. }) = token.peek() { - let base = token.clone(); - let _ = token.next().unwrap(); - return Ok(Some(Self( - state.give_or_fail(token, ||"either: no condition")?, - state.give_or_fail(token, ||"either: no content 1")?, - state.give_or_fail(token, ||"either: no content 2")?, - ))) - } - Ok(None) - } -} +#[cfg(feature = "dsl")] take!(Either, A, B|state, words|Ok( +if let Some(Token { value: Value::Key("either"), .. }) = words.peek() { + let base = words.clone(); + let _ = words.next().unwrap(); + return Ok(Some(Self( + state.give_or_fail(words, ||"either: no condition")?, + state.give_or_fail(words, ||"either: no content 1")?, + state.give_or_fail(words, ||"either: no content 2")?, + ))) +} else { + None +})); impl, B: Render> Content for Either { fn layout (&self, to: E::Area) -> E::Area { let Self(cond, a, b) = self; diff --git a/output/src/ops/transform.rs b/output/src/ops/transform.rs index 5e0ec04..593a518 100644 --- a/output/src/ops/transform.rs +++ b/output/src/ops/transform.rs @@ -32,26 +32,19 @@ macro_rules! transform_xy { #[inline] pub const fn y (item: A) -> Self { Self::Y(item) } #[inline] pub const fn xy (item: A) -> Self { Self::XY(item) } } - #[cfg(feature = "dsl")] - impl<'n, A: 'n, T: Give> Take<'n, T> for $Enum { - fn take <'source> (state: &T, token: &mut TokenIter<'source>) - -> Perhaps - { - if let Some(Token { value: Value::Key(k), .. }) = token.peek() { - let mut base = token.clone(); - return Ok(Some(match token.next() { - Some(Token{value:Value::Key($x),..}) => - Self::x(state.give_or_fail(token, ||"x: no content")?), - Some(Token{value:Value::Key($y),..}) => - Self::y(state.give_or_fail(token, ||"y: no content")?), - Some(Token{value:Value::Key($xy),..}) => - Self::xy(state.give_or_fail(token, ||"xy: no content")?), - _ => unreachable!() - })) - } - Ok(None) - } - } + #[cfg(feature = "dsl")] take!($Enum, A|state, words|Ok( + if let Some(Token { value: Value::Key(k), .. }) = words.peek() { + let mut base = words.clone(); + let content = state.give_or_fail(words, ||format!("{k}: no content"))?; + return Ok(Some(match words.next() { + Some(Token{value: Value::Key($x),..}) => Self::x(content), + Some(Token{value: Value::Key($y),..}) => Self::y(content), + Some(Token{value: Value::Key($xy),..}) => Self::xy(content), + _ => unreachable!() + })) + } else { + None + })); impl> Content for $Enum { fn content (&self) -> impl Render + '_ { match self { @@ -78,56 +71,45 @@ macro_rules! transform_xy_unit { #[inline] pub const fn y (y: U, item: A) -> Self { Self::Y(y, item) } #[inline] pub const fn xy (x: U, y: U, item: A) -> Self { Self::XY(x, y, item) } } - #[cfg(feature = "dsl")] - impl<'n, A: 'n, U: Coordinate + 'n, T: Give + Give> Take<'n, T> for $Enum { - fn take <'source> ( - state: &T, token: &mut TokenIter<'source> - ) -> Perhaps { - Ok(if let Some(Token { value: Value::Key($x|$y|$xy), .. }) = token.peek() { - let mut base = token.clone(); - Some(match token.next() { - Some(Token { value: Value::Key($x), .. }) => Self::x( - state.give_or_fail(token, ||"x: no unit")?, - state.give_or_fail(token, ||"x: no content")?, - ), - Some(Token { value: Value::Key($y), .. }) => Self::y( - state.give_or_fail(token, ||"y: no unit")?, - state.give_or_fail(token, ||"y: no content")?, - ), - Some(Token { value: Value::Key($x), .. }) => Self::xy( - state.give_or_fail(token, ||"xy: no unit x")?, - state.give_or_fail(token, ||"xy: no unit y")?, - state.give_or_fail(token, ||"xy: no content")? - ), - _ => unreachable!(), - }) - } else { - None + #[cfg(feature = "dsl")] take!($Enum, U, A|state, words|Ok( + if let Some(Token { value: Value::Key($x|$y|$xy), .. }) = words.peek() { + let mut base = words.clone(); + Some(match words.next() { + Some(Token { value: Value::Key($x), .. }) => Self::x( + state.give_or_fail(words, ||"x: no unit")?, + state.give_or_fail(words, ||"x: no content")?, + ), + Some(Token { value: Value::Key($y), .. }) => Self::y( + state.give_or_fail(words, ||"y: no unit")?, + state.give_or_fail(words, ||"y: no content")?, + ), + Some(Token { value: Value::Key($x), .. }) => Self::xy( + state.give_or_fail(words, ||"xy: no unit x")?, + state.give_or_fail(words, ||"xy: no unit y")?, + state.give_or_fail(words, ||"xy: no content")? + ), + _ => unreachable!(), }) - } - } + } else { + None + })); impl> Content for $Enum { - fn content (&self) -> impl Render + '_ { - Some(match self { - Self::X(_, content) => content, - Self::Y(_, content) => content, - Self::XY(_, _, content) => content, - }) - } fn layout (&$self, $to: E::Area) -> E::Area { $layout.into() } + fn content (&self) -> impl Render + '_ { + use $Enum::*; + Some(match self { X(_, c) => c, Y(_, c) => c, XY(_, _, c) => c, }) + } } - impl $Enum { + impl $Enum { #[inline] pub fn dx (&self) -> U { - match self { - Self::X(x, _) => *x, Self::Y(_, _) => 0.into(), Self::XY(x, _, _) => *x, - } + use $Enum::*; + match self { X(x, _) => *x, Y(_, _) => 0.into(), XY(x, _, _) => *x, } } #[inline] pub fn dy (&self) -> U { - match self { - Self::X(_, _) => 0.into(), Self::Y(y, _) => *y, Self::XY(_, y, _) => *y, - } + use $Enum::*; + match self { X(_, _) => 0.into(), Y(y, _) => *y, XY(_, y, _) => *y, } } } } diff --git a/output/src/ops/when.rs b/output/src/ops/when.rs index db295ab..6324900 100644 --- a/output/src/ops/when.rs +++ b/output/src/ops/when.rs @@ -1,33 +1,22 @@ use crate::*; - /// Show an item only when a condition is true. pub struct When(pub bool, pub A); - impl When { /// Create a binary condition. pub const fn new (c: bool, a: A) -> Self { Self(c, a) } } - -#[cfg(feature = "dsl")] -impl<'n, State: Give, A: Take<'n, State>> Take<'n, State> for When { - fn take <'source> (state: &State, words: &mut TokenIter<'source>) -> Perhaps { - Ok(if let Some(Token { - value: Value::Key("when"), - .. - }) = words.peek() { - let _ = words.next(); - let base = words.clone(); - return Ok(Some(Self( - state.give_or_fail(words, ||"cond: no condition")?, - A::take_or_fail(state, words, ||"cond: no content")?, - ))) - } else { - None - }) - } -} +#[cfg(feature = "dsl")]take!(When, A|state, words|Ok(Some(match words.peek() { + Some(Token { value: Value::Key("when"), .. }) => { + let _ = words.next(); + let base = words.clone(); + let cond = state.give_or_fail(words, ||"cond: no condition")?; + let cont = state.give_or_fail(words, ||"cond: no content")?; + Self(cond, cont) + }, + _ => return Ok(None) +}))); impl> Content for When { fn layout (&self, to: E::Area) -> E::Area { diff --git a/proc/src/proc_command.rs b/proc/src/proc_command.rs index b8cf812..ddbc205 100644 --- a/proc/src/proc_command.rs +++ b/proc/src/proc_command.rs @@ -149,10 +149,9 @@ impl ToTokens for CommandDef { } } /// Generated by [tengri_proc::command]. - impl<'n> ::tengri::dsl::Take<'n, #state> for #command_enum { - fn take <'source> ( - state: &#state, - words: &mut ::tengri::dsl::TokenIter<'source> + impl<'state> ::tengri::dsl::Take<'state, #state> for #command_enum { + fn take <'source: 'state> ( + state: &#state, mut words: ::tengri::dsl::TokenIter<'source> ) -> Perhaps { let mut words = words.clone(); let token = words.next(); diff --git a/proc/src/proc_expose.rs b/proc/src/proc_expose.rs index 11f4c03..4d0b928 100644 --- a/proc/src/proc_expose.rs +++ b/proc/src/proc_expose.rs @@ -9,9 +9,6 @@ pub(crate) struct ExposeMeta; #[derive(Debug, Clone)] pub(crate) struct ExposeImpl(ItemImpl, BTreeMap>); -#[derive(Debug, Clone)] -struct ExposeArm(String, Ident); - #[derive(Debug, Clone)] struct ExposeSym(LitStr); @@ -82,13 +79,23 @@ impl ToTokens for ExposeImpl { }, _ => quote! {}, }; - let values = variants.iter().map(ExposeArm::from); + let values = variants.iter().map(|(key, value)|{ + let key = LitStr::new(&key, Span::call_site()); + quote! { Some(::tengri::dsl::Value::Sym(#key)) => state.#value(), } + }); write_quote_to(out, quote! { + /// Generated by [tengri_proc::expose]. + impl<'n> ::tengri::dsl::Give<'n, #t> for #state { + fn give <'source: 'n> ( + &self, words: ::tengri::dsl::TokenIter<'source> + ) -> Perhaps<#t> { + Take::take(self, words) + } + } /// Generated by [tengri_proc::expose]. impl<'n> ::tengri::dsl::Take<'n, #state> for #t { - fn take <'source> ( - state: &#state, - words: &mut ::tengri::dsl::TokenIter<'source> + fn take <'source: 'n> ( + state: &#state, mut words: ::tengri::dsl::TokenIter<'source> ) -> Perhaps { Ok(Some(match words.next().map(|x|x.value) { #predefined @@ -105,22 +112,6 @@ impl ToTokens for ExposeImpl { } } -impl From<(&String, &Ident)> for ExposeArm { - fn from ((a, b): (&String, &Ident)) -> Self { - Self(a.clone(), b.clone()) - } -} - -impl ToTokens for ExposeArm { - fn to_tokens (&self, out: &mut TokenStream2) { - let Self(key, value) = self; - let key = LitStr::new(&key, Span::call_site()); - write_quote_to(out, quote! { - Some(::tengri::dsl::Value::Sym(#key)) => state.#value(), - }) - } -} - impl From for ExposeSym { fn from (this: LitStr) -> Self { Self(this) } } impl PartialOrd for ExposeSym { diff --git a/proc/src/proc_view.rs b/proc/src/proc_view.rs index 08d1684..f16852f 100644 --- a/proc/src/proc_view.rs +++ b/proc/src/proc_view.rs @@ -43,52 +43,38 @@ impl ToTokens for ViewDef { let self_ty = &block.self_ty; // Expressions are handled by built-in functions // that operate over constants and symbols. - let builtins: Vec<_> = builtins_with_types().iter().map(|ty|write_quote(quote! { - ::tengri::dsl::Value::Exp(_, expr) => { - Give::<#ty>::give(&mut expr.clone()).map(|value|value.boxed()) - }, - })).collect(); + let builtin = builtins_with_types().map(|ty|write_quote(quote! { #ty })); // Symbols are handled by user-taked functions // that take no parameters but `&self`. - let exposed: Vec<_> = exposed.iter().map(|(key, value)|write_quote(quote! { - ::tengri::dsl::Value::Sym(#key) => { - Some(Box::new(Thunk::new(move||#self_ty::#value(self)))) - }, - })).collect(); + let exposed = exposed.iter().map(|(key, value)|write_quote(quote! { + ::tengri::dsl::Value::Sym(#key) => Some(Box::new(Thunk::new( + move||#self_ty::#value(state))))})); write_quote_to(out, quote! { /// Generated by [tengri_proc]. /// /// Gives [#self_ty] the ability to construct the [Render]able /// which might corresponds to a given [TokenStream], /// while taking [#self_ty]'s state into consideration. - give!(Box>|state:#self_ty, words|Ok(None)); - //impl <'n, State: ::tengri::dsl::Give>>> - //Take<'n, Box> for #self_ty - //{ - //fn give <'source> (&self, words: &mut ::tengri::dsl::TokenIter<'source>) - //-> Perhaps>> - //{ - //Ok(if let Some(::tengri::dsl::Token { value, .. }) = words.peek() { - //match value { - //// Expressions are handled by built-in functions - //// that operate over constants and symbols. - //::tengri::dsl::Value::Exp(_, exp) => { - //#(#builtins)* - //None - //}, - //// Symbols are handled by user-taked functions - //// that take no parameters but `&self`. - //::tengri::dsl::Value::Sym(sym) => match sym { - //#(#exposed)* - //_ => None - //}, - //_ => None - //} - //} else { - //None - //}) - //} - //} + impl<'state> Give<'state, Box + 'state>> for #self_ty { + fn give <'source: 'state> (&self, mut words: TokenIter<'source>) + -> Perhaps + 'state>> + { + let state = self; + Ok(if let Some(::tengri::dsl::Token { value, .. }) = words.peek() { + match value { + #(::tengri::dsl::Value::Exp(_, expr) => { + #builtin::take(state, expr)?.map(|value|value.boxed()) + },)* + #( + #exposed, + )* + _ => None + } + } else { + None + }) + } + } /// Generated by [tengri_proc]. /// /// Delegates the rendering of [#self_ty] to the [#self_ty::view} method, @@ -105,21 +91,21 @@ impl ToTokens for ViewDef { } } -fn builtins_with_types () -> [TokenStream2;14] { +fn builtins_with_types () -> impl Iterator { [ - quote! { When< Box + '_> > }, - quote! { Either< Box + '_>, Box + '_>> }, - quote! { Align< Box + '_> > }, - quote! { Bsp< Box + '_>, Box + '_>> }, - quote! { Fill< Box + '_> > }, - quote! { Fixed<_, Box + '_> > }, - quote! { Min<_, Box + '_> > }, - quote! { Max<_, Box + '_> > }, - quote! { Shrink<_, Box + '_> > }, - quote! { Expand<_, Box + '_> > }, - quote! { Push<_, Box + '_> > }, - quote! { Pull<_, Box + '_> > }, - quote! { Margin<_, Box + '_> > }, - quote! { Padding<_, Box + '_> > }, - ] + quote! { When::< Box> > }, + quote! { Either::< Box>, Box>> }, + quote! { Align::< Box> > }, + quote! { Bsp::< Box>, Box>> }, + quote! { Fill::< Box> > }, + quote! { Fixed::<_, Box> > }, + quote! { Min::<_, Box> > }, + quote! { Max::<_, Box> > }, + quote! { Shrink::<_, Box> > }, + quote! { Expand::<_, Box> > }, + quote! { Push::<_, Box> > }, + quote! { Pull::<_, Box> > }, + quote! { Margin::<_, Box> > }, + quote! { Padding::<_, Box> > }, + ].into_iter() }