fix(proc): update macros
Some checks failed
/ build (push) Has been cancelled

This commit is contained in:
🪞👃🪞 2025-07-20 04:49:10 +03:00
parent 73eb935282
commit 360b404b69
3 changed files with 82 additions and 65 deletions

View file

@ -7,7 +7,6 @@ use const_panic::PanicFmt;
use std::fmt::Debug;
pub(crate) use ::tengri_core::*;
pub(crate) use std::error::Error;
pub(crate) use std::sync::Arc;
pub(crate) use konst::string::{str_range, char_indices};
pub(crate) use thiserror::Error;
pub(crate) use self::DslError::*;
@ -24,6 +23,10 @@ impl<'s> Dsl for &'s str {
fn src (&self) -> &str { self }
}
impl Dsl for String {
fn src (&self) -> &str { self.as_str() }
}
impl Dsl for std::sync::Arc<str> {
fn src (&self) -> &str { self.as_ref() }
}

View file

@ -11,12 +11,6 @@ pub trait FromDsl<T>: Sized {
}
}
impl<'s, T: FromDsl<U>, U> DslInto<'s, T> for U {
fn dsl_into (&self, dsl: &impl Dsl) -> Perhaps<T> {
T::from_dsl(self, dsl)
}
}
/// `self` + [Dsl] -> `T`
pub trait DslInto<'s, T> {
fn dsl_into (&'s self, dsl: &impl Dsl) -> Perhaps<T>;
@ -28,6 +22,17 @@ pub trait DslInto<'s, T> {
}
}
/// `self` + `T` -> [Dsl]
pub trait DslFrom<T> {
fn dsl_from (&self, dsl: &T) -> Perhaps<impl Dsl>;
fn dsl_from_or (&self, dsl: &T, err: Box<dyn Error>) -> Usually<impl Dsl> {
self.dsl_from(dsl)?.ok_or(err)
}
fn dsl_from_or_else (&self, dsl: &T, err: impl Fn()->Box<dyn Error>) -> Usually<impl Dsl> {
self.dsl_from(dsl)?.ok_or_else(err)
}
}
/// `self` + `T` + -> [Dsl]
pub trait IntoDsl<T> {
fn into_dsl (&self, state: &T) -> Perhaps<impl Dsl>;
@ -39,13 +44,14 @@ pub trait IntoDsl<T> {
}
}
/// `self` + `T` -> [Dsl]
pub trait DslFrom<T> {
fn dsl_from (&self, dsl: &impl Dsl) -> Perhaps<impl Dsl>;
fn dsl_from_or (&self, dsl: &impl Dsl, err: Box<dyn Error>) -> Usually<impl Dsl> {
self.dsl_from(dsl)?.ok_or(err)
}
fn dsl_from_or_else (&self, dsl: &impl Dsl, err: impl Fn()->Box<dyn Error>) -> Usually<impl Dsl> {
self.dsl_from(dsl)?.ok_or_else(err)
impl<'s, T: FromDsl<U>, U> DslInto<'s, T> for U {
fn dsl_into (&self, dsl: &impl Dsl) -> Perhaps<T> {
T::from_dsl(self, dsl)
}
}
impl<T: DslFrom<U>, U> IntoDsl<T> for U {
fn into_dsl (&self, state: &T) -> Perhaps<impl Dsl> {
T::dsl_from(state, self)
}
}

View file

@ -50,10 +50,28 @@ impl ToTokens for ViewDef {
impl ViewDef {
fn generated (&self) -> impl ToTokens {
let Self(ViewMeta { output }, ViewImpl { block, .. }) = self;
let self_ty = &block.self_ty;
let builtins = self.builtins();
let exposed = self.exposed();
let Self(ViewMeta { output }, ViewImpl { block, exposed }) = self;
let self_ty = &block.self_ty;
// Expressions are handled by built-in functions that operate over constants and symbols.
let builtins = builtins_with_boxes_output(quote! { #output })
.map(|(builtin, builtin_ty)|match builtin {
Single(name) => quote! {
if dsl.exp_head()?.key()? == Some(#name) {
return Ok(Some(#builtin_ty::from_dsl_or_else(self, dsl,
||format!("failed to load builtin").into())?.boxed()))
}
},
Prefix(name) => quote! {
if let Some(key) = dsl.exp_head()?.key()? && key.starts_with(#name) {
return Ok(Some(#builtin_ty::from_dsl_or_else(self, dsl,
||format!("failed to load builtin").into())?.boxed()))
}
},
});
// Symbols are handled by user-provided functions that take no parameters but `&self`.
let exposed = exposed.iter().map(|(key, value)|write_quote(quote! {
#key => return Ok(Some(self.#value().boxed())),
}));
quote! {
/// Generated by [tengri_proc].
///
@ -66,63 +84,53 @@ impl ViewDef {
fn dsl_into (&'state self, dsl: &impl ::tengri::dsl::Dsl)
-> Perhaps<Box<dyn ::tengri::output::Render<#output> + 'state>>
{
Ok(match dsl.val() { #builtins #exposed _ => return Ok(None) })
#(#builtins)*
if let Some(sym) = dsl.sym()? {
match sym {
#(#exposed)*
_ => return Err(format!("unknown symbol {sym}").into())
}
}
Ok(None)
}
}
}
}
/// Expressions are handled by built-in functions
/// that operate over constants and symbols.
fn builtins (&self) -> impl ToTokens {
let Self(ViewMeta { output }, ViewImpl { .. }) = self;
let builtins = builtins_with_boxes_output(quote! { #output }).map(|builtin|quote! {
::tengri::dsl::Val::Exp(_, expr) => return Ok(Some(
#builtin::from_dsl_or_else(
self,
&expr,
|| { format!("failed to load builtin").into() }
)?.boxed()
)),
});
quote! { #(#builtins)* }
}
/// Symbols are handled by user-taked functions that take no parameters but `&self`.
fn exposed (&self) -> impl ToTokens {
let Self(ViewMeta { .. }, ViewImpl { exposed, .. }) = self;
let exposed = exposed.iter().map(|(key, value)|write_quote(quote! {
#key => return Ok(Some(self.#value().boxed())),
}));
quote! { ::tengri::dsl::Val::Sym(key) => match key.as_ref() { #(#exposed)* _ => panic!() } }
}
}
fn _builtins_with_holes () -> impl Iterator<Item=TokenStream2> {
enum Builtin {
Single(TokenStream2),
Prefix(TokenStream2),
}
use Builtin::*;
fn builtins_with (n: TokenStream2, c: TokenStream2) -> impl Iterator<Item=(Builtin, TokenStream2)> {
[
(Single(quote!("when")), quote!(When::< #c >)),
(Single(quote!("either")), quote!(Either::< #c, #c>)),
(Prefix(quote!("align/")), quote!(Align::< #c >)),
(Prefix(quote!("bsp/")), quote!(Bsp::< #c, #c>)),
(Prefix(quote!("fill/")), quote!(Fill::< #c >)),
(Prefix(quote!("fixed/")), quote!(Fixed::<#n, #c >)),
(Prefix(quote!("min/")), quote!(Min::<#n, #c >)),
(Prefix(quote!("max/")), quote!(Max::<#n, #c >)),
(Prefix(quote!("shrink/")), quote!(Shrink::<#n, #c >)),
(Prefix(quote!("expand/")), quote!(Expand::<#n, #c >)),
(Prefix(quote!("push/")), quote!(Push::<#n, #c >)),
(Prefix(quote!("pull/")), quote!(Pull::<#n, #c >)),
(Prefix(quote!("margin/")), quote!(Margin::<#n, #c >)),
(Prefix(quote!("padding/")), quote!(Padding::<#n, #c >)),
].into_iter()
}
fn _builtins_with_holes () -> impl Iterator<Item=(Builtin, TokenStream2)> {
builtins_with(quote! { _ }, quote! { _ })
}
fn _builtins_with_boxes () -> impl Iterator<Item=TokenStream2> {
fn _builtins_with_boxes () -> impl Iterator<Item=(Builtin, TokenStream2)> {
builtins_with(quote! { _ }, quote! { Box<dyn Render<_>> })
}
fn builtins_with_boxes_output (o: TokenStream2) -> impl Iterator<Item=TokenStream2> {
fn builtins_with_boxes_output (o: TokenStream2) -> impl Iterator<Item=(Builtin, TokenStream2)> {
builtins_with(quote! { _ }, quote! { Box<dyn Render<#o>> })
}
fn builtins_with (n: TokenStream2, c: TokenStream2) -> impl Iterator<Item=TokenStream2> {
[
quote! { When::< #c > },
quote! { Either::< #c, #c> },
quote! { Align::< #c > },
quote! { Bsp::< #c, #c> },
quote! { Fill::< #c > },
quote! { Fixed::<#n, #c > },
quote! { Min::<#n, #c > },
quote! { Max::<#n, #c > },
quote! { Shrink::<#n, #c > },
quote! { Expand::<#n, #c > },
quote! { Push::<#n, #c > },
quote! { Pull::<#n, #c > },
quote! { Margin::<#n, #c > },
quote! { Padding::<#n, #c > },
].into_iter()
}