From ff4d0c9db5d07d7cc40a31fd0c16c18af34494a3 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Wed, 3 Sep 2025 03:30:06 +0300 Subject: [PATCH] dsl: split ns trait --- dsl/src/dsl_expr.rs | 15 +++++++ dsl/src/dsl_ns.rs | 104 +------------------------------------------- dsl/src/dsl_word.rs | 17 ++++++++ 3 files changed, 33 insertions(+), 103 deletions(-) diff --git a/dsl/src/dsl_expr.rs b/dsl/src/dsl_expr.rs index d22115a..4179f94 100644 --- a/dsl/src/dsl_expr.rs +++ b/dsl/src/dsl_expr.rs @@ -68,3 +68,18 @@ dsl_type!(DslExpr { ($name, get) }),* )? ]; }); + +pub trait DslNsExprs<'a, T: 'a>: 'a { + /// Known expressions. + const EXPRS: DslExprs<'a, Self, T> = &[]; + /// Resolve an expression if known. + fn from_expr (&'a self, dsl: impl DslExpr + 'a) -> Perhaps { + let head = dsl.head()?; + for (key, get) in Self::EXPRS.iter() { + if Some(*key) == head { + return get(self, dsl.tail()?.unwrap_or("")) + } + } + return Ok(None) + } +} diff --git a/dsl/src/dsl_ns.rs b/dsl/src/dsl_ns.rs index b9c81f8..f17c283 100644 --- a/dsl/src/dsl_ns.rs +++ b/dsl/src/dsl_ns.rs @@ -1,10 +1,6 @@ use crate::*; -pub trait DslNs<'a, T: 'a>: 'a { - /// Known symbols. - const WORDS: DslWords<'a, Self, T> = &[]; - /// Known expressions. - const EXPRS: DslExprs<'a, Self, T> = &[]; +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) { @@ -19,102 +15,4 @@ pub trait DslNs<'a, T: 'a>: 'a { fn from_literal (&self, _: impl Dsl) -> Perhaps { Ok(None) } - /// Resolve a symbol if known. - fn from_word (&'a self, dsl: impl DslWord) -> Perhaps { - if let Some(dsl) = dsl.word()? { - for (key, get) in Self::WORDS.iter() { - if dsl == *key { - let value = get(self); - return value - } - } - } - return Ok(None) - } - /// Resolve an expression if known. - fn from_expr (&'a self, dsl: impl DslExpr + 'a) -> Perhaps { - let head = dsl.head()?; - for (key, get) in Self::EXPRS.iter() { - if Some(*key) == head { - return get(self, dsl.tail()?.unwrap_or("")) - } - } - return Ok(None) - } } - -/// Define a DSL namespace that provides values to words and expressions. -#[macro_export] macro_rules! dsl_ns ( - // Special form for numeric types - (num |$state:ident : $State: ty| $($($num:lifetime)? $Type:ty $(=> { $( - $pat:tt => $body:expr - ),* $(,)? })?;)+) => { - $(dsl_ns!(num |$state: $State| -> $($num)? $Type { $( $($pat => $body),* )? });)+ - }; - // Special form for numeric types - (num |$state:ident : $State: ty| -> $Type:ty { $( $pat:tt => $body:expr ),* $(,)? }) => { - impl<'a> DslNs<'a, $Type> for $State { - const WORDS: DslWords<'a, $State, $Type> = &[ - $(dsl_ns!{@word 'a ($state: $State) -> $Type { $pat => $body }}),*]; - const EXPRS: DslExprs<'a, $State, $Type> = &[ - $(dsl_ns!{@exp 'a ($state: $State) -> $Type { $pat => $body }}),*]; - fn from_literal (&self, dsl: impl Dsl) -> Perhaps<$Type> { - Ok(if let Some(src) = dsl.src()? { - Some(to_number(src)? as $Type) - } else { - None - }) - } - } - }; - // A namespace may resolve one or more types. - (|$state:ident : $State: ty| $($Type:ty $(=> { $( $pat:tt => $body:expr ),* $(,)? })? ;)+) => { - $(dsl_ns!(|$state: $State| -> $Type { $( $($pat => $body),* )? });)+ - }; - // Regular form for single type - (|$state:ident : $State: ty| -> $Type:ty { $( $pat:tt => $body:expr ),* $(,)? }) => { - impl<'a> DslNs<'a, $Type> for $State { - const WORDS: DslWords<'a, $State, $Type> = - &[$(dsl_ns!{@word 'a ($state: $State) -> $Type { $pat => $body }}),*]; - const EXPRS: DslExprs<'a, $State, $Type> = - &[$(dsl_ns!{@exp 'a ($state: $State) -> $Type { $pat => $body }}),*]; - } - }; - // Symbols only. - (@word $l:lifetime ($state:ident: $State:ty) -> $Type:ty { - $word:literal => $body:expr - }) => {{ - let get: GetDslWord<$l, Self, $Type> = (|$state: &$State|Ok(Some($body))); - ($word, get) - }}; - // Expression handlers only. - (@exp $l:lifetime ($state:ident: $State:ty) -> $Type:ty { - ($head:literal $(,$arg:ident:$ty:ty)* $(,)*) => $body:expr - }) => {{ - let get: GetDslExpr<$l, Self, $Type> = |$state, 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!("{}: missing argument: {} ({}); got: {tail}", - $head, - stringify!($arg), - stringify!($Type), - ).into()) - }; - )* - Ok(Some($body)) - }; - ($head, get) - }}; - // Nothing else in symbols. - (@word $l:lifetime ($state:ident: $State:ty) -> $Type:ty { $pat:tt => $body:expr }) => { - ("", ((|_|Ok(None)) as GetDslWord<$l, Self, $Type>)) // FIXME don't emit at all - }; - // Nothing else in expression handlers. - (@exp $l:lifetime ($state:ident: $State:ty) -> $Type:ty { $pat:tt => $body:expr }) => { - ("", ((|_, _|Ok(None)) as GetDslExpr<$l, Self, $Type>)) // FIXME don't emit at all - }; -); diff --git a/dsl/src/dsl_word.rs b/dsl/src/dsl_word.rs index 48b5c59..5abb61a 100644 --- a/dsl/src/dsl_word.rs +++ b/dsl/src/dsl_word.rs @@ -30,3 +30,20 @@ dsl_type!(DslWord { ($word, get) }),* )?]; }); + +pub trait DslNsWords<'a, T: 'a>: 'a { + /// Known symbols. + const WORDS: DslWords<'a, Self, T> = &[]; + /// Resolve a symbol if known. + fn from_word (&'a self, dsl: impl DslWord) -> Perhaps { + if let Some(dsl) = dsl.word()? { + for (key, get) in Self::WORDS.iter() { + if dsl == *key { + let value = get(self); + return value + } + } + } + return Ok(None) + } +}