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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
extern crate proc_macro;
use proc_macro::TokenStream;
use syn::{parse_macro_input, parse_quote, ItemFn, FnArg, Expr};
use syn::punctuated::Punctuated;
use syn::Token;
use quote::{quote, format_ident};
fn translate_formal(input : &FnArg) -> FnArg {
match input {
FnArg::Typed(ref pattype) => {
let pat = &pattype.pat.as_ref();
return parse_quote!{ #pat : extendr_api::SEXP };
},
_ => ()
}
panic!("Exported function argument must be a primitive or Robj.");
}
fn translate_actual(input : &FnArg) -> Expr {
match input {
FnArg::Typed(ref pattype) => {
let pat = &pattype.pat.as_ref();
let ty = &pattype.ty.as_ref();
return parse_quote!{ extendr_api::unwrap_or_throw(from_robj::<#ty>(&new_borrowed(#pat))) };
},
_ => ()
}
panic!("Exported function argument must be a primitive or Robj.");
}
#[proc_macro_attribute]
pub fn export_function(_attr: TokenStream, item: TokenStream) -> TokenStream {
let func = parse_macro_input!(item as ItemFn);
let func_name = &func.sig.ident;
let wrap_name = format_ident!("__wrap__{}", func_name);
let formal_args : Punctuated<FnArg, Token![,]> = func.sig.inputs.iter()
.map(|input| {
translate_formal(input)
}).collect();
let actual_args : Punctuated<Expr, Token![,]> = func.sig.inputs.iter()
.map(|input| {
translate_actual(input)
}).collect();
let expanded = quote! {
#func
#[no_mangle]
pub extern "C" fn #wrap_name(#formal_args) -> extendr_api::SEXP {
use extendr_api::{from_robj, new_borrowed};
unsafe {
extendr_api::Robj::from(#func_name(#actual_args)).get()
}
}
};
TokenStream::from(expanded)
}