1use proc_macro2::{Delimiter, Group, TokenStream, TokenTree};
41use quote::quote;
42
43pub(crate) fn try_lower(tail: &TokenStream, env_expr: &TokenStream) -> Option<TokenStream> {
51 let tokens: Vec<TokenTree> = tail.clone().into_iter().collect();
52 let call = classify_call(&tokens)?;
53 Some(emit_call(&call, env_expr))
54}
55
56#[derive(#[automatically_derived]
impl ::core::fmt::Debug for LowerCall {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "LowerCall",
"fun", &self.fun, "args", &&self.args)
}
}Debug)]
62pub(crate) struct LowerCall {
63 fun: LowerFun,
65 args: Vec<LowerArg>,
67}
68
69#[derive(#[automatically_derived]
impl ::core::fmt::Debug for LowerFun {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::Simple(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Simple",
&__self_0),
Self::Namespaced { pkg: __self_0, fun: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"Namespaced", "pkg", __self_0, "fun", &__self_1),
}
}
}Debug)]
71enum LowerFun {
72 Simple(String),
74 Namespaced { pkg: String, fun: String },
76}
77
78#[derive(#[automatically_derived]
impl ::core::fmt::Debug for LowerArg {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "LowerArg",
"name", &self.name, "value", &&self.value)
}
}Debug)]
80struct LowerArg {
81 name: Option<String>,
82 value: LowerAtom,
83}
84
85#[derive(#[automatically_derived]
impl ::core::fmt::Debug for LowerAtom {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::StringLit(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"StringLit", &__self_0),
Self::IntLit(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "IntLit",
&__self_0),
Self::RealLit(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"RealLit", &__self_0),
Self::Bool(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Bool",
&__self_0),
Self::Null => ::core::fmt::Formatter::write_str(f, "Null"),
Self::Na => ::core::fmt::Formatter::write_str(f, "Na"),
Self::NaInteger =>
::core::fmt::Formatter::write_str(f, "NaInteger"),
Self::NaReal => ::core::fmt::Formatter::write_str(f, "NaReal"),
Self::NaCharacter =>
::core::fmt::Formatter::write_str(f, "NaCharacter"),
Self::Inf => ::core::fmt::Formatter::write_str(f, "Inf"),
Self::NaN => ::core::fmt::Formatter::write_str(f, "NaN"),
Self::Symbol(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Symbol",
&__self_0),
Self::Call(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Call",
&__self_0),
}
}
}Debug)]
87enum LowerAtom {
88 StringLit(String),
90 IntLit(i32),
92 RealLit(f64),
95 Bool(bool),
97 Null,
99 Na,
101 NaInteger,
103 NaReal,
105 NaCharacter,
107 Inf,
109 NaN,
111 Symbol(String),
113 Call(Box<LowerCall>),
115}
116
117fn classify_call(tokens: &[TokenTree]) -> Option<LowerCall> {
130 if tokens.len() < 2 {
132 return None;
133 }
134
135 let group = match tokens.last() {
137 Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Parenthesis => g,
138 _ => return None,
139 };
140
141 let head = &tokens[..tokens.len() - 1];
142
143 if let [TokenTree::Ident(name)] = head {
145 let fun = LowerFun::Simple(name.to_string());
146 let args = classify_args(group)?;
147 return Some(LowerCall { fun, args });
148 }
149
150 if let [
155 TokenTree::Ident(pkg),
156 TokenTree::Punct(c1),
157 TokenTree::Punct(c2),
158 TokenTree::Ident(fun),
159 ] = head
160 && c1.as_char() == ':'
161 && c1.spacing() == proc_macro2::Spacing::Joint
162 && c2.as_char() == ':'
163 {
164 let fun = LowerFun::Namespaced {
165 pkg: pkg.to_string(),
166 fun: fun.to_string(),
167 };
168 let args = classify_args(group)?;
169 return Some(LowerCall { fun, args });
170 }
171
172 if let Some(name) = try_parse_r_dotname(head) {
176 let fun = LowerFun::Simple(name);
177 let args = classify_args(group)?;
178 return Some(LowerCall { fun, args });
179 }
180
181 None
183}
184
185fn try_parse_r_dotname(tokens: &[TokenTree]) -> Option<String> {
191 if tokens.is_empty() || tokens.len().is_multiple_of(2) {
192 return None;
193 }
194 let mut name = String::new();
196 for (i, tt) in tokens.iter().enumerate() {
197 if i % 2 == 0 {
198 match tt {
200 TokenTree::Ident(id) => {
201 if i > 0 {
202 name.push('.');
203 }
204 name.push_str(&id.to_string());
205 }
206 _ => return None,
207 }
208 } else {
209 match tt {
211 TokenTree::Punct(p) if p.as_char() == '.' => {}
212 _ => return None,
213 }
214 }
215 }
216 if name.is_empty() { None } else { Some(name) }
217}
218
219fn classify_args(g: &Group) -> Option<Vec<LowerArg>> {
222 let inner: Vec<TokenTree> = g.stream().into_iter().collect();
223 if inner.is_empty() {
224 return Some(Vec::new());
225 }
226 let segments = split_by_comma_owned(&inner);
228 let mut args = Vec::with_capacity(segments.len());
229 for seg in segments {
230 args.push(classify_one_arg(&seg)?);
231 }
232 Some(args)
233}
234
235fn split_by_comma_owned(tokens: &[TokenTree]) -> Vec<Vec<TokenTree>> {
237 let mut result: Vec<Vec<TokenTree>> = Vec::new();
238 let mut current: Vec<TokenTree> = Vec::new();
239 for tt in tokens {
240 if #[allow(non_exhaustive_omitted_patterns)] match tt {
TokenTree::Punct(p) if p.as_char() == ',' => true,
_ => false,
}matches!(tt, TokenTree::Punct(p) if p.as_char() == ',') {
241 result.push(current.clone());
242 current.clear();
243 } else {
244 current.push(tt.clone());
245 }
246 }
247 result.push(current);
248 result
249}
250
251fn classify_one_arg(tokens: &[TokenTree]) -> Option<LowerArg> {
253 if tokens.len() >= 3
257 && let (TokenTree::Ident(name), TokenTree::Punct(eq)) = (&tokens[0], &tokens[1])
258 && eq.as_char() == '='
259 {
260 let name_str = name.to_string();
261 let value_tokens = &tokens[2..];
262 let atom = classify_atom(value_tokens)?;
263 return Some(LowerArg {
264 name: Some(name_str),
265 value: atom,
266 });
267 }
268
269 let atom = classify_atom(tokens)?;
271 Some(LowerArg {
272 name: None,
273 value: atom,
274 })
275}
276
277fn classify_atom(tokens: &[TokenTree]) -> Option<LowerAtom> {
279 match tokens {
280 [TokenTree::Literal(lit)] => {
282 let s = lit.to_string();
283 if s.starts_with('"') {
284 let ts: TokenStream = std::iter::once(TokenTree::Literal(lit.clone())).collect();
286 let lit_str: syn::LitStr = syn::parse2(ts).ok()?;
287 return Some(LowerAtom::StringLit(lit_str.value()));
288 }
289 if s.ends_with('L') {
292 let digits = &s[..s.len() - 1];
293 if !digits.contains('.')
295 && !digits.contains('e')
296 && !digits.contains('E')
297 && let Ok(v) = digits.parse::<i64>()
298 && v > i32::MIN as i64
299 && v <= i32::MAX as i64
300 {
301 return Some(LowerAtom::IntLit(v as i32));
302 }
303 return None;
304 }
305 if s.contains('.') || s.to_lowercase().contains('e') {
307 let v: f64 = s.parse().ok()?;
308 return Some(LowerAtom::RealLit(v));
309 }
310 if let Ok(v) = s.parse::<i64>() {
314 let real = v as f64;
317 if real as i64 == v {
318 return Some(LowerAtom::RealLit(real));
319 }
320 }
321 None
323 }
324
325 [TokenTree::Punct(minus), rest @ ..] if minus.as_char() == '-' && !rest.is_empty() => {
327 match classify_atom(rest)? {
328 LowerAtom::IntLit(v) => {
329 let neg = v.checked_neg()?;
331 Some(LowerAtom::IntLit(neg))
332 }
333 LowerAtom::RealLit(v) => Some(LowerAtom::RealLit(-v)),
334 LowerAtom::Inf => Some(LowerAtom::RealLit(f64::NEG_INFINITY)),
336 _ => None,
337 }
338 }
339
340 [TokenTree::Ident(id)] => {
342 Some(match id.to_string().as_str() {
343 "TRUE" => LowerAtom::Bool(true),
344 "FALSE" => LowerAtom::Bool(false),
345 "NULL" => LowerAtom::Null,
346 "NA" => LowerAtom::Na,
347 "NA_integer_" => LowerAtom::NaInteger,
348 "NA_real_" => LowerAtom::NaReal,
349 "NA_character_" => LowerAtom::NaCharacter,
350 "NA_complex_" => return None, "Inf" => LowerAtom::Inf,
352 "NaN" => LowerAtom::NaN,
353 sym => LowerAtom::Symbol(sym.to_string()),
354 })
355 }
356
357 _ => {
359 let call = classify_call(tokens)?;
360 Some(LowerAtom::Call(Box::new(call)))
361 }
362 }
363}
364
365fn emit_call(call: &LowerCall, env_expr: &TokenStream) -> TokenStream {
395 let mut scope_lets: Vec<TokenStream> = Vec::new();
397 let mut rcall_chain: Vec<TokenStream> = Vec::new();
398
399 for (i, arg) in call.args.iter().enumerate() {
400 let var = match ::quote::__private::IdentFragmentAdapter(&i) {
arg =>
::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("__r_arg_{0}", arg))
}), ::quote::__private::Option::None.or(arg.span())),
}quote::format_ident!("__r_arg_{}", i);
401 let val_ts = emit_atom(&arg.value, &mut scope_lets);
402 scope_lets.push({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&var, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "__r_scope");
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "protect_raw");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&val_ts, &mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote! {
403 let #var = __r_scope.protect_raw(#val_ts);
404 });
405 if let Some(ref name) = arg.name {
406 rcall_chain.push({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "named_arg");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&name, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&var, &mut _s);
_s
});
_s
}quote! {
407 .named_arg(#name, #var)
408 });
409 } else {
410 rcall_chain.push({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "arg");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&var, &mut _s);
_s
});
_s
}quote! {
411 .arg(#var)
412 });
413 }
414 }
415
416 match &call.fun {
423 LowerFun::Simple(name) => {
424 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_or_or(&mut _s);
::quote::__private::push_rarrow(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "result");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Result");
::quote::__private::push_lt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "expression");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "REvalError");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "unsafe");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "__r_scope");
::quote::__private::push_eq(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "gc_protect");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ProtectScope");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "new");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_semi(&mut _s);
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut scope_lets, i) = scope_lets.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let scope_lets =
match scope_lets.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&scope_lets, &mut _s);
}
}
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "expression");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "RCall");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "new");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&name, &mut _s);
_s
});
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut rcall_chain, i) = rcall_chain.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let rcall_chain =
match rcall_chain.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&rcall_chain, &mut _s);
}
}
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "eval");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&env_expr, &mut _s);
_s
});
_s
});
_s
});
_s
});
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
}quote! {
425 (|| -> ::std::result::Result<::miniextendr_api::SEXP, ::miniextendr_api::expression::REvalError> {
426 unsafe {
427 let __r_scope = ::miniextendr_api::gc_protect::ProtectScope::new();
428 #(#scope_lets)*
429 ::miniextendr_api::expression::RCall::new(#name)
430 #(#rcall_chain)*
431 .eval(#env_expr)
432 }
433 })()
434 }
435 }
436 LowerFun::Namespaced { pkg, fun } => {
437 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_or_or(&mut _s);
::quote::__private::push_rarrow(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "result");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Result");
::quote::__private::push_lt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "expression");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "REvalError");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "__r_ns_call");
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "unsafe");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "expression");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "RCall");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "namespaced");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&pkg, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&fun, &mut _s);
_s
});
::quote::__private::push_question(&mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "unsafe");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "__r_scope");
::quote::__private::push_eq(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "gc_protect");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ProtectScope");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "new");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_semi(&mut _s);
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut scope_lets, i) = scope_lets.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let scope_lets =
match scope_lets.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&scope_lets, &mut _s);
}
}
::quote::__private::push_ident(&mut _s, "__r_ns_call");
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut rcall_chain, i) = rcall_chain.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let rcall_chain =
match rcall_chain.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&rcall_chain, &mut _s);
}
}
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "eval");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&env_expr, &mut _s);
_s
});
_s
});
_s
});
_s
});
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
}quote! {
438 (|| -> ::std::result::Result<::miniextendr_api::SEXP, ::miniextendr_api::expression::REvalError> {
439 let __r_ns_call = unsafe {
440 ::miniextendr_api::expression::RCall::namespaced(#pkg, #fun)?
441 };
442 unsafe {
443 let __r_scope = ::miniextendr_api::gc_protect::ProtectScope::new();
444 #(#scope_lets)*
445 __r_ns_call
446 #(#rcall_chain)*
447 .eval(#env_expr)
448 }
449 })()
450 }
451 }
452 }
453}
454
455fn emit_atom(atom: &LowerAtom, scope_lets: &mut Vec<TokenStream>) -> TokenStream {
460 match atom {
461 LowerAtom::StringLit(s) => {
462 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "scalar_string_from_str");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&s, &mut _s);
_s
});
_s
}quote! { ::miniextendr_api::SEXP::scalar_string_from_str(#s) }
463 }
464 LowerAtom::IntLit(v) => {
465 let v = *v;
466 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "scalar_integer");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&v, &mut _s);
_s
});
_s
}quote! { ::miniextendr_api::SEXP::scalar_integer(#v) }
467 }
468 LowerAtom::RealLit(v) => {
469 let bits = v.to_bits();
471 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "scalar_real");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "f64");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "from_bits");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&bits, &mut _s);
_s
});
_s
});
_s
}quote! {
472 ::miniextendr_api::SEXP::scalar_real(f64::from_bits(#bits))
473 }
474 }
475 LowerAtom::Bool(b) => {
476 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "scalar_logical");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&b, &mut _s);
_s
});
_s
}quote! { ::miniextendr_api::SEXP::scalar_logical(#b) }
477 }
478 LowerAtom::Null => {
479 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "nil");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
}quote! { ::miniextendr_api::SEXP::nil() }
480 }
481 LowerAtom::Na => {
482 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "scalar_logical_raw");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "altrep_traits");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "NA_LOGICAL");
_s
});
_s
}quote! {
484 ::miniextendr_api::SEXP::scalar_logical_raw(
485 ::miniextendr_api::altrep_traits::NA_LOGICAL
486 )
487 }
488 }
489 LowerAtom::NaInteger => {
490 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "scalar_integer");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "i32");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "MIN");
_s
});
_s
}quote! { ::miniextendr_api::SEXP::scalar_integer(i32::MIN) }
491 }
492 LowerAtom::NaReal => {
493 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "scalar_real");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "altrep_traits");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "NA_REAL");
_s
});
_s
}quote! {
494 ::miniextendr_api::SEXP::scalar_real(
495 ::miniextendr_api::altrep_traits::NA_REAL
496 )
497 }
498 }
499 LowerAtom::NaCharacter => {
500 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "scalar_string");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "na_string");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
});
_s
}quote! {
501 ::miniextendr_api::SEXP::scalar_string(
502 ::miniextendr_api::SEXP::na_string()
503 )
504 }
505 }
506 LowerAtom::Inf => {
507 let bits = f64::INFINITY.to_bits();
508 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "scalar_real");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "f64");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "from_bits");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&bits, &mut _s);
_s
});
_s
});
_s
}quote! { ::miniextendr_api::SEXP::scalar_real(f64::from_bits(#bits)) }
509 }
510 LowerAtom::NaN => {
511 let bits = f64::NAN.to_bits();
513 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "scalar_real");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "f64");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "from_bits");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&bits, &mut _s);
_s
});
_s
});
_s
}quote! { ::miniextendr_api::SEXP::scalar_real(f64::from_bits(#bits)) }
514 }
515 LowerAtom::Symbol(name) => {
516 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SEXP");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "symbol");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&name, &mut _s);
_s
});
_s
}quote! {
519 ::miniextendr_api::SEXP::symbol(#name)
520 }
521 }
522 LowerAtom::Call(nested) => {
523 emit_nested_call(nested, scope_lets)
528 }
529 }
530}
531
532fn emit_nested_call(call: &LowerCall, scope_lets: &mut Vec<TokenStream>) -> TokenStream {
539 static COUNTER: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
541 let idx = COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
542
543 let mut arg_names: Vec<proc_macro2::Ident> = Vec::new();
544 let mut arg_named: Vec<bool> = Vec::new();
545 let mut arg_names_str: Vec<String> = Vec::new();
546
547 for (i, arg) in call.args.iter().enumerate() {
548 let var = match ::quote::__private::IdentFragmentAdapter(&idx) {
arg =>
match ::quote::__private::IdentFragmentAdapter(&i) {
arg =>
::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("__r_nested_{0}_{1}", arg,
arg))
}),
::quote::__private::Option::None.or(arg.span()).or(arg.span())),
},
}quote::format_ident!("__r_nested_{}_{}", idx, i);
549 let val_ts = emit_atom(&arg.value, scope_lets);
550 scope_lets.push({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&var, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "__r_scope");
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "protect_raw");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&val_ts, &mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote! {
551 let #var = __r_scope.protect_raw(#val_ts);
552 });
553 arg_names.push(var);
554 arg_named.push(arg.name.is_some());
555 arg_names_str.push(arg.name.clone().unwrap_or_default());
556 }
557
558 let builder_init: TokenStream = match &call.fun {
561 LowerFun::Simple(name) => {
562 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "expression");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "RCall");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "new");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&name, &mut _s);
_s
});
_s
}quote! { ::miniextendr_api::expression::RCall::new(#name) }
563 }
564 LowerFun::Namespaced { pkg, fun } => {
565 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "expression");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "RCall");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "namespaced");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&pkg, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&fun, &mut _s);
_s
});
::quote::__private::push_question(&mut _s);
_s
}quote! { ::miniextendr_api::expression::RCall::namespaced(#pkg, #fun)? }
566 }
567 };
568
569 let mut chain = builder_init;
571 for (i, var) in arg_names.iter().enumerate() {
572 if arg_named[i] {
573 let name = &arg_names_str[i];
574 chain = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&chain, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "named_arg");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&name, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&var, &mut _s);
_s
});
_s
}quote! { #chain.named_arg(#name, #var) };
575 } else {
576 chain = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&chain, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "arg");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&var, &mut _s);
_s
});
_s
}quote! { #chain.arg(#var) };
577 }
578 }
579
580 let call_var = match ::quote::__private::IdentFragmentAdapter(&idx) {
arg =>
::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("__r_call_sexp_{0}", arg))
}), ::quote::__private::Option::None.or(arg.span())),
}quote::format_ident!("__r_call_sexp_{}", idx);
583 scope_lets.push({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&call_var, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "__r_scope");
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "protect_raw");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&chain, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "build");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote! {
584 let #call_var = __r_scope.protect_raw(#chain.build());
585 });
586
587 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&call_var, &mut _s);
_s
}quote! { #call_var }
588}
589
590#[cfg(test)]
595mod tests {
596 use super::*;
597
598 fn parse(s: &str) -> Vec<TokenTree> {
599 let ts: TokenStream = s.parse().expect("failed to parse");
600 ts.into_iter().collect()
601 }
602
603 fn is_lowerable(s: &str) -> bool {
604 classify_call(&parse(s)).is_some()
605 }
606
607 #[test]
610 fn simple_call_no_args() {
611 assert!(is_lowerable("noop()"));
612 }
613
614 #[test]
615 fn simple_call_integer_l_suffix() {
616 assert!(is_lowerable("identity(42L)"));
617 }
618
619 #[test]
620 fn simple_call_negative_integer() {
621 assert!(is_lowerable("identity(-1L)"));
622 }
623
624 #[test]
625 fn simple_call_string() {
626 assert!(is_lowerable(r#"paste("hello", "world")"#));
627 }
628
629 #[test]
630 fn simple_call_float() {
631 assert!(is_lowerable("identity(3.14)"));
632 }
633
634 #[test]
635 fn simple_call_true_false() {
636 assert!(is_lowerable("identity(TRUE)"));
637 assert!(is_lowerable("identity(FALSE)"));
638 }
639
640 #[test]
641 fn simple_call_null() {
642 assert!(is_lowerable("is.null(NULL)"));
643 }
644
645 #[test]
646 fn simple_call_na_forms() {
647 assert!(is_lowerable("identity(NA)"));
648 assert!(is_lowerable("identity(NA_integer_)"));
649 assert!(is_lowerable("identity(NA_real_)"));
650 assert!(is_lowerable("identity(NA_character_)"));
651 }
652
653 #[test]
654 fn simple_call_inf_nan() {
655 assert!(is_lowerable("identity(Inf)"));
656 assert!(is_lowerable("identity(NaN)"));
657 }
658
659 #[test]
660 fn simple_call_neg_inf() {
661 assert!(is_lowerable("identity(-Inf)"));
662 }
663
664 #[test]
665 fn simple_call_bare_symbol() {
666 assert!(is_lowerable("identity(x)"));
667 }
668
669 #[test]
670 fn named_arg() {
671 assert!(is_lowerable("seq(1L, 10L, by = 2L)"));
672 }
673
674 #[test]
675 fn nested_call() {
676 assert!(is_lowerable("c(1L, c(2L, 3L))"));
677 }
678
679 #[test]
680 fn namespaced_call() {
681 assert!(is_lowerable("base::sum(1L, 2L)"));
682 }
683
684 #[test]
685 fn plain_integer_lowers_as_double() {
686 let call = classify_call(&parse("identity(42)")).unwrap();
689 assert!(matches!(call.args[0].value, LowerAtom::RealLit(v) if v == 42.0));
690 let call = classify_call(&parse("identity(42L)")).unwrap();
691 assert!(matches!(call.args[0].value, LowerAtom::IntLit(42)));
692 }
693
694 #[test]
695 fn bare_na_is_logical_na() {
696 let call = classify_call(&parse("identity(NA)")).unwrap();
698 assert!(matches!(call.args[0].value, LowerAtom::Na));
699 }
700
701 #[test]
704 fn arithmetic_not_lowerable() {
705 assert!(!is_lowerable("1L + 2L"));
706 }
707
708 #[test]
709 fn assignment_not_lowerable() {
710 assert!(!is_lowerable("x <- 5L"));
711 }
712
713 #[test]
714 fn semicolon_sequence_not_lowerable() {
715 assert!(!is_lowerable("x <- 5L; x"));
717 }
718
719 #[test]
720 fn indexing_not_lowerable() {
721 assert!(!is_lowerable("x[1L]"));
722 }
723
724 #[test]
725 fn dollar_not_lowerable() {
726 assert!(!is_lowerable("x$y"));
727 }
728
729 #[test]
730 fn bare_symbol_not_lowerable() {
731 assert!(!is_lowerable("x"));
733 }
734
735 #[test]
736 fn na_complex_arg_not_lowerable() {
737 assert!(!is_lowerable("identity(NA_complex_)"));
739 }
740
741 #[test]
742 fn if_not_lowerable() {
743 assert!(!is_lowerable("if (TRUE) 1L else 2L"));
744 }
745
746 #[test]
747 fn empty_arg_slot_not_lowerable() {
748 assert!(!is_lowerable("matrix(, 2, 2)"));
752 assert!(!is_lowerable("f(x,,y)"));
753 }
754
755 #[test]
756 fn spaced_colons_not_namespaced() {
757 assert!(!is_lowerable("pkg : : fn(1L)"));
760 }
761}
762
763