diff --git a/Cargo.lock b/Cargo.lock index 0df7fbe..d9ccc29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -998,6 +998,7 @@ dependencies = [ "tengri_dsl", "tengri_input", "tengri_output", + "tengri_proc", "unicode-width 0.2.0", ] diff --git a/dsl/src/dsl_macros.rs b/dsl/src/dsl_macros.rs index 338583f..93b2cea 100644 --- a/dsl/src/dsl_macros.rs +++ b/dsl/src/dsl_macros.rs @@ -24,127 +24,6 @@ } } -/// Implement `Context` for one or more base structs, types, and keys. */ -#[macro_export] macro_rules! expose { - ($([$self:ident:$State:ty] $(([$($Type:tt)*] $(($pat:literal $expr:expr))*))*)*) => { - $(expose!(@impl [$self: $State] { $([$($Type)*] => { $($pat => $expr),* })* });)* - }; - ($([$self:ident:$State:ty] { $([$($Type:tt)*] => { $($pat:pat => $expr:expr),* $(,)? })* })*) => { - $(expose!(@impl [$self: $State] { $([$($Type)*] => { $($pat => $expr),* })* });)* - }; - (@impl [$self:ident:$State:ty] { $([$($Type:tt)*] => { $($pat:pat => $expr:expr),* $(,)? })* }) => { - $(expose!(@type [$($Type)*] [$self: $State] => { $($pat => $expr),* });)* - }; - (@type [bool] [$self:ident: $State:ty] => { $($pat:pat => $expr:expr),* $(,)? }) => { - provide_bool!(bool: |$self: $State| { $($pat => $expr),* }); - }; - (@type [u16] [$self:ident: $State:ty] => { $($pat:pat => $expr:expr),* $(,)? }) => { - provide_num!(u16: |$self: $State| { $($pat => $expr),* }); - }; - (@type [usize] [$self:ident: $State:ty] => { $($pat:pat => $expr:expr),* $(,)? }) => { - provide_num!(usize: |$self: $State| { $($pat => $expr),* }); - }; - (@type [isize] [$self:ident: $State:ty] => { $($pat:pat => $expr:expr),* $(,)? }) => { - provide_num!(isize: |$self: $State| { $($pat => $expr),* }); - }; - (@type [$Type:ty] [$self:ident: $State:ty] => { $($pat:pat => $expr:expr),* $(,)? }) => { - provide!($Type: |$self: $State| { $($pat => $expr),* }); - }; -} - -/// Implement `Context` for a context and type. -#[macro_export] macro_rules! provide { - // Provide a value to the EDN template - ($type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => { - impl Context<$type> for $State { - #[allow(unreachable_code)] - fn get (&$self, dsl: &Value) -> Option<$type> { - use Value::*; - Some(match dsl { $(Sym($pat) => $expr,)* _ => return None }) - } - } - }; - // Provide a value more generically - ($lt:lifetime: $type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => { - impl<$lt> Context<$lt, $type> for $State { - #[allow(unreachable_code)] - fn get (&$lt $self, dsl: &Value) -> Option<$type> { - use Value::*; - Some(match dsl { $(Sym($pat) => $expr,)* _ => return None }) - } - } - }; -} - -/// Implement `Context` for a context and numeric type. -/// -/// This enables support for numeric literals. -#[macro_export] macro_rules! provide_num { - // 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),* $(,)? }) => { - impl<$T: $Trait> Context<$type> for $T { - fn get (&$self, dsl: &Value) -> Option<$type> { - use Value::*; - Some(match dsl { $(Sym($pat) => $expr,)* Num(n) => *n as $type, _ => return None }) - } - } - }; - // 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),* $(,)? }) => { - impl Context<$type> for $State { - fn get (&$self, dsl: &Value) -> Option<$type> { - use Value::*; - Some(match dsl { $(Sym($pat) => $expr,)* Num(n) => *n as $type, _ => return None }) - } - } - }; -} - -/// Implement `Context` for a context and the boolean type. -/// -/// This enables support for boolean literals. -#[macro_export] macro_rules! provide_bool { - // 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),* $(,)? }) => { - impl<$T: $Trait> Context<$type> for $T { - fn get (&$self, dsl: &Value) -> Option<$type> { - use Value::*; - Some(match dsl { - Num(n) => match *n { 0 => false, _ => true }, - Sym(":false") | Sym(":f") => false, - Sym(":true") | Sym(":t") => true, - $(Sym($pat) => $expr,)* - _ => return Context::get(self, dsl) - }) - } - } - }; - // 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),* $(,)? }) => { - impl Context<$type> for $State { - fn get (&$self, dsl: &Value) -> Option<$type> { - use Value::*; - Some(match dsl { - Num(n) => match *n { 0 => false, _ => true }, - Sym(":false") | Sym(":f") => false, - Sym(":true") | Sym(":t") => true, - $(Sym($pat) => $expr,)* - _ => return None - }) - } - } - }; -} - -#[macro_export] macro_rules! impose { - ([$self:ident:$Struct:ty] $(($Command:ty : $(($cmd:literal $args:tt $result:expr))*))*) => { - $(atom_command!($Command: |$self: $Struct| { $(($cmd $args $result))* });)* - }; - ([$self:ident:$Struct:ty] { $($Command:ty => $variants:tt)* }) => { - $(atom_command!($Command: |$self: $Struct| $variants);)* - }; -} - #[macro_export] macro_rules! get_value { ($state:expr => $token:expr) => { if let Some(value) = $state.get(&$token.value) { diff --git a/dsl/src/lib.rs b/dsl/src/lib.rs index 994fc80..411974a 100644 --- a/dsl/src/lib.rs +++ b/dsl/src/lib.rs @@ -116,16 +116,18 @@ mod dsl_macros; #[cfg(test)] #[test] fn test_dsl_context () { struct Test; - provide_bool!(bool: |self: Test|{ - ":provide-bool" => true - }); - let test = Test; - assert_eq!(test.get(&Value::Sym(":false")), Some(false)); - assert_eq!(test.get(&Value::Sym(":true")), Some(true)); - assert_eq!(test.get(&Value::Sym(":provide-bool")), Some(true)); - assert_eq!(test.get(&Value::Sym(":missing-bool")), None); - assert_eq!(test.get(&Value::Num(0)), Some(false)); - assert_eq!(test.get(&Value::Num(1)), Some(true)); + #[tengri_proc::expose] + impl Test { + fn some_bool (&self) -> bool { + true + } + } + assert_eq!(Test.get(&Value::Sym(":false")), Some(false)); + assert_eq!(Test.get(&Value::Sym(":true")), Some(true)); + assert_eq!(Test.get(&Value::Sym(":some-bool")), Some(true)); + assert_eq!(Test.get(&Value::Sym(":missing-bool")), None); + assert_eq!(Test.get(&Value::Num(0)), Some(false)); + assert_eq!(Test.get(&Value::Num(1)), Some(true)); } //#[cfg(test)] #[test] fn test_examples () -> Result<(), ParseError> { diff --git a/input/src/input_macros.rs b/input/src/input_macros.rs index c3e13e9..689c94e 100644 --- a/input/src/input_macros.rs +++ b/input/src/input_macros.rs @@ -1,30 +1,5 @@ use crate::*; -/** Implement `Command` for given `State` and collection - * of `Variant` to `handler` mappings. */ -#[macro_export] macro_rules! defcom { - ([$self:ident, $state:ident:$State:ty] $(($Command:ident $(( - $Variant:ident [$($($param:ident: $Param:ty),+)?] $expr:expr - ))*))*) => { - $(#[derive(Clone, Debug)] pub enum $Command { - $($Variant $(($($Param),+))?),* - })* - $(command!(|$self: $Command, $state: $State|match $self { - $($Command::$Variant $(($($param),+))? => $expr),* - });)* - }; - (|$self:ident, $state:ident:$State:ty| $($Command:ident { $( - $Variant:ident $(($($param:ident: $Param:ty),+))? => $expr:expr - )* $(,)? })*) => { - $(#[derive(Clone, Debug)] pub enum $Command { - $($Variant $(($($Param),+))?),* - })* - $(command!(|$self: $Command, $state: $State|match $self { - $($Command::$Variant $(($($param),+))? => $expr),* - });)* - }; -} - /** Implement `Command` for given `State` and `handler` */ #[macro_export] macro_rules! command { ($(<$($l:lifetime),+>)?|$self:ident:$Command:ty,$state:ident:$State:ty|$handler:expr) => { @@ -35,97 +10,3 @@ use crate::*; } }; } - -/** Implement `DslCommand` for given `State` and `Command` */ -#[cfg(feature = "dsl")] -#[macro_export] macro_rules! atom_command { - ($Command:ty : |$state:ident:<$State:ident: $Trait:path>| { $(( - // identifier - $key:literal [ - // named parameters - $( - // argument name - $arg:ident - // if type is not provided defaults to Dsl - $( - // type:name separator - : - // argument type - $type:ty - )? - ),* - // rest of parameters - $(, ..$rest:ident)? - ] - // bound command: - $command:expr - ))* }) => { - impl<'a, $State: $Trait> TryFromDsl<'a, $State> for $Command { - fn try_from_expr ($state: &$State, iter: TokenIter) -> Option { - let iter = iter.clone(); - match iter.next() { - $(Some(Token { value: Value::Key($key), .. }) => { - let iter = iter.clone(); - $( - let next = iter.next(); - if next.is_none() { panic!("no argument: {}", stringify!($arg)); } - let $arg = next.unwrap(); - $(let $arg: Option<$type> = Context::<$type>::get($state, &$arg.value);)? - )* - $(let $rest = iter.clone();)? - return $command - },)* - _ => None - } - None - } - } - }; - ($Command:ty : |$state:ident:$State:ty| { $(( - // identifier - $key:literal [ - // named parameters - $( - // argument name - $arg:ident - // if type is not provided defaults to Dsl - $( - // type:name separator - : - // argument type - $type:ty - )? - ),* - // rest of parameters - $(, ..$rest:ident)? - ] - // bound command: - $command:expr - ))* }) => { - impl<'a> TryFromDsl<'a, $State> for $Command { - fn try_from_expr ($state: &$State, iter: TokenIter) -> Option { - let mut iter = iter.clone(); - match iter.next() { - $(Some(Token { value: Value::Key($key), .. }) => { - let mut iter = iter.clone(); - $( - let next = iter.next(); - if next.is_none() { panic!("no argument: {}", stringify!($arg)); } - let $arg = next.unwrap(); - $(let $arg: Option<$type> = Context::<$type>::get($state, &$arg.value);)? - )* - $(let $rest = iter.clone();)? - return $command - }),* - _ => None - } - } - } - }; - (@bind $state:ident =>$arg:ident ? : $type:ty) => { - let $arg: Option<$type> = Context::<$type>::get($state, $arg); - }; - (@bind $state:ident => $arg:ident : $type:ty) => { - let $arg: $type = Context::<$type>::get_or_fail($state, $arg); - }; -} diff --git a/proc/src/proc_command.rs b/proc/src/proc_command.rs index 7102fd8..b9ececc 100644 --- a/proc/src/proc_command.rs +++ b/proc/src/proc_command.rs @@ -227,8 +227,6 @@ impl ToTokens for CommandArm { out.append(Group::new(Delimiter::Parenthesis, { let mut out = TokenStream2::new(); out.append(self.to_enum_variant_ident()); - for arg in args.iter() { - } out })); out.append(Punct::new('=', Joint)); diff --git a/proc/src/proc_expose.rs b/proc/src/proc_expose.rs index f3bb235..affb192 100644 --- a/proc/src/proc_expose.rs +++ b/proc/src/proc_expose.rs @@ -84,6 +84,7 @@ impl ToTokens for ExposeImpl { }; let values = variants.iter().map(ExposeArm::from); write_quote_to(out, quote! { + /// Generated by [tengri_proc]. impl ::tengri::dsl::Context<#t> for #target { fn get (&self, dsl: &::tengri::dsl::Value) -> Option<#t> { Some(match dsl { diff --git a/tui/Cargo.toml b/tui/Cargo.toml index 5bf0dc2..a9eb4d9 100644 --- a/tui/Cargo.toml +++ b/tui/Cargo.toml @@ -20,8 +20,9 @@ tengri_output = { path = "../output" } tengri_dsl = { optional = true, path = "../dsl" } [dev-dependencies] -tengri = { path = "../tengri", features = [ "dsl" ] } -tengri_dsl = { path = "../dsl" } +tengri = { path = "../tengri", features = [ "dsl" ] } +tengri_dsl = { path = "../dsl" } +tengri_proc = { path = "../proc" } [features] dsl = [ "tengri_dsl", "tengri_input/dsl", "tengri_output/dsl" ] diff --git a/tui/examples/demo.rs.old b/tui/examples/demo.rs.old deleted file mode 100644 index ba013de..0000000 --- a/tui/examples/demo.rs.old +++ /dev/null @@ -1,131 +0,0 @@ -use tek::*; - -fn main () -> Usually<()> { - Tui::run(Arc::new(RwLock::new(Demo::new())))?; - Ok(()) -} - -pub struct Demo { - index: usize, - items: Vec>> -} - -impl Demo { - fn new () -> Self { - Self { - index: 0, - items: vec![] - } - } -} - -impl Content for Demo { - type Engine = Tui; - fn content (&self) -> dyn Render { - let border_style = Style::default().fg(Color::Rgb(0,0,0)); - Align::Center(Layers::new(move|add|{ - - add(&Background(Color::Rgb(0,128,128)))?; - - add(&Margin::XY(1, 1, Stack::down(|add|{ - - add(&Layers::new(|add|{ - add(&Background(Color::Rgb(128,96,0)))?; - add(&Border(Square(border_style)))?; - add(&Margin::XY(2, 1, "..."))?; - Ok(()) - }).debug())?; - - add(&Layers::new(|add|{ - add(&Background(Color::Rgb(128,64,0)))?; - add(&Border(Lozenge(border_style)))?; - add(&Margin::XY(4, 2, "---"))?; - Ok(()) - }).debug())?; - - add(&Layers::new(|add|{ - add(&Background(Color::Rgb(96,64,0)))?; - add(&Border(SquareBold(border_style)))?; - add(&Margin::XY(6, 3, "~~~"))?; - Ok(()) - }).debug())?; - - Ok(()) - })).debug())?; - - Ok(()) - - })) - //Align::Center(Margin::X(1, Layers::new(|add|{ - //add(&Background(Color::Rgb(128,0,0)))?; - //add(&Stack::down(|add|{ - //add(&Margin::Y(1, Layers::new(|add|{ - //add(&Background(Color::Rgb(0,128,0)))?; - //add(&Align::Center("12345"))?; - //add(&Align::Center("FOO")) - //})))?; - //add(&Margin::XY(1, 1, Layers::new(|add|{ - //add(&Align::Center("1234567"))?; - //add(&Align::Center("BAR"))?; - //add(&Background(Color::Rgb(0,0,128))) - //}))) - //})) - //}))) - - //Align::Y(Layers::new(|add|{ - //add(&Background(Color::Rgb(128,0,0)))?; - //add(&Margin::X(1, Align::Center(Stack::down(|add|{ - //add(&Align::X(Margin::Y(1, Layers::new(|add|{ - //add(&Background(Color::Rgb(0,128,0)))?; - //add(&Align::Center("12345"))?; - //add(&Align::Center("FOO")) - //})))?; - //add(&Margin::XY(1, 1, Layers::new(|add|{ - //add(&Align::Center("1234567"))?; - //add(&Align::Center("BAR"))?; - //add(&Background(Color::Rgb(0,0,128))) - //})))?; - //Ok(()) - //}))))) - //})) - } -} - -impl Handle for Demo { - fn handle (&mut self, from: &TuiIn) -> Perhaps { - use KeyCode::{PageUp, PageDown}; - match from.event() { - kexp!(PageUp) => { - self.index = (self.index + 1) % self.items.len(); - }, - kexp!(PageDown) => { - self.index = if self.index > 1 { - self.index - 1 - } else { - self.items.len() - 1 - }; - }, - _ => return Ok(None) - } - Ok(Some(true)) - } -} - -//lisp!(CONTENT Demo (LET - //(BORDER-STYLE (STYLE (FG (RGB 0 0 0)))) - //(BG-COLOR-0 (RGB 0 128 128)) - //(BG-COLOR-1 (RGB 128 96 0)) - //(BG-COLOR-2 (RGB 128 64 0)) - //(BG-COLOR-3 (RGB 96 64 0)) - //(CENTER (LAYERS - //(BACKGROUND BG-COLOR-0) - //(OUTSET-XY 1 1 (SPLIT-DOWN - //(LAYERS (BACKGROUND BG-COLOR-1) - //(BORDER SQUARE BORDER-STYLE) - //(OUTSET-XY 2 1 "...")) - //(LAYERS (BACKGROUND BG-COLOR-2) - //(BORDER LOZENGE BORDER-STYLE) - //(OUTSET-XY 4 2 "---")) - //(LAYERS (BACKGROUND BG-COLOR-3) - //(BORDER SQUARE-BOLD BORDER-STYLE) - //(OUTSET-XY 2 1 "~~~")))))))) diff --git a/tui/examples/tui.rs b/tui/examples/tui.rs index 7d9f9d7..3869a8e 100644 --- a/tui/examples/tui.rs +++ b/tui/examples/tui.rs @@ -41,23 +41,24 @@ handle!(TuiIn: |self: Example, input|{ }) }); -defcom! { |self, state: Example| - ExampleCommand { - Next => { - state.0 = (state.0 + 1) % EXAMPLES.len(); - None - } - Prev => { - state.0 = if state.0 > 0 { state.0 - 1 } else { EXAMPLES.len() - 1 }; - None - } - } +#[tengri_proc::expose] +impl Example { + //[bool] => {} + //[u16] => {} + //[usize] => {} } -atom_command!(ExampleCommand: |app: Example| { - ("prev" [] Some(Self::Prev)) - ("next" [] Some(Self::Next)) -}); +#[tengri_proc::command(Example)] +impl ExampleCommand { + fn next (state: &mut Example) -> Perhaps { + state.0 = (state.0 + 1) % EXAMPLES.len(); + Ok(None) + } + fn prev (state: &mut Example) -> Perhaps { + state.0 = if state.0 > 0 { state.0 - 1 } else { EXAMPLES.len() - 1 }; + Ok(None) + } +} view!(TuiOut: |self: Example|{ let index = self.0 + 1; @@ -77,11 +78,3 @@ view!(TuiOut: |self: Example|{ ":map-e" => Map::east(5u16, ||0..5u16, |n, i|format!("{n}")).boxed(), ":map-s" => Map::south(5u16, ||0..5u16, |n, i|format!("{n}")).boxed(), }); - -expose! { - [self: Example] { - [bool] => {} - [u16] => {} - [usize] => {} - } -}