wip: fix(dsl): maybe getting somewhere?
Some checks are pending
/ build (push) Waiting to run

This commit is contained in:
🪞👃🪞 2025-06-21 13:48:45 +03:00
parent 91dc77cfea
commit a46d0d2258
16 changed files with 506 additions and 513 deletions

View file

@ -49,11 +49,10 @@
use crate::*;
use Direction::*;
mod map; pub use self::map::*;
mod memo; pub use self::memo::*;
mod stack; pub use self::stack::*;
mod thunk; pub use self::thunk::*;
mod transform; //pub use self::transform::*;
mod map; pub use self::map::*;
mod memo; pub use self::memo::*;
mod stack; pub use self::stack::*;
mod thunk; pub use self::thunk::*;
/// Renders multiple things on top of each other,
#[macro_export] macro_rules! lay {
@ -223,7 +222,7 @@ pub trait BspAreas<E: Output, A: Content<E>, B: Content<E>> {
let [x, y, w, h] = outer.center_xy([aw.max(bw), ah + bh]);
let a = [(x + w/2.into()).minus(aw/2.into()), y, aw, ah];
let b = [(x + w/2.into()).minus(bw/2.into()), y + ah, bw, bh];
[a.into(), b.into(), [x, y, w, h].into()]
[a.into(), b.into(), [x, y, w, h].into()]
},
North => {
let [x, y, w, h] = outer.center_xy([aw.max(bw), ah + bh]);
@ -380,3 +379,310 @@ transform_xy_unit!("padding/x" "padding/y" "padding/xy"|self: Padding, area|{
let dy = self.dy();
[area.x().plus(dx), area.y().plus(dy), area.w().minus(dy.plus(dy)), area.h().minus(dy.plus(dy))]
});
/// Enabling the `dsl` feature implements [DslFrom] for
/// the layout elements that are provided by this crate.
#[cfg(feature = "dsl")] mod ops_dsl {
use crate::*;
use ::tengri_dsl::*;
//macro_rules! dsl {
//($(
//($Struct:ident $(<$($A:ident),+>)? $op:literal $(/)? [$($arg:ident $(:$ty:ty)?),*] $expr:expr)
//)*) => {
//$(
//impl<S,$($($A),+)?> DslFrom<S> for $Struct$(<$($A),+>)? {
//fn try_dsl_from (
//state: &S, dsl: &impl Dsl
//) -> Perhaps<Self> {
//todo!()
//}
//}
//)*
//}
//}
macro_rules! dsl {
(
$Struct:ident $(<$($A:ident),+>)?
$op:literal $(/)? [$head: ident, $tail: ident] $expr:expr
) => {
impl<S,$($($A),+)?> DslFrom<S> for $Struct$(<$($A),+>)? {
fn try_dsl_from (
_state: &S, _dsl: &impl Dsl
) -> Perhaps<Self> {
todo!()
}
}
}
}
macro_rules! dsl_ns {
(
$Struct:ident $(<$($A:ident),+>)?
$op:literal $(/)? [$head: ident, $tail: ident] $expr:expr
) => {
impl<S,$($($A),+)?> DslFrom<S> for $Struct$(<$($A),+>)? {
fn try_dsl_from (
_state: &S, _dsl: &impl Dsl
) -> Perhaps<Self> {
todo!()
}
}
}
}
dsl!(When<A> "when" [_head, tail] Self(tail(0)?, tail(1)?));
dsl!(Either<A, B> "either" [_head, tail] Self(tail(0)?, tail(1)?, tail(2)?));
dsl_ns!(Align<A> "align/" [head, tail] match head {
"c" => Self::c(tail(0)?),
"x" => Self::x(tail(0)?),
"y" => Self::y(tail(0)?),
"n" => Self::n(tail(0)?),
"s" => Self::s(tail(0)?),
"e" => Self::e(tail(0)?),
"w" => Self::w(tail(0)?),
"nw" => Self::nw(tail(0)?),
"ne" => Self::ne(tail(0)?),
"sw" => Self::sw(tail(0)?),
"se" => Self::se(tail(0)?),
_ => return Err("invalid align variant".into()) });
dsl_ns!(Bsp<A, B> "bsp/" [head, tail] match head {
"n" => Self::n(tail(0)?, tail(1)?),
"s" => Self::s(tail(0)?, tail(1)?),
"e" => Self::e(tail(0)?, tail(1)?),
"w" => Self::w(tail(0)?, tail(1)?),
"a" => Self::a(tail(0)?, tail(1)?),
"b" => Self::b(tail(0)?, tail(1)?),
_ => return Err("invalid bsp variant".into()) });
dsl_ns!(Fill<A> "fill/" [head, tail] match x {
"x" => Self::x(tail(0)?),
"y" => Self::y(tail(0)?),
"xy" => Self::xy(tail(0)?),
_ => return Err("invalid fill variant".into()) });
dsl_ns!(Fixed<U, A> "fixed/" [head, tail] match x {
"x" => Self::x(tail(0)?, tail(1)?),
"y" => Self::y(tail(0)?, tail(1)?),
"xy" => Self::xy(tail(0)?, tail(1)?, tail(2)?),
_ => return Err("invalid fill variant".into()) });
dsl_ns!(Min<U, A> "min/" [head, tail] match x {
"x" => Self::x(tail(0)?, tail(1)?),
"y" => Self::y(tail(0)?, tail(1)?),
"xy" => Self::xy(tail(0)?, tail(1)?, tail(2)?),
_ => return Err("invalid min variant".into()) });
dsl_ns!(Max<U, A> "max/" [head, tail] match x {
"x" => Self::x(tail(0)?, tail(1)?),
"y" => Self::y(tail(0)?, tail(1)?),
"xy" => Self::xy(tail(0)?, tail(1)?, tail(2)?),
_ => return Err("invalid max variant".into()) });
dsl_ns!(Shrink<U, A> "shrink/" [head, tail] match x {
"x" => Self::x(tail(0)?, tail(1)?),
"y" => Self::y(tail(0)?, tail(1)?),
"xy" => Self::xy(tail(0)?, tail(1)?, tail(2)?),
_ => return Err("invalid min variant".into()) });
dsl_ns!(Expand<U, A> "expand/" [head, tail] match x {
"x" => Self::x(tail(0)?, tail(1)?),
"y" => Self::y(tail(0)?, tail(1)?),
"xy" => Self::xy(tail(0)?, tail(1)?, tail(2)?),
_ => return Err("invalid max variant".into()) });
dsl_ns!(Pull<U, A> "pull/" [head, tail] match x {
"x" => Self::x(tail(0)?, tail(1)?),
"y" => Self::y(tail(0)?, tail(1)?),
"xy" => Self::xy(tail(0)?, tail(1)?, tail(2)?),
_ => return Err("invalid max variant".into()) });
dsl_ns!(Push<U, A> "push/" [head, tail] match x {
"x" => Self::x(tail(0)?, tail(1)?),
"y" => Self::y(tail(0)?, tail(1)?),
"xy" => Self::xy(tail(0)?, tail(1)?, tail(2)?),
_ => return Err("invalid max variant".into()) });
dsl_ns!(Margin<U, A> "margin/" [head, tail] match x {
"x" => Self::x(tail(0)?, tail(1)?),
"y" => Self::y(tail(0)?, tail(1)?),
"xy" => Self::xy(tail(0)?, tail(1)?, tail(2)?),
_ => return Err("invalid max variant".into()) });
dsl_ns!(Padding<U, A> "padding/" [head, tail] match x {
"x" => Self::x(tail(0)?, tail(1)?),
"y" => Self::y(tail(0)?, tail(1)?),
"xy" => Self::xy(tail(0)?, tail(1)?, tail(2)?),
_ => return Err("invalid max variant".into()) });
///// The syntagm `(when :condition :content)` corresponds to a [When] layout element.
//impl<S, A> FromDsl<S> for When<A> where bool: FromDsl<S>, A: FromDsl<S> {
//fn try_provide (state: &S, source: &DslVal<impl DslStr, impl DslExp>) -> Perhaps<Self> {
//source.exp_match("when", |_, tail|Ok(Some(Self(
//FromDsl::<S>::provide(state,
//tail.nth(0, ||"no condition".into())?, ||"no condition".into())?,
//FromDsl::<S>::provide(state,
//tail.nth(1, ||"no content".into())?, ||"no content".into())?,
//))))
//}
//}
///// The syntagm `(either :condition :content1 :content2)` corresponds to an [Either] layout element.
//impl<S, A, B> FromDsl<S> for Either<A, B> where S: Eval<Ast, bool> + Eval<Ast, A> + Eval<Ast, B> {
//fn try_provide (state: &S, source: &DslVal<impl DslStr, impl DslExp>) -> Perhaps<Self> {
//source.exp_match("either", |_, tail|Ok(Some(Self(
//state.eval(tail.nth(0, ||"no condition")?, ||"no condition")?,
//state.eval(tail.nth(1, ||"no content 1")?, ||"no content 1")?,
//state.eval(tail.nth(2, ||"no content 1")?, ||"no content 2")?,
//))))
//}
//}
///// The syntagm `(align/* :content)` corresponds to an [Align] layout element,
///// where `*` specifies the direction of the alignment.
//impl<S, A> FromDsl<S> for Align<A> where S: Eval<Option<Ast>, A> {
//fn try_provide (state: &S, source: &DslVal<impl DslStr, impl DslExp>) -> Perhaps<Self> {
//source.exp_match("align/", |head, tail|Ok(Some(match head {
//"c" => Self::c(state.eval(tail.nth(0, ||"no content")?, ||"no content")),
//"x" => Self::x(state.eval(tail.nth(0, ||"no content")?, ||"no content")),
//"y" => Self::y(state.eval(tail.nth(0, ||"no content")?, ||"no content")),
//"n" => Self::n(state.eval(tail.nth(0, ||"no content")?, ||"no content")),
//"s" => Self::s(state.eval(tail.nth(0, ||"no content")?, ||"no content")),
//"e" => Self::e(state.eval(tail.nth(0, ||"no content")?, ||"no content")),
//"w" => Self::w(state.eval(tail.nth(0, ||"no content")?, ||"no content")),
//"nw" => Self::nw(state.eval(tail.nth(0, ||"no content")?, ||"no content")),
//"ne" => Self::ne(state.eval(tail.nth(0, ||"no content")?, ||"no content")),
//"sw" => Self::sw(state.eval(tail.nth(0, ||"no content")?, ||"no content")),
//"se" => Self::se(state.eval(tail.nth(0, ||"no content")?, ||"no content")),
//_ => return Err("invalid align variant".into())
//})))
//}
//}
///// The syntagm `(bsp/* :content1 :content2)` corresponds to a [Bsp] layout element,
///// where `*` specifies the direction of the split.
//impl<S, A, B> FromDsl<S> for Bsp<A, B> where S: Eval<Option<Ast>, A> + Eval<Option<Ast>, B> {
//fn try_provide (state: &S, source: &DslVal<impl DslStr, impl DslExp>) -> Perhaps<Self> {
//source.exp_match("bsp/", |head, tail|Ok(Some(match head {
//"n" => Self::n(tail.nth(0, ||"no content 1"), tail.nth(1, ||"no content 2")),
//"s" => Self::s(tail.nth(0, ||"no content 1"), tail.nth(1, ||"no content 2")),
//"e" => Self::e(tail.nth(0, ||"no content 1"), tail.nth(1, ||"no content 2")),
//"w" => Self::w(tail.nth(0, ||"no content 1"), tail.nth(1, ||"no content 2")),
//"a" => Self::a(tail.nth(0, ||"no content 1"), tail.nth(1, ||"no content 2")),
//"b" => Self::b(tail.nth(0, ||"no content 1"), tail.nth(1, ||"no content 2")),
//_ => return Ok(None),
//})))
//}
//}
//#[cfg(feature = "dsl")] take!($Enum<A>, A|state, words|Ok(
//if let Some(Token { value: Key(k), .. }) = words.peek() {
//let mut base = words.clone();
//let content = state.give_or_fail(words, ||format!("{k}: no content"))?;
//return Ok(Some(match words.next() {
//Some(Token{value: Key($x),..}) => Self::x(content),
//Some(Token{value: Key($y),..}) => Self::y(content),
//Some(Token{value: Key($xy),..}) => Self::xy(content),
//_ => unreachable!()
//}))
//} else {
//None
//}));
//#[cfg(feature = "dsl")] take!($Enum<U, A>, U, A|state, words|Ok(
//if let Some(Token { value: Key($x|$y|$xy), .. }) = words.peek() {
//let mut base = words.clone();
//Some(match words.next() {
//Some(Token { value: Key($x), .. }) => Self::x(
//state.give_or_fail(words, ||"x: no unit")?,
//state.give_or_fail(words, ||"x: no content")?,
//),
//Some(Token { value: Key($y), .. }) => Self::y(
//state.give_or_fail(words, ||"y: no unit")?,
//state.give_or_fail(words, ||"y: no content")?,
//),
//Some(Token { value: Key($x), .. }) => Self::xy(
//state.give_or_fail(words, ||"xy: no unit x")?,
//state.give_or_fail(words, ||"xy: no unit y")?,
//state.give_or_fail(words, ||"xy: no content")?
//),
//_ => unreachable!(),
//})
//} else {
//None
//}));
//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(
//state.eval(rest.next(), ||"bsp/n: no content 1")?,
//state.eval(rest.next(), ||"bsp/n: no content 2")?,
//),
//Some("bsp/s") => Self::s(
//state.eval(rest.next(), ||"bsp/s: no content 1")?,
//state.eval(rest.next(), ||"bsp/s: no content 2")?,
//),
//Some("bsp/e") => Self::e(
//state.eval(rest.next(), ||"bsp/e: no content 1")?,
//state.eval(rest.next(), ||"bsp/e: no content 2")?,
//),
//Some("bsp/w") => Self::w(
//state.eval(rest.next(), ||"bsp/w: no content 1")?,
//state.eval(rest.next(), ||"bsp/w: no content 2")?,
//),
//Some("bsp/a") => Self::a(
//state.eval(rest.next(), ||"bsp/a: no content 1")?,
//state.eval(rest.next(), ||"bsp/a: no content 2")?,
//),
//Some("bsp/b") => Self::b(
//state.eval(rest.next(), ||"bsp/b: no content 1")?,
//state.eval(rest.next(), ||"bsp/b: no content 2")?,
//),
//_ => return Ok(None),
//}))
//}
//Ok(None)
//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: no content")?),
//Some("align/x") => Self::x(state.eval(rest.next(), ||"align/x: no content")?),
//Some("align/y") => Self::y(state.eval(rest.next(), ||"align/y: no content")?),
//Some("align/n") => Self::n(state.eval(rest.next(), ||"align/n: no content")?),
//Some("align/s") => Self::s(state.eval(rest.next(), ||"align/s: no content")?),
//Some("align/e") => Self::e(state.eval(rest.next(), ||"align/e: no content")?),
//Some("align/w") => Self::w(state.eval(rest.next(), ||"align/w: no content")?),
//Some("align/nw") => Self::nw(state.eval(rest.next(), ||"align/nw: no content")?),
//Some("align/ne") => Self::ne(state.eval(rest.next(), ||"align/ne: no content")?),
//Some("align/sw") => Self::sw(state.eval(rest.next(), ||"align/sw: no content")?),
//Some("align/se") => Self::se(state.eval(rest.next(), ||"align/se: no content")?),
//_ => return Ok(None),
//}))
//}
//Ok(None)
//Ok(match source.exp_head().and_then(|e|e.key()) {
//Some("either") => Some(Self(
//source.exp_tail().and_then(|t|t.get(0)).map(|x|state.eval(x, ||"when: no condition"))?,
//source.exp_tail().and_then(|t|t.get(1)).map(|x|state.eval(x, ||"when: no content 1"))?,
//source.exp_tail().and_then(|t|t.get(2)).map(|x|state.eval(x, ||"when: no content 2"))?,
//)),
//_ => None
//})
//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: no condition")?,
//state.eval(exp.next().unwrap(), ||"either: no content 1")?,
//state.eval(exp.next().unwrap(), ||"either: no content 2")?,
//)))
//}
//Ok(None)
//Ok(match source.exp_head().and_then(|e|e.key()) {
//Some("when") => Some(Self(
//source.exp_tail().and_then(|t|t.get(0)).map(|x|state.eval(x, ||"when: no condition"))?,
//source.exp_tail().and_then(|t|t.get(1)).map(|x|state.eval(x, ||"when: no content"))?,
//)),
//_ => None
//})
}