From 7097333993c070f9a5bafe651f8f2e4632b8e4e7 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Mon, 26 May 2025 01:30:13 +0300 Subject: [PATCH 1/2] wip: dsl: more rework --- dsl/src/dsl_ast.rs | 54 ++++++++-------- dsl/src/dsl_domain.rs | 26 +++++--- input/src/input_dsl.rs | 86 +++++++++++-------------- output/src/ops_dsl.rs | 138 +++++++++++++++++++---------------------- 4 files changed, 145 insertions(+), 159 deletions(-) diff --git a/dsl/src/dsl_ast.rs b/dsl/src/dsl_ast.rs index 7922d26..15c4374 100644 --- a/dsl/src/dsl_ast.rs +++ b/dsl/src/dsl_ast.rs @@ -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; - fn next (&mut self) -> Option; - fn rest (self) -> Option>; -} - -/// A [Cst] can be used as an [Ast]. -impl<'source: 'static> Ast for Cst<'source> { - fn peek (&self) -> Option { - Cst::peek(self).map(|token|token.value.into()) - } - fn next (&mut self) -> Option { - Iterator::next(self).map(|token|token.value.into()) - } - fn rest (self) -> Option> { - self.peek().is_some().then(||Box::new(self) as Box) - } -} - #[derive(Clone, Default, Debug)] -pub enum AstValue { +pub enum Ast { #[default] Nil, Err(DslError), Num(usize), Sym(Arc), Key(Arc), Str(Arc), - Exp(Arc>), + Exp(Arc>), } -impl std::fmt::Display for AstValue { +/// Emits tokens. +pub trait AstIter: Debug { + fn peek (&self) -> Option; + fn next (&mut self) -> Option; + fn rest (self) -> Option>; +} + +/// A [Cst] can be used as an [Ast]. +impl<'source: 'static> AstIter for Cst<'source> { + fn peek (&self) -> Option { + Cst::peek(self).map(|token|token.value.into()) + } + fn next (&mut self) -> Option { + Iterator::next(self).map(|token|token.value.into()) + } + fn rest (self) -> Option> { + self.peek().is_some().then(||Box::new(self) as Box) + } +} + +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> for AstValue { +impl<'source: 'static> From> for Ast { fn from (other: CstValue<'source>) -> Self { use CstValue::*; match other { @@ -63,8 +63,8 @@ impl<'source: 'static> From> for AstValue { } } -impl<'source: 'static> Into> for Cst<'source> { - fn into (self) -> Box { +impl<'source: 'static> Into> for Cst<'source> { + fn into (self) -> Box { Box::new(self) } } diff --git a/dsl/src/dsl_domain.rs b/dsl/src/dsl_domain.rs index 283d79a..88af556 100644 --- a/dsl/src/dsl_domain.rs +++ b/dsl/src/dsl_domain.rs @@ -1,25 +1,37 @@ use crate::*; pub trait Eval { - fn eval (&self, input: Input) -> Perhaps; + fn try_eval (&self, input: Input) -> Perhaps; + fn eval >, F: Fn()->E> ( + &self, input: Input, error: F + ) -> Usually { + 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; +pub trait Dsl: Sized { + fn try_provide (state: State, source: Ast) -> Perhaps; fn provide >, F: Fn()->E> ( - state: Self::State, source: impl Ast, error: F + state: State, source: Ast, error: F ) -> Usually { - 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, S> Eval for S { + fn try_eval (&self, input: Ast) -> Perhaps { todo!() } +} + //pub trait Give<'state, 'source, Type> { ///// Implement this to be able to [Give] [Type] from the [Cst]. ///// Advance the stream if returning `Ok>`. diff --git a/input/src/input_dsl.rs b/input/src/input_dsl.rs index 3610f36..c6d26e1 100644 --- a/input/src/input_dsl.rs +++ b/input/src/input_dsl.rs @@ -1,67 +1,53 @@ use crate::*; use std::marker::PhantomData; +use std::fmt::Debug; /// List of input layers with optional conditional filters. #[derive(Default, Debug)] pub struct InputLayers(Vec>); #[derive(Default, Debug)] pub struct InputLayer{ __: PhantomData, - condition: Option>, - bindings: Box, + condition: Option, + binding: Ast, } impl InputLayers { - pub fn new (layer: Box) -> Self - { Self(vec![]).layer(layer) } - pub fn layer (mut self, layer: Box) -> Self - { self.add_layer(layer); self } - pub fn layer_if (mut self, condition: Box, layer: Box) -> Self - { self.add_layer_if(Some(condition), layer); self } - pub fn add_layer (&mut self, layer: Box) -> &mut Self - { self.add_layer_if(None, layer.into()); self } - pub fn add_layer_if ( - &mut self, - condition: Option>, - bindings: Box - ) -> &mut Self { - self.0.push(InputLayer { condition, bindings, __: Default::default() }); + pub fn new (layer: Ast) -> Self { + Self(vec![]).layer(layer) + } + pub fn layer (mut self, layer: Ast) -> Self { + self.add_layer(layer); self + } + pub fn layer_if (mut self, condition: Ast, layer: Ast) -> Self { + self.add_layer_if(Some(condition), layer); self + } + 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, binding: Ast) -> &mut Self { + self.0.push(InputLayer { condition, binding, __: Default::default() }); self } } -impl, I: Input, O: Command> Eval for InputLayers { - fn eval (&self, input: I) -> Perhaps { - for layer in self.0.iter() { - if let Some(command) = Ok(if let Some(condition) = layer.condition.as_ref() { - if self.matches(condition)? { - self.state().eval(*self)? - } else { - None +impl + Eval, C: Command, I: Debug + Eval> Eval<(S, I), C> for InputLayers { + fn try_eval (&self, (state, input): (S, I)) -> Perhaps { + for InputLayer { condition, binding, .. } in self.0.iter() { + let mut matches = true; + if let Some(condition) = condition { + matches = state.eval(condition.clone(), ||"input: no condition")?; + } + if matches { + if let Ast::Exp(e) = binding { + if let Some(ast) = e.peek() { + if input.eval(ast.clone(), ||"InputLayers: input.eval(binding) failed")? + && let Some(command) = state.try_eval(ast)? { + return Ok(Some(command)) + } + } else { + unreachable!("InputLayer") + } + } else { + panic!("InputLayer: expected expression, got: {input:?}") } - } else { - self.state().eval(*self)? - })? { - return Ok(Some(command)) } } - } -} -/// [Input] state that can be matched against a [CstValue]. -pub trait InputState: Input { - fn state (&self) -> &S; - fn matches (&self, condition: &Box) -> Usually; -} -impl, I: InputState, O: Command> Eval -for InputLayer { - fn eval (&self, input: I) -> Perhaps { - if let Some(AstToken::Exp(exp)) = iter.peek() { - let mut e = exp.clone(); - if let Some(AstToken::Sym(binding)) = e.next() - && input.matches_dsl(binding) - && let Some(command) = Dsl::from_dsl(input.state(), e)? { - return Ok(Some(command)) - } else { - unreachable!("InputLayer: expected symbol, got: {e:?}") - } - } else { - panic!("InputLayer: expected expression, got: {self:?}") - } Ok(None) } } diff --git a/output/src/ops_dsl.rs b/output/src/ops_dsl.rs index d34cc34..d718b10 100644 --- a/output/src/ops_dsl.rs +++ b/output/src/ops_dsl.rs @@ -1,143 +1,131 @@ use crate::*; -impl Eval> for S where - S: Eval + Eval -{ - fn eval (&self, source: I) -> Perhaps { +impl Dsl for When where S: Eval + Eval { + fn try_provide (state: S, source: Ast) -> Perhaps { Ok(match source.peek() { Some(Value::Key("when")) => Some(Self( - self.provide(source, ||"when: expected condition")?, - self.provide(source, ||"when: expected content")?, + state.eval(source, ||"when: expected condition")?, + state.eval(source, ||"when: expected content")?, )), _ => None }) } } -impl Eval> for S where - S: Eval + Eval + Eval -{ - fn eval (&self, source: I) -> Perhaps { +impl Dsl for Either where S: Eval + Eval + Eval { + fn try_provide (state: S, source: Ast) -> Perhaps { Ok(match source.peek() { Some(Value::Key("either")) => Some(Self( - self.provide(source, ||"either: expected condition")?, - self.provide(source, ||"either: expected content 1")?, - self.provide(source, ||"either: expected content 2")? + state.eval(source, ||"either: expected condition")?, + state.eval(source, ||"either: expected content 1")?, + state.eval(source, ||"either: expected content 2")? )), _ => None }) } } -impl Eval> for S where - S: Eval + Eval -{ - fn eval (&self, source: I) -> Perhaps { - Ok(if let Some(Value::Key(key)) = source.peek() { - Some(match key { - "bsp/n" => { - let _ = source.next(); - let a: A = self.provide(source, ||"bsp/n: expected content 1")?; - let b: B = self.provide(source, ||"bsp/n: expected content 2")?; - Self::n(a, b) - }, - "bsp/s" => { - let _ = source.next(); - let a: A = self.provide(source, ||"bsp/s: expected content 1")?; - let b: B = self.provide(source, ||"bsp/s: expected content 2")?; - Self::s(a, b) - }, - "bsp/e" => { - let _ = source.next(); - let a: A = self.provide(source, ||"bsp/e: expected content 1")?; - let b: B = self.provide(source, ||"bsp/e: expected content 2")?; - Self::e(a, b) - }, - "bsp/w" => { - let _ = source.next(); - let a: A = self.provide(source, ||"bsp/w: expected content 1")?; - let b: B = self.provide(source, ||"bsp/w: expected content 2")?; - Self::w(a, b) - }, - "bsp/a" => { - let _ = source.next(); - let a: A = self.provide(source, ||"bsp/a: expected content 1")?; - let b: B = self.provide(source, ||"bsp/a: expected content 2")?; - Self::a(a, b) - }, - "bsp/b" => { - let _ = source.next(); - let a: A = self.provide(source, ||"bsp/b: expected content 1")?; - let b: B = self.provide(source, ||"bsp/b: expected content 2")?; - Self::b(a, b) - }, - _ => return Ok(None), - }) - } else { - None - }) +impl Dsl for Bsp where S: Eval + Eval { + fn try_provide (state: S, source: Ast) -> Perhaps { + Ok(Some(match source.peek() { + Some(Value::Key("bsp/n")) => { + let _ = source.next(); + let a: A = state.eval(source, ||"bsp/n: expected content 1")?; + let b: B = state.eval(source, ||"bsp/n: expected content 2")?; + Self::n(a, b) + }, + Some(Value::Key("bsp/s")) => { + let _ = source.next(); + let a: A = state.eval(source, ||"bsp/s: expected content 1")?; + let b: B = state.eval(source, ||"bsp/s: expected content 2")?; + Self::s(a, b) + }, + Some(Value::Key("bsp/e")) => { + let _ = source.next(); + let a: A = state.eval(source, ||"bsp/e: expected content 1")?; + let b: B = state.eval(source, ||"bsp/e: expected content 2")?; + Self::e(a, b) + }, + Some(Value::Key("bsp/w")) => { + let _ = source.next(); + let a: A = state.eval(source, ||"bsp/w: expected content 1")?; + let b: B = state.eval(source, ||"bsp/w: expected content 2")?; + Self::w(a, b) + }, + Some(Value::Key("bsp/a")) => { + let _ = source.next(); + let a: A = state.eval(source, ||"bsp/a: expected content 1")?; + let b: B = state.eval(source, ||"bsp/a: expected content 2")?; + Self::a(a, b) + }, + Some(Value::Key("bsp/b")) => { + let _ = source.next(); + let a: A = state.eval(source, ||"bsp/b: expected content 1")?; + let b: B = state.eval(source, ||"bsp/b: expected content 2")?; + Self::b(a, b) + }, + _ => return Ok(None), + })) } } -impl Eval> for S where - S: Eval -{ - fn eval (&self, source: I) -> Perhaps { +impl Dsl for Align where S: Eval { + fn try_provide (state: S, source: Ast) -> Perhaps { Ok(if let Some(Value::Key(key)) = source.peek() { Some(match key { "align/c" => { let _ = source.next(); - let content: A = self.provide(source, ||"align/c: expected content")?; + let content: A = state.eval(source, ||"align/c: expected content")?; Self::c(content) }, "align/x" => { let _ = source.next(); - let content: A = self.provide(source, ||"align/x: expected content")?; + let content: A = state.eval(source, ||"align/x: expected content")?; Self::x(content) }, "align/y" => { let _ = source.next(); - let content: A = self.provide(source, ||"align/y: expected content")?; + let content: A = state.eval(source, ||"align/y: expected content")?; Self::y(content) }, "align/n" => { let _ = source.next(); - let content: A = self.provide(source, ||"align/n: expected content")?; + let content: A = state.eval(source, ||"align/n: expected content")?; Self::n(content) }, "align/s" => { let _ = source.next(); - let content: A = self.provide(source, ||"align/s: expected content")?; + let content: A = state.eval(source, ||"align/s: expected content")?; Self::s(content) }, "align/e" => { let _ = source.next(); - let content: A = self.provide(source, ||"align/e: expected content")?; + let content: A = state.eval(source, ||"align/e: expected content")?; Self::e(content) }, "align/w" => { let _ = source.next(); - let content: A = self.provide(source, ||"align/w: expected content")?; + let content: A = state.eval(source, ||"align/w: expected content")?; Self::w(content) }, "align/nw" => { let _ = source.next(); - let content: A = self.provide(source, ||"align/nw: expected content")?; + let content: A = state.eval(source, ||"align/nw: expected content")?; Self::nw(content) }, "align/ne" => { let _ = source.next(); - let content: A = self.provide(source, ||"align/ne: expected content")?; + let content: A = state.eval(source, ||"align/ne: expected content")?; Self::ne(content) }, "align/sw" => { let _ = source.next(); - let content: A = self.provide(source, ||"align/sw: expected content")?; + let content: A = state.eval(source, ||"align/sw: expected content")?; Self::sw(content) }, "align/se" => { let _ = source.next(); - let content: A = self.provide(source, ||"align/se: expected content")?; + let content: A = state.eval(source, ||"align/se: expected content")?; Self::se(content) }, _ => return Ok(None), From 93b1cf1a5cebb22909c914a40e9685af125d7d42 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Mon, 26 May 2025 01:45:08 +0300 Subject: [PATCH 2/2] wip: dsl: getting interesting --- output/src/ops_dsl.rs | 180 ++++++++++++++++++++---------------------- 1 file changed, 86 insertions(+), 94 deletions(-) diff --git a/output/src/ops_dsl.rs b/output/src/ops_dsl.rs index d718b10..e86a634 100644 --- a/output/src/ops_dsl.rs +++ b/output/src/ops_dsl.rs @@ -2,137 +2,129 @@ use crate::*; impl Dsl for When where S: Eval + Eval { fn try_provide (state: S, source: Ast) -> Perhaps { - Ok(match source.peek() { - Some(Value::Key("when")) => Some(Self( - state.eval(source, ||"when: expected condition")?, - state.eval(source, ||"when: expected content")?, - )), - _ => None - }) + if let Ast::Exp(source) = source { + if let Some(Ast::Key(id)) = source.next() && *id == *"when" { + return Ok(Some(Self( + state.eval(source.next().unwrap(), ||"when: expected condition")?, + state.eval(source.next().unwrap(), ||"when: expected content")?, + ))) + } + } + Ok(None) } } impl Dsl for Either where S: Eval + Eval + Eval { - fn try_provide (state: S, source: Ast) -> Perhaps { - Ok(match source.peek() { - Some(Value::Key("either")) => Some(Self( - state.eval(source, ||"either: expected condition")?, - state.eval(source, ||"either: expected content 1")?, - state.eval(source, ||"either: expected content 2")? - )), - _ => None - }) + fn try_provide (state: S, mut source: Ast) -> Perhaps { + if let Ast::Exp(mut source) = source { + if let Some(Ast::Key(id)) = source.next() && *id == *"either" { + return Ok(Some(Self( + state.eval(source.next().unwrap(), ||"either: expected condition")?, + state.eval(source.next().unwrap(), ||"either: expected content 1")?, + state.eval(source.next().unwrap(), ||"either: expected content 2")?, + ))) + } + } + Ok(None) } } -impl Dsl for Bsp where S: Eval + Eval { +impl Dsl for Bsp +where S: Eval, A> + Eval, B> { fn try_provide (state: S, source: Ast) -> Perhaps { - Ok(Some(match source.peek() { - Some(Value::Key("bsp/n")) => { - let _ = source.next(); - let a: A = state.eval(source, ||"bsp/n: expected content 1")?; - let b: B = state.eval(source, ||"bsp/n: expected content 2")?; - Self::n(a, b) - }, - Some(Value::Key("bsp/s")) => { - let _ = source.next(); - let a: A = state.eval(source, ||"bsp/s: expected content 1")?; - let b: B = state.eval(source, ||"bsp/s: expected content 2")?; - Self::s(a, b) - }, - Some(Value::Key("bsp/e")) => { - let _ = source.next(); - let a: A = state.eval(source, ||"bsp/e: expected content 1")?; - let b: B = state.eval(source, ||"bsp/e: expected content 2")?; - Self::e(a, b) - }, - Some(Value::Key("bsp/w")) => { - let _ = source.next(); - let a: A = state.eval(source, ||"bsp/w: expected content 1")?; - let b: B = state.eval(source, ||"bsp/w: expected content 2")?; - Self::w(a, b) - }, - Some(Value::Key("bsp/a")) => { - let _ = source.next(); - let a: A = state.eval(source, ||"bsp/a: expected content 1")?; - let b: B = state.eval(source, ||"bsp/a: expected content 2")?; - Self::a(a, b) - }, - Some(Value::Key("bsp/b")) => { - let _ = source.next(); - let a: A = state.eval(source, ||"bsp/b: expected content 1")?; - let b: B = state.eval(source, ||"bsp/b: expected content 2")?; - Self::b(a, b) - }, - _ => return Ok(None), + Ok(Some(if let Ast::Exp(source) = source { + match source.next() { + Some(Value::Key("bsp/n")) => { + let a: A = state.eval(source.next(), ||"bsp/n: expected content 1")?; + let b: B = state.eval(source.next(), ||"bsp/n: expected content 2")?; + Self::n(a, b) + }, + Some(Value::Key("bsp/s")) => { + let a: A = state.eval(source.next(), ||"bsp/s: expected content 1")?; + let b: B = state.eval(source.next(), ||"bsp/s: expected content 2")?; + Self::s(a, b) + }, + Some(Value::Key("bsp/e")) => { + let a: A = state.eval(source.next(), ||"bsp/e: expected content 1")?; + let b: B = state.eval(source.next(), ||"bsp/e: expected content 2")?; + Self::e(a, b) + }, + Some(Value::Key("bsp/w")) => { + let a: A = state.eval(source.next(), ||"bsp/w: expected content 1")?; + let b: B = state.eval(source.next(), ||"bsp/w: expected content 2")?; + Self::w(a, b) + }, + Some(Value::Key("bsp/a")) => { + let a: A = state.eval(source.next(), ||"bsp/a: expected content 1")?; + let b: B = state.eval(source.next(), ||"bsp/a: expected content 2")?; + Self::a(a, b) + }, + Some(Value::Key("bsp/b")) => { + let a: A = state.eval(source.next(), ||"bsp/b: expected content 1")?; + let b: B = state.eval(source.next(), ||"bsp/b: expected content 2")?; + Self::b(a, b) + }, + _ => return Ok(None), + } + } else { + return Ok(None) })) } } -impl Dsl for Align where S: Eval { +impl Dsl for Align where S: Eval, A> { fn try_provide (state: S, source: Ast) -> Perhaps { - Ok(if let Some(Value::Key(key)) = source.peek() { - Some(match key { - "align/c" => { - let _ = source.next(); - let content: A = state.eval(source, ||"align/c: expected content")?; + Ok(Some(if let Ast::Exp(source) = source { + match source.next() { + Some(Value::Key("align/c")) => { + let content: A = state.eval(source.next(), ||"align/c: expected content")?; Self::c(content) }, - "align/x" => { - let _ = source.next(); - let content: A = state.eval(source, ||"align/x: expected content")?; + Some(Value::Key("align/x")) => { + let content: A = state.eval(source.next(), ||"align/x: expected content")?; Self::x(content) }, - "align/y" => { - let _ = source.next(); - let content: A = state.eval(source, ||"align/y: expected content")?; + Some(Value::Key("align/y")) => { + let content: A = state.eval(source.next(), ||"align/y: expected content")?; Self::y(content) }, - "align/n" => { - let _ = source.next(); - let content: A = state.eval(source, ||"align/n: expected content")?; + Some(Value::Key("align/n")) => { + let content: A = state.eval(source.next(), ||"align/n: expected content")?; Self::n(content) }, - "align/s" => { - let _ = source.next(); - let content: A = state.eval(source, ||"align/s: expected content")?; + Some(Value::Key("align/s")) => { + let content: A = state.eval(source.next(), ||"align/s: expected content")?; Self::s(content) }, - "align/e" => { - let _ = source.next(); - let content: A = state.eval(source, ||"align/e: expected content")?; + Some(Value::Key("align/e")) => { + let content: A = state.eval(source.next(), ||"align/e: expected content")?; Self::e(content) }, - "align/w" => { - let _ = source.next(); - let content: A = state.eval(source, ||"align/w: expected content")?; + Some(Value::Key("align/w")) => { + let content: A = state.eval(source.next(), ||"align/w: expected content")?; Self::w(content) }, - "align/nw" => { - let _ = source.next(); - let content: A = state.eval(source, ||"align/nw: expected content")?; + Some(Value::Key("align/nw")) => { + let content: A = state.eval(source.next(), ||"align/nw: expected content")?; Self::nw(content) }, - "align/ne" => { - let _ = source.next(); - let content: A = state.eval(source, ||"align/ne: expected content")?; + Some(Value::Key("align/ne")) => { + let content: A = state.eval(source.next(), ||"align/ne: expected content")?; Self::ne(content) }, - "align/sw" => { - let _ = source.next(); - let content: A = state.eval(source, ||"align/sw: expected content")?; + Some(Value::Key("align/sw")) => { + let content: A = state.eval(source.next(), ||"align/sw: expected content")?; Self::sw(content) }, - "align/se" => { - let _ = source.next(); - let content: A = state.eval(source, ||"align/se: expected content")?; + Some(Value::Key("align/se")) => { + let content: A = state.eval(source.next(), ||"align/se: expected content")?; Self::se(content) }, _ => return Ok(None), - }) + } } else { - None - }) + return Ok(None) + })) } }