From a4931d8e4f941a9eca4b5d595cb18386a94c1cfb Mon Sep 17 00:00:00 2001 From: i do not exist Date: Mon, 10 Aug 2026 17:24:57 +0300 Subject: [PATCH] wip support for expressions in #[commands] procmacro --- proc/src/lib.rs | 79 +++++++++++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 29 deletions(-) diff --git a/proc/src/lib.rs b/proc/src/lib.rs index 602e8f69..7e8b2213 100644 --- a/proc/src/lib.rs +++ b/proc/src/lib.rs @@ -3,8 +3,8 @@ use proc_macro2::{TokenStream as TokenStream2, Span}; use quote::{quote, ToTokens, TokenStreamExt}; use std::collections::{HashMap, BTreeMap}; use syn::{ - Error, Path, Lit, Ident, Variant, Fields, BinOp, - Expr, ExprPath, ExprBinary, ExprAssign, ExprLit, + Error, Path, Ident, Variant, Fields, BinOp, + Expr, ExprPath, ExprBinary, ExprAssign, ExprLit, Lit, LitStr, ItemEnum, ItemImpl, ImplItem, ImplItemFn, Signature, MetaList, Type, TypePath, FnArg, PatType, parse::{ParseStream, Parse, Result}, @@ -28,9 +28,9 @@ macro_rules! attribute { attribute!(commands { #[derive(Debug, Clone)] pub struct Def(pub Meta, pub Item); - #[derive(Debug, Clone)] pub struct Meta(pub Path, pub Lit); + #[derive(Debug, Clone)] pub struct Meta(pub Path, pub LitStr); #[derive(Debug, Clone)] pub struct Item( - pub Path, pub ItemImpl, pub HashMap, Lit)> + pub Path, pub ItemImpl, pub HashMap, LitStr)> ); impl Parse for Meta { @@ -38,7 +38,7 @@ attribute!(commands { let meta = input.parse()?; if let Expr::Assign(ExprAssign { ref left, ref right, .. }) = meta && let Expr::Path(ExprPath { path, .. }) = &**left - && let Expr::Lit(ExprLit { lit, .. }) = &**right + && let Expr::Lit(ExprLit { lit: Lit::Str(lit), .. }) = &**right { Ok(Self(path.clone(), lit.clone())) } else { @@ -57,7 +57,7 @@ attribute!(commands { } else { return Err(Error::new(item.self_ty.span(), format!("must be path to struct"))) }; - let mut dispatch: HashMap, Lit)> = Default::default(); + let mut dispatch: HashMap, LitStr)> = Default::default(); for item in item.items.iter_mut() { if let ImplItem::Fn(ImplItemFn { attrs, sig: Signature { ident, inputs, .. }, .. @@ -67,7 +67,7 @@ attribute!(commands { && path == &Path::from(Ident::new("command", Span::call_site())) && let Ok(handler) = syn::parse2::(tokens.clone()) && let Expr::Assign(ExprAssign { ref left, ref right, .. }) = handler - && let Expr::Lit(ExprLit { lit, .. }) = &**right + && let Expr::Lit(ExprLit { lit: Lit::Str(lit), .. }) = &**right && let Expr::Path(ExprPath { path, .. }) = &**left && path.segments.len() == 1 { dispatch.insert(ident.clone(), ( @@ -90,41 +90,62 @@ attribute!(commands { impl ToTokens for Def { fn to_tokens (&self, out: &mut TokenStream2) { - let Self(Meta(command, namespace), Item(ident, item, items)) = self; + let Self(Meta(command, namespace), Item(state, item, items)) = self; let mut variants = quote! {}; let mut dispatch = quote! {}; + 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 args = quote! {}; let mut has_args = false; for arg in inputs.iter() { - match arg { - FnArg::Receiver(_) => {}, - FnArg::Typed(PatType { pat, ty, .. }) => { - has_args = true; - append(&mut params, quote! { #pat: #ty, }); - append(&mut args, quote! { #pat, }) - } + 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 = format!("{}/{}", namespace.value(), keyword.value()); if has_args { - params = quote! { { #params } }; - args = quote! { { #args } }; + append(&mut expressions, quote! { + #keyword (#typed) => { #command::#variant { #params } }, + }); + } else { + append(&mut keywords, quote! { + #keyword => #command::#variant, + }); } - append(&mut variants, quote! { #variant #params, }); - append(&mut dispatch, quote! { #command::#variant #args => { todo!() }, }); } append(out, quote! { - #item - pub enum #command { #variants } - impl dizzle::Act<#ident> for #command { - fn act (&self, state: &mut #ident) -> Perhaps { - match self { - #dispatch - _ => unreachable!() - } + #[derive(Debug, Clone)] pub enum #command { #variants } + + impl<'a> dizzle::Namespace<'a, #command> for #state { + symbols!('a |state| -> #command { + #keywords + }); + expressions!('a |state| -> #command { + #expressions + }); + } + + impl #command { + pub fn act (self, state: &mut #state) -> Perhaps { + match self { #dispatch _ => unreachable!() } } } + + #item }) } } @@ -269,7 +290,7 @@ attribute!(keyword { #item impl<'a> Namespace<'a, #ident> for #state { - symbols!('a |stte| -> #ident { + symbols!('a |_state| -> #ident { #body, }); }