mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2025-12-06 11:46:42 +01:00
147 lines
6.3 KiB
Rust
147 lines
6.3 KiB
Rust
use crate::*;
|
|
use ::tengri_dsl::{Dsl, DslExpr, DslWord, DslNs};
|
|
|
|
pub trait View<O, U> {
|
|
fn view_expr <'a> (&'a self, output: &mut O, expr: &'a impl DslExpr) -> Usually<U> {
|
|
Err(format!("View::view_expr: no exprs defined: {expr:?}").into())
|
|
}
|
|
fn view_word <'a> (&'a self, output: &mut O, word: &'a impl DslWord) -> Usually<U> {
|
|
Err(format!("View::view_word: no words defined: {word:?}").into())
|
|
}
|
|
fn view <'a> (&'a self, output: &mut O, dsl: &'a impl Dsl) -> Usually<U> {
|
|
if let Ok(Some(expr)) = dsl.expr() {
|
|
self.view_expr(output, &expr)
|
|
} else if let Ok(Some(word)) = dsl.word() {
|
|
self.view_word(output, &word)
|
|
} else {
|
|
panic!("{dsl:?}: invalid")
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn evaluate_output_expression <'a, O: Out + 'a, S> (
|
|
state: &S, output: &mut O, expr: &'a impl DslExpr
|
|
) -> Usually<bool> where
|
|
S: View<O, ()>
|
|
+ for<'b>DslNs<'b, bool>
|
|
+ for<'b>DslNs<'b, O::Unit>
|
|
{
|
|
// First element of expression is used for dispatch.
|
|
// Dispatch is proto-namespaced using separator character
|
|
let head = expr.head()?;
|
|
let mut frags = head.src()?.unwrap_or_default().split("/");
|
|
// The rest of the tokens in the expr are arguments.
|
|
// Their meanings depend on the dispatched operation
|
|
let args = expr.tail();
|
|
let arg0 = args.head();
|
|
let tail0 = args.tail();
|
|
let arg1 = tail0.head();
|
|
let tail1 = tail0.tail();
|
|
let arg2 = tail1.head();
|
|
// And we also have to do the above binding dance
|
|
// so that the Perhaps<token>s remain in scope.
|
|
match frags.next() {
|
|
|
|
Some("when") => output.place(&When::new(
|
|
state.from(arg0?)?.unwrap(),
|
|
Thunk::new(move|output: &mut O|state.view(output, &arg1).unwrap())
|
|
)),
|
|
|
|
Some("either") => output.place(&Either::new(
|
|
state.from(arg0?)?.unwrap(),
|
|
Thunk::new(move|output: &mut O|state.view(output, &arg1).unwrap()),
|
|
Thunk::new(move|output: &mut O|state.view(output, &arg2).unwrap())
|
|
)),
|
|
|
|
Some("bsp") => output.place(&{
|
|
let a = Thunk::new(move|output: &mut O|state.view(output, &arg0).unwrap());
|
|
let b = Thunk::new(move|output: &mut O|state.view(output, &arg1).unwrap());
|
|
match frags.next() {
|
|
Some("n") => Bsp::n(a, b),
|
|
Some("s") => Bsp::s(a, b),
|
|
Some("e") => Bsp::e(a, b),
|
|
Some("w") => Bsp::w(a, b),
|
|
Some("a") => Bsp::a(a, b),
|
|
Some("b") => Bsp::b(a, b),
|
|
frag => unimplemented!("bsp/{frag:?}")
|
|
}
|
|
}),
|
|
|
|
Some("align") => output.place(&{
|
|
let a = Thunk::new(move|output: &mut O|state.view(output, &arg0).unwrap());
|
|
match frags.next() {
|
|
Some("n") => Align::n(a),
|
|
Some("s") => Align::s(a),
|
|
Some("e") => Align::e(a),
|
|
Some("w") => Align::w(a),
|
|
Some("x") => Align::x(a),
|
|
Some("y") => Align::y(a),
|
|
Some("c") => Align::c(a),
|
|
frag => unimplemented!("align/{frag:?}")
|
|
}
|
|
}),
|
|
|
|
Some("fill") => output.place(&{
|
|
let a = Thunk::new(move|output: &mut O|state.view(output, &arg0).unwrap());
|
|
match frags.next() {
|
|
Some("xy") | None => Fill::XY(a),
|
|
Some("x") => Fill::X(a),
|
|
Some("y") => Fill::Y(a),
|
|
frag => unimplemented!("fill/{frag:?}")
|
|
}
|
|
}),
|
|
|
|
Some("fixed") => output.place(&{
|
|
let axis = frags.next();
|
|
let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") };
|
|
let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap());
|
|
match axis {
|
|
Some("xy") | None => Fixed::XY(state.from(arg0?)?.unwrap(), state.from(arg1?)?.unwrap(), cb),
|
|
Some("x") => Fixed::X(state.from(arg0?)?.unwrap(), cb),
|
|
Some("y") => Fixed::Y(state.from(arg0?)?.unwrap(), cb),
|
|
frag => unimplemented!("fixed/{frag:?} ({expr:?}) ({head:?}) ({:?})",
|
|
head.src()?.unwrap_or_default().split("/").next())
|
|
}
|
|
}),
|
|
|
|
Some("min") => output.place(&{
|
|
let axis = frags.next();
|
|
let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") };
|
|
let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap());
|
|
match axis {
|
|
Some("xy") | None => Min::XY(state.from(arg0?)?.unwrap(), state.from(arg1?)?.unwrap(), cb),
|
|
Some("x") => Min::X(state.from(arg0?)?.unwrap(), cb),
|
|
Some("y") => Min::Y(state.from(arg0?)?.unwrap(), cb),
|
|
frag => unimplemented!("min/{frag:?}")
|
|
}
|
|
}),
|
|
|
|
Some("max") => output.place(&{
|
|
let axis = frags.next();
|
|
let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") };
|
|
let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap());
|
|
match axis {
|
|
Some("xy") | None => Max::XY(state.from(arg0?)?.unwrap(), state.from(arg1?)?.unwrap(), cb),
|
|
Some("x") => Max::X(state.from(arg0?)?.unwrap(), cb),
|
|
Some("y") => Max::Y(state.from(arg0?)?.unwrap(), cb),
|
|
frag => unimplemented!("max/{frag:?}")
|
|
}
|
|
}),
|
|
|
|
Some("push") => output.place(&{
|
|
let axis = frags.next();
|
|
let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") };
|
|
let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap());
|
|
match axis {
|
|
Some("xy") | None => Push::XY(state.from(arg0?)?.unwrap(), state.from(arg1?)?.unwrap(), cb),
|
|
Some("x") => Push::X(state.from(arg0?)?.unwrap(), cb),
|
|
Some("y") => Push::Y(state.from(arg0?)?.unwrap(), cb),
|
|
frag => unimplemented!("push/{frag:?}")
|
|
}
|
|
}),
|
|
|
|
_ => return Ok(false)
|
|
|
|
};
|
|
Ok(true)
|
|
}
|