diff --git a/dsl/src/dsl.rs b/dsl/src/dsl.rs index de6a978..d6cc366 100644 --- a/dsl/src/dsl.rs +++ b/dsl/src/dsl.rs @@ -289,22 +289,16 @@ fn ok_flat (x: Option>) -> DslPerhaps { // Special form for numeric types (num |$state:ident : $State: ty| -> $Type:ty { $( $pat:tt => $body:expr ),* $(,)? }) => { impl<'t> DslNs<'t, $Type> for $State { - const WORDS: DslNsMap<'t, fn (&'t $State)->Perhaps<$Type>> = + const WORDS: DslNsMap<'t, fn (&$State)->Perhaps<$Type>> = DslNsMap::new(&[$(dsl_ns!{@word ($state: $State) -> $Type { $pat => $body }}),*]); - const EXPRS: DslNsMap<'t, fn (&'t $State, &str)->Perhaps<$Type>> = + const EXPRS: DslNsMap<'t, fn (&$State, &str)->Perhaps<$Type>> = DslNsMap::new(&[$(dsl_ns!{@exp ($state: $State) -> $Type { $pat => $body }}),*]); - fn from (&'t self, dsl: D) -> Perhaps<$Type> { - if let Ok(Some(src)) = dsl.src() { - if let Ok(num) = to_number(src) { - Ok(Some(num as $Type)) - } else if let Ok(Some(src)) = src.word() { - self.from_word(src) - } else { - self.from_expr(src) - } + fn from_literal (&self, dsl: &D) -> Perhaps<$Type> { + Ok(if let Some(src) = dsl.src()? { + Some(to_number(src)? as $Type) } else { - Ok(None) - } + None + }) } } }; @@ -315,9 +309,9 @@ fn ok_flat (x: Option>) -> DslPerhaps { // Regular form for single type (|$state:ident : $State: ty| -> $Type:ty { $( $pat:tt => $body:expr ),* $(,)? }) => { impl<'t> DslNs<'t, $Type> for $State { - const WORDS: DslNsMap<'t, fn (&'t $State)->Perhaps<$Type>> = + const WORDS: DslNsMap<'t, fn (&$State)->Perhaps<$Type>> = DslNsMap::new(&[$(dsl_ns!{@word ($state: $State) -> $Type { $pat => $body }}),*]); - const EXPRS: DslNsMap<'t, fn (&'t $State, &str)->Perhaps<$Type>> = + const EXPRS: DslNsMap<'t, fn (&$State, &str)->Perhaps<$Type>> = DslNsMap::new(&[$(dsl_ns!{@exp ($state: $State) -> $Type { $pat => $body }}),*]); } }; @@ -358,34 +352,36 @@ fn ok_flat (x: Option>) -> DslPerhaps { pub trait DslNs<'t, T: 't>: 't { /// Known symbols. - const WORDS: DslNsMap<'t, fn (&'t Self)->Perhaps> = DslNsMap::new(&[]); + const WORDS: DslNsMap<'t, fn (&Self)->Perhaps> = DslNsMap::new(&[]); /// Known expressions. - const EXPRS: DslNsMap<'t, fn (&'t Self, &str)->Perhaps> = DslNsMap::new(&[]); + const EXPRS: DslNsMap<'t, fn (&Self, &str)->Perhaps> = DslNsMap::new(&[]); /// Resolve an expression or symbol. - fn from (&'t self, dsl: D) -> Perhaps { - if let Ok(Some(src)) = dsl.src() { - if let Ok(Some(src)) = src.word() { - self.from_word(src) - } else { - self.from_expr(src) - } + fn from (&self, dsl: &D) -> Perhaps { + if let Ok(Some(literal)) = self.from_literal(dsl) { + Ok(Some(literal)) + } else if let Ok(Some(meaning)) = self.from_word(dsl) { + Ok(Some(meaning)) } else { - Ok(None) + self.from_expr(dsl) } } + /// Resolve as literal if valid. + fn from_literal (&self, dsl: &D) -> Perhaps { + Ok(None) + } /// Resolve a symbol if known. - fn from_word (&'t self, dsl: D) -> Perhaps { + fn from_word (&self, dsl: &D) -> Perhaps { if let Some(dsl) = dsl.word()? { - for (word, get) in Self::WORDS.0 { if dsl == *word { return get(self) } } + for (key, get) in Self::WORDS.0 { if dsl == *key { return get(self) } } } return Ok(None) } /// Resolve an expression if known. - fn from_expr (&'t self, dsl: D) -> Perhaps { - if let Some(head) = dsl.expr().head()? { - for (key, value) in Self::EXPRS.0.iter() { - if head == *key { - return value(self, dsl.expr().tail()?.unwrap_or("")) + fn from_expr (&self, dsl: &D) -> Perhaps { + if let Some(expr) = dsl.expr()? { + for (key, get) in Self::EXPRS.0.iter() { + if Some(*key) == expr.head()? { + return get(self, &expr.tail()?.unwrap_or("")) } } } @@ -400,3 +396,35 @@ impl<'t, T: Debug + 't> DslNsMap<'t, T> { /// Populate a namespace with pre-existing values. pub const fn new (data: &'t [(&'t str, T)]) -> Self { Self(data) /* TODO a search trie */ } } + +#[macro_export] macro_rules!dsl_words((|$state:ident|->$Type:ty$({ + $($word:literal => $body:expr),* $(,)? +})?)=>{ + const WORDS: DslNsMap<'t, fn (&Self)->Perhaps<$Type>> = DslNsMap::new(&[$( + $(($word, |$state: &Self|{Ok(Some($body))})),* + )? ]); +}); + + +#[macro_export] macro_rules!dsl_exprs((|$state:ident|->$Type:ty$({ + $($name:literal ($($arg:ident:$ty:ty),* $(,)?) => $body:expr),* $(,)? +})?)=>{ + const EXPRS: DslNsMap<'t, fn (&Self, &str)->Perhaps<$Type>> = DslNsMap::new(&[$( + $(($name, |$state: &Self, tail: &str|{ + $( + let head = tail.head()?.unwrap_or_default(); + let tail = tail.tail()?.unwrap_or_default(); + let $arg: $ty = if let Some(arg) = $state.from(&head)? { + arg + } else { + return Err(format!("{}: arg \"{}\" ({}) got: {head} {tail}", + $name, + stringify!($arg), + stringify!($ty), + ).into()) + }; + )* + Ok(Some($body)) + })),* + )? ]); +});