use crate::*; pub trait DslNs<'a, T: 'a>: DslNsWords<'a, T> + DslNsExprs<'a, T> { /// Resolve an expression or symbol. fn from (&'a self, dsl: impl Dsl + 'a) -> 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 { self.from_expr(dsl) } } /// Resolve as literal if valid. fn from_literal (&self, _: impl Dsl) -> Perhaps { Ok(None) } } #[macro_export] macro_rules! dsl_ns { ($State:ty: $Type:ty { $(literal = |$dsl:ident| $literal:expr;)? $(word = |$state_w:ident| { $($word:literal => $body_w:expr),* $(,)? };)? $(expr = |$state_e:ident| { $($head:literal $args:tt => $body_e:expr),* $(,)? };)? }) => { impl<'a> DslNs<'a, $Type> for $State { $(fn from_literal (&self, $dsl: impl Dsl) -> Perhaps<$Type> { $literal })? } impl<'a> DslNsWords<'a, $Type> for $State { $(dsl_words! { 'a |$state_w| -> $Type { $($word => $body_w),* } })? } impl<'a> DslNsExprs<'a, $Type> for $State { $(dsl_exprs! { 'a |$state_e| -> $Type { $($head $args => $body_e),* } })? } } }