modppl_macros/
lib.rs

1#![crate_name = "modppl_macros"]
2#![crate_type = "proc-macro"]
3#![warn(non_camel_case_types)]
4
5extern crate proc_macro;
6
7
8use syn::parse_macro_input;
9use syn::{Pat,PatType,ItemFn,FnArg,ReturnType};
10use syn::visit_mut::VisitMut;
11use quote::quote;
12
13mod address;
14use address::ReplaceAddressedCalls;
15
16mod proposal;
17use proposal::ty_is_weak_trace_ref;
18
19
20#[proc_macro]
21pub fn dyngen(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
22    // embed(TokenStream::from(input)).into()
23    let input_fn = parse_macro_input!(input as ItemFn);
24
25    // Extracting types, identifiers, and mutability from the function arguments
26    let arg_details: Vec<_> = input_fn.sig.inputs.iter().map(|fn_arg| {
27        match fn_arg {
28            FnArg::Typed(PatType { pat, ty, .. }) => {
29                // Extract the identifier and check for mutability
30                let (ident, is_mut) = match **pat {
31                    Pat::Ident(ref pat_ident) => {
32                        (pat_ident.ident.clone(), pat_ident.mutability.is_some())
33                    },
34                    _ => panic!("Expected function arguments to have identifiers"),
35                };
36
37                // Extract the type
38                let arg_type = ty.clone();
39
40                (ident, is_mut, arg_type)
41            },
42            _ => panic!("Expected typed arguments"),
43        }
44    }).collect();
45
46    // Unpacking the vectors of identifiers, mutabilities, and types
47    let (arg_idents, mutabilities, arg_tys): (Vec<_>, Vec<_>, Vec<_>) = arg_details.into_iter()
48        .fold((vec![], vec![], vec![]), |mut acc, (ident, is_mut, ty)| {
49            acc.0.push(ident);
50            acc.1.push(is_mut);
51            acc.2.push(ty);
52            acc
53        });
54    
55    let args_idents_tuple: proc_macro2::TokenStream; 
56    let args_ty_tuple: proc_macro2::TokenStream; 
57    if arg_tys.len() > 0 && ty_is_weak_trace_ref(&arg_tys[0]) {
58        let trace_ident = &arg_idents[0];
59        let trace_ty = &arg_tys[0];
60        let mut trace_ident_token = quote! { #trace_ident };
61        if mutabilities[0] {
62            trace_ident_token = quote! { mut #trace_ident };
63        }
64        
65        let proposal_arg_details = arg_idents.iter().zip(mutabilities.iter()).skip(1).map(|(ident, &is_mut)| {
66            if is_mut {
67                quote! { mut #ident }
68            } else {
69                quote! { #ident }
70            }
71        }).collect::<Vec<_>>();
72    
73        args_idents_tuple = quote! { (#trace_ident_token, (#(#proposal_arg_details),*)) };
74        let proposal_arg_tys = &arg_tys[1..].iter().collect::<Vec<_>>();
75        args_ty_tuple = quote! { (#trace_ty, (#(#proposal_arg_tys),*)) };
76    } else {
77        let arg_idents_tokens = arg_idents.iter().zip(mutabilities.iter()).map(|(ident, &is_mut)| {
78            if is_mut {
79                quote! { mut #ident }
80            } else {
81                quote! { #ident }
82            }
83        }).collect::<Vec<_>>();
84    
85        args_idents_tuple = quote! { (#(#arg_idents_tokens),*) };
86        args_ty_tuple = quote! { (#(#arg_tys),*) };
87    }
88
89    // Retrieve the return type
90    let ret_ty = match input_fn.sig.output {
91        ReturnType::Default => quote! { () },
92        ReturnType::Type(_, ref ty) => quote! { #ty },
93    };
94
95    // Modify the function name by appending an underscore
96    let original_ident = &input_fn.sig.ident;
97    let new_ident = syn::Ident::new(&format!("__{}", original_ident), original_ident.span());
98
99    let mut fn_body = input_fn.block;
100
101    let handler_type = quote! { DynGenFnHandler<#args_ty_tuple, #ret_ty> };
102    let genfn_type = quote! { DynGenFn<#args_ty_tuple, #ret_ty> };
103
104    ReplaceAddressedCalls.visit_block_mut(&mut fn_body);
105
106    // Reconstruct the function with the new argument and modified name
107    quote! {
108        fn #new_ident(__g: &mut #handler_type, __args: #args_ty_tuple) -> #ret_ty {
109            let #args_idents_tuple: #args_ty_tuple = __args;
110            #fn_body
111        }
112        pub const #original_ident: #genfn_type = DynGenFn { func: #new_ident };
113    }.into()
114}