tengri/dsl/src/dsl_expr.rs
unspeaker ff4d0c9db5
Some checks failed
/ build (push) Has been cancelled
dsl: split ns trait
2025-09-03 03:30:06 +03:00

85 lines
3 KiB
Rust

use crate::*;
pub type GetDslExpr<'a, S, T> = for<'b> fn(&'a S, &'b str)->Perhaps<T>;
pub type DslExprs<'a, S, T> = &'a [(&'a str, GetDslExpr<'a, S, T>)];
dsl_type!(DslExpr {
fn expr (&self) -> DslPerhaps<&str> {ok_flat(self.src()?.map(expr_peek_inner_only))}
fn head (&self) -> DslPerhaps<&str> {ok_flat(self.src()?.map(peek))}
fn tail (&self) -> DslPerhaps<&str> {ok_flat(self.src()?.map(peek_tail))}
/// my other car is a cdr :<
fn each (&self, mut cb: impl FnMut(&str)->Usually<()>) -> Usually<()> {
Ok(if let Some(head) = self.head()? {
cb(head)?;
if let Some(tail) = self.tail()? {
tail.each(cb)?;
}
})
}
} {
pub const fn expr_peek [generated];
pub const fn expr_peek_only [generated];
pub const fn expr_seek [generated];
pub const fn expr_seek_start (src) {
for_each!((i, c) in char_indices(src) =>
if is_expr_start(c) { return Ok(Some(i)) } else
if !is_space(c) { return Err(Unexpected(c, Some(i), Some("expected expression start"))) });
Ok(None)
}
pub const fn expr_seek_length (src) {
let mut depth = 0;
for_each!((i, c) in char_indices(src) =>
if is_expr_start(c) { depth += 1; } else
if is_expr_end(c) {
if depth == 0 {
return Err(Unexpected(c, Some(i), Some("expected expression end")))
} else if depth == 1 {
return Ok(Some(i + 1))
} else {
depth -= 1;
}
});
Err(Incomplete)
}
});
#[macro_export] macro_rules!dsl_exprs(($l:lifetime |$state:ident|->$Type:ty$({
$($name:literal ($($arg:ident:$ty:ty),* $(,)?) => $body:expr),* $(,)?
})?)=>{
const EXPRS: DslExprs<$l, Self, $Type> = &[$( $({
let get: GetDslExpr<$l, Self, $Type> = |$state: &$l Self, tail_base|{
let tail = tail_base;
$(
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 as $Type))
};
($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<T> {
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)
}
}