mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2025-12-06 11:46:42 +01:00
This commit is contained in:
parent
73eb935282
commit
360b404b69
3 changed files with 82 additions and 65 deletions
|
|
@ -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() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue