1use std::collections::hash_map::DefaultHasher;
8use std::hash::{Hash, Hasher};
9
10use crate::interpreter::value::*;
11
12pub fn try_dispatch(
17 name: &str,
18 args: &[RValue],
19 _named: &[(String, RValue)],
20 env: &crate::interpreter::environment::Environment,
21) -> Option<Result<RValue, RError>> {
22 match name {
23 "ffi_init_r_library" | "ffi_init_rlang" => {
26 register_rlang_ccallables();
27 Some(Ok(RValue::Null))
28 }
29 "ffi_fini_rlang" | "ffi_glue_is_here" => Some(Ok(RValue::Null)),
30
31 "ffi_is_character" => Some(ffi_is_character(args)),
33 "ffi_is_string" => Some(ffi_is_string(args)),
34 "ffi_is_logical" => Some(ffi_is_logical(args)),
35 "ffi_is_integer" => Some(ffi_is_integer(args)),
36 "ffi_is_double" => Some(ffi_is_double(args)),
37 "ffi_is_complex" => Some(ffi_is_complex(args)),
38 "ffi_is_raw" => Some(ffi_is_raw(args)),
39 "ffi_is_list" => Some(ffi_is_list(args)),
40 "ffi_is_vector" => Some(ffi_is_vector(args)),
41 "ffi_is_atomic" => Some(ffi_is_atomic(args)),
42 "ffi_is_function" => Some(ffi_is_function(args)),
43 "ffi_is_closure" => Some(ffi_is_closure(args)),
44 "ffi_is_primitive" => Some(ffi_is_primitive(args)),
45 "ffi_is_primitive_eager" => Some(ffi_is_primitive_eager(args)),
46 "ffi_is_primitive_lazy" => Some(ffi_is_primitive_lazy(args)),
47 "ffi_is_formula" => Some(ffi_is_formula(args)),
48 "ffi_is_call" => Some(ffi_is_call(args)),
49 "ffi_is_integerish" => Some(ffi_is_integerish(args)),
50 "ffi_is_finite" => Some(ffi_is_finite(args)),
51 "ffi_is_reference" => Some(ffi_is_reference(args)),
52 "ffi_is_weakref" => Some(Ok(r_false())),
53 "ffi_is_splice_box" => Some(Ok(r_false())),
54
55 "ffi_length" => Some(ffi_length(args)),
57 "ffi_names" => Some(ffi_names(args)),
58 "ffi_set_names" => Some(ffi_set_names(args)),
59 "ffi_missing_arg" => Some(Ok(RValue::Null)),
60 "ffi_duplicate" => Some(ffi_duplicate(args)),
61 "ffi_symbol" => Some(ffi_symbol(args)),
62 "ffi_compiled_by_gcc" => Some(Ok(r_false())),
63 "ffi_obj_address" => Some(ffi_obj_address(args)),
64 "ffi_hash" => Some(ffi_hash(args)),
65 "ffi_format_error_arg" => Some(ffi_format_error_arg(args)),
66 "ffi_cnd_type" => Some(ffi_cnd_type(args)),
67
68 "ffi_env_has" => Some(ffi_env_has(args)),
70 "ffi_env_poke_parent" => Some(ffi_env_poke_parent(args)),
71 "ffi_env_clone" => Some(ffi_env_clone(args)),
72 "ffi_find_var" => Some(ffi_find_var(args)),
73 "ffi_ns_registry_env" => Some(ffi_ns_registry_env()),
74 "ffi_env_binding_types" => Some(ffi_env_binding_types(args)),
75
76 "ffi_list2" | "ffi_dots_list" | "ffi_dots_pairlist" => {
78 let mut elements: Vec<(Option<String>, RValue)> = Vec::new();
82 for v in args {
84 elements.push((None, v.clone()));
85 }
86 if let Some(RValue::List(dots)) = env.get("...") {
88 for (opt_name, value) in &dots.values {
89 elements.push((opt_name.clone(), value.clone()));
90 }
91 }
92 Some(Ok(RValue::List(crate::interpreter::value::RList::new(
93 elements,
94 ))))
95 }
96
97 "ffi_promise_expr" => Some(Ok(RValue::Null)),
99 "ffi_promise_value" => Some(Ok(RValue::Null)),
100 "ffi_promise_env" => Some(Ok(RValue::Null)),
101
102 "ffi_standalone_is_bool_1.0.7" => Some(ffi_standalone_is_bool(args)),
104 "ffi_standalone_check_number_1.0.7" => Some(ffi_standalone_check_number(args)),
105
106 _ if name.ends_with("_linked_version") => {
110 let pkg_name = name.trim_end_matches("_linked_version");
111 let version = std::fs::read_to_string(format!("cran/{pkg_name}/DESCRIPTION"))
113 .ok()
114 .and_then(|desc| {
115 desc.lines()
116 .find(|l| l.starts_with("Version:"))
117 .map(|l| l.trim_start_matches("Version:").trim().to_string())
118 })
119 .unwrap_or_default();
120 Some(Ok(RValue::vec(Vector::Character(
121 vec![Some(version)].into(),
122 ))))
123 }
124
125 _ if name.ends_with("_init_library") || name.ends_with("_init_utils") => {
128 tracing::debug!(symbol = name, "intercepted package init — no-op");
129 Some(Ok(RValue::Null))
130 }
131
132 _ if name.starts_with("ffi_") => {
135 tracing::debug!(symbol = name, "unhandled rlang FFI — returning NULL");
136 Some(Ok(RValue::Null))
137 }
138 _ => None,
139 }
140}
141
142fn lgl(v: bool) -> RValue {
145 RValue::vec(Vector::Logical(vec![Some(v)].into()))
146}
147
148fn r_false() -> RValue {
149 lgl(false)
150}
151
152fn r_bool(v: bool) -> RValue {
153 RValue::vec(Vector::Logical(vec![Some(v)].into()))
154}
155
156fn arg(args: &[RValue], i: usize) -> &RValue {
158 args.get(i).unwrap_or(&RValue::Null)
159}
160
161fn is_r_null(v: &RValue) -> bool {
163 v.is_null()
164}
165
166fn int_scalar(v: &RValue) -> Option<i64> {
168 if is_r_null(v) {
169 return None;
170 }
171 v.as_vector().and_then(|v| v.as_integer_scalar())
172}
173
174fn lgl_scalar(v: &RValue) -> Option<bool> {
176 if is_r_null(v) {
177 return None;
178 }
179 v.as_vector().and_then(|v| v.as_logical_scalar())
180}
181
182fn check_length(actual: usize, expected_n: Option<i64>) -> bool {
184 match expected_n {
185 None => true,
186 Some(n) => {
187 let expected = u64::try_from(n).unwrap_or(0);
188 u64::try_from(actual).unwrap_or(0) == expected
189 }
190 }
191}
192
193fn as_char_vec(v: &RValue) -> Option<&[Option<String>]> {
195 match v {
196 RValue::Vector(rv) => match &rv.inner {
197 Vector::Character(c) => Some(c.as_slice()),
198 _ => None,
199 },
200 _ => None,
201 }
202}
203
204fn ffi_is_character(args: &[RValue]) -> Result<RValue, RError> {
210 let x = arg(args, 0);
211 let n = int_scalar(arg(args, 1));
212
213 let result = match x.as_vector() {
214 Some(Vector::Character(chars)) => {
215 if !check_length(chars.len(), n) {
216 false
217 } else {
218 let missing_ok = lgl_scalar(arg(args, 2));
219 let empty_ok = lgl_scalar(arg(args, 3));
220 check_character_constraints(chars, missing_ok, empty_ok)
221 }
222 }
223 _ => false,
224 };
225
226 Ok(r_bool(result))
227}
228
229fn check_character_constraints(
231 chars: &[Option<String>],
232 missing_ok: Option<bool>,
233 empty_ok: Option<bool>,
234) -> bool {
235 if missing_ok == Some(false) && chars.iter().any(|s| s.is_none()) {
237 return false;
238 }
239 if empty_ok == Some(false) && chars.iter().any(|s| s.as_deref() == Some("")) {
241 return false;
242 }
243 true
244}
245
246fn ffi_is_string(args: &[RValue]) -> Result<RValue, RError> {
248 let x = arg(args, 0);
249 let string_arg = arg(args, 1);
250 let empty_arg = arg(args, 2);
251
252 let result = match x.as_vector() {
253 Some(Vector::Character(chars)) if chars.len() == 1 => {
254 match &chars[0] {
256 None => false,
257 Some(s) => {
258 if lgl_scalar(empty_arg) == Some(false) && s.is_empty() {
260 return Ok(r_false());
261 }
262 if !is_r_null(string_arg) {
264 if let Some(allowed) = as_char_vec(string_arg) {
265 allowed.iter().any(|a| a.as_deref() == Some(s.as_str()))
266 } else {
267 false
268 }
269 } else {
270 true
271 }
272 }
273 }
274 }
275 _ => false,
276 };
277
278 Ok(r_bool(result))
279}
280
281fn ffi_is_logical(args: &[RValue]) -> Result<RValue, RError> {
283 let x = arg(args, 0);
284 let n = int_scalar(arg(args, 1));
285
286 let result = match x.as_vector() {
287 Some(Vector::Logical(v)) => check_length(v.len(), n),
288 _ => false,
289 };
290
291 Ok(r_bool(result))
292}
293
294fn ffi_is_integer(args: &[RValue]) -> Result<RValue, RError> {
296 let x = arg(args, 0);
297 let n = int_scalar(arg(args, 1));
298
299 let result = match x.as_vector() {
300 Some(Vector::Integer(v)) => check_length(v.len(), n),
301 _ => false,
302 };
303
304 Ok(r_bool(result))
305}
306
307fn ffi_is_double(args: &[RValue]) -> Result<RValue, RError> {
309 let x = arg(args, 0);
310 let n = int_scalar(arg(args, 1));
311 let finite = lgl_scalar(arg(args, 2));
312
313 let result = match x.as_vector() {
314 Some(Vector::Double(v)) => {
315 if !check_length(v.len(), n) {
316 false
317 } else if finite == Some(true) {
318 v.iter_opt().all(|opt| opt.is_some_and(|f| f.is_finite()))
319 } else {
320 true
321 }
322 }
323 _ => false,
324 };
325
326 Ok(r_bool(result))
327}
328
329fn ffi_is_complex(args: &[RValue]) -> Result<RValue, RError> {
331 let x = arg(args, 0);
332 let n = int_scalar(arg(args, 1));
333 let finite = lgl_scalar(arg(args, 2));
334
335 let result = match x.as_vector() {
336 Some(Vector::Complex(v)) => {
337 if !check_length(v.len(), n) {
338 false
339 } else if finite == Some(true) {
340 v.iter()
341 .all(|opt| opt.is_some_and(|c| c.re.is_finite() && c.im.is_finite()))
342 } else {
343 true
344 }
345 }
346 _ => false,
347 };
348
349 Ok(r_bool(result))
350}
351
352fn ffi_is_raw(args: &[RValue]) -> Result<RValue, RError> {
354 let x = arg(args, 0);
355 let n = int_scalar(arg(args, 1));
356
357 let result = match x.as_vector() {
358 Some(Vector::Raw(v)) => check_length(v.len(), n),
359 _ => false,
360 };
361
362 Ok(r_bool(result))
363}
364
365fn ffi_is_list(args: &[RValue]) -> Result<RValue, RError> {
367 let x = arg(args, 0);
368 let n = int_scalar(arg(args, 1));
369
370 let result = match x {
371 RValue::List(l) => check_length(l.values.len(), n),
372 _ => false,
373 };
374
375 Ok(r_bool(result))
376}
377
378fn ffi_is_vector(args: &[RValue]) -> Result<RValue, RError> {
380 let x = arg(args, 0);
381 let n = int_scalar(arg(args, 1));
382
383 let result = match x {
384 RValue::Vector(rv) => check_length(rv.inner.len(), n),
385 RValue::List(l) => check_length(l.values.len(), n),
386 RValue::Null => check_length(0, n),
387 _ => false,
388 };
389
390 Ok(r_bool(result))
391}
392
393fn ffi_is_atomic(args: &[RValue]) -> Result<RValue, RError> {
395 let x = arg(args, 0);
396 let n = int_scalar(arg(args, 1));
397
398 let result = match x {
399 RValue::Vector(rv) => check_length(rv.inner.len(), n),
400 RValue::Null => check_length(0, n),
401 _ => false,
402 };
403
404 Ok(r_bool(result))
405}
406
407fn ffi_is_function(args: &[RValue]) -> Result<RValue, RError> {
409 let x = arg(args, 0);
410 Ok(r_bool(matches!(x, RValue::Function(_))))
411}
412
413fn ffi_is_closure(args: &[RValue]) -> Result<RValue, RError> {
415 let x = arg(args, 0);
416 Ok(r_bool(matches!(
417 x,
418 RValue::Function(RFunction::Closure { .. })
419 )))
420}
421
422fn ffi_is_primitive(args: &[RValue]) -> Result<RValue, RError> {
424 let x = arg(args, 0);
425 Ok(r_bool(matches!(
426 x,
427 RValue::Function(RFunction::Builtin { .. })
428 )))
429}
430
431fn ffi_is_primitive_eager(args: &[RValue]) -> Result<RValue, RError> {
433 ffi_is_primitive(args)
434}
435
436fn ffi_is_primitive_lazy(args: &[RValue]) -> Result<RValue, RError> {
438 let _x = arg(args, 0);
439 Ok(r_false())
440}
441
442fn ffi_is_formula(args: &[RValue]) -> Result<RValue, RError> {
444 let x = arg(args, 0);
445 let _n = int_scalar(arg(args, 1));
446 let _lhs = lgl_scalar(arg(args, 2));
447
448 let result = match x {
451 RValue::Language(lang) => {
452 let has_formula_class = lang
454 .class()
455 .is_some_and(|c| c.iter().any(|s| s == "formula"));
456 if has_formula_class {
457 true
458 } else {
459 matches!(
460 lang.inner.as_ref(),
461 crate::parser::ast::Expr::Formula { .. }
462 )
463 }
464 }
465 _ => false,
466 };
467
468 Ok(r_bool(result))
469}
470
471fn ffi_is_call(args: &[RValue]) -> Result<RValue, RError> {
473 let x = arg(args, 0);
474 let _name = arg(args, 1);
475 let _n = int_scalar(arg(args, 2));
476 let _ns = arg(args, 3);
477
478 let result = matches!(x, RValue::Language(_));
480
481 Ok(r_bool(result))
482}
483
484fn ffi_is_integerish(args: &[RValue]) -> Result<RValue, RError> {
486 let x = arg(args, 0);
487 let n = int_scalar(arg(args, 1));
488 let finite = lgl_scalar(arg(args, 2));
489
490 let result = match x.as_vector() {
491 Some(Vector::Integer(v)) => {
492 if !check_length(v.len(), n) {
493 false
494 } else if finite == Some(true) {
495 v.iter().all(|opt| opt.is_some())
497 } else {
498 true
499 }
500 }
501 Some(Vector::Double(v)) => {
502 if !check_length(v.len(), n) {
503 false
504 } else {
505 v.iter_opt().all(|opt| match opt {
507 None => finite != Some(true), Some(f) => {
509 if finite == Some(true) && !f.is_finite() {
510 false
511 } else if f.is_nan() || f.is_infinite() {
512 finite != Some(true)
513 } else {
514 f == f.trunc()
515 }
516 }
517 })
518 }
519 }
520 _ => false,
521 };
522
523 Ok(r_bool(result))
524}
525
526fn ffi_is_finite(args: &[RValue]) -> Result<RValue, RError> {
528 let x = arg(args, 0);
529
530 let result = match x.as_vector() {
531 Some(Vector::Double(v)) => v.iter_opt().all(|opt| opt.is_some_and(|f| f.is_finite())),
532 Some(Vector::Integer(v)) => v.iter().all(|opt| opt.is_some()),
533 Some(Vector::Logical(v)) => v.iter().all(|opt| opt.is_some()),
534 Some(Vector::Complex(v)) => v
535 .iter()
536 .all(|opt| opt.is_some_and(|c| c.re.is_finite() && c.im.is_finite())),
537 Some(Vector::Character(_) | Vector::Raw(_)) => true,
538 None => matches!(x, RValue::Null),
539 };
540
541 Ok(r_bool(result))
542}
543
544fn ffi_is_reference(args: &[RValue]) -> Result<RValue, RError> {
547 let x = arg(args, 0);
548 let y = arg(args, 1);
549
550 let result = match (x, y) {
551 (RValue::Environment(a), RValue::Environment(b)) => a.ptr_eq(b),
552 _ => std::ptr::eq(x, y),
553 };
554
555 Ok(r_bool(result))
556}
557
558fn ffi_length(args: &[RValue]) -> Result<RValue, RError> {
564 let x = arg(args, 0);
565 let len = i64::try_from(x.length()).unwrap_or(i64::MAX);
566 Ok(RValue::vec(Vector::Integer(vec![Some(len)].into())))
567}
568
569fn ffi_names(args: &[RValue]) -> Result<RValue, RError> {
571 let x = arg(args, 0);
572
573 match x {
574 RValue::Vector(rv) => match rv.get_attr("names") {
575 Some(v) => Ok(v.clone()),
576 None => Ok(RValue::Null),
577 },
578 RValue::List(l) => {
579 let names: Vec<Option<String>> =
580 l.values.iter().map(|(name, _)| name.clone()).collect();
581 if names.iter().all(|n| n.is_none()) {
582 Ok(RValue::Null)
583 } else {
584 Ok(RValue::vec(Vector::Character(names.into())))
585 }
586 }
587 _ => Ok(RValue::Null),
588 }
589}
590
591fn ffi_set_names(args: &[RValue]) -> Result<RValue, RError> {
594 let x = arg(args, 0).clone();
595 let names_val = arg(args, 1);
596
597 match x {
598 RValue::Vector(mut rv) => {
599 if names_val.is_null() {
600 if let Some(ref mut attrs) = rv.attrs {
601 attrs.shift_remove("names");
602 }
603 } else {
604 rv.set_attr("names".to_string(), names_val.clone());
605 }
606 Ok(RValue::Vector(rv))
607 }
608 RValue::List(mut l) => {
609 if let Some(char_names) = as_char_vec(names_val) {
610 for (i, entry) in l.values.iter_mut().enumerate() {
611 entry.0 = char_names.get(i).cloned().flatten();
612 }
613 } else if names_val.is_null() {
614 for entry in &mut l.values {
615 entry.0 = None;
616 }
617 }
618 Ok(RValue::List(l))
619 }
620 other => Ok(other),
621 }
622}
623
624fn ffi_duplicate(args: &[RValue]) -> Result<RValue, RError> {
628 let x = arg(args, 0);
629 Ok(x.clone())
630}
631
632fn ffi_symbol(args: &[RValue]) -> Result<RValue, RError> {
634 let x = arg(args, 0);
635 let name = x
636 .as_vector()
637 .and_then(|v| v.as_character_scalar())
638 .unwrap_or_default();
639 Ok(RValue::Language(Language::new(
640 crate::parser::ast::Expr::Symbol(name),
641 )))
642}
643
644fn ffi_obj_address(args: &[RValue]) -> Result<RValue, RError> {
647 let x = arg(args, 0);
648 let mut hasher = DefaultHasher::new();
649 format!("{x:?}").hash(&mut hasher);
650 let addr = format!("0x{:016x}", hasher.finish());
651 Ok(RValue::vec(Vector::Character(vec![Some(addr)].into())))
652}
653
654fn ffi_hash(args: &[RValue]) -> Result<RValue, RError> {
656 let x = arg(args, 0);
657 let mut hasher = DefaultHasher::new();
658 format!("{x:?}").hash(&mut hasher);
659 let hash_str = format!("{:016x}", hasher.finish());
660 Ok(RValue::vec(Vector::Character(vec![Some(hash_str)].into())))
661}
662
663fn ffi_format_error_arg(args: &[RValue]) -> Result<RValue, RError> {
666 let x = arg(args, 0);
667 let formatted = match x {
668 RValue::Vector(rv) => match &rv.inner {
669 Vector::Character(c) => c
670 .first()
671 .cloned()
672 .flatten()
673 .map(|s| format!("`{s}`"))
674 .unwrap_or_else(|| "``".to_string()),
675 _ => format!("`{x}`"),
676 },
677 RValue::Language(lang) => format!("`{:?}`", lang.inner),
678 _ => format!("`{x}`"),
679 };
680 Ok(RValue::vec(Vector::Character(vec![Some(formatted)].into())))
681}
682
683fn ffi_cnd_type(args: &[RValue]) -> Result<RValue, RError> {
687 let x = arg(args, 0);
688
689 let class = match x {
690 RValue::List(l) => l.class(),
691 RValue::Vector(rv) => rv.class(),
692 _ => None,
693 };
694
695 let cnd_type = match class {
696 Some(classes) => {
697 if classes.iter().any(|c| c == "error") {
698 "error"
699 } else if classes.iter().any(|c| c == "warning") {
700 "warning"
701 } else if classes.iter().any(|c| c == "message") {
702 "message"
703 } else {
704 "condition"
705 }
706 }
707 None => "condition",
708 };
709
710 Ok(RValue::vec(Vector::Character(
711 vec![Some(cnd_type.to_string())].into(),
712 )))
713}
714
715fn ffi_env_has(args: &[RValue]) -> Result<RValue, RError> {
721 let env_val = arg(args, 0);
722 let names_val = arg(args, 1);
723 let inherit = lgl_scalar(arg(args, 2)).unwrap_or(false);
724
725 let env = match env_val {
726 RValue::Environment(e) => e,
727 _ => return Ok(r_false()),
728 };
729
730 let names = match as_char_vec(names_val) {
731 Some(n) => n,
732 None => return Ok(RValue::vec(Vector::Logical(vec![].into()))),
733 };
734
735 let results: Vec<Option<bool>> = names
736 .iter()
737 .map(|name| {
738 let name_str = name.as_deref().unwrap_or("");
739 let found = if inherit {
740 env.get(name_str).is_some()
741 } else {
742 env.has_local(name_str)
743 };
744 Some(found)
745 })
746 .collect();
747
748 let mut rv = RVector::from(Vector::Logical(results.into()));
749 rv.set_attr("names".to_string(), names_val.clone());
751
752 Ok(RValue::Vector(rv))
753}
754
755fn ffi_env_poke_parent(args: &[RValue]) -> Result<RValue, RError> {
757 let env_val = arg(args, 0);
758 let parent_val = arg(args, 1);
759
760 if let RValue::Environment(env) = env_val {
761 if let RValue::Environment(parent) = parent_val {
762 env.set_parent(Some(parent.clone()));
763 }
764 }
765
766 Ok(RValue::Null)
767}
768
769fn ffi_env_clone(args: &[RValue]) -> Result<RValue, RError> {
771 let env_val = arg(args, 0);
772
773 match env_val {
774 RValue::Environment(env) => {
775 let parent = env.parent();
776 let new_env = match parent {
777 Some(ref p) => crate::interpreter::environment::Environment::new_child(p),
778 None => crate::interpreter::environment::Environment::new_global(),
779 };
780 for name in env.ls() {
782 if let Some(val) = env.get(&name) {
783 new_env.set(name, val);
784 }
785 }
786 Ok(RValue::Environment(new_env))
787 }
788 _ => Ok(RValue::Null),
789 }
790}
791
792fn ffi_find_var(args: &[RValue]) -> Result<RValue, RError> {
794 let sym_val = arg(args, 0);
795 let env_val = arg(args, 1);
796
797 let sym_name = match sym_val {
798 RValue::Vector(rv) => rv.as_character_scalar(),
799 RValue::Language(lang) => match lang.inner.as_ref() {
800 crate::parser::ast::Expr::Symbol(s) => Some(s.clone()),
801 _ => None,
802 },
803 _ => None,
804 };
805
806 let sym_name = match sym_name {
807 Some(s) => s,
808 None => return Ok(RValue::Null),
809 };
810
811 match env_val {
812 RValue::Environment(env) => Ok(env.get(&sym_name).unwrap_or(RValue::Null)),
813 _ => Ok(RValue::Null),
814 }
815}
816
817fn ffi_ns_registry_env() -> Result<RValue, RError> {
819 Ok(RValue::Environment(
820 crate::interpreter::environment::Environment::new_global(),
821 ))
822}
823
824fn ffi_env_binding_types(args: &[RValue]) -> Result<RValue, RError> {
827 let env_val = arg(args, 0);
828 let names_val = arg(args, 1);
829
830 let env = match env_val {
831 RValue::Environment(e) => e,
832 _ => return Ok(RValue::vec(Vector::Integer(vec![].into()))),
833 };
834
835 let names = match as_char_vec(names_val) {
836 Some(n) => n,
837 None => return Ok(RValue::vec(Vector::Integer(vec![].into()))),
838 };
839
840 let types: Vec<Option<i64>> = names
841 .iter()
842 .map(|name| {
843 let name_str = name.as_deref().unwrap_or("");
844 if env.get_local_active_binding(name_str).is_some() {
845 Some(1) } else {
847 Some(0) }
849 })
850 .collect();
851
852 let mut rv = RVector::from(Vector::Integer(types.into()));
853 rv.set_attr("names".to_string(), names_val.clone());
854
855 Ok(RValue::Vector(rv))
856}
857
858fn ffi_standalone_is_bool(args: &[RValue]) -> Result<RValue, RError> {
864 let x = args.first().unwrap_or(&RValue::Null);
865 let allow_na = args
866 .get(1)
867 .and_then(|v| v.as_vector()?.as_logical_scalar())
868 .unwrap_or(false);
869 let allow_null = args
870 .get(2)
871 .and_then(|v| v.as_vector()?.as_logical_scalar())
872 .unwrap_or(false);
873
874 if matches!(x, RValue::Null) {
875 return Ok(lgl(allow_null));
876 }
877
878 if let RValue::Vector(rv) = x {
879 if let Vector::Logical(l) = &rv.inner {
880 if l.len() == 1 {
881 return match l[0] {
882 None => Ok(lgl(allow_na)),
883 Some(_) => Ok(lgl(true)),
884 };
885 }
886 }
887 }
888
889 Ok(lgl(false))
890}
891
892fn ffi_standalone_check_number(args: &[RValue]) -> Result<RValue, RError> {
895 let x = args.first().unwrap_or(&RValue::Null);
896 let allow_decimal = args
897 .get(1)
898 .and_then(|v| v.as_vector()?.as_logical_scalar())
899 .unwrap_or(true);
900 let allow_infinite = args
901 .get(4)
902 .and_then(|v| v.as_vector()?.as_logical_scalar())
903 .unwrap_or(true);
904 let allow_na = args
905 .get(5)
906 .and_then(|v| v.as_vector()?.as_logical_scalar())
907 .unwrap_or(false);
908 let allow_null = args
909 .get(6)
910 .and_then(|v| v.as_vector()?.as_logical_scalar())
911 .unwrap_or(false);
912
913 if matches!(x, RValue::Null) {
914 return Ok(int_val(if allow_null { 0 } else { 1 }));
915 }
916
917 if let RValue::Vector(rv) = x {
918 match &rv.inner {
919 Vector::Integer(i) if i.len() == 1 => {
920 return match i.get_opt(0) {
921 None => Ok(int_val(if allow_na { 0 } else { 4 })),
922 Some(_) => Ok(int_val(0)),
923 };
924 }
925 Vector::Double(d) if d.len() == 1 => {
926 return match d.get_opt(0) {
927 None => Ok(int_val(if allow_na { 0 } else { 4 })),
928 Some(val) => {
929 if val.is_infinite() && !allow_infinite {
930 Ok(int_val(5))
931 } else if !allow_decimal && val.fract() != 0.0 {
932 Ok(int_val(2))
933 } else {
934 Ok(int_val(0))
935 }
936 }
937 };
938 }
939 Vector::Logical(l) if l.len() == 1 && l[0].is_none() => {
940 return Ok(int_val(if allow_na { 0 } else { 4 }));
941 }
942 _ => {}
943 }
944 }
945
946 Ok(int_val(1))
947}
948
949fn int_val(v: i64) -> RValue {
950 RValue::vec(Vector::Integer(vec![Some(v)].into()))
951}
952
953use std::ffi::CStr;
965use std::os::raw::{c_char, c_int, c_void};
966
967use crate::interpreter::native::runtime::{
968 R_NilValue, R_RegisterCCallable, R_alloc, Rf_allocVector, Rf_getAttrib, Rf_inherits, Rf_mkChar,
969 Rf_mkString,
970};
971use crate::interpreter::native::sexp::{self, Sexp};
972
973extern "C" fn rlang_obj_type_friendly_full(x: Sexp, value: c_int, _length: c_int) -> *const c_char {
986 let desc = if x.is_null() || x == unsafe { R_NilValue } {
987 "NULL"
988 } else {
989 let stype = unsafe { (*x).stype };
990 match stype {
991 sexp::NILSXP => "NULL",
992 sexp::LGLSXP => {
993 let len = unsafe { (*x).length };
994 if value != 0 && len == 1 {
995 "`TRUE` or `FALSE`"
996 } else {
997 "a logical vector"
998 }
999 }
1000 sexp::INTSXP => {
1001 if Rf_inherits(x, c"factor".as_ptr()) != 0 {
1002 "a factor"
1003 } else {
1004 let len = unsafe { (*x).length };
1005 if value != 0 && len == 1 {
1006 "an integer"
1007 } else {
1008 "an integer vector"
1009 }
1010 }
1011 }
1012 sexp::REALSXP => {
1013 let len = unsafe { (*x).length };
1014 if value != 0 && len == 1 {
1015 "a number"
1016 } else {
1017 "a double vector"
1018 }
1019 }
1020 sexp::CPLXSXP => "a complex vector",
1021 sexp::STRSXP => {
1022 let len = unsafe { (*x).length };
1023 if value != 0 && len == 1 {
1024 "a string"
1025 } else {
1026 "a character vector"
1027 }
1028 }
1029 sexp::RAWSXP => "a raw vector",
1030 sexp::VECSXP => {
1031 if Rf_inherits(x, c"data.frame".as_ptr()) != 0 {
1032 "a data frame"
1033 } else if Rf_inherits(x, c"tbl_df".as_ptr()) != 0 {
1034 "a tibble"
1035 } else {
1036 "a list"
1037 }
1038 }
1039 2 => "a pairlist",
1041 3 => "a function",
1043 4 => {
1045 if Rf_inherits(x, c"rlang_data_mask".as_ptr()) != 0 {
1046 "a data mask"
1047 } else {
1048 "an environment"
1049 }
1050 }
1051 5 => "a promise",
1053 6 => {
1055 if Rf_inherits(x, c"formula".as_ptr()) != 0 {
1056 "a formula"
1057 } else {
1058 "a call"
1059 }
1060 }
1061 7 => "a primitive function",
1063 8 => "a primitive function",
1065 sexp::CHARSXP => "an internal string",
1066 20 => "an expression vector",
1068 22 => "an external pointer",
1070 sexp::SYMSXP => "a symbol",
1072 _ => "an object",
1073 }
1074 };
1075
1076 let len = desc.len() + 1;
1078 let buf = R_alloc(len, 1);
1079 if buf.is_null() {
1080 return c"an object".as_ptr();
1081 }
1082 unsafe {
1083 std::ptr::copy_nonoverlapping(desc.as_ptr(), buf as *mut u8, desc.len());
1084 *buf.add(desc.len()) = 0; }
1086 buf
1087}
1088
1089extern "C" fn rlang_format_error_arg(arg: Sexp) -> *const c_char {
1101 if arg.is_null() || arg == unsafe { R_NilValue } {
1102 return c"``".as_ptr();
1103 }
1104
1105 let name = unsafe {
1107 if (*arg).stype == sexp::STRSXP && (*arg).length >= 1 && !(*arg).data.is_null() {
1108 let elt = *((*arg).data as *const Sexp);
1109 if !elt.is_null() {
1110 sexp::char_data(elt)
1111 } else {
1112 ""
1113 }
1114 } else if (*arg).stype == sexp::SYMSXP && !(*arg).data.is_null() {
1115 sexp::char_data(arg)
1116 } else {
1117 ""
1118 }
1119 };
1120
1121 let formatted = format!("`{name}`");
1123 let len = formatted.len() + 1;
1124 let buf = R_alloc(len, 1);
1125 if buf.is_null() {
1126 return c"``".as_ptr();
1127 }
1128 unsafe {
1129 std::ptr::copy_nonoverlapping(formatted.as_ptr(), buf as *mut u8, formatted.len());
1130 *buf.add(formatted.len()) = 0;
1131 }
1132 buf
1133}
1134
1135extern "C" fn rlang_stop_internal(func: *const c_char, fmt: *const c_char) {
1147 let func_name = if func.is_null() {
1149 "<unknown>"
1150 } else {
1151 unsafe { CStr::from_ptr(func) }
1152 .to_str()
1153 .unwrap_or("<unknown>")
1154 };
1155 let msg = if fmt.is_null() {
1156 "internal error"
1157 } else {
1158 unsafe { CStr::from_ptr(fmt) }
1159 .to_str()
1160 .unwrap_or("internal error")
1161 };
1162
1163 let full_msg = format!("Internal error in `{func_name}()`: {msg}\0");
1165 extern "C" {
1166 fn Rf_error(fmt: *const c_char, ...) -> !;
1167 }
1168 unsafe {
1169 Rf_error(c"%s".as_ptr(), full_msg.as_ptr() as *const c_char);
1170 }
1171}
1172
1173extern "C" fn rlang_stop_internal2(
1177 _file: *const c_char,
1178 _line: c_int,
1179 _call: Sexp,
1180 fmt: *const c_char,
1181) {
1182 let msg = if fmt.is_null() {
1183 "internal error"
1184 } else {
1185 unsafe { CStr::from_ptr(fmt) }
1186 .to_str()
1187 .unwrap_or("internal error")
1188 };
1189 let full_msg = format!("Internal error: {msg}\0");
1190 extern "C" {
1191 fn Rf_error(fmt: *const c_char, ...) -> !;
1192 }
1193 unsafe {
1194 Rf_error(c"%s".as_ptr(), full_msg.as_ptr() as *const c_char);
1195 }
1196}
1197
1198extern "C" fn rlang_is_quosure(x: Sexp) -> c_int {
1208 Rf_inherits(x, c"quosure".as_ptr())
1209}
1210
1211extern "C" fn rlang_str_as_symbol(x: Sexp) -> Sexp {
1219 if x.is_null() || x == unsafe { R_NilValue } {
1220 return unsafe { R_NilValue };
1221 }
1222 unsafe {
1223 let charsxp = if (*x).stype == sexp::STRSXP && (*x).length >= 1 && !(*x).data.is_null() {
1225 *((*x).data as *const Sexp)
1226 } else if (*x).stype == sexp::CHARSXP {
1227 x
1228 } else {
1229 return R_NilValue;
1230 };
1231
1232 if charsxp.is_null() {
1233 return R_NilValue;
1234 }
1235
1236 let name_ptr = (*charsxp).data as *const c_char;
1238 if name_ptr.is_null() {
1239 return R_NilValue;
1240 }
1241 crate::interpreter::native::runtime::Rf_install(name_ptr)
1242 }
1243}
1244
1245extern "C" fn rlang_names_as_unique(names: Sexp, _quiet: c_int) -> Sexp {
1256 if names.is_null() || names == unsafe { R_NilValue } {
1257 return unsafe { R_NilValue };
1258 }
1259 names
1261}
1262
1263extern "C" fn rlang_eval_tidy(expr: Sexp, _data: Sexp, env: Sexp) -> Sexp {
1274 crate::interpreter::native::runtime::Rf_eval(expr, env)
1276}
1277
1278extern "C" fn rlang_new_data_mask(bottom: Sexp, _top: Sexp) -> Sexp {
1288 if bottom.is_null() || bottom == unsafe { R_NilValue } {
1289 return unsafe { R_NilValue };
1290 }
1291 bottom
1292}
1293
1294extern "C" fn rlang_as_data_mask(data: Sexp) -> Sexp {
1298 data
1299}
1300
1301extern "C" fn rlang_as_data_pronoun(env: Sexp) -> Sexp {
1305 env
1306}
1307
1308extern "C" fn rlang_env_unbind(_env: Sexp, _names: Sexp) {
1318 }
1320
1321extern "C" fn rlang_as_function(x: Sexp, _arg: *const c_char) -> Sexp {
1329 if !x.is_null() && x != unsafe { R_NilValue } {
1331 let stype = unsafe { (*x).stype };
1332 if matches!(stype, 3 | 7 | 8) {
1333 return x;
1334 }
1335 }
1336 x
1338}
1339
1340extern "C" fn rlang_quo_get_expr(quo: Sexp) -> Sexp {
1346 if quo.is_null() || quo == unsafe { R_NilValue } {
1349 return unsafe { R_NilValue };
1350 }
1351 unsafe {
1353 if (*quo).stype == 6 {
1354 if !(*quo).data.is_null() {
1356 let pd = (*quo).data as *const sexp::PairlistData;
1357 let cdr = (*pd).cdr;
1358 if !cdr.is_null() && !(*cdr).data.is_null() {
1359 let pd2 = (*cdr).data as *const sexp::PairlistData;
1360 return (*pd2).car;
1361 }
1362 }
1363 }
1364 R_NilValue
1365 }
1366}
1367
1368extern "C" fn rlang_quo_get_env(quo: Sexp) -> Sexp {
1370 if quo.is_null() || quo == unsafe { R_NilValue } {
1372 return unsafe { R_NilValue };
1373 }
1374 let env_sym = crate::interpreter::native::runtime::Rf_install(c".environment".as_ptr());
1376 let env = Rf_getAttrib(quo, env_sym);
1377 if env.is_null() || env == unsafe { R_NilValue } {
1378 return unsafe { R_NilValue };
1379 }
1380 env
1381}
1382
1383extern "C" fn rlang_quo_set_expr(quo: Sexp, _expr: Sexp) -> Sexp {
1385 quo
1387}
1388
1389extern "C" fn rlang_quo_set_env(quo: Sexp, _env: Sexp) -> Sexp {
1391 quo
1393}
1394
1395extern "C" fn rlang_new_quosure(_expr: Sexp, _env: Sexp) -> Sexp {
1397 unsafe { R_NilValue }
1399}
1400
1401extern "C" fn rlang_arg_match(_arg: Sexp, _values: Sexp, _error_arg: Sexp) -> Sexp {
1407 _arg
1409}
1410
1411extern "C" fn rlang_arg_match_2(
1413 _arg: Sexp,
1414 _values: Sexp,
1415 _error_arg: Sexp,
1416 _error_call: Sexp,
1417) -> Sexp {
1418 _arg
1419}
1420
1421extern "C" fn rlang_is_splice_box(_x: Sexp) -> c_int {
1423 0
1424}
1425
1426extern "C" fn rlang_obj_encode_utf8(x: Sexp) -> Sexp {
1428 x
1430}
1431
1432extern "C" fn rlang_sym_as_character(sym: Sexp) -> Sexp {
1434 if sym.is_null() || sym == unsafe { R_NilValue } {
1435 return Rf_mkString(c"".as_ptr());
1436 }
1437 unsafe {
1438 if (*sym).stype == sexp::SYMSXP && !(*sym).data.is_null() {
1439 let name_ptr = (*sym).data as *const c_char;
1440 return Rf_mkString(name_ptr);
1441 }
1442 }
1443 Rf_mkString(c"".as_ptr())
1444}
1445
1446extern "C" fn rlang_sym_as_string(sym: Sexp) -> Sexp {
1448 if sym.is_null() || sym == unsafe { R_NilValue } {
1449 return Rf_mkChar(c"".as_ptr());
1450 }
1451 unsafe {
1452 if (*sym).stype == sexp::SYMSXP && !(*sym).data.is_null() {
1453 let name_ptr = (*sym).data as *const c_char;
1454 return Rf_mkChar(name_ptr);
1455 }
1456 }
1457 Rf_mkChar(c"".as_ptr())
1458}
1459
1460extern "C" fn rlang_unbox(x: Sexp) -> Sexp {
1462 if !x.is_null() && x != unsafe { R_NilValue } {
1464 unsafe {
1465 if (*x).stype == sexp::VECSXP && (*x).length == 1 && !(*x).data.is_null() {
1466 return *((*x).data as *const Sexp);
1467 }
1468 }
1469 }
1470 x
1471}
1472
1473extern "C" fn rlang_squash_if(_x: Sexp, _type: Sexp, _predicate: Sexp) -> Sexp {
1475 unsafe { R_NilValue }
1476}
1477
1478extern "C" fn rlang_env_dots_list(_env: Sexp) -> Sexp {
1480 Rf_allocVector(sexp::VECSXP as c_int, 0)
1482}
1483
1484extern "C" fn rlang_env_dots_values(_env: Sexp) -> Sexp {
1486 Rf_allocVector(sexp::VECSXP as c_int, 0)
1487}
1488
1489extern "C" fn rlang_print_backtrace() {
1491 }
1493
1494extern "C" fn rlang_env_print(_env: Sexp) {
1496 }
1498
1499extern "C" fn rlang_xxh3_64bits(_data: *const c_void, _len: usize) -> u64 {
1501 0
1502}
1503
1504pub fn register_rlang_ccallables() {
1514 let registrations: &[(&str, *const ())] = &[
1515 (
1516 "rlang_obj_type_friendly_full",
1517 rlang_obj_type_friendly_full as *const (),
1518 ),
1519 (
1520 "rlang_format_error_arg",
1521 rlang_format_error_arg as *const (),
1522 ),
1523 ("rlang_stop_internal", rlang_stop_internal as *const ()),
1524 ("rlang_stop_internal2", rlang_stop_internal2 as *const ()),
1525 ("rlang_is_quosure", rlang_is_quosure as *const ()),
1526 ("rlang_str_as_symbol", rlang_str_as_symbol as *const ()),
1527 ("rlang_names_as_unique", rlang_names_as_unique as *const ()),
1528 ("rlang_eval_tidy", rlang_eval_tidy as *const ()),
1529 (
1530 "rlang_new_data_mask_3.0.0",
1531 rlang_new_data_mask as *const (),
1532 ),
1533 ("rlang_as_data_mask_3.0.0", rlang_as_data_mask as *const ()),
1534 ("rlang_as_data_pronoun", rlang_as_data_pronoun as *const ()),
1535 ("rlang_env_unbind", rlang_env_unbind as *const ()),
1536 ("rlang_as_function", rlang_as_function as *const ()),
1537 ("rlang_quo_get_expr", rlang_quo_get_expr as *const ()),
1538 ("rlang_quo_get_env", rlang_quo_get_env as *const ()),
1539 ("rlang_quo_set_expr", rlang_quo_set_expr as *const ()),
1540 ("rlang_quo_set_env", rlang_quo_set_env as *const ()),
1541 ("rlang_new_quosure", rlang_new_quosure as *const ()),
1542 ("rlang_arg_match", rlang_arg_match as *const ()),
1543 ("rlang_arg_match_2", rlang_arg_match_2 as *const ()),
1544 ("rlang_is_splice_box", rlang_is_splice_box as *const ()),
1545 ("rlang_obj_encode_utf8", rlang_obj_encode_utf8 as *const ()),
1546 (
1547 "rlang_sym_as_character",
1548 rlang_sym_as_character as *const (),
1549 ),
1550 ("rlang_sym_as_string", rlang_sym_as_string as *const ()),
1551 ("rlang_unbox", rlang_unbox as *const ()),
1552 ("rlang_squash_if", rlang_squash_if as *const ()),
1553 ("rlang_env_dots_list", rlang_env_dots_list as *const ()),
1554 ("rlang_env_dots_values", rlang_env_dots_values as *const ()),
1555 ("rlang_as_data_mask", rlang_as_data_mask as *const ()),
1556 ("rlang_new_data_mask", rlang_new_data_mask as *const ()),
1557 ("rlang_print_backtrace", rlang_print_backtrace as *const ()),
1558 ("rlang_env_print", rlang_env_print as *const ()),
1559 ("rlang_xxh3_64bits", rlang_xxh3_64bits as *const ()),
1560 ];
1561
1562 for &(name, fptr) in registrations {
1563 let pkg = std::ffi::CString::new("rlang").expect("CString::new");
1564 let nm = std::ffi::CString::new(name).expect("CString::new");
1565 R_RegisterCCallable(pkg.as_ptr(), nm.as_ptr(), fptr);
1566 }
1567
1568 tracing::debug!("registered {} rlang CCallable shims", registrations.len());
1569}
1570
1571