use proc_macro::TokenStream; use quote::quote; use syn; // cbind!(fn start_cwtch(app_dir: &str, tor_path: &str) -> i32 {c_StartCwtch}); #[proc_macro] pub fn cbind(_def: TokenStream) -> TokenStream { let ast: syn::ItemFn = syn::parse(_def).unwrap(); let (fn_name, fn_args, fn_ret, fn_call) = extract(ast); dbg!(generate(fn_name, fn_args, fn_ret, fn_call)); TokenStream::new() } fn extract(ast: syn::ItemFn) -> (String, Vec<(String, String)>, Option, String) { let fn_name = ast.sig.ident.to_string(); let fn_call = match &ast.block.stmts[0] { syn::Stmt::Expr(expr) => match expr { syn::Expr::Path(expr) => expr.path.segments[0].ident.to_string(), _ => panic!("Could not find binding function to call, did you include '{}'", "{ bingden_fn_to_call() }"), } _ => panic!("Could not find binding function to call, did you include '{}'", "{ bingden_fn_to_call() }"), }; let ret_type = match &ast.sig.output { syn::ReturnType::Type(_, box_type) => { let ty = &**box_type; match ty { syn::Type::Path(p) => { if p.path.segments.len() == 1 { Some(p.path.segments[0].ident.to_string()) } else { None } } _ => None } } _ => None }; let mut args: Vec<(String, String)> = vec!(); for arg in &ast.sig.inputs { let arg_name = match arg { syn::FnArg::Typed(pat_type) => { (match &*pat_type.pat { syn::Pat::Ident(ident) => ident.ident.to_string(), _ => panic!("Could not find argument name") }, match &*pat_type.ty { syn::Type::Reference(tref) => match &*tref.elem { syn::Type::Path(path) => path.path.segments[0].ident.to_string(), _ => panic!("Could not find argument type") }, _ => panic!("Could not find argument type") }) } _ => panic!("Could not find expected argument") }; args.push(arg_name); }; (fn_name, args, ret_type, fn_call) } fn generate(fn_name: String, fn_args: Vec<(String, String)>, fn_ret: Option, fn_call: String) -> TokenStream { let mut arg_str = "&self".to_string(); for arg in fn_args { arg_str.push_str(format!(", {}: {}", arg.0, arg.1).as_str()); } dbg!(&arg_str); dbg!(quote!(fn start_cwtch(&self, arg1: &str, arg2: &str) {} )); dbg!(quote!("fn start_cwtch(&self, arg1: &str, arg2: &str) {} ")); quote!(fn #fn_name(#arg_str) {}).into() //TokenStream::new() } #[cfg(test)] mod tests { #[test] fn it_works() { let result = 2 + 2; assert_eq!(result, 4); } }