diff options
Diffstat (limited to 'mingling_macros/src/attr/help.rs')
| -rw-r--r-- | mingling_macros/src/attr/help.rs | 98 |
1 files changed, 31 insertions, 67 deletions
diff --git a/mingling_macros/src/attr/help.rs b/mingling_macros/src/attr/help.rs index 6defae4..b4ad989 100644 --- a/mingling_macros/src/attr/help.rs +++ b/mingling_macros/src/attr/help.rs @@ -1,7 +1,7 @@ use proc_macro::TokenStream; -use quote::{ToTokens, quote}; +use quote::quote; use syn::spanned::Spanned; -use syn::{Ident, ItemFn, ReturnType, Signature, TypePath, parse_macro_input}; +use syn::{Ident, ItemFn, Pat, ReturnType, Signature, TypePath, parse_macro_input}; use crate::get_global_set; use crate::res_injection::{extract_args_info, generate_immut_resource_bindings}; @@ -25,8 +25,8 @@ pub(crate) fn help_attr(item: TokenStream) -> TokenStream { .into(); } - // Extract the entry type, parameter name, and resource injection params - let (prev_param, entry_type, resources) = match extract_args_info(&input_fn.sig) { + // Extract the entry type and resource injection params + let (_, entry_type, resources) = match extract_args_info(&input_fn.sig) { Ok(info) => info, Err(e) => return e.to_compile_error().into(), }; @@ -66,13 +66,31 @@ pub(crate) fn help_attr(item: TokenStream) -> TokenStream { // Generate immutable resource bindings let immut_resource_stmts = generate_immut_resource_bindings(resources.iter(), &program_type); - // Build the render_help body with resource injection - // Use modify_res for mutable resources same pattern as renderer.rs + // Build the call to the original function with resource arguments injected + let resource_args: Vec<_> = resources + .iter() + .map(|res| { + let var_name = &res.var_name; + quote! { #var_name } + }) + .collect(); + + // Use a fixed parameter name `prev` for the trait method, regardless of + // the user's original parameter name (which may be `_` and cannot be + // referenced in expression position). + let fixed_prev: Pat = syn::parse_quote!(prev); - let wrapped_body = if mut_resources.is_empty() { - quote! { #(#fn_body_stmts)* } + let fn_call = if has_resources { + quote! { #fn_name(#fixed_prev, #(#resource_args),*) } } else { - let mut wrapped = quote! { #(#fn_body_stmts)* }; + quote! { #fn_name(#fixed_prev) } + }; + + // Wrap the function call with modify_res for mutable resources + let inner_call = if mut_resources.is_empty() { + fn_call + } else { + let mut wrapped = fn_call; for res in mut_resources.iter().rev() { let var_name = &res.var_name; let inner_type = &res.inner_type; @@ -88,10 +106,10 @@ pub(crate) fn help_attr(item: TokenStream) -> TokenStream { let help_render_body = if has_resources { quote! { #(#immut_resource_stmts)* - #wrapped_body + #inner_call } } else { - quote! { #(#fn_body_stmts)* } + quote! { #inner_call } }; // Register the help request mapping @@ -128,7 +146,7 @@ pub(crate) fn help_attr(item: TokenStream) -> TokenStream { impl ::mingling::HelpRequest for #struct_name { type Entry = #entry_type; - fn render_help(#prev_param: Self::Entry) -> ::mingling::RenderResult { + fn render_help(#fixed_prev: Self::Entry) -> ::mingling::RenderResult { let __help_result = { #help_render_body }; ::std::convert::Into::into(__help_result) } @@ -136,8 +154,7 @@ pub(crate) fn help_attr(item: TokenStream) -> TokenStream { ::mingling::macros::register_help!(#entry_type, #struct_name); - // Keep the original function unchanged - #[allow(dead_code)] + // Keep the original function unchanged #(#fn_attrs)* #vis fn #fn_name(#original_inputs) -> #original_return_type { #(#fn_body_stmts)* @@ -159,56 +176,3 @@ fn build_help_entry(struct_name: &Ident, entry_type: &TypePath) -> proc_macro2:: } } } - -pub(crate) fn register_help(input: TokenStream) -> TokenStream { - // Parse the input as a comma-separated list of arguments - let input_parsed = syn::parse_macro_input!(input with syn::punctuated::Punctuated<syn::Expr, syn::Token![,]>::parse_terminated); - - // Check if there are exactly two elements - if input_parsed.len() != 2 { - return syn::Error::new( - input_parsed.span(), - "Expected exactly two comma-separated arguments: `EntryType, StructName`", - ) - .to_compile_error() - .into(); - } - - // Extract the two elements - let entry_type_expr = &input_parsed[0]; - let struct_name_expr = &input_parsed[1]; - - // Convert expressions to TypePath and Ident - let entry_type = match syn::parse2::<TypePath>(entry_type_expr.to_token_stream()) { - Ok(ty) => ty, - Err(e) => return e.to_compile_error().into(), - }; - - let struct_name = match syn::parse2::<syn::Ident>(struct_name_expr.to_token_stream()) { - Ok(ident) => ident, - Err(e) => return e.to_compile_error().into(), - }; - - // Register the help request mapping - let help_entry = build_help_entry(&struct_name, &entry_type); - let entry_str = help_entry.to_string(); - - // Check if entry was already pre-inserted by `#[help]` attribute - let mut helps = get_global_set(&crate::HELP_REQUESTS).lock().unwrap(); - if helps.contains(&entry_str) { - // Already registered by `#[help]`, no duplicate check needed - return quote! {}.into(); - } - - // Check for duplicate variant (different struct, same type) - let variant_name = entry_type.path.segments.last().unwrap().ident.to_string(); - if let Err(err) = - crate::check_duplicate_variant(&helps, &entry_str, &variant_name, "help", entry_type.span()) - { - return err.into(); - } - - helps.insert(entry_str); - - quote! {}.into() -} |
