wip: refactor dsl
Some checks failed
/ build (push) Has been cancelled

This commit is contained in:
🪞👃🪞 2025-06-14 16:08:02 +03:00
parent c8827b43c3
commit 91dc77cfea
16 changed files with 931 additions and 823 deletions

110
dsl/src/dsl.rs Normal file
View file

@ -0,0 +1,110 @@
use crate::*;
#[derive(Error, Debug, Copy, Clone, PartialEq)] pub enum DslError {
#[error("parse failed: not implemented")]
Unimplemented,
#[error("parse failed: empty")]
Empty,
#[error("parse failed: incomplete")]
Incomplete,
#[error("parse failed: unexpected character '{0}'")]
Unexpected(char),
#[error("parse failed: error #{0}")]
Code(u8),
}
/// Thing that may construct itself from `State` and [DslValue].
pub trait FromDsl<State>: Sized {
fn try_provide (
state: &State,
value: DslValue<impl DslStr, impl DslExp>
) -> Perhaps<Self>;
fn provide (
state: &State,
value: DslValue<impl DslStr, impl DslExp>,
error: impl Fn()->Box<dyn std::error::Error>
) -> Usually<Self> {
match Self::try_provide(state, value)? {
Some(value) => Ok(value),
_ => Err(error())
}
}
}
pub type DslResult<T> = Result<T, DslError>;
/// Marker trait for supported string types.
pub trait DslStr: PartialEq + Clone + Default + Debug + AsRef<str> {}
impl<T: PartialEq + Clone + Default + Debug + AsRef<str>> DslStr for T {}
/// Marker trait for supported expression types.
pub trait DslExp: PartialEq + Clone + Default + Debug {}
impl<T: PartialEq + Clone + Default + Debug> DslExp for T {}
/// A DSL value generic over string and expression types.
/// See [CstValue] and [AstValue].
#[derive(Clone, Debug, PartialEq, Default)]
pub enum DslValue<Str: DslStr, Exp: DslExp> {
#[default]
Nil,
Err(DslError),
Num(usize),
Sym(Str),
Key(Str),
Str(Str),
Exp(usize, Exp),
}
impl<Str: DslStr, Exp: DslExp> DslValue<Str, Exp> {
pub fn is_nil (&self) -> bool {
matches!(self, Self::Nil)
}
pub fn as_err (&self) -> Option<&DslError> {
if let Self::Err(e) = self { Some(e) } else { None }
}
pub fn as_num (&self) -> Option<usize> {
if let Self::Num(n) = self { Some(*n) } else { None }
}
pub fn as_sym (&self) -> Option<&str> {
if let Self::Sym(s) = self { Some(s.as_ref()) } else { None }
}
pub fn as_key (&self) -> Option<&str> {
if let Self::Key(k) = self { Some(k.as_ref()) } else { None }
}
pub fn as_str (&self) -> Option<&str> {
if let Self::Str(s) = self { Some(s.as_ref()) } else { None }
}
pub fn as_exp (&self) -> Option<&Exp> {
if let Self::Exp(_, x) = self { Some(x) } else { None }
}
pub fn exp_match <T, F> (&self, namespace: &str, cb: F) -> Perhaps<T>
where F: Fn(&str, &Exp)-> Perhaps<T> {
if let Some(Self::Key(key)) = self.exp_head()
&& key.as_ref().starts_with(namespace)
&& let Some(tail) = self.exp_tail() {
cb(key.as_ref().split_at(namespace.len()).1, tail)
} else {
Ok(None)
}
}
pub fn exp_depth (&self) -> Option<usize> {
todo!()
}
pub fn exp_head (&self) -> Option<&Self> {
todo!()
} // TODO
pub fn exp_tail (&self) -> Option<&Exp> {
todo!()
} // TODO
pub fn peek (&self) -> Option<Self> {
todo!()
}
pub fn next (&mut self) -> Option<Self> {
todo!()
}
pub fn rest (self) -> Vec<Self> {
todo!()
}
}
impl<Str: DslStr + Copy, Exp: DslExp + Copy> Copy for DslValue<Str, Exp> {}