mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2025-12-06 19:56:44 +01:00
wip: dsl: more rework
This commit is contained in:
parent
f1b24d436a
commit
7097333993
4 changed files with 145 additions and 159 deletions
|
|
@ -2,40 +2,40 @@ use crate::*;
|
|||
use std::sync::Arc;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
|
||||
/// Emits tokens.
|
||||
pub trait Ast: Debug {
|
||||
fn peek (&self) -> Option<AstValue>;
|
||||
fn next (&mut self) -> Option<AstValue>;
|
||||
fn rest (self) -> Option<Box<dyn Ast>>;
|
||||
}
|
||||
|
||||
/// A [Cst] can be used as an [Ast].
|
||||
impl<'source: 'static> Ast for Cst<'source> {
|
||||
fn peek (&self) -> Option<AstValue> {
|
||||
Cst::peek(self).map(|token|token.value.into())
|
||||
}
|
||||
fn next (&mut self) -> Option<AstValue> {
|
||||
Iterator::next(self).map(|token|token.value.into())
|
||||
}
|
||||
fn rest (self) -> Option<Box<dyn Ast>> {
|
||||
self.peek().is_some().then(||Box::new(self) as Box<dyn Ast>)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
pub enum AstValue {
|
||||
pub enum Ast {
|
||||
#[default] Nil,
|
||||
Err(DslError),
|
||||
Num(usize),
|
||||
Sym(Arc<str>),
|
||||
Key(Arc<str>),
|
||||
Str(Arc<str>),
|
||||
Exp(Arc<Box<dyn Ast>>),
|
||||
Exp(Arc<Box<dyn AstIter>>),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for AstValue {
|
||||
/// Emits tokens.
|
||||
pub trait AstIter: Debug {
|
||||
fn peek (&self) -> Option<Ast>;
|
||||
fn next (&mut self) -> Option<Ast>;
|
||||
fn rest (self) -> Option<Box<dyn AstIter>>;
|
||||
}
|
||||
|
||||
/// A [Cst] can be used as an [Ast].
|
||||
impl<'source: 'static> AstIter for Cst<'source> {
|
||||
fn peek (&self) -> Option<Ast> {
|
||||
Cst::peek(self).map(|token|token.value.into())
|
||||
}
|
||||
fn next (&mut self) -> Option<Ast> {
|
||||
Iterator::next(self).map(|token|token.value.into())
|
||||
}
|
||||
fn rest (self) -> Option<Box<dyn AstIter>> {
|
||||
self.peek().is_some().then(||Box::new(self) as Box<dyn AstIter>)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Ast {
|
||||
fn fmt (&self, out: &mut Formatter) -> Result<(), std::fmt::Error> {
|
||||
use AstValue::*;
|
||||
use Ast::*;
|
||||
write!(out, "{}", match self {
|
||||
Nil => String::new(),
|
||||
Err(e) => format!("[error: {e}]"),
|
||||
|
|
@ -48,7 +48,7 @@ impl std::fmt::Display for AstValue {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'source: 'static> From<CstValue<'source>> for AstValue {
|
||||
impl<'source: 'static> From<CstValue<'source>> for Ast {
|
||||
fn from (other: CstValue<'source>) -> Self {
|
||||
use CstValue::*;
|
||||
match other {
|
||||
|
|
@ -63,8 +63,8 @@ impl<'source: 'static> From<CstValue<'source>> for AstValue {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'source: 'static> Into<Box<dyn Ast>> for Cst<'source> {
|
||||
fn into (self) -> Box<dyn Ast> {
|
||||
impl<'source: 'static> Into<Box<dyn AstIter>> for Cst<'source> {
|
||||
fn into (self) -> Box<dyn AstIter> {
|
||||
Box::new(self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,37 @@
|
|||
use crate::*;
|
||||
|
||||
pub trait Eval<Input, Output> {
|
||||
fn eval (&self, input: Input) -> Perhaps<Output>;
|
||||
fn try_eval (&self, input: Input) -> Perhaps<Output>;
|
||||
fn eval <E: Into<Box<dyn std::error::Error>>, F: Fn()->E> (
|
||||
&self, input: Input, error: F
|
||||
) -> Usually<Output> {
|
||||
if let Some(value) = self.try_eval(input)? {
|
||||
Ok(value)
|
||||
} else {
|
||||
Result::Err(format!("Eval: {}", error().into()).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// May construct [Self] from token stream.
|
||||
pub trait Dsl: Sized {
|
||||
type State;
|
||||
fn try_provide (state: Self::State, source: impl Ast) -> Perhaps<Self>;
|
||||
pub trait Dsl<State>: Sized {
|
||||
fn try_provide (state: State, source: Ast) -> Perhaps<Self>;
|
||||
fn provide <E: Into<Box<dyn std::error::Error>>, F: Fn()->E> (
|
||||
state: Self::State, source: impl Ast, error: F
|
||||
state: State, source: Ast, error: F
|
||||
) -> Usually<Self> {
|
||||
let next = source.peek().clone();
|
||||
let next = source.clone();
|
||||
if let Some(value) = Self::try_provide(state, source)? {
|
||||
Ok(value)
|
||||
} else {
|
||||
Result::Err(format!("dsl: {}: {next:?}", error().into()).into())
|
||||
Result::Err(format!("Dsl: {}: {next:?}", error().into()).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Dsl<S>, S> Eval<Ast, T> for S {
|
||||
fn try_eval (&self, input: Ast) -> Perhaps<T> { todo!() }
|
||||
}
|
||||
|
||||
//pub trait Give<'state, 'source, Type> {
|
||||
///// Implement this to be able to [Give] [Type] from the [Cst].
|
||||
///// Advance the stream if returning `Ok<Some<Type>>`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue