1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
use proc_macro::TokenStream; use syn::fold::Fold; use syn::{parse_quote, ItemFn, Ident}; struct InsertWrapperR; impl Fold for InsertWrapperR { fn fold_item_fn(&mut self, expr: ItemFn) -> ItemFn { let orig_name = expr.sig.ident.clone(); let new_name = Ident::new(&format!("_RINTEROP_{}", &orig_name), orig_name.span()) ; let inputs = expr.sig.inputs.clone(); let new_args = inputs.iter().map(|input|{ match input { syn::FnArg::Typed(pat) => { let ty : &syn::Type = &pat.ty; let expr : syn::ExprBlock = parse_quote!({unsafe{r_args = r_args .as_ref() .unwrap() .sxp .list .cdr}; <#ty as FromR>::from_r(unsafe{r_args.as_ref().unwrap().sxp.list.car}).unwrap() }); expr } _ => unimplemented!() } }).collect::< syn::punctuated::Punctuated<_, syn::token::Comma>>(); let parsed : ItemFn = parse_quote!( #[no_mangle] pub extern "C" fn #new_name(mut r_args: *mut sexpr::Sexpr) -> *const sexpr::Sexpr { (#orig_name)(#new_args).return_to_r() } ); parsed } } #[allow(non_snake_case)] #[proc_macro_attribute] pub fn R_export(_attr: TokenStream, item: TokenStream) -> TokenStream { let tree: ItemFn = syn::parse(item.clone()).expect("has to e applied to func"); let wrapped_fn = InsertWrapperR.fold_item_fn(tree.clone()); let expanded :proc_macro2::TokenStream = parse_quote! { #tree #wrapped_fn }; TokenStream::from(expanded) }