rework command/namespace dispatch
Some checks are pending
/ build (push) Waiting to run

This commit is contained in:
i do not exist 2026-08-12 11:32:51 +03:00
parent def7a1b210
commit 9f2327f96c
12 changed files with 499 additions and 347 deletions

View file

@ -167,69 +167,18 @@ attribute!(commands {
let mut keywords = quote! {};
let mut expressions = quote! {};
for (ident, (variant, inputs, keyword)) in items.iter() {
let mut typed = quote! {};
let mut params = quote! {};
let mut has_args = false;
for arg in inputs.iter() {
if let FnArg::Typed(PatType { pat, ty, .. }) = arg {
has_args = true;
append(&mut typed, quote! { #pat: #ty, });
append(&mut params, quote! { #pat, });
}
}
append(&mut variants, if has_args {
quote! { #variant { #typed }, }
} else {
quote! { #variant, }
});
append(&mut dispatch, if has_args {
quote! { #command::#variant { #params } => state.#ident(#params), }
} else {
quote! { #command::#variant => state.#ident(), }
});
let keyword = if let Some(namespace) = namespace {
format!("{}/{}", namespace.value(), keyword.value())
} else {
keyword.value()
};
if has_args {
append(&mut expressions, quote! {
#keyword (#typed) => { #command::#variant { #params } },
});
} else {
append(&mut keywords, quote! {
#keyword => #command::#variant,
});
}
write_variant(
&mut expressions, &mut keywords, &mut variants, &mut dispatch,
ident, command, variant, inputs, namespace, keyword,
)
}
let impls = match item {
Item::Impl(ItemImpl { generics, .. }) => {
let lts = Punctuated::<_, Comma>::from_iter(generics.lifetimes());
let tys = Punctuated::<_, Comma>::from_iter(generics.type_params());
let cns = Punctuated::<_, Comma>::from_iter(generics.const_params());
quote! {
impl<'n, #tys> dizzle::Namespace<'n, #command> for #state {
symbols!('n |state: Self| -> #command { #keywords });
expressions!('n |state: Self| -> #command { #expressions });
}
impl #generics #command {
pub fn act (self, state: &mut #state) -> Perhaps<Self> {
match self { #dispatch _ => unreachable!() }
}
}
}
},
Item::Trait { .. } => quote! {
impl<'n, T: #state + 'n> dizzle::Namespaced<'n, T> for #command {
symbols!('n |state: T| -> Self { #keywords });
expressions!('n |state: T| -> Self { #expressions });
}
impl #command {
pub fn act <'n, T: #state + 'n> (self, state: &mut T) -> Perhaps<Self> {
match self { #dispatch _ => unreachable!() }
}
}
},
Item::Impl(ItemImpl { generics, .. }) => write_for_struct(
keywords, expressions, dispatch, state, command, generics,
),
Item::Trait { .. } => write_for_trait(
keywords, expressions, dispatch, state, command,
),
_ => panic!("trait or inherent impl needed for #[commands]")
};
append(out, quote! {
@ -240,6 +189,145 @@ attribute!(commands {
})
}
}
fn write_variant (
exps: &mut TokenStream2,
syms: &mut TokenStream2,
vars: &mut TokenStream2,
disp: &mut TokenStream2,
ident: &Ident,
command: &Path,
variant: &Ident,
inputs: &[FnArg],
namespace: &Option<LitStr>,
keyword: &LitStr,
) {
let keyword = if let Some(namespace) = namespace {
format!("{}/{}", namespace.value(), keyword.value())
} else {
keyword.value()
};
let mut typed = quote! {};
let mut params = quote! {};
let mut obtain = quote! {};
let mut has_args = false;
for arg in inputs.iter() {
if let FnArg::Typed(PatType { pat, ty, .. }) = arg {
has_args = true;
append(&mut typed, quote! { #pat: #ty, });
append(&mut params, quote! { #pat, });
append(&mut obtain, quote! { let #pat: #ty = {
let head = tail.head()?.unwrap_or_default();
let tail = tail.tail()?.unwrap_or_default();
match dizzle::Namespace::<#ty>::namespace(state, &head)? {
Some(arg) => arg,
None => return Err(format!("{}: arg \"{}\" ({}) got: {head} {tail}",
#keyword, stringify!(#pat), stringify!(#ty),
).into())
}
};});
}
}
if has_args {
append(vars, quote! { #variant { #typed }, });
append(disp, quote! { #command::#variant { #params } => state.#ident(#params), });
append(exps, quote! {
let tail_base = tail;
if head.src()? == Some(#keyword) {
let tail = tail_base;
#obtain
return Ok(Some(#command::#variant { #params }))
}
});
} else {
append(vars, quote! { #variant, });
append(disp, quote! { #command::#variant => state.#ident(), });
append(syms, quote! {
if word == #keyword { return Ok(Some(#command::#variant)); }
});
}
}
fn write_for_struct (
syms: TokenStream2,
exps: TokenStream2,
disp: TokenStream2,
state: &Path,
command: &Path,
generics: &syn::Generics,
) -> TokenStream2 {
//let lts = Punctuated::<_, Comma>::from_iter(generics.lifetimes());
//let cns = Punctuated::<_, Comma>::from_iter(generics.const_params());
let tys = Punctuated::<_, Comma>::from_iter(generics.type_params());
quote! {
impl<#tys> dizzle::Namespace<#command> for #state {
//def_namespace_symbols!('n |state: Self| -> #command {
//#syms
//});
//def_namespace_exps!('n |state: Self| -> #command {
//#exps
//});
fn namespace_symbol (&self, word: impl Symbol) -> Perhaps<#command> {
if let Some(word) = word.word()? {
#syms
}
Ok(None)
}
fn namespace_expression (&self, expr: impl Expression) -> Perhaps<#command> {
let state = self;
if let Some(expr) = expr.expr()? {
let head = expr.head()?;
let tail = expr.tail()?;
#exps
}
Ok(None)
}
}
impl #generics dizzle::Dispatch<#state> for #command {
fn dispatch (self, state: &mut #state) -> Perhaps<Self> {
match self {
#disp
_ => unreachable!()
}
}
}
}
}
fn write_for_trait (
syms: TokenStream2,
exps: TokenStream2,
disp: TokenStream2,
state: &Path,
command: &Path,
) -> TokenStream2 {
quote! {
impl<T: #state> dizzle::Namespaced<T> for #command {
fn namespaced_symbol <L: Symbol> (state: &T, word: L) -> Perhaps<#command> {
if let Some(word) = word.word()? {
#syms
}
Ok(None)
}
fn namespaced_expression <L: Expression> (state: &T, expr: L) -> Perhaps<#command> {
if let Some(expr) = expr.expr()? {
let head = expr.head()?;
let tail = expr.tail()?;
#exps
}
Ok(None)
}
}
impl<T: #state> dizzle::Dispatch<T> for #command {
fn dispatch (self, state: &mut T) -> Perhaps<Self> {
match self {
#disp
_ => unreachable!()
}
}
}
}
}
});
attribute!(command {
@ -393,8 +481,8 @@ attribute!(keyword {
append(out, quote! {
#item
impl<'n> Namespace<'n, #ident> for #state {
symbols!('n |_state: #state| -> #ident { #body, });
impl Namespace<#ident> for #state {
def_namespace_symbols!(|_state: #state| -> #ident { #body, });
}
})
}