extendr_macros/
R.rs
1use proc_macro2::TokenStream;
2use quote::quote;
3use syn::{parse_quote, punctuated::Punctuated, Expr, Token};
4
5#[allow(non_snake_case)]
6pub fn R(item: TokenStream, expand_params: bool) -> TokenStream {
7 let lit = match syn::parse2::<syn::LitStr>(item.clone()) {
9 Ok(lit) => lit,
10 Err(_) => {
11 let src = format!("{}", item);
13 return quote!(extendr_api::functions::eval_string(#src));
14 }
15 };
16
17 let mut src = lit.value();
18
19 let mut expressions: Punctuated<Expr, Token!(,)> = Punctuated::new();
20 if expand_params {
21 while let Some(start) = src.find("{{") {
23 if let Some(end) = src[start + 2..].find("}}") {
24 if let Ok(param) = syn::parse_str::<Expr>(&src[start + 2..start + 2 + end]) {
25 src = format!(
26 "{} param.{} {}",
27 &src[0..start],
28 expressions.len(),
29 &src[start + 2 + end + 2..]
30 );
31 expressions.push(parse_quote!(&extendr_api::Robj::from(#param)));
32 } else {
33 return quote!(compile_error!("Not a valid rust expression."));
34 }
35 } else {
36 return quote!(compile_error!("Unterminated {{ block."));
37 }
38 }
39 }
40
41 if expressions.is_empty() {
42 quote!(extendr_api::functions::eval_string(#src))
43 } else {
44 quote!(
45 {
46 let params = &[#expressions];
47 extendr_api::functions::eval_string_with_params(#src, params)
48 }
49 )
50 }
51}
52
53#[cfg(test)]
54mod test {
55 use super::*;
56
57 #[test]
58 fn test_r_macro() {
59 assert_eq!(
63 format!("{}", R(quote!(data.frame), true)),
64 format!(
65 "{}",
66 quote!(extendr_api::functions::eval_string("data . frame"))
67 )
68 );
69
70 assert_eq!(
72 format!("{}", R(quote!("data.frame"), true)),
73 format!(
74 "{}",
75 quote!(extendr_api::functions::eval_string("data.frame"))
76 )
77 );
78
79 assert_eq!(
81 format!("{}", R(quote!("a <- {{1}}"), true)),
82 format!(
83 "{}",
84 quote!({
85 let params = &[&extendr_api::Robj::from(1)];
86 extendr_api::functions::eval_string_with_params("a <- param.0 ", params)
87 })
88 )
89 );
90
91 assert_eq!(
93 format!("{}", R(quote!(r#""hello""#), true)),
94 format!(
95 "{}",
96 quote!(extendr_api::functions::eval_string("\"hello\""))
97 )
98 );
99
100 assert_eq!(
102 format!("{}", R(quote!("a <- {{1}}"), false)),
103 format!(
104 "{}",
105 quote!(extendr_api::functions::eval_string("a <- {{1}}"))
106 )
107 );
108 }
109}