mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2025-12-06 03:36:42 +01:00
85 lines
3 KiB
Rust
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)
|
|
}
|
|
}
|