mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2025-12-06 03:36:42 +01:00
This commit is contained in:
parent
17506726cb
commit
c8827b43c3
9 changed files with 114 additions and 135 deletions
|
|
@ -1,4 +1,4 @@
|
|||
use std::error::Error;
|
||||
pub(crate) use std::error::Error;
|
||||
|
||||
/// Standard result type.
|
||||
pub type Usually<T> = Result<T, Box<dyn Error>>;
|
||||
|
|
@ -16,29 +16,56 @@ pub type Perhaps<T> = Result<Option<T>, Box<dyn Error>>;
|
|||
}
|
||||
|
||||
pub trait Has<T>: Send + Sync {
|
||||
fn get (&self) -> &T;
|
||||
fn get (&self) -> &T;
|
||||
fn get_mut (&mut self) -> &mut T;
|
||||
}
|
||||
|
||||
#[macro_export] macro_rules! has {
|
||||
($T:ty: |$self:ident : $S:ty| $x:expr) => {
|
||||
impl Has<$T> for $S {
|
||||
fn get (&$self) -> &$T { &$x }
|
||||
fn get (&$self) -> &$T { &$x }
|
||||
fn get_mut (&mut $self) -> &mut $T { &mut $x }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub trait MaybeHas<T>: Send + Sync {
|
||||
fn get (&self) -> Option<&T>;
|
||||
fn get (&self) -> Option<&T>;
|
||||
fn get_mut (&mut self) -> Option<&mut T>;
|
||||
}
|
||||
|
||||
#[macro_export] macro_rules! maybe_has {
|
||||
($T:ty: |$self:ident : $S:ty| $x:block; $y:block $(;)?) => {
|
||||
impl MaybeHas<$T> for $S {
|
||||
fn get (&$self) -> Option<&$T> $x
|
||||
fn get (&$self) -> Option<&$T> $x
|
||||
fn get_mut (&mut $self) -> Option<&mut $T> $y
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// May compute a `RetVal` from `Args`.
|
||||
pub trait Eval<Args, RetVal> {
|
||||
/// A custom operation on [Args] that may return [Result::Err] or [Option::None].
|
||||
fn try_eval (&self, args: Args) -> Perhaps<RetVal>;
|
||||
/// Invoke a custom operation, converting a `None` result to a custom `Box<dyn Error>`.
|
||||
fn eval <E: Into<Box<dyn std::error::Error>>> (&self, args: Args, error: impl Fn()->E)
|
||||
-> Usually<RetVal>
|
||||
{
|
||||
match self.try_eval(args)? {
|
||||
Some(value) => Ok(value),
|
||||
_ => Result::Err(format!("Eval: {}", error().into()).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//impl<S: Eval<I, O>, I, O> Eval<I, O> for &S {
|
||||
//fn try_eval (&self, input: I) -> Perhaps<O> {
|
||||
//(*self).try_eval(input)
|
||||
//}
|
||||
//}
|
||||
|
||||
//impl<S: Eval<I, O>, I: Ast, O: Dsl<S>> Eval<I, O> for S {
|
||||
//fn try_eval (&self, input: I) -> Perhaps<O> {
|
||||
//Dsl::try_provide(self, input)
|
||||
//}
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -1,30 +1,29 @@
|
|||
use crate::*;
|
||||
use std::fmt::{Display, Formatter, Error as FormatError};
|
||||
|
||||
impl Display for Ast {
|
||||
fn fmt (&self, out: &mut Formatter) -> Result<(), FormatError> {
|
||||
use Value::*;
|
||||
write!(out, "{}", match &self.0 {
|
||||
Nil => String::new(),
|
||||
Err(e) => format!("[error: {e}]"),
|
||||
Num(n) => format!("{n}"),
|
||||
Sym(s) => format!("{s}"),
|
||||
Key(s) => format!("{s}"),
|
||||
Str(s) => format!("{s}"),
|
||||
Exp(_, e) => format!("{e:?}"),
|
||||
})
|
||||
match &self.0 {
|
||||
Value::Nil => Ok(()),
|
||||
Value::Err(e) => write!(out, "[error: {e}]"),
|
||||
Value::Num(n) => write!(out, "{n}"),
|
||||
Value::Sym(s) => write!(out, "{s}"),
|
||||
Value::Key(s) => write!(out, "{s}"),
|
||||
Value::Str(s) => write!(out, "{s}"),
|
||||
Value::Exp(_, e) => write!(out, "{e:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'source> Display for CstValue<'source> {
|
||||
fn fmt (&self, out: &mut Formatter) -> Result<(), FormatError> {
|
||||
use Value::*;
|
||||
write!(out, "{}", match self {
|
||||
Nil => String::new(),
|
||||
Err(e) => format!("[error: {e}]"),
|
||||
Num(n) => format!("{n}"),
|
||||
Sym(s) => format!("{s}"),
|
||||
Key(s) => format!("{s}"),
|
||||
Str(s) => format!("{s}"),
|
||||
Exp(_, e) => format!("{e:?}"),
|
||||
})
|
||||
match self {
|
||||
Value::Nil => Ok(()),
|
||||
Value::Err(e) => write!(out, "[error: {e}]"),
|
||||
Value::Num(n) => write!(out, "{n}"),
|
||||
Value::Sym(s) => write!(out, "{s}"),
|
||||
Value::Key(s) => write!(out, "{s}"),
|
||||
Value::Str(s) => write!(out, "{s}"),
|
||||
Value::Exp(_, e) => write!(out, "{e:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,84 +0,0 @@
|
|||
use crate::*;
|
||||
|
||||
pub trait Eval<Input, 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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//impl<S: Eval<I, O>, I, O> Eval<I, O> for &S {
|
||||
//fn try_eval (&self, input: I) -> Perhaps<O> {
|
||||
//(*self).try_eval(input)
|
||||
//}
|
||||
//}
|
||||
|
||||
//impl<S: Eval<I, O>, I: Ast, O: Dsl<S>> Eval<I, O> for S {
|
||||
//fn try_eval (&self, input: I) -> Perhaps<O> {
|
||||
//Dsl::try_provide(self, input)
|
||||
//}
|
||||
//}
|
||||
|
||||
/// May construct [Self] from token stream.
|
||||
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: &State, source: Ast, error: F
|
||||
) -> Usually<Self> {
|
||||
let next = format!("{source:?}");
|
||||
if let Some(value) = Self::try_provide(state, source)? {
|
||||
Ok(value)
|
||||
} else {
|
||||
Result::Err(format!("Dsl: {}: {next:?}", error().into()).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//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>>`.
|
||||
//fn give (&'state self, words: Cst<'source>) -> Perhaps<Type>;
|
||||
///// Return custom error on [None].
|
||||
//fn give_or_fail <E: Into<Box<dyn std::error::Error>>, F: Fn()->E> (
|
||||
//&'state self, mut words: Cst<'source>, error: F
|
||||
//) -> Usually<Type> {
|
||||
//let next = words.peek().map(|x|x.value).clone();
|
||||
//if let Some(value) = Give::<Type>::give(self, words)? {
|
||||
//Ok(value)
|
||||
//} else {
|
||||
//Result::Err(format!("give: {}: {next:?}", error().into()).into())
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
//#[macro_export] macro_rules! give {
|
||||
//($Type:ty|$state:ident:$State:ident,$words:ident|$expr:expr) => {
|
||||
//impl Give<$Type> for $State {
|
||||
//fn give (&self, mut $words: Cst) -> Perhaps<$Type> {
|
||||
//let $state = self;
|
||||
//$expr
|
||||
//}
|
||||
//}
|
||||
//};
|
||||
//($Type:path$(,$Arg:ident)*|$state:ident,$words:ident|$expr:expr) => {
|
||||
//impl<State: $(Give<$Arg>)++ $(, $Arg)*> Give<$Type> for State {
|
||||
//fn give (&self, mut $words: Cst) -> Perhaps<$Type> {
|
||||
//let $state = self;
|
||||
//$expr
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
/////// Implement the [Give] trait, which boils down to
|
||||
/////// specifying two types and providing an expression.
|
||||
//#[macro_export] macro_rules! from_dsl {
|
||||
//($Type:ty: |$state:ident:$State:ty, $words:ident|$expr:expr) => {
|
||||
//give! { $Type|$state:$State,$words|$expr }
|
||||
//};
|
||||
//}
|
||||
|
||||
|
|
@ -1,5 +1,20 @@
|
|||
use crate::*;
|
||||
use std::fmt::Display;
|
||||
|
||||
/// Thing that may construct itself from state and [DslValue].
|
||||
pub trait Dsl<State>: Sized {
|
||||
fn try_provide (state: &State, value: impl DslValue) -> Perhaps<Self>;
|
||||
fn provide (
|
||||
state: &State,
|
||||
value: impl DslValue,
|
||||
error: impl Fn()->Box<dyn std::error::Error>
|
||||
) -> Usually<Self> {
|
||||
match Self::try_provide(state, value)? {
|
||||
Some(value) => Ok(value),
|
||||
_ => Err(error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait DslValue: PartialEq + Clone + Default + Debug {
|
||||
type Str: AsRef<str> + PartialEq + Clone + Default + Debug;
|
||||
type Exp: PartialEq + Clone + Default + Debug;
|
||||
|
|
@ -29,6 +44,7 @@ pub trait DslValue: PartialEq + Clone + Default + Debug {
|
|||
fn exp_head (&self) -> Option<&Self> { None } // TODO
|
||||
fn exp_tail (&self) -> Option<&[Self]> { None } // TODO
|
||||
}
|
||||
|
||||
impl<
|
||||
Str: AsRef<str> + PartialEq + Clone + Default + Debug,
|
||||
Exp: PartialEq + Clone + Default + Debug,
|
||||
|
|
@ -40,8 +56,20 @@ impl<
|
|||
}
|
||||
}
|
||||
|
||||
pub enum Value<S, X> { Nil, Err(DslError), Num(usize), Sym(S), Key(S), Str(S), Exp(usize, X), }
|
||||
impl<S, X> Default for Value<S, X> { fn default () -> Self { Self:: Nil } }
|
||||
pub enum Value<S, X> {
|
||||
Nil,
|
||||
Err(DslError),
|
||||
Num(usize),
|
||||
Sym(S),
|
||||
Key(S),
|
||||
Str(S),
|
||||
Exp(usize, X),
|
||||
}
|
||||
|
||||
impl<S, X> Default for Value<S, X> {
|
||||
fn default () -> Self { Self:: Nil }
|
||||
}
|
||||
|
||||
impl<S: PartialEq, X: PartialEq,> PartialEq for Value<S, X> {
|
||||
fn eq (&self, other: &Self) -> bool {
|
||||
use Value::*;
|
||||
|
|
@ -57,6 +85,7 @@ impl<S: PartialEq, X: PartialEq,> PartialEq for Value<S, X> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Clone, X: Clone,> Clone for Value<S, X> {
|
||||
fn clone (&self) -> Self {
|
||||
use Value::*;
|
||||
|
|
@ -71,12 +100,15 @@ impl<S: Clone, X: Clone,> Clone for Value<S, X> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Copy, X: Copy,> Copy for Value<S, X> {}
|
||||
|
||||
impl<S: Debug, X: Debug,> Debug for Value<S, X> {
|
||||
fn fmt (&self, _f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Display, X: Display,> Display for Value<S, X> {
|
||||
fn fmt (&self, _f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
todo!()
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#![feature(impl_trait_in_fn_trait_return)]
|
||||
pub(crate) use ::tengri_core::*;
|
||||
pub(crate) use std::fmt::Debug;
|
||||
pub(crate) use std::fmt::{Display, Formatter, Error as FormatError};
|
||||
pub(crate) use konst::iter::{ConstIntoIter, IsIteratorKind};
|
||||
pub(crate) use konst::string::{split_at, str_range, char_indices};
|
||||
pub(crate) use thiserror::Error;
|
||||
|
|
@ -43,7 +44,6 @@ pub(crate) use self::DslError::*;
|
|||
mod dsl_ast; pub use self::dsl_ast::*;
|
||||
mod dsl_cst; pub use self::dsl_cst::*;
|
||||
mod dsl_display; //pub use self::dsl_display::*;
|
||||
mod dsl_domain; pub use self::dsl_domain::*;
|
||||
mod dsl_error; pub use self::dsl_error::*;
|
||||
mod dsl_iter; pub use self::dsl_iter::*;
|
||||
mod dsl_token; pub use self::dsl_token::*;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,10 @@ use std::fmt::Debug;
|
|||
|
||||
#[derive(Default, Debug)] pub struct InputLayers(Vec<InputLayer>);
|
||||
|
||||
#[derive(Default, Debug)] pub struct InputLayer(Option<Ast>, Ast);
|
||||
#[derive(Default, Debug)] pub struct InputLayer {
|
||||
condition: Option<Ast>,
|
||||
bindings: Ast,
|
||||
}
|
||||
|
||||
impl InputLayers {
|
||||
pub fn new (layer: Ast) -> Self {
|
||||
|
|
@ -19,8 +22,8 @@ impl InputLayers {
|
|||
pub fn add_layer (&mut self, layer: Ast) -> &mut Self {
|
||||
self.add_layer_if(None, layer.into()); self
|
||||
}
|
||||
pub fn add_layer_if (&mut self, condition: Option<Ast>, binding: Ast) -> &mut Self {
|
||||
self.0.push(InputLayer(condition, binding));
|
||||
pub fn add_layer_if (&mut self, condition: Option<Ast>, bindings: Ast) -> &mut Self {
|
||||
self.0.push(InputLayer { condition, bindings });
|
||||
self
|
||||
}
|
||||
pub fn handle <S: Eval<Ast, bool> + Eval<Ast, O>, I: Eval<Ast, bool>, O: Command<S>> (&self, state: &mut S, input: I) -> Perhaps<O> {
|
||||
|
|
@ -33,13 +36,13 @@ pub struct InputHandle<'a, S>(&'a mut S, &'a [InputLayer]);
|
|||
impl<'a, S: Eval<Ast, bool> + Eval<Ast, O>, I: Eval<Ast, bool>, O: Command<S>> Eval<I, O> for InputHandle<'a, S> {
|
||||
fn try_eval (&self, input: I) -> Perhaps<O> {
|
||||
let Self(state, layers) = self;
|
||||
for InputLayer(condition, binding) in layers.iter() {
|
||||
for InputLayer { condition, bindings } in layers.iter() {
|
||||
let mut matches = true;
|
||||
if let Some(condition) = condition {
|
||||
matches = state.eval(condition.clone(), ||"input: no condition")?;
|
||||
}
|
||||
if matches
|
||||
&& let Some(exp) = binding.exp()
|
||||
&& let Some(exp) = bindings.exp()
|
||||
&& let Some(ast) = exp.peek()
|
||||
&& input.eval(ast.clone(), ||"InputLayers: input.eval(binding) failed")?
|
||||
&& let Some(command) = state.try_eval(ast)? {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@ use crate::*;
|
|||
use Value::*;
|
||||
|
||||
impl<S, A> Dsl<S> for When<A> where S: Eval<Ast, bool> + Eval<Ast, A> {
|
||||
fn try_provide (state: &S, source: Ast) -> Perhaps<Self> {
|
||||
if let Exp(_, mut exp) = source.0 && let Some(Ast(Key(id))) = exp.peek() && *id == *"when" {
|
||||
fn try_provide (state: &S, source: impl DslValue) -> Perhaps<Self> {
|
||||
if let Exp(_, mut exp) = source.value()
|
||||
&& let Some(Ast(Key(id))) = exp.peek() && *id == *"when" {
|
||||
let _ = exp.next();
|
||||
return Ok(Some(Self(
|
||||
state.eval(exp.next().unwrap(), ||"when: expected condition")?,
|
||||
|
|
@ -15,8 +16,9 @@ impl<S, A> Dsl<S> for When<A> where S: Eval<Ast, bool> + Eval<Ast, A> {
|
|||
}
|
||||
|
||||
impl<S, A, B> Dsl<S> for Either<A, B> where S: Eval<Ast, bool> + Eval<Ast, A> + Eval<Ast, B> {
|
||||
fn try_provide (state: &S, source: Ast) -> Perhaps<Self> {
|
||||
if let Exp(_, mut exp) = source.0 && let Some(Ast(Key(id))) = exp.peek() && *id == *"either" {
|
||||
fn try_provide (state: &S, source: impl DslValue) -> Perhaps<Self> {
|
||||
if let Exp(_, mut exp) = source.value()
|
||||
&& let Some(Ast(Key(id))) = exp.peek() && *id == *"either" {
|
||||
let _ = exp.next();
|
||||
return Ok(Some(Self(
|
||||
state.eval(exp.next().unwrap(), ||"either: expected condition")?,
|
||||
|
|
@ -29,8 +31,8 @@ impl<S, A, B> Dsl<S> for Either<A, B> where S: Eval<Ast, bool> + Eval<Ast, A> +
|
|||
}
|
||||
|
||||
impl<S, A> Dsl<S> for Align<A> where S: Eval<Option<Ast>, A> {
|
||||
fn try_provide (state: &S, source: Ast) -> Perhaps<Self> {
|
||||
if let Exp(_, source) = source.0 {
|
||||
fn try_provide (state: &S, source: impl DslValue) -> Perhaps<Self> {
|
||||
if let Exp(_, source) = source.value() {
|
||||
let mut rest = source.clone();
|
||||
return Ok(Some(match rest.next().as_ref().and_then(|x|x.key()) {
|
||||
Some("align/c") => Self::c(state.eval(rest.next(), ||"align/c: expected content")?),
|
||||
|
|
@ -52,8 +54,8 @@ impl<S, A> Dsl<S> for Align<A> where S: Eval<Option<Ast>, A> {
|
|||
}
|
||||
|
||||
impl<S, A, B> Dsl<S> for Bsp<A, B> where S: Eval<Option<Ast>, A> + Eval<Option<Ast>, B> {
|
||||
fn try_provide (state: &S, source: Ast) -> Perhaps<Self> {
|
||||
if let Exp(_, exp) = source.0 {
|
||||
fn try_provide (state: &S, source: impl DslValue) -> Perhaps<Self> {
|
||||
if let Exp(_, exp) = source.value() {
|
||||
let mut rest = exp.clone();
|
||||
return Ok(Some(match rest.next().as_ref().and_then(|x|x.key()) {
|
||||
Some("bsp/n") => Self::n(
|
||||
|
|
|
|||
|
|
@ -64,7 +64,9 @@ impl ToTokens for ViewDef {
|
|||
/// which might correspond to a given [TokenStream],
|
||||
/// while taking [#self_ty]'s state into consideration.
|
||||
impl<'state> ::tengri::dsl::Dsl<Box<dyn Render<#output> + 'state>> for #self_ty {
|
||||
fn try_provide (state: &'state #self_ty, mut words: ::tengri::dsl::Ast) -> Perhaps<Box<dyn Render<#output> + 'state>> {
|
||||
fn try_provide (state: &'state #self_ty, mut words: ::tengri::dsl::Ast) ->
|
||||
Perhaps<Box<dyn Render<#output> + 'state>>
|
||||
{
|
||||
Ok(if let Some(::tengri::dsl::Token { value, .. }) = words.peek() {
|
||||
match value { #(#builtin)* #(#exposed)* _ => None }
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
use crate::*;
|
||||
|
||||
#[test] fn test_subcommand () -> Usually<()> {
|
||||
use crate::input::{Command, Handle, handle};
|
||||
//use crate::dsl::TokenIter;
|
||||
use crate::tui::TuiIn;
|
||||
use crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState};
|
||||
//use crate::input::*;
|
||||
//use crate::dsl::*;
|
||||
use crate::input::*;
|
||||
use crate::dsl::*;
|
||||
struct Test {
|
||||
//keys: InputMap<'static, Test, TestCommand, TuiIn, TokenIter<'static>>
|
||||
keys: InputLayers
|
||||
}
|
||||
handle!(TuiIn: |self: Test, input|if let Some(command) = self.keys.command(self, input) {
|
||||
Ok(Some(true))
|
||||
|
|
@ -37,12 +35,12 @@ use crate::*;
|
|||
}
|
||||
}
|
||||
let mut test = Test {
|
||||
keys: InputMap::new("
|
||||
keys: InputLayers::new(SourceIter::new("
|
||||
(@a do-thing)
|
||||
(@b do-thing-arg 0)
|
||||
(@c do-sub do-other-thing)
|
||||
(@d do-sub do-other-thing-arg 0)
|
||||
".into())
|
||||
".into()))
|
||||
};
|
||||
assert_eq!(Some(true), test.handle(&TuiIn(Default::default(), Event::Key(KeyEvent {
|
||||
kind: KeyEventKind::Press,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue