1mod args;
2mod coercion;
3#[cfg(feature = "collections")]
4pub mod collections;
5mod conditions;
6pub mod connections;
7mod dataframes;
8#[cfg(feature = "datetime")]
9mod datetime;
10#[cfg(any(feature = "digest", feature = "blake3"))]
11mod digest;
12mod factors;
13pub mod graphics;
14pub mod grid;
15mod interp;
16#[cfg(feature = "io")]
17pub mod io;
18#[cfg(feature = "json")]
19mod json;
20pub mod math;
21#[cfg(feature = "native")]
22mod native_code;
23#[cfg(feature = "tls")]
24mod net;
25#[cfg(feature = "parquet")]
26mod parquet;
27mod pre_eval;
28#[cfg(feature = "progress")]
29pub mod progress;
30#[cfg(feature = "random")]
31mod random;
32#[cfg(feature = "native")]
33pub mod rlang_ffi;
34mod s4;
35pub mod serialize;
36mod stats;
37pub mod strings;
38mod stubs;
39pub mod system;
40mod tables;
41#[cfg(feature = "tables")]
42mod tables_display;
43#[cfg(feature = "toml")]
44mod toml;
45mod types;
46
47use unicode_width::UnicodeWidthStr;
48
49use crate::interpreter::environment::Environment;
50use crate::interpreter::value::*;
51use crate::interpreter::BuiltinContext;
52use crate::parser::ast::{Arg, Param};
53use itertools::Itertools;
54use linkme::distributed_slice;
55use minir_macros::{builtin, interpreter_builtin};
56
57pub use crate::interpreter::value::{
58 BuiltinDescriptor, BuiltinFn, BuiltinImplementation, InterpreterBuiltinFn, PreEvalBuiltinFn,
59};
60pub(crate) use args::CallArgs;
61
62#[distributed_slice]
63pub static BUILTIN_REGISTRY: [BuiltinDescriptor];
64
65fn register_builtin_binding(env: &Environment, binding_name: &str, descriptor: BuiltinDescriptor) {
66 env.set(
67 binding_name.to_string(),
68 RValue::Function(RFunction::Builtin {
69 name: binding_name.to_string(),
70 implementation: descriptor.implementation,
71 min_args: descriptor.min_args,
72 max_args: descriptor.max_args,
73 formals: descriptor.formals,
74 }),
75 );
76}
77
78#[inline]
80pub fn math_unary_op(args: &[RValue], f: fn(f64) -> f64) -> Result<RValue, RError> {
81 match args.first() {
82 Some(RValue::Vector(v)) => {
83 let result: Vec<Option<f64>> = v.to_doubles().iter().map(|x| x.map(f)).collect();
84 Ok(RValue::vec(Vector::Double(result.into())))
85 }
86 _ => Err(RError::new(
87 RErrorKind::Argument,
88 "non-numeric argument to mathematical function".to_string(),
89 )),
90 }
91}
92
93pub fn find_builtin(name: &str) -> Option<&'static BuiltinDescriptor> {
95 BUILTIN_REGISTRY
96 .iter()
97 .find(|d| d.name == name || d.aliases.contains(&name))
98}
99
100pub fn find_builtin_ns(namespace: &str, name: &str) -> Option<&'static BuiltinDescriptor> {
102 BUILTIN_REGISTRY
103 .iter()
104 .find(|d| d.namespace == namespace && (d.name == name || d.aliases.contains(&name)))
105}
106
107pub fn format_help(descriptor: &BuiltinDescriptor) -> String {
110 let mut out = String::new();
111 let header = format!("{}::{}", descriptor.namespace, descriptor.name);
112 out.push_str(&format!("{header}\n"));
113 out.push_str(&"─".repeat(header.len().max(20)));
114 out.push('\n');
115
116 if descriptor.doc.is_empty() {
117 out.push_str(&format!(
118 " .Primitive(\"{}\") [{} arg{}]\n",
119 descriptor.name,
120 descriptor.min_args,
121 if descriptor.min_args == 1 { "" } else { "s" }
122 ));
123 } else {
124 for line in descriptor.doc.lines() {
125 let line = line.trim();
126 if let Some(rest) = line.strip_prefix("@param ") {
127 if let Some((param, desc)) = rest.split_once(' ') {
128 out.push_str(&format!(" {:<12} {}\n", param, desc));
129 } else {
130 out.push_str(&format!(" {}\n", rest));
131 }
132 } else if let Some(ret) = line.strip_prefix("@return ") {
133 out.push_str(&format!("\nReturns: {ret}\n"));
134 } else if !line.is_empty() {
135 out.push_str(&format!("{}\n", line));
136 }
137 }
138 }
139
140 if !descriptor.aliases.is_empty() {
141 out.push_str(&format!("\nAliases: {}\n", descriptor.aliases.join(", ")));
142 }
143 out
144}
145
146fn extract_param_names_from_doc(doc: &str) -> Vec<String> {
148 doc.lines()
149 .filter_map(|line| {
150 let line = line.trim();
151 line.strip_prefix("@param ")
152 .and_then(|rest| rest.split_whitespace().next().map(|name| name.to_string()))
153 })
154 .collect()
155}
156
157pub fn synthesize_builtin_help(index: &mut crate::interpreter::packages::rd::RdHelpIndex) {
161 use crate::interpreter::packages::rd::{RdDoc, RdIndexEntry};
162
163 for desc in BUILTIN_REGISTRY {
164 if desc.doc.is_empty() {
165 continue;
166 }
167
168 let mut title = None;
169 let mut description_lines = Vec::new();
170 let mut arguments = Vec::new();
171 let mut return_val = None;
172 let mut in_description = false;
173
174 for line in desc.doc.lines() {
175 let line = line.trim();
176 if let Some(rest) = line.strip_prefix("@param ") {
177 in_description = false;
178 if let Some((param, param_desc)) = rest.split_once(' ') {
179 arguments.push((param.to_string(), param_desc.to_string()));
180 }
181 } else if let Some(ret) = line.strip_prefix("@return ") {
182 in_description = false;
183 return_val = Some(ret.to_string());
184 } else if line.starts_with('@') {
185 in_description = false;
187 } else if title.is_none() && !line.is_empty() {
188 title = Some(line.to_string());
189 in_description = true;
190 } else if in_description && !line.is_empty() {
191 description_lines.push(line.to_string());
192 } else if line.is_empty() && in_description && !description_lines.is_empty() {
193 description_lines.push(String::new());
195 }
196 }
197
198 let params = extract_param_names_from_doc(desc.doc);
200 let usage = if params.is_empty() {
201 format!("{}(...)", desc.name)
202 } else {
203 format!("{}({})", desc.name, params.join(", "))
204 };
205
206 let description = if description_lines.is_empty() {
207 None
208 } else {
209 Some(description_lines.join("\n").trim_end().to_string())
210 };
211
212 let doc = RdDoc {
213 name: Some(desc.name.to_string()),
214 aliases: desc
215 .aliases
216 .iter()
217 .map(|a| a.to_string())
218 .chain(std::iter::once(desc.name.to_string()))
219 .collect(),
220 title,
221 description,
222 usage: Some(usage),
223 arguments,
224 value: return_val,
225 ..Default::default()
226 };
227
228 let ns = if desc.namespace.is_empty() {
229 "base"
230 } else {
231 desc.namespace
232 };
233
234 let entry = RdIndexEntry {
235 package: ns.to_string(),
236 file_path: format!("<builtin:{}>", desc.name),
237 doc,
238 };
239
240 index.register_entry(desc.name, entry.clone());
242 for alias in desc.aliases {
243 index.register_entry(alias, entry.clone());
244 }
245 }
246}
247
248pub fn generate_rd_docs(dir: &std::path::Path) -> Result<usize, std::io::Error> {
254 use crate::interpreter::packages::rd::RdDoc;
255 use std::collections::{HashMap, HashSet};
256
257 let mut docs: HashMap<String, RdDoc> = HashMap::new();
261 let mut seen_aliases: HashSet<String> = HashSet::new();
262
263 for desc in BUILTIN_REGISTRY {
264 if desc.doc.is_empty() {
265 continue;
266 }
267
268 if seen_aliases.contains(desc.name) {
271 continue;
272 }
273
274 let mut title = None;
275 let mut description_lines = Vec::new();
276 let mut arguments = Vec::new();
277 let mut return_val = None;
278 let mut in_description = false;
279
280 for line in desc.doc.lines() {
281 let line = line.trim();
282 if let Some(rest) = line.strip_prefix("@param ") {
283 in_description = false;
284 if let Some((param, param_desc)) = rest.split_once(' ') {
285 arguments.push((param.to_string(), param_desc.to_string()));
286 }
287 } else if let Some(ret) = line.strip_prefix("@return ") {
288 in_description = false;
289 return_val = Some(ret.to_string());
290 } else if line.starts_with('@') {
291 in_description = false;
292 } else if title.is_none() && !line.is_empty() {
293 title = Some(line.to_string());
294 in_description = true;
295 } else if in_description && !line.is_empty() {
296 description_lines.push(line.to_string());
297 } else if line.is_empty() && in_description && !description_lines.is_empty() {
298 description_lines.push(String::new());
299 }
300 }
301
302 let params = extract_param_names_from_doc(desc.doc);
303 let usage = if params.is_empty() {
304 format!("{}(...)", desc.name)
305 } else {
306 format!("{}({})", desc.name, params.join(", "))
307 };
308
309 let description = if description_lines.is_empty() {
310 None
311 } else {
312 Some(description_lines.join("\n").trim_end().to_string())
313 };
314
315 let mut aliases: Vec<String> = vec![desc.name.to_string()];
316 for a in desc.aliases {
317 if !aliases.contains(&a.to_string()) {
318 aliases.push(a.to_string());
319 }
320 seen_aliases.insert(a.to_string());
321 }
322 seen_aliases.insert(desc.name.to_string());
323
324 let doc = RdDoc {
325 name: Some(desc.name.to_string()),
326 aliases,
327 title,
328 description,
329 usage: Some(usage),
330 arguments,
331 value: return_val,
332 keywords: if desc.namespace.is_empty() {
333 vec![]
334 } else {
335 vec![desc.namespace.to_string()]
336 },
337 ..Default::default()
338 };
339
340 let safe_name = sanitize_rd_filename(desc.name);
341 docs.entry(safe_name).or_insert(doc);
342 }
343
344 std::fs::create_dir_all(dir)?;
347
348 let mut written: HashSet<String> = HashSet::new();
349 let mut count = 0usize;
350 for (safe_name, doc) in &docs {
351 let lower = safe_name.to_lowercase();
352 if written.contains(&lower) {
353 continue;
354 }
355 let rd_content = doc.to_rd();
356 let file_path = dir.join(format!("{safe_name}.Rd"));
357 std::fs::write(&file_path, rd_content)?;
358 written.insert(lower);
359 count += 1;
360 }
361
362 Ok(count)
363}
364
365fn sanitize_rd_filename(name: &str) -> String {
371 if name
372 .chars()
373 .all(|c| c.is_alphanumeric() || c == '_' || c == '.')
374 {
375 return name.to_string();
376 }
377
378 let mut out = String::new();
379 for ch in name.chars() {
380 match ch {
381 '+' => out.push_str("plus"),
382 '-' => out.push_str("minus"),
383 '*' => out.push_str("star"),
384 '/' => out.push_str("slash"),
385 '^' => out.push_str("caret"),
386 '<' => out.push_str("lt"),
387 '>' => out.push_str("gt"),
388 '=' => out.push_str("eq"),
389 '!' => out.push_str("bang"),
390 '&' => out.push_str("and"),
391 '|' => out.push_str("or"),
392 '%' => out.push_str("pct"),
393 '~' => out.push_str("tilde"),
394 ':' => out.push_str("colon"),
395 '[' => out.push_str("lbracket"),
396 ']' => out.push_str("rbracket"),
397 '(' => out.push_str("lparen"),
398 ')' => out.push_str("rparen"),
399 '{' => out.push_str("lbrace"),
400 '}' => out.push_str("rbrace"),
401 '$' => out.push_str("dollar"),
402 '@' => out.push_str("at"),
403 _ => out.push(ch),
404 }
405 }
406 out
407}
408
409pub fn register_builtins(env: &Environment) {
410 for descriptor in BUILTIN_REGISTRY {
411 register_builtin_binding(env, descriptor.name, *descriptor);
412 for &alias in descriptor.aliases {
413 register_builtin_binding(env, alias, *descriptor);
414 }
415 }
416
417 env.set(
419 "pi".to_string(),
420 RValue::vec(Vector::Double(vec![Some(std::f64::consts::PI)].into())),
421 );
422 env.set(
423 "T".to_string(),
424 RValue::vec(Vector::Logical(vec![Some(true)].into())),
425 );
426 env.set(
427 "F".to_string(),
428 RValue::vec(Vector::Logical(vec![Some(false)].into())),
429 );
430 env.set(
431 "TRUE".to_string(),
432 RValue::vec(Vector::Logical(vec![Some(true)].into())),
433 );
434 env.set(
435 "FALSE".to_string(),
436 RValue::vec(Vector::Logical(vec![Some(false)].into())),
437 );
438 env.set(
439 "Inf".to_string(),
440 RValue::vec(Vector::Double(vec![Some(f64::INFINITY)].into())),
441 );
442 env.set(
443 "NaN".to_string(),
444 RValue::vec(Vector::Double(vec![Some(f64::NAN)].into())),
445 );
446 env.set(
447 "NA".to_string(),
448 RValue::vec(Vector::Logical(vec![None].into())),
449 );
450 env.set(
451 "NA_integer_".to_string(),
452 RValue::vec(Vector::Integer(vec![None].into())),
453 );
454 env.set(
455 "NA_real_".to_string(),
456 RValue::vec(Vector::Double(vec![None].into())),
457 );
458 env.set(
459 "NA_character_".to_string(),
460 RValue::vec(Vector::Character(vec![None].into())),
461 );
462 env.set(
463 "LETTERS".to_string(),
464 RValue::vec(Vector::Character(
465 (b'A'..=b'Z')
466 .map(|c| Some(String::from(c as char)))
467 .collect::<Vec<_>>()
468 .into(),
469 )),
470 );
471 env.set(
472 "letters".to_string(),
473 RValue::vec(Vector::Character(
474 (b'a'..=b'z')
475 .map(|c| Some(String::from(c as char)))
476 .collect::<Vec<_>>()
477 .into(),
478 )),
479 );
480 env.set(
481 ".Machine".to_string(),
482 RValue::List(RList::new(vec![
483 (
484 Some("integer.max".to_string()),
485 RValue::vec(Vector::Integer(vec![Some(i64::from(i32::MAX))].into())),
486 ),
487 (
488 Some("double.eps".to_string()),
489 RValue::vec(Vector::Double(vec![Some(f64::EPSILON)].into())),
490 ),
491 (
492 Some("double.neg.eps".to_string()),
493 RValue::vec(Vector::Double(vec![Some(f64::EPSILON / 2.0)].into())),
494 ),
495 (
496 Some("double.xmax".to_string()),
497 RValue::vec(Vector::Double(vec![Some(f64::MAX)].into())),
498 ),
499 (
500 Some("double.xmin".to_string()),
501 RValue::vec(Vector::Double(vec![Some(f64::MIN_POSITIVE)].into())),
502 ),
503 (
504 Some("double.digits".to_string()),
505 RValue::vec(Vector::Integer(vec![Some(53)].into())),
506 ),
507 (
508 Some("double.max.exp".to_string()),
509 RValue::vec(Vector::Integer(vec![Some(1024)].into())),
510 ),
511 (
512 Some("double.min.exp".to_string()),
513 RValue::vec(Vector::Integer(vec![Some(-1021)].into())),
514 ),
515 (
516 Some("sizeof.long".to_string()),
517 RValue::vec(Vector::Integer(
518 vec![Some(
519 i64::try_from(std::mem::size_of::<std::ffi::c_long>()).unwrap_or(8),
520 )]
521 .into(),
522 )),
523 ),
524 (
525 Some("sizeof.longlong".to_string()),
526 RValue::vec(Vector::Integer(
527 vec![Some(
528 i64::try_from(std::mem::size_of::<std::ffi::c_longlong>()).unwrap_or(8),
529 )]
530 .into(),
531 )),
532 ),
533 (
534 Some("sizeof.pointer".to_string()),
535 RValue::vec(Vector::Integer(
536 vec![Some(
537 i64::try_from(std::mem::size_of::<*const u8>()).unwrap_or(8),
538 )]
539 .into(),
540 )),
541 ),
542 (
543 Some("longdouble.eps".to_string()),
544 RValue::vec(Vector::Double(vec![Some(f64::EPSILON)].into())),
545 ),
546 (
547 Some("longdouble.max".to_string()),
548 RValue::vec(Vector::Double(vec![Some(f64::MAX)].into())),
549 ),
550 (
551 Some("longdouble.digits".to_string()),
552 RValue::vec(Vector::Integer(vec![Some(53)].into())),
553 ),
554 ])),
555 );
556
557 let os_type = if cfg!(unix) { "unix" } else { "windows" };
559 let file_sep = if cfg!(windows) { "\\" } else { "/" };
560 let path_sep = if cfg!(windows) { ";" } else { ":" };
561 let dynlib_ext = if cfg!(target_os = "macos") {
562 ".dylib"
563 } else if cfg!(windows) {
564 ".dll"
565 } else {
566 ".so"
567 };
568 env.set(
569 ".Platform".to_string(),
570 RValue::List(RList::new(vec![
571 (
572 Some("OS.type".to_string()),
573 RValue::vec(Vector::Character(vec![Some(os_type.to_string())].into())),
574 ),
575 (
576 Some("file.sep".to_string()),
577 RValue::vec(Vector::Character(vec![Some(file_sep.to_string())].into())),
578 ),
579 (
580 Some("path.sep".to_string()),
581 RValue::vec(Vector::Character(vec![Some(path_sep.to_string())].into())),
582 ),
583 (
584 Some("dynlib.ext".to_string()),
585 RValue::vec(Vector::Character(vec![Some(dynlib_ext.to_string())].into())),
586 ),
587 (
588 Some("pkgType".to_string()),
589 RValue::vec(Vector::Character(vec![Some("source".to_string())].into())),
590 ),
591 ])),
592 );
593
594 env.set(
596 "R.version".to_string(),
597 RValue::List(RList::new(vec![
598 (
599 Some("major".to_string()),
600 RValue::vec(Vector::Character(vec![Some("4".to_string())].into())),
601 ),
602 (
603 Some("minor".to_string()),
604 RValue::vec(Vector::Character(vec![Some("4.0".to_string())].into())),
605 ),
606 (
607 Some("version.string".to_string()),
608 RValue::vec(Vector::Character(
609 vec![Some("miniR version 0.1.0 (R-compat 4.4.0)".to_string())].into(),
610 )),
611 ),
612 ])),
613 );
614 env.set(
615 "R.version.string".to_string(),
616 RValue::vec(Vector::Character(
617 vec![Some("miniR version 0.1.0 (R-compat 4.4.0)".to_string())].into(),
618 )),
619 );
620
621 register_operator_builtins(env);
623}
624
625fn register_operator_builtins(env: &Environment) {
630 use crate::interpreter::value::*;
631
632 env.set(
634 "[[".to_string(),
635 RValue::Function(RFunction::Builtin {
636 name: "[[".to_string(),
637 implementation: BuiltinImplementation::Eager(|args, _| {
638 if args.len() < 2 {
639 return Err(RError::new(
640 RErrorKind::Argument,
641 "`[[` requires 2 arguments".to_string(),
642 ));
643 }
644 let obj = &args[0];
645 let idx = &args[1];
646 match obj {
647 RValue::List(list) => match idx {
648 RValue::Vector(rv) if matches!(rv.inner, Vector::Character(_)) => {
649 let name = rv.inner.as_character_scalar().unwrap_or_default();
650 for (n, v) in &list.values {
651 if n.as_deref() == Some(&name) {
652 return Ok(v.clone());
653 }
654 }
655 Ok(RValue::Null)
656 }
657 RValue::Vector(v) => {
658 let i = v.as_integer_scalar().unwrap_or(0) as usize;
659 if i > 0 && i <= list.values.len() {
660 Ok(list.values[i - 1].1.clone())
661 } else {
662 Ok(RValue::Null)
663 }
664 }
665 _ => Ok(RValue::Null),
666 },
667 RValue::Vector(v) => match idx {
668 RValue::Vector(idx_rv)
669 if matches!(idx_rv.inner, Vector::Character(_)) =>
670 {
671 let name = idx_rv.inner.as_character_scalar().unwrap_or_default();
672 if let Some(names_attr) = v.get_attr("names") {
673 if let Some(names_vec) = names_attr.as_vector() {
674 let name_strs = names_vec.to_characters();
675 for (j, n) in name_strs.iter().enumerate() {
676 if n.as_deref() == Some(name.as_str()) && j < v.len() {
677 return Ok(
678 crate::interpreter::indexing::extract_vector_element(
679 v, j,
680 ),
681 );
682 }
683 }
684 }
685 }
686 Ok(RValue::Null)
687 }
688 RValue::Vector(idx_rv) => {
689 let i = idx_rv.as_integer_scalar().unwrap_or(0) as usize;
690 if i > 0 && i <= v.len() {
691 Ok(crate::interpreter::indexing::extract_vector_element(v, i - 1))
692 } else {
693 Ok(RValue::Null)
694 }
695 }
696 _ => Ok(RValue::Null),
697 },
698 _ => Err(RError::other("object of type 'closure' is not subsettable".to_string())),
699 }
700 }),
701 min_args: 2,
702 max_args: None,
703 formals: &[],
704 }),
705 );
706
707 env.set(
709 "[".to_string(),
710 RValue::Function(RFunction::Builtin {
711 name: "[".to_string(),
712 implementation: BuiltinImplementation::Eager(|args, _| {
713 if args.is_empty() {
714 return Err(RError::new(
715 RErrorKind::Argument,
716 "`[` requires at least 1 argument".to_string(),
717 ));
718 }
719 if args.len() == 1 {
720 return Ok(args[0].clone());
721 }
722 match (&args[0], &args[1]) {
725 (RValue::Vector(v), RValue::Vector(idx)) => {
726 let i = idx.as_integer_scalar().unwrap_or(0) as usize;
727 if i > 0 && i <= v.len() {
728 Ok(crate::interpreter::indexing::extract_vector_element(
729 v,
730 i - 1,
731 ))
732 } else {
733 Ok(RValue::Null)
734 }
735 }
736 (RValue::List(list), RValue::Vector(idx)) => {
737 let i = idx.as_integer_scalar().unwrap_or(0) as usize;
738 if i > 0 && i <= list.values.len() {
739 let (name, val) = &list.values[i - 1];
740 Ok(RValue::List(RList::new(vec![(name.clone(), val.clone())])))
741 } else {
742 Ok(RValue::Null)
743 }
744 }
745 _ => Ok(RValue::Null),
746 }
747 }),
748 min_args: 1,
749 max_args: None,
750 formals: &[],
751 }),
752 );
753}
754
755#[cfg(test)]
756mod tests {
757 use std::collections::HashSet;
758
759 use super::BUILTIN_REGISTRY;
760
761 #[test]
762 fn builtin_registry_names_are_unique() {
763 let mut names = HashSet::new();
764
765 for descriptor in BUILTIN_REGISTRY {
766 assert!(
767 names.insert(descriptor.name),
768 "duplicate builtin name or alias in registry: {}",
769 descriptor.name
770 );
771 for &alias in descriptor.aliases {
772 assert!(
773 names.insert(alias),
774 "duplicate builtin name or alias in registry: {}",
775 alias
776 );
777 }
778 }
779 }
780}
781
782#[builtin]
792pub fn builtin_c(args: &[RValue], named: &[(String, RValue)]) -> Result<RValue, RError> {
793 let mut all_entries: Vec<(Option<String>, RValue)> = Vec::new();
795 for arg in args {
796 all_entries.push((None, arg.clone()));
797 }
798 for (name, val) in named {
799 all_entries.push((Some(name.clone()), val.clone()));
800 }
801
802 if all_entries.is_empty() {
803 return Ok(RValue::Null);
804 }
805
806 let all_values: Vec<RValue> = all_entries.iter().map(|(_, v)| v.clone()).collect();
807
808 let has_list = all_values.iter().any(|v| matches!(v, RValue::List(_)));
810 if has_list {
811 let mut result = Vec::new();
812 for val in &all_values {
813 match val {
814 RValue::List(l) => result.extend(l.values.clone()),
815 RValue::Null => {}
816 other => result.push((None, other.clone())),
817 }
818 }
819 return Ok(RValue::List(RList::new(result)));
820 }
821
822 let mut has_char = false;
824 let mut has_complex = false;
825 let mut has_double = false;
826 let mut has_int = false;
827 let mut has_logical = false;
828 let mut has_raw = false;
829
830 for val in &all_values {
831 match val {
832 RValue::Vector(rv) if matches!(rv.inner, Vector::Character(_)) => has_char = true,
833 RValue::Vector(rv) if matches!(rv.inner, Vector::Complex(_)) => has_complex = true,
834 RValue::Vector(rv) if matches!(rv.inner, Vector::Double(_)) => has_double = true,
835 RValue::Vector(rv) if matches!(rv.inner, Vector::Integer(_)) => has_int = true,
836 RValue::Vector(rv) if matches!(rv.inner, Vector::Logical(_)) => has_logical = true,
837 RValue::Vector(rv) if matches!(rv.inner, Vector::Raw(_)) => has_raw = true,
838 RValue::Null => {}
839 _ => {}
840 }
841 }
842
843 let vec_result = if has_char {
844 let mut result = Vec::new();
845 for val in &all_values {
846 match val {
847 RValue::Vector(v) => result.extend(v.to_characters()),
848 RValue::Null => {}
849 _ => {}
850 }
851 }
852 RValue::vec(Vector::Character(result.into()))
853 } else if has_complex {
854 let mut result = Vec::new();
855 for val in &all_values {
856 match val {
857 RValue::Vector(v) => result.extend(v.inner.to_complex()),
858 RValue::Null => {}
859 _ => {}
860 }
861 }
862 RValue::vec(Vector::Complex(result.into()))
863 } else if has_double {
864 let mut result = Vec::new();
865 for val in &all_values {
866 match val {
867 RValue::Vector(v) => result.extend(v.to_doubles()),
868 RValue::Null => {}
869 _ => {}
870 }
871 }
872 RValue::vec(Vector::Double(result.into()))
873 } else if has_int {
874 let mut result = Vec::new();
875 for val in &all_values {
876 match val {
877 RValue::Vector(v) => result.extend(v.to_integers()),
878 RValue::Null => {}
879 _ => {}
880 }
881 }
882 RValue::vec(Vector::Integer(result.into()))
883 } else if has_logical || !has_raw {
884 let mut result = Vec::new();
885 for val in &all_values {
886 match val {
887 RValue::Vector(v) => result.extend(v.to_logicals()),
888 RValue::Null => {}
889 _ => {}
890 }
891 }
892 RValue::vec(Vector::Logical(result.into()))
893 } else {
894 let mut result = Vec::new();
895 for val in &all_values {
896 match val {
897 RValue::Vector(v) => result.extend(v.inner.to_raw()),
898 RValue::Null => {}
899 _ => {}
900 }
901 }
902 RValue::vec(Vector::Raw(result))
903 };
904
905 let result = vec_result;
907 let names = collect_c_names(&all_entries);
908 if names.iter().any(|n| n.is_some()) {
909 match result {
910 RValue::Vector(mut rv) => {
911 rv.set_attr(
912 "names".to_string(),
913 RValue::vec(Vector::Character(names.into())),
914 );
915 Ok(RValue::Vector(rv))
916 }
917 other => Ok(other),
918 }
919 } else {
920 Ok(result)
921 }
922}
923
924fn collect_c_names(entries: &[(Option<String>, RValue)]) -> Vec<Option<String>> {
927 let mut names = Vec::new();
928 for (arg_name, val) in entries {
929 match val {
930 RValue::Vector(rv) => {
931 let len = rv.inner.len();
932 let existing_names = rv
934 .get_attr("names")
935 .and_then(|v| v.as_vector())
936 .map(|v| v.to_characters());
937
938 if let Some(ref enames) = existing_names {
939 for i in 0..len {
940 names.push(enames.get(i).cloned().flatten());
941 }
942 } else if len == 1 {
943 names.push(arg_name.clone());
945 } else {
946 for _ in 0..len {
948 names.push(None);
949 }
950 }
951 }
952 RValue::Null => {}
953 _ => names.push(arg_name.clone()),
954 }
955 }
956 names
957}
958
959#[interpreter_builtin(min_args = 1)]
964fn interp_help(
965 args: &[RValue],
966 named: &[(String, RValue)],
967 context: &BuiltinContext,
968) -> Result<RValue, RError> {
969 let name = match args.first() {
970 Some(RValue::Vector(rv)) => rv.as_character_scalar().unwrap_or_default(),
971 Some(RValue::Function(RFunction::Builtin { name, .. })) => name.clone(),
972 _ => String::new(),
973 };
974 if name.is_empty() {
975 return Ok(RValue::Null);
976 }
977
978 let pkg = named.iter().find_map(|(k, v)| {
980 if k == "package" {
981 if let RValue::Vector(rv) = v {
982 rv.as_character_scalar()
983 } else {
984 None
985 }
986 } else {
987 None
988 }
989 });
990 let name = if let Some(ref pkg) = pkg {
991 format!("{pkg}::{name}")
992 } else {
993 name
994 };
995
996 if BUILTIN_REGISTRY.iter().any(|d| d.namespace == name) {
998 let mut fns: Vec<&str> = BUILTIN_REGISTRY
999 .iter()
1000 .filter(|d| d.namespace == name)
1001 .map(|d| d.name)
1002 .collect();
1003 fns.sort();
1004 fns.dedup();
1005 println!("Package '{name}'");
1006 println!("{}", "─".repeat(20 + name.len()));
1007 println!();
1008 println!("{} functions:", fns.len());
1009 println!();
1010 let max_width = fns.iter().map(|f| f.len()).max().unwrap_or(10) + 2;
1011 let cols = 80 / max_width.max(1);
1012 for (i, f) in fns.iter().enumerate() {
1013 print!("{:<width$}", f, width = max_width);
1014 if (i + 1) % cols == 0 {
1015 println!();
1016 }
1017 }
1018 if !fns.len().is_multiple_of(cols) {
1019 println!();
1020 }
1021 println!();
1022 println!("Use ?{name}::name for help on a specific function.");
1023 return Ok(RValue::Null);
1024 }
1025
1026 let rd_result = {
1028 let index = context.interpreter().rd_help_index.borrow();
1029 if let Some((ns, n)) = name.split_once("::") {
1030 index.lookup_in_package(n, ns).map(|e| e.doc.format_text())
1031 } else {
1032 index.lookup(&name).first().map(|e| e.doc.format_text())
1033 }
1034 };
1035 if let Some(text) = rd_result {
1036 context.write(&text);
1037 context.write("\n");
1038 return Ok(RValue::Null);
1039 }
1040
1041 let descriptor = if let Some((ns, n)) = name.split_once("::") {
1043 find_builtin_ns(ns, n)
1044 } else {
1045 find_builtin(&name)
1046 };
1047 match descriptor {
1048 Some(d) => {
1049 context.write(&format!("{}\n", format_help(d)));
1050 Ok(RValue::Null)
1051 }
1052 None => {
1053 context.write(&format!("No documentation for '{name}'\n"));
1054 Ok(RValue::Null)
1055 }
1056 }
1057}
1058
1059#[interpreter_builtin(name = "cat")]
1074fn builtin_cat(
1075 args: &[RValue],
1076 named: &[(String, RValue)],
1077 context: &BuiltinContext,
1078) -> Result<RValue, RError> {
1079 let sep = named
1080 .iter()
1081 .find(|(n, _)| n == "sep")
1082 .and_then(|(_, v)| v.as_vector()?.as_character_scalar())
1083 .unwrap_or_else(|| " ".to_string());
1084
1085 let file = named
1086 .iter()
1087 .find(|(n, _)| n == "file")
1088 .and_then(|(_, v)| v.as_vector()?.as_character_scalar());
1089
1090 let append = named
1091 .iter()
1092 .find(|(n, _)| n == "append")
1093 .and_then(|(_, v)| v.as_vector()?.as_logical_scalar())
1094 .unwrap_or(false);
1095
1096 let parts: Vec<String> = args
1097 .iter()
1098 .map(|arg| match arg {
1099 RValue::Vector(v) => {
1100 let elems: Vec<String> = match &v.inner {
1101 Vector::Raw(vals) => vals.iter().map(|b| format!("{:02x}", b)).collect(),
1102 Vector::Character(vals) => vals
1103 .iter()
1104 .map(|x| x.clone().unwrap_or_else(|| "NA".to_string()))
1105 .collect(),
1106 Vector::Double(vals) => vals
1107 .iter_opt()
1108 .map(|x| x.map(format_r_double).unwrap_or_else(|| "NA".to_string()))
1109 .collect(),
1110 Vector::Integer(vals) => vals
1111 .iter_opt()
1112 .map(|x| x.map(|i| i.to_string()).unwrap_or_else(|| "NA".to_string()))
1113 .collect(),
1114 Vector::Logical(vals) => vals
1115 .iter()
1116 .map(|x| match x {
1117 Some(true) => "TRUE".to_string(),
1118 Some(false) => "FALSE".to_string(),
1119 None => "NA".to_string(),
1120 })
1121 .collect(),
1122 Vector::Complex(vals) => vals
1123 .iter()
1124 .map(|x| x.map(format_r_complex).unwrap_or_else(|| "NA".to_string()))
1125 .collect(),
1126 };
1127 elems.join(&sep)
1128 }
1129 RValue::Null => "".to_string(),
1130 other => format!("{}", other),
1131 })
1132 .collect();
1133
1134 let output = parts.join(&sep);
1135
1136 match file {
1137 Some(ref path) if !path.is_empty() => {
1138 use std::fs::OpenOptions;
1139 use std::io::Write;
1140 let path = context.interpreter().resolve_path(path);
1141 let mut f = OpenOptions::new()
1142 .write(true)
1143 .create(true)
1144 .append(append)
1145 .truncate(!append)
1146 .open(&path)
1147 .map_err(|e| {
1148 RError::other(format!("cannot open file '{}': {}", path.display(), e))
1149 })?;
1150 f.write_all(output.as_bytes()).map_err(|e| {
1151 RError::other(format!("error writing to '{}': {}", path.display(), e))
1152 })?;
1153 }
1154 _ => {
1155 context.write(&output);
1156 }
1157 }
1158
1159 Ok(RValue::Null)
1160}
1161
1162#[builtin]
1173fn builtin_paste(args: &[RValue], named: &[(String, RValue)]) -> Result<RValue, RError> {
1174 let sep = named
1175 .iter()
1176 .find(|(n, _)| n == "sep")
1177 .and_then(|(_, v)| v.as_vector()?.as_character_scalar())
1178 .unwrap_or_else(|| " ".to_string());
1179 let collapse = named
1180 .iter()
1181 .find(|(n, _)| n == "collapse")
1182 .and_then(|(_, v)| v.as_vector()?.as_character_scalar());
1183
1184 let char_vecs: Vec<Vec<String>> = args
1186 .iter()
1187 .map(|arg| match arg {
1188 RValue::Vector(v) => v
1189 .to_characters()
1190 .into_iter()
1191 .map(|s| s.unwrap_or_else(|| "NA".to_string()))
1192 .collect(),
1193 RValue::Null => vec![],
1194 other => vec![format!("{}", other)],
1195 })
1196 .collect();
1197
1198 if char_vecs.is_empty() {
1199 return Ok(RValue::vec(Vector::Character(
1200 vec![Some(String::new())].into(),
1201 )));
1202 }
1203
1204 let max_len = char_vecs.iter().map(|v| v.len()).max().unwrap_or(0);
1206 if max_len == 0 {
1207 return Ok(RValue::vec(Vector::Character(vec![].into())));
1208 }
1209
1210 let result: Vec<Option<String>> = (0..max_len)
1211 .map(|i| {
1212 let parts: Vec<&str> = char_vecs
1213 .iter()
1214 .filter(|v| !v.is_empty())
1215 .map(|v| v[i % v.len()].as_str())
1216 .collect();
1217 Some(parts.join(&sep))
1218 })
1219 .collect();
1220
1221 match collapse {
1222 Some(col) => {
1223 let collapsed: String = result.iter().filter_map(|s| s.as_ref()).join(&col);
1224 Ok(RValue::vec(Vector::Character(vec![Some(collapsed)].into())))
1225 }
1226 None => Ok(RValue::vec(Vector::Character(result.into()))),
1227 }
1228}
1229
1230#[builtin]
1238fn builtin_paste0(args: &[RValue], named: &[(String, RValue)]) -> Result<RValue, RError> {
1239 let mut new_named = named.to_vec();
1240 if !new_named.iter().any(|(n, _)| n == "sep") {
1241 new_named.push((
1242 "sep".to_string(),
1243 RValue::vec(Vector::Character(vec![Some(String::new())].into())),
1244 ));
1245 }
1246 builtin_paste(args, &new_named)
1247}
1248
1249#[builtin(min_args = 1)]
1254fn builtin_length(args: &[RValue], _named: &[(String, RValue)]) -> Result<RValue, RError> {
1255 let len = args.first().map(|v| v.length()).unwrap_or(0);
1256 Ok(RValue::vec(Vector::Integer(
1257 vec![Some(i64::try_from(len)?)].into(),
1258 )))
1259}
1260
1261#[builtin(min_args = 1)]
1267fn builtin_nchar(args: &[RValue], named: &[(String, RValue)]) -> Result<RValue, RError> {
1268 use unicode_segmentation::UnicodeSegmentation;
1269
1270 let nchar_type = named
1272 .iter()
1273 .find(|(k, _)| k == "type")
1274 .and_then(|(_, v)| match v {
1275 RValue::Vector(rv) => rv.inner.as_character_scalar(),
1276 _ => None,
1277 })
1278 .unwrap_or_else(|| "chars".to_string());
1279
1280 match args.first() {
1281 Some(RValue::Vector(rv)) if matches!(rv.inner, Vector::Character(_)) => {
1282 let Vector::Character(vals) = &rv.inner else {
1283 unreachable!()
1284 };
1285 let result: Vec<Option<i64>> = vals
1286 .iter()
1287 .map(|s| {
1288 s.as_ref().map(|s| {
1289 let n = match nchar_type.as_str() {
1290 "bytes" => s.len(),
1291 "width" => UnicodeWidthStr::width(s.as_str()),
1292 "graphemes" => s.graphemes(true).count(),
1293 #[cfg(feature = "bytecount")]
1294 _ => bytecount::num_chars(s.as_bytes()), #[cfg(not(feature = "bytecount"))]
1296 _ => s.chars().count(), };
1298 i64::try_from(n).unwrap_or(0)
1299 })
1300 })
1301 .collect();
1302 Ok(RValue::vec(Vector::Integer(result.into())))
1303 }
1304 _ => Ok(RValue::vec(Vector::Integer(vec![None].into()))),
1305 }
1306}
1307
1308#[builtin(min_args = 1)]
1313fn builtin_names(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
1314 match args.first() {
1315 Some(RValue::Vector(rv)) => match rv.get_attr("names") {
1316 Some(v) => Ok(v.clone()),
1317 None => Ok(RValue::Null),
1318 },
1319 Some(RValue::List(l)) => Ok(list_names_value(l)),
1320 _ => Ok(RValue::Null),
1321 }
1322}
1323
1324#[builtin(name = "names<-", min_args = 2)]
1330fn builtin_names_set(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
1331 let names_val = args.get(1).cloned().unwrap_or(RValue::Null);
1332 match args.first() {
1333 Some(RValue::Vector(rv)) => {
1334 let mut rv = rv.clone();
1335 if names_val.is_null() {
1336 rv.attrs.as_mut().map(|a| a.shift_remove("names"));
1337 } else {
1338 rv.set_attr("names".to_string(), names_val);
1339 }
1340 Ok(RValue::Vector(rv))
1341 }
1342 Some(RValue::List(l)) => {
1343 let mut l = l.clone();
1344 set_list_names(&mut l, &names_val);
1345 Ok(RValue::List(l))
1346 }
1347 other => Ok(other.cloned().unwrap_or(RValue::Null)),
1348 }
1349}
1350
1351fn character_name_vector(values: Vec<Option<String>>) -> RValue {
1352 RValue::vec(Vector::Character(values.into()))
1353}
1354
1355fn coerce_name_strings(value: &RValue) -> RValue {
1356 match value {
1357 RValue::Vector(rv) => match &rv.inner {
1358 Vector::Character(_) => value.clone(),
1359 Vector::Integer(values) => RValue::vec(Vector::Character(
1360 values
1361 .iter_opt()
1362 .map(|value| value.map(|value| value.to_string()))
1363 .collect::<Vec<_>>()
1364 .into(),
1365 )),
1366 Vector::Double(values) => RValue::vec(Vector::Character(
1367 values
1368 .iter_opt()
1369 .map(|value| value.map(format_r_double))
1370 .collect::<Vec<_>>()
1371 .into(),
1372 )),
1373 _ => RValue::Null,
1374 },
1375 _ => RValue::Null,
1376 }
1377}
1378
1379fn coerce_name_values(value: &RValue) -> Option<Vec<Option<String>>> {
1380 let coerced = coerce_name_strings(value);
1381 coerced.as_vector().map(|values| values.to_characters())
1382}
1383
1384fn list_names_value(list: &RList) -> RValue {
1385 if let Some(names_attr) = list.get_attr("names") {
1386 return coerce_name_strings(names_attr);
1387 }
1388
1389 let names: Vec<Option<String>> = list.values.iter().map(|(name, _)| name.clone()).collect();
1390 if names.iter().all(|name| name.is_none()) {
1391 RValue::Null
1392 } else {
1393 character_name_vector(names)
1394 }
1395}
1396
1397fn set_list_names(list: &mut RList, names_val: &RValue) {
1398 if let Some(mut names) = coerce_name_values(names_val) {
1399 names.resize(list.values.len(), None);
1400 for (entry, name) in list.values.iter_mut().zip(names.iter()) {
1401 entry.0 = name.clone();
1402 }
1403 list.set_attr("names".to_string(), character_name_vector(names));
1404 return;
1405 }
1406
1407 if names_val.is_null() {
1408 for entry in &mut list.values {
1409 entry.0 = None;
1410 }
1411 list.attrs.as_mut().map(|attrs| attrs.shift_remove("names"));
1412 }
1413}
1414
1415fn data_frame_row_count(list: &RList) -> usize {
1416 list.get_attr("row.names")
1417 .map(RValue::length)
1418 .unwrap_or_else(|| {
1419 list.values
1420 .iter()
1421 .map(|(_, value)| value.length())
1422 .max()
1423 .unwrap_or(0)
1424 })
1425}
1426
1427fn automatic_row_names_value(count: usize) -> Result<RValue, RError> {
1428 Ok(RValue::vec(Vector::Integer(
1429 (1..=i64::try_from(count)?)
1430 .map(Some)
1431 .collect::<Vec<_>>()
1432 .into(),
1433 )))
1434}
1435
1436fn data_frame_dimnames_value(list: &RList) -> Result<RValue, RError> {
1437 let row_names = list
1438 .get_attr("row.names")
1439 .map(coerce_name_strings)
1440 .unwrap_or(automatic_row_names_value(data_frame_row_count(list))?);
1441 let col_names = list_names_value(list);
1442 Ok(RValue::List(RList::new(vec![
1443 (None, row_names),
1444 (None, col_names),
1445 ])))
1446}
1447
1448fn set_data_frame_row_names(list: &mut RList, row_names: &RValue) -> Result<(), RError> {
1449 if row_names.is_null() {
1450 list.set_attr(
1451 "row.names".to_string(),
1452 automatic_row_names_value(data_frame_row_count(list))?,
1453 );
1454 return Ok(());
1455 }
1456
1457 let Some(names) = coerce_name_values(row_names) else {
1458 return Err(RError::other(
1459 "row names supplied are of the wrong length".to_string(),
1460 ));
1461 };
1462 if names.len() != data_frame_row_count(list) {
1463 return Err(RError::other(
1464 "row names supplied are of the wrong length".to_string(),
1465 ));
1466 }
1467 list.set_attr("row.names".to_string(), character_name_vector(names));
1468 Ok(())
1469}
1470
1471fn set_data_frame_col_names(list: &mut RList, col_names: &RValue) -> Result<(), RError> {
1472 if col_names.is_null() {
1473 set_list_names(list, col_names);
1474 return Ok(());
1475 }
1476
1477 let Some(names) = coerce_name_values(col_names) else {
1478 return Err(RError::other(
1479 "'names' attribute [1] must be the same length as the vector [0]".to_string(),
1480 ));
1481 };
1482 if names.len() != list.values.len() {
1483 return Err(RError::other(format!(
1484 "'names' attribute [{}] must be the same length as the vector [{}]",
1485 names.len(),
1486 list.values.len()
1487 )));
1488 }
1489 set_list_names(list, &character_name_vector(names));
1490 Ok(())
1491}
1492
1493fn set_data_frame_dimnames(list: &mut RList, dimnames: &RValue) -> Result<(), RError> {
1494 let RValue::List(values) = dimnames else {
1495 return Err(RError::other(
1496 "invalid 'dimnames' given for data frame".to_string(),
1497 ));
1498 };
1499 if values.values.len() != 2 {
1500 return Err(RError::other(
1501 "invalid 'dimnames' given for data frame".to_string(),
1502 ));
1503 }
1504
1505 let row_names = &values.values[0].1;
1506 let col_names = &values.values[1].1;
1507
1508 let Some(row_values) = coerce_name_values(row_names) else {
1509 return Err(RError::other(
1510 "invalid 'dimnames' given for data frame".to_string(),
1511 ));
1512 };
1513 let Some(col_values) = coerce_name_values(col_names) else {
1514 return Err(RError::other(
1515 "invalid 'dimnames' given for data frame".to_string(),
1516 ));
1517 };
1518
1519 if row_values.len() != data_frame_row_count(list) || col_values.len() != list.values.len() {
1520 return Err(RError::other(
1521 "invalid 'dimnames' given for data frame".to_string(),
1522 ));
1523 }
1524
1525 list.set_attr("row.names".to_string(), character_name_vector(row_values));
1526 set_list_names(list, &character_name_vector(col_values));
1527 list.attrs
1528 .as_mut()
1529 .map(|attrs| attrs.shift_remove("dimnames"));
1530 Ok(())
1531}
1532
1533fn updated_dimnames_component(current: Option<&RValue>, index: usize, value: &RValue) -> RValue {
1534 let mut components = match current {
1535 Some(RValue::List(list)) => {
1536 let mut components: Vec<RValue> =
1537 list.values.iter().map(|(_, value)| value.clone()).collect();
1538 components.resize(2, RValue::Null);
1539 components
1540 }
1541 _ => vec![RValue::Null, RValue::Null],
1542 };
1543
1544 if index < components.len() {
1545 components[index] = value.clone();
1546 }
1547
1548 if components.iter().all(RValue::is_null) {
1549 RValue::Null
1550 } else {
1551 RValue::List(RList::new(
1552 components.into_iter().map(|value| (None, value)).collect(),
1553 ))
1554 }
1555}
1556
1557struct BindInput {
1558 data: Vec<Option<f64>>,
1559 nrow: usize,
1560 ncol: usize,
1561 row_names: Option<Vec<Option<String>>>,
1562 col_names: Option<Vec<Option<String>>>,
1563}
1564
1565fn dimnames_component(dimnames: Option<&RValue>, index: usize) -> Option<Vec<Option<String>>> {
1566 let Some(RValue::List(list)) = dimnames else {
1567 return None;
1568 };
1569 list.values
1570 .get(index)
1571 .and_then(|(_, value)| coerce_name_values(value))
1572}
1573
1574fn bind_dimnames_value(
1575 row_names: Vec<Option<String>>,
1576 col_names: Vec<Option<String>>,
1577) -> Option<RValue> {
1578 let has_row_names = row_names.iter().any(|name| name.is_some());
1579 let has_col_names = col_names.iter().any(|name| name.is_some());
1580 if !has_row_names && !has_col_names {
1581 return None;
1582 }
1583
1584 Some(RValue::List(RList::new(vec![
1585 (None, character_name_vector(row_names)),
1586 (None, character_name_vector(col_names)),
1587 ])))
1588}
1589
1590#[builtin(name = "row.names", names = ["rownames"], min_args = 1)]
1595fn builtin_row_names(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
1596 match args.first() {
1597 Some(RValue::List(list)) => Ok(list
1598 .get_attr("row.names")
1599 .map(coerce_name_strings)
1600 .unwrap_or(RValue::Null)),
1601 Some(RValue::Vector(rv)) => {
1602 if let Some(RValue::List(dimnames)) = rv.get_attr("dimnames") {
1603 if let Some((_, row_names)) = dimnames.values.first() {
1604 return Ok(coerce_name_strings(row_names));
1605 }
1606 }
1607 Ok(RValue::Null)
1608 }
1609 _ => Ok(RValue::Null),
1610 }
1611}
1612
1613#[builtin(name = "colnames", min_args = 1)]
1618fn builtin_col_names(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
1619 match args.first() {
1620 Some(value @ RValue::List(list)) => {
1621 if has_class(value, "data.frame") {
1622 return Ok(list_names_value(list));
1623 }
1624 if let Some(RValue::List(dimnames)) = list.get_attr("dimnames") {
1625 if let Some((_, col_names)) = dimnames.values.get(1) {
1626 return Ok(coerce_name_strings(col_names));
1627 }
1628 }
1629 Ok(RValue::Null)
1630 }
1631 Some(RValue::Vector(rv)) => {
1632 if let Some(RValue::List(dimnames)) = rv.get_attr("dimnames") {
1633 if let Some((_, col_names)) = dimnames.values.get(1) {
1634 return Ok(coerce_name_strings(col_names));
1635 }
1636 }
1637 Ok(RValue::Null)
1638 }
1639 _ => Ok(RValue::Null),
1640 }
1641}
1642
1643#[builtin(name = "rownames<-", names = ["row.names<-"], min_args = 2)]
1649fn builtin_row_names_set(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
1650 let row_names = args.get(1).cloned().unwrap_or(RValue::Null);
1651 match args.first() {
1652 Some(value @ RValue::List(list)) if has_class(value, "data.frame") => {
1653 let mut list = list.clone();
1654 set_data_frame_row_names(&mut list, &row_names)?;
1655 Ok(RValue::List(list))
1656 }
1657 Some(RValue::Vector(rv)) => {
1658 let mut rv = rv.clone();
1659 let dimnames = updated_dimnames_component(rv.get_attr("dimnames"), 0, &row_names);
1660 if dimnames.is_null() {
1661 rv.attrs
1662 .as_mut()
1663 .map(|attrs| attrs.shift_remove("dimnames"));
1664 } else {
1665 rv.set_attr("dimnames".to_string(), dimnames);
1666 }
1667 Ok(RValue::Vector(rv))
1668 }
1669 Some(RValue::List(list)) => {
1670 let mut list = list.clone();
1671 let dimnames = updated_dimnames_component(list.get_attr("dimnames"), 0, &row_names);
1672 if dimnames.is_null() {
1673 list.attrs
1674 .as_mut()
1675 .map(|attrs| attrs.shift_remove("dimnames"));
1676 } else {
1677 list.set_attr("dimnames".to_string(), dimnames);
1678 }
1679 Ok(RValue::List(list))
1680 }
1681 other => Ok(other.cloned().unwrap_or(RValue::Null)),
1682 }
1683}
1684
1685#[builtin(name = "colnames<-", min_args = 2)]
1691fn builtin_col_names_set(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
1692 let col_names = args.get(1).cloned().unwrap_or(RValue::Null);
1693 match args.first() {
1694 Some(value @ RValue::List(list)) if has_class(value, "data.frame") => {
1695 let mut list = list.clone();
1696 set_data_frame_col_names(&mut list, &col_names)?;
1697 Ok(RValue::List(list))
1698 }
1699 Some(RValue::Vector(rv)) => {
1700 let mut rv = rv.clone();
1701 let dimnames = updated_dimnames_component(rv.get_attr("dimnames"), 1, &col_names);
1702 if dimnames.is_null() {
1703 rv.attrs
1704 .as_mut()
1705 .map(|attrs| attrs.shift_remove("dimnames"));
1706 } else {
1707 rv.set_attr("dimnames".to_string(), dimnames);
1708 }
1709 Ok(RValue::Vector(rv))
1710 }
1711 Some(RValue::List(list)) => {
1712 let mut list = list.clone();
1713 let dimnames = updated_dimnames_component(list.get_attr("dimnames"), 1, &col_names);
1714 if dimnames.is_null() {
1715 list.attrs
1716 .as_mut()
1717 .map(|attrs| attrs.shift_remove("dimnames"));
1718 } else {
1719 list.set_attr("dimnames".to_string(), dimnames);
1720 }
1721 Ok(RValue::List(list))
1722 }
1723 other => Ok(other.cloned().unwrap_or(RValue::Null)),
1724 }
1725}
1726
1727#[builtin(name = "class<-", min_args = 2)]
1733fn builtin_class_set(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
1734 let class_val = args.get(1).cloned().unwrap_or(RValue::Null);
1735 match args.first() {
1736 Some(RValue::Vector(rv)) => {
1737 let mut rv = rv.clone();
1738 if class_val.is_null() {
1739 rv.attrs.as_mut().map(|a| a.shift_remove("class"));
1740 } else {
1741 rv.set_attr("class".to_string(), class_val);
1742 }
1743 Ok(RValue::Vector(rv))
1744 }
1745 Some(RValue::List(l)) => {
1746 let mut l = l.clone();
1747 if class_val.is_null() {
1748 l.attrs.as_mut().map(|a| a.shift_remove("class"));
1749 } else {
1750 l.set_attr("class".to_string(), class_val);
1751 }
1752 Ok(RValue::List(l))
1753 }
1754 Some(RValue::Language(lang)) => {
1755 let mut lang = lang.clone();
1756 if class_val.is_null() {
1757 lang.attrs.as_mut().map(|a| a.shift_remove("class"));
1758 } else {
1759 lang.set_attr("class".to_string(), class_val);
1760 }
1761 Ok(RValue::Language(lang))
1762 }
1763 other => Ok(other.cloned().unwrap_or(RValue::Null)),
1764 }
1765}
1766
1767#[builtin(name = "oldClass<-", min_args = 2)]
1773fn builtin_old_class_set(args: &[RValue], named: &[(String, RValue)]) -> Result<RValue, RError> {
1774 builtin_class_set(args, named)
1775}
1776
1777#[builtin(min_args = 1)]
1785fn builtin_typeof(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
1786 let t = args.first().map(|v| v.type_name()).unwrap_or("NULL");
1787 Ok(RValue::vec(Vector::Character(
1788 vec![Some(t.to_string())].into(),
1789 )))
1790}
1791
1792#[builtin(min_args = 1)]
1800fn builtin_class(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
1801 if let Some(RValue::Vector(rv)) = args.first() {
1803 if let Some(cls) = rv.get_attr("class") {
1804 return Ok(cls.clone());
1805 }
1806 }
1807 if let Some(RValue::List(l)) = args.first() {
1809 if let Some(cls) = l.get_attr("class") {
1810 return Ok(cls.clone());
1811 }
1812 }
1813 if let Some(RValue::Language(lang)) = args.first() {
1814 if let Some(cls) = lang.get_attr("class") {
1815 return Ok(cls.clone());
1816 }
1817 }
1818 let c = match args.first() {
1819 Some(RValue::Vector(rv)) => match &rv.inner {
1820 Vector::Raw(_) => "raw",
1821 Vector::Logical(_) => "logical",
1822 Vector::Integer(_) => "integer",
1823 Vector::Double(_) => "numeric",
1824 Vector::Complex(_) => "complex",
1825 Vector::Character(_) => "character",
1826 },
1827 Some(RValue::List(_)) => "list",
1828 Some(RValue::Function(_)) => "function",
1829 Some(RValue::Language(lang)) => match &**lang {
1830 Expr::Symbol(_) => "name",
1831 _ => "call",
1832 },
1833 Some(RValue::Null) => "NULL",
1834 _ => "NULL",
1835 };
1836 Ok(RValue::vec(Vector::Character(
1837 vec![Some(c.to_string())].into(),
1838 )))
1839}
1840
1841#[builtin(min_args = 1)]
1848fn builtin_mode(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
1849 let m = match args.first() {
1850 Some(RValue::Vector(rv)) => match &rv.inner {
1851 Vector::Raw(_) => "raw",
1852 Vector::Logical(_) => "logical",
1853 Vector::Integer(_) | Vector::Double(_) => "numeric",
1854 Vector::Complex(_) => "complex",
1855 Vector::Character(_) => "character",
1856 },
1857 Some(RValue::List(_)) => "list",
1858 Some(RValue::Function(_)) => "function",
1859 Some(RValue::Language(lang)) => match &**lang {
1860 Expr::Symbol(_) => "name",
1861 _ => "call",
1862 },
1863 Some(RValue::Null) => "NULL",
1864 _ => "NULL",
1865 };
1866 Ok(RValue::vec(Vector::Character(
1867 vec![Some(m.to_string())].into(),
1868 )))
1869}
1870
1871#[interpreter_builtin(min_args = 1)]
1880fn interp_str(
1881 args: &[RValue],
1882 _named: &[(String, RValue)],
1883 context: &BuiltinContext,
1884) -> Result<RValue, RError> {
1885 match args.first() {
1886 Some(val) => {
1887 #[cfg(feature = "tables")]
1889 if let Some(output) = tables_display::str_data_frame(val) {
1890 context.write(&output);
1891 return Ok(RValue::Null);
1892 }
1893
1894 match val {
1895 RValue::Vector(v) => {
1896 let len = v.len();
1897 let type_name = v.type_name();
1898 let preview: String = match &v.inner {
1899 Vector::Raw(vals) => {
1900 vals.iter().take(10).map(|b| format!("{:02x}", b)).join(" ")
1901 }
1902 Vector::Double(vals) => vals
1903 .iter()
1904 .take(10)
1905 .map(|x| match x {
1906 Some(f) => format_r_double(f),
1907 None => "NA".to_string(),
1908 })
1909 .join(" "),
1910 Vector::Integer(vals) => vals
1911 .iter()
1912 .take(10)
1913 .map(|x| match x {
1914 Some(i) => i.to_string(),
1915 None => "NA".to_string(),
1916 })
1917 .join(" "),
1918 Vector::Logical(vals) => vals
1919 .iter()
1920 .take(10)
1921 .map(|x| match x {
1922 Some(true) => "TRUE".to_string(),
1923 Some(false) => "FALSE".to_string(),
1924 None => "NA".to_string(),
1925 })
1926 .join(" "),
1927 Vector::Complex(vals) => vals
1928 .iter()
1929 .take(10)
1930 .map(|x| match x {
1931 Some(c) => format_r_complex(*c),
1932 None => "NA".to_string(),
1933 })
1934 .join(" "),
1935 Vector::Character(vals) => vals
1936 .iter()
1937 .take(10)
1938 .map(|x| match x {
1939 Some(s) => format!("\"{}\"", s),
1940 None => "NA".to_string(),
1941 })
1942 .join(" "),
1943 };
1944 context.write(&format!(" {} [1:{}] {}\n", type_name, len, preview));
1945 }
1946 RValue::List(l) => {
1947 context.write(&format!("List of {}\n", l.values.len()));
1948 for (i, (name, elem)) in l.values.iter().enumerate() {
1949 let label = name.clone().unwrap_or_else(|| format!("[[{}]]", i + 1));
1950 let child = str_format_element(elem, 1);
1951 context.write(&format!(" $ {:<13}:{}\n", label, child));
1952 }
1953 }
1954 RValue::Null => context.write(" NULL\n"),
1955 _ => context.write(&format!(" {}\n", val)),
1956 }
1957 Ok(RValue::Null)
1958 }
1959 None => Ok(RValue::Null),
1960 }
1961}
1962
1963fn str_format_element(val: &RValue, indent: usize) -> String {
1967 let prefix = " ".repeat(indent);
1968 match val {
1969 RValue::Null => format!("{prefix} NULL"),
1970 RValue::Vector(v) => {
1971 let len = v.len();
1972 let type_name = v.type_name();
1973 let preview = str_vector_preview(v);
1974 if len == 1 {
1975 format!("{prefix} {type_name} {preview}")
1976 } else {
1977 let dots = if len > 10 { " ..." } else { "" };
1978 format!("{prefix} {type_name} [1:{len}] {preview}{dots}")
1979 }
1980 }
1981 RValue::List(l) => {
1982 let mut out = format!("{prefix}List of {}", l.values.len());
1983 for (i, (name, elem)) in l.values.iter().enumerate() {
1984 let label = name.clone().unwrap_or_else(|| format!("[[{}]]", i + 1));
1985 let child = str_format_element(elem, indent + 1);
1986 out.push_str(&format!("\n{prefix} $ {label:<13}:{child}"));
1987 }
1988 out
1989 }
1990 RValue::Function(_) => format!("{prefix}function (...)"),
1991 RValue::Environment(_) => format!("{prefix}<environment>"),
1992 RValue::Language(_) => format!("{prefix} language ..."),
1993 RValue::Promise(p) => {
1994 let inner = p.borrow();
1995 if let Some(ref val) = inner.value {
1996 str_format_element(val, indent)
1997 } else {
1998 format!("{prefix} promise ...")
1999 }
2000 }
2001 }
2002}
2003
2004fn str_vector_preview(v: &RVector) -> String {
2006 let len = v.inner.len().min(10);
2007 let elems: Vec<String> = (0..len)
2008 .map(|i| match &v.inner {
2009 Vector::Raw(vals) => format!("{:02x}", vals[i]),
2010 Vector::Logical(vals) => match vals[i] {
2011 Some(true) => "TRUE".to_string(),
2012 Some(false) => "FALSE".to_string(),
2013 None => "NA".to_string(),
2014 },
2015 Vector::Integer(vals) => match vals.get_opt(i) {
2016 Some(n) => n.to_string(),
2017 None => "NA".to_string(),
2018 },
2019 Vector::Double(vals) => match vals.get_opt(i) {
2020 Some(f) => format_r_double(f),
2021 None => "NA".to_string(),
2022 },
2023 Vector::Complex(vals) => match vals[i] {
2024 Some(c) => format_r_complex(c),
2025 None => "NA".to_string(),
2026 },
2027 Vector::Character(vals) => match &vals[i] {
2028 Some(s) => format!("\"{}\"", s),
2029 None => "NA".to_string(),
2030 },
2031 })
2032 .collect();
2033 elems.join(" ")
2034}
2035
2036#[builtin(min_args = 2)]
2046fn builtin_identical(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
2047 if args.len() < 2 {
2048 return Err(RError::new(
2049 RErrorKind::Argument,
2050 "need 2 arguments".to_string(),
2051 ));
2052 }
2053 let result = r_identical(&args[0], &args[1]);
2054 Ok(RValue::vec(Vector::Logical(vec![Some(result)].into())))
2055}
2056
2057fn r_identical(a: &RValue, b: &RValue) -> bool {
2062 match (a, b) {
2063 (RValue::Null, RValue::Null) => true,
2064 (RValue::Vector(va), RValue::Vector(vb)) => {
2065 vectors_identical(&va.inner, &vb.inner) && attrs_identical(&va.attrs, &vb.attrs)
2066 }
2067 (RValue::List(la), RValue::List(lb)) => {
2068 if la.values.len() != lb.values.len() {
2069 return false;
2070 }
2071 for ((na, va), (nb, vb)) in la.values.iter().zip(lb.values.iter()) {
2072 if na != nb {
2073 return false;
2074 }
2075 if !r_identical(va, vb) {
2076 return false;
2077 }
2078 }
2079 attrs_identical(&la.attrs, &lb.attrs)
2080 }
2081 (RValue::Function(fa), RValue::Function(fb)) => match (fa, fb) {
2082 (RFunction::Builtin { name: na, .. }, RFunction::Builtin { name: nb, .. }) => na == nb,
2083 (
2084 RFunction::Closure {
2085 params: pa,
2086 body: ba,
2087 ..
2088 },
2089 RFunction::Closure {
2090 params: pb,
2091 body: bb,
2092 ..
2093 },
2094 ) => pa == pb && ba == bb,
2095 _ => false,
2096 },
2097 (RValue::Environment(ea), RValue::Environment(eb)) => {
2098 ea.ptr_eq(eb)
2100 }
2101 (RValue::Language(la), RValue::Language(lb)) => {
2102 *la.inner == *lb.inner && attrs_identical(&la.attrs, &lb.attrs)
2103 }
2104 _ => false,
2105 }
2106}
2107
2108fn attrs_identical(a: &Option<Box<Attributes>>, b: &Option<Box<Attributes>>) -> bool {
2110 match (a, b) {
2111 (None, None) => true,
2112 (Some(aa), Some(bb)) => {
2113 if aa.len() != bb.len() {
2114 return false;
2115 }
2116 for (key, val_a) in aa.iter() {
2117 match bb.get(key) {
2118 Some(val_b) => {
2119 if !r_identical(val_a, val_b) {
2120 return false;
2121 }
2122 }
2123 None => return false,
2124 }
2125 }
2126 true
2127 }
2128 _ => false,
2129 }
2130}
2131
2132fn vectors_identical(a: &Vector, b: &Vector) -> bool {
2137 match (a, b) {
2138 (Vector::Logical(va), Vector::Logical(vb)) => va.0 == vb.0,
2139 (Vector::Integer(va), Vector::Integer(vb)) => va.0 == vb.0,
2140 (Vector::Character(va), Vector::Character(vb)) => va.0 == vb.0,
2141 (Vector::Raw(va), Vector::Raw(vb)) => va == vb,
2142 (Vector::Double(va), Vector::Double(vb)) => {
2143 if va.len() != vb.len() {
2144 return false;
2145 }
2146 va.iter().zip(vb.iter()).all(|(x, y)| match (x, y) {
2147 (None, None) => true,
2148 (Some(fx), Some(fy)) => fx.to_bits() == fy.to_bits(),
2149 _ => false,
2150 })
2151 }
2152 (Vector::Complex(va), Vector::Complex(vb)) => {
2153 if va.len() != vb.len() {
2154 return false;
2155 }
2156 va.iter().zip(vb.iter()).all(|(x, y)| match (x, y) {
2157 (None, None) => true,
2158 (Some(cx), Some(cy)) => {
2159 cx.re.to_bits() == cy.re.to_bits() && cx.im.to_bits() == cy.im.to_bits()
2160 }
2161 _ => false,
2162 })
2163 }
2164 _ => false, }
2166}
2167
2168#[builtin(min_args = 2)]
2182fn builtin_all_equal(args: &[RValue], named: &[(String, RValue)]) -> Result<RValue, RError> {
2183 let tolerance = named
2184 .iter()
2185 .find(|(n, _)| n == "tolerance")
2186 .and_then(|(_, v)| v.as_vector()?.as_double_scalar())
2187 .unwrap_or(1.5e-8);
2188
2189 let check_attributes = named
2190 .iter()
2191 .find(|(n, _)| n == "check.attributes")
2192 .and_then(|(_, v)| v.as_vector()?.as_logical_scalar())
2193 .unwrap_or(true);
2194
2195 let check_names = named
2196 .iter()
2197 .find(|(n, _)| n == "check.names")
2198 .and_then(|(_, v)| v.as_vector()?.as_logical_scalar())
2199 .unwrap_or(true);
2200
2201 if args.len() < 2 {
2202 return Err(RError::new(
2203 RErrorKind::Argument,
2204 "need 2 arguments".to_string(),
2205 ));
2206 }
2207
2208 let mut diffs = Vec::new();
2209 all_equal_recurse(
2210 &args[0],
2211 &args[1],
2212 tolerance,
2213 check_attributes,
2214 check_names,
2215 "",
2216 &mut diffs,
2217 );
2218
2219 if diffs.is_empty() {
2220 Ok(RValue::vec(Vector::Logical(vec![Some(true)].into())))
2221 } else {
2222 let msgs: Vec<Option<String>> = diffs.into_iter().map(Some).collect();
2223 Ok(RValue::vec(Vector::Character(msgs.into())))
2224 }
2225}
2226
2227fn all_equal_recurse(
2229 target: &RValue,
2230 current: &RValue,
2231 tolerance: f64,
2232 check_attributes: bool,
2233 check_names: bool,
2234 prefix: &str,
2235 diffs: &mut Vec<String>,
2236) {
2237 match (target, current) {
2238 (RValue::Null, RValue::Null) => {}
2240
2241 (RValue::Null, _) | (_, RValue::Null) => {
2243 diffs.push(format!(
2244 "{}target is {}, current is {}",
2245 prefix,
2246 target.type_name(),
2247 current.type_name()
2248 ));
2249 }
2250
2251 (RValue::Vector(v1), RValue::Vector(v2)) => {
2253 all_equal_vectors(
2254 v1,
2255 v2,
2256 tolerance,
2257 check_attributes,
2258 check_names,
2259 prefix,
2260 diffs,
2261 );
2262 }
2263
2264 (RValue::List(l1), RValue::List(l2)) => {
2266 all_equal_lists(
2267 l1,
2268 l2,
2269 tolerance,
2270 check_attributes,
2271 check_names,
2272 prefix,
2273 diffs,
2274 );
2275 }
2276
2277 _ => {
2279 diffs.push(format!(
2280 "{}target is {}, current is {}",
2281 prefix,
2282 target.type_name(),
2283 current.type_name()
2284 ));
2285 }
2286 }
2287}
2288
2289fn all_equal_vectors(
2291 v1: &RVector,
2292 v2: &RVector,
2293 tolerance: f64,
2294 check_attributes: bool,
2295 check_names: bool,
2296 prefix: &str,
2297 diffs: &mut Vec<String>,
2298) {
2299 let t1 = v1.inner.type_name();
2300 let t2 = v2.inner.type_name();
2301
2302 let is_numeric = |t: &str| matches!(t, "double" | "integer" | "logical");
2304
2305 if t1 == "character" && t2 == "character" {
2306 all_equal_character(v1, v2, prefix, diffs);
2307 } else if is_numeric(t1) && is_numeric(t2) {
2308 all_equal_numeric(v1, v2, tolerance, prefix, diffs);
2309 } else if t1 != t2 {
2310 diffs.push(format!("{}target is {}, current is {}", prefix, t1, t2));
2311 return;
2312 } else {
2313 all_equal_numeric(v1, v2, tolerance, prefix, diffs);
2315 }
2316
2317 if check_attributes {
2319 all_equal_attrs(
2320 v1.attrs.as_deref(),
2321 v2.attrs.as_deref(),
2322 check_names,
2323 prefix,
2324 diffs,
2325 );
2326 } else if check_names {
2327 all_equal_names_attr(v1.attrs.as_deref(), v2.attrs.as_deref(), prefix, diffs);
2329 }
2330}
2331
2332fn all_equal_numeric(
2334 v1: &RVector,
2335 v2: &RVector,
2336 tolerance: f64,
2337 prefix: &str,
2338 diffs: &mut Vec<String>,
2339) {
2340 let d1 = v1.to_doubles();
2341 let d2 = v2.to_doubles();
2342
2343 if d1.len() != d2.len() {
2344 diffs.push(format!(
2345 "{}Lengths ({}, {}) differ",
2346 prefix,
2347 d1.len(),
2348 d2.len()
2349 ));
2350 return;
2351 }
2352
2353 if d1.is_empty() {
2354 return;
2355 }
2356
2357 let mut sum_abs_diff = 0.0;
2359 let mut sum_abs_target = 0.0;
2360 let mut count = 0usize;
2361
2362 for (a, b) in d1.iter().zip(d2.iter()) {
2363 match (a, b) {
2364 (Some(a), Some(b)) => {
2365 sum_abs_diff += (a - b).abs();
2366 sum_abs_target += a.abs();
2367 count += 1;
2368 }
2369 (None, None) => {} _ => {
2371 count += 1;
2373 sum_abs_diff += f64::INFINITY;
2374 }
2375 }
2376 }
2377
2378 if count == 0 {
2379 return;
2380 }
2381
2382 let mean_abs_diff = sum_abs_diff / count as f64;
2383 let mean_abs_target = sum_abs_target / count as f64;
2384
2385 if mean_abs_target.is_finite() && mean_abs_target > tolerance {
2388 let relative_diff = mean_abs_diff / mean_abs_target;
2389 if relative_diff > tolerance {
2390 diffs.push(format!(
2391 "{}Mean relative difference: {}",
2392 prefix, relative_diff
2393 ));
2394 }
2395 } else if mean_abs_diff > tolerance {
2396 diffs.push(format!(
2397 "{}Mean absolute difference: {}",
2398 prefix, mean_abs_diff
2399 ));
2400 }
2401}
2402
2403fn all_equal_character(v1: &RVector, v2: &RVector, prefix: &str, diffs: &mut Vec<String>) {
2405 let c1 = v1.to_characters();
2406 let c2 = v2.to_characters();
2407
2408 if c1.len() != c2.len() {
2409 diffs.push(format!(
2410 "{}Lengths ({}, {}) differ",
2411 prefix,
2412 c1.len(),
2413 c2.len()
2414 ));
2415 return;
2416 }
2417
2418 let mut mismatches = 0usize;
2419 for (a, b) in c1.iter().zip(c2.iter()) {
2420 if a != b {
2421 mismatches += 1;
2422 }
2423 }
2424
2425 if mismatches > 0 {
2426 diffs.push(format!(
2427 "{}{} string mismatch{}",
2428 prefix,
2429 mismatches,
2430 if mismatches == 1 { "" } else { "es" }
2431 ));
2432 }
2433}
2434
2435fn all_equal_lists(
2437 l1: &RList,
2438 l2: &RList,
2439 tolerance: f64,
2440 check_attributes: bool,
2441 check_names: bool,
2442 prefix: &str,
2443 diffs: &mut Vec<String>,
2444) {
2445 if l1.values.len() != l2.values.len() {
2446 diffs.push(format!(
2447 "{}Lengths ({}, {}) differ",
2448 prefix,
2449 l1.values.len(),
2450 l2.values.len()
2451 ));
2452 return;
2453 }
2454
2455 if check_names {
2457 let names1: Vec<Option<&str>> = l1.values.iter().map(|(n, _)| n.as_deref()).collect();
2458 let names2: Vec<Option<&str>> = l2.values.iter().map(|(n, _)| n.as_deref()).collect();
2459 if names1 != names2 {
2460 diffs.push(format!("{}Component names differ", prefix));
2461 }
2462 }
2463
2464 for (i, ((_, v1), (name, v2))) in l1.values.iter().zip(l2.values.iter()).enumerate() {
2466 let elem_prefix = match name {
2467 Some(n) => format!("Component \"{}\": ", n),
2468 None => format!("Component {}: ", i + 1),
2469 };
2470 all_equal_recurse(
2471 v1,
2472 v2,
2473 tolerance,
2474 check_attributes,
2475 check_names,
2476 &elem_prefix,
2477 diffs,
2478 );
2479 }
2480
2481 if check_attributes {
2483 all_equal_attrs(
2484 l1.attrs.as_deref(),
2485 l2.attrs.as_deref(),
2486 check_names,
2487 prefix,
2488 diffs,
2489 );
2490 }
2491}
2492
2493fn all_equal_attrs(
2495 attrs1: Option<&Attributes>,
2496 attrs2: Option<&Attributes>,
2497 check_names: bool,
2498 prefix: &str,
2499 diffs: &mut Vec<String>,
2500) {
2501 let empty = indexmap::IndexMap::new();
2502 let a1 = attrs1.unwrap_or(&empty);
2503 let a2 = attrs2.unwrap_or(&empty);
2504
2505 let mut keys1: Vec<&str> = a1.keys().map(|s| s.as_str()).collect();
2506 let mut keys2: Vec<&str> = a2.keys().map(|s| s.as_str()).collect();
2507
2508 if !check_names {
2509 keys1.retain(|k| *k != "names");
2510 keys2.retain(|k| *k != "names");
2511 }
2512
2513 keys1.sort();
2514 keys2.sort();
2515
2516 if keys1 != keys2 {
2517 diffs.push(format!("{}Attributes differ", prefix));
2518 return;
2519 }
2520
2521 for key in &keys1 {
2522 if let (Some(v1), Some(v2)) = (a1.get(*key), a2.get(*key)) {
2523 let attr_prefix = format!("{}Attributes: <{}> - ", prefix, key);
2524 all_equal_recurse(v1, v2, 1.5e-8, true, true, &attr_prefix, diffs);
2525 }
2526 }
2527}
2528
2529fn all_equal_names_attr(
2531 attrs1: Option<&Attributes>,
2532 attrs2: Option<&Attributes>,
2533 prefix: &str,
2534 diffs: &mut Vec<String>,
2535) {
2536 let n1 = attrs1.and_then(|a| a.get("names"));
2537 let n2 = attrs2.and_then(|a| a.get("names"));
2538
2539 match (n1, n2) {
2540 (None, None) => {}
2541 (Some(_), None) | (None, Some(_)) => {
2542 diffs.push(format!("{}Names differ", prefix));
2543 }
2544 (Some(v1), Some(v2)) => {
2545 let attr_prefix = format!("{}Names: ", prefix);
2546 all_equal_recurse(v1, v2, 1.5e-8, false, false, &attr_prefix, diffs);
2547 }
2548 }
2549}
2550
2551#[builtin]
2557fn builtin_any(args: &[RValue], named: &[(String, RValue)]) -> Result<RValue, RError> {
2558 let na_rm = named
2559 .iter()
2560 .find(|(n, _)| n == "na.rm")
2561 .and_then(|(_, v)| v.as_vector()?.as_logical_scalar())
2562 .unwrap_or(false);
2563
2564 for arg in args {
2565 if let Some(v) = arg.as_vector() {
2566 for l in v.to_logicals() {
2567 match l {
2568 Some(true) => return Ok(RValue::vec(Vector::Logical(vec![Some(true)].into()))),
2569 None if !na_rm => return Ok(RValue::vec(Vector::Logical(vec![None].into()))),
2570 _ => {}
2571 }
2572 }
2573 }
2574 }
2575 Ok(RValue::vec(Vector::Logical(vec![Some(false)].into())))
2576}
2577
2578#[builtin]
2584fn builtin_all(args: &[RValue], named: &[(String, RValue)]) -> Result<RValue, RError> {
2585 let na_rm = named
2586 .iter()
2587 .find(|(n, _)| n == "na.rm")
2588 .and_then(|(_, v)| v.as_vector()?.as_logical_scalar())
2589 .unwrap_or(false);
2590
2591 for arg in args {
2592 if let Some(v) = arg.as_vector() {
2593 for l in v.to_logicals() {
2594 match l {
2595 Some(false) => {
2596 return Ok(RValue::vec(Vector::Logical(vec![Some(false)].into())))
2597 }
2598 None if !na_rm => return Ok(RValue::vec(Vector::Logical(vec![None].into()))),
2599 _ => {}
2600 }
2601 }
2602 }
2603 }
2604 Ok(RValue::vec(Vector::Logical(vec![Some(true)].into())))
2605}
2606
2607#[builtin(min_args = 2)]
2616fn builtin_xor(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
2617 if args.len() < 2 {
2618 return Err(RError::new(
2619 RErrorKind::Argument,
2620 "need 2 arguments".to_string(),
2621 ));
2622 }
2623 let a_vec = match &args[0] {
2624 RValue::Vector(v) => v.to_logicals(),
2625 _ => {
2626 return Err(RError::new(
2627 RErrorKind::Argument,
2628 "argument 'x' must be coercible to logical".to_string(),
2629 ))
2630 }
2631 };
2632 let b_vec = match &args[1] {
2633 RValue::Vector(v) => v.to_logicals(),
2634 _ => {
2635 return Err(RError::new(
2636 RErrorKind::Argument,
2637 "argument 'y' must be coercible to logical".to_string(),
2638 ))
2639 }
2640 };
2641 let len = a_vec.len().max(b_vec.len());
2642 let result: Vec<Option<bool>> = (0..len)
2643 .map(|i| {
2644 let a = a_vec[i % a_vec.len()];
2645 let b = b_vec[i % b_vec.len()];
2646 match (a, b) {
2647 (Some(a), Some(b)) => Some(a ^ b),
2648 _ => None,
2649 }
2650 })
2651 .collect();
2652 Ok(RValue::vec(Vector::Logical(result.into())))
2653}
2654
2655#[builtin]
2662fn builtin_list(args: &[RValue], named: &[(String, RValue)]) -> Result<RValue, RError> {
2663 let mut values: Vec<(Option<String>, RValue)> = Vec::new();
2664 for arg in args {
2665 values.push((None, arg.clone()));
2666 }
2667 for (name, val) in named {
2668 values.push((Some(name.clone()), val.clone()));
2669 }
2670 Ok(RValue::List(RList::new(values)))
2671}
2672
2673#[builtin(name = "expand.grid")]
2685fn builtin_expand_grid(args: &[RValue], named: &[(String, RValue)]) -> Result<RValue, RError> {
2686 let mut inputs: Vec<(String, Vec<RValue>)> = Vec::new();
2688 let mut unnamed_idx = 0usize;
2689
2690 for arg in args {
2695 unnamed_idx += 1;
2696 let name = format!("Var{unnamed_idx}");
2697 let items = vector_to_items(arg);
2698 if items.is_empty() {
2699 return Ok(empty_expand_grid());
2700 }
2701 inputs.push((name, items));
2702 }
2703 for (name, val) in named {
2704 if name == "stringsAsFactors" || name == "KEEP.OUT.ATTRS" {
2705 continue; }
2707 let items = vector_to_items(val);
2708 if items.is_empty() {
2709 return Ok(empty_expand_grid());
2710 }
2711 inputs.push((name.clone(), items));
2712 }
2713
2714 if inputs.is_empty() {
2715 return Ok(empty_expand_grid());
2716 }
2717
2718 let nrow: usize = inputs.iter().map(|(_, v)| v.len()).product();
2720
2721 let mut columns: Vec<(Option<String>, RValue)> = Vec::with_capacity(inputs.len());
2728 let mut repeat_each: usize = 1;
2729
2730 for (col_name, items) in &inputs {
2731 let len_k = items.len();
2732 let mut col_values: Vec<RValue> = Vec::with_capacity(nrow);
2733
2734 let cycle_len = len_k * repeat_each;
2737 let n_cycles = nrow / cycle_len;
2738
2739 for _ in 0..n_cycles {
2740 for item in items {
2741 for _ in 0..repeat_each {
2742 col_values.push(item.clone());
2743 }
2744 }
2745 }
2746
2747 let col_vec = combine_expand_grid_column(&col_values);
2749 columns.push((Some(col_name.clone()), col_vec));
2750
2751 repeat_each *= len_k;
2752 }
2753
2754 let col_names: Vec<Option<String>> = columns.iter().map(|(n, _)| n.clone()).collect();
2756 let mut result = RList::new(columns);
2757 result.set_attr(
2758 "class".to_string(),
2759 RValue::vec(Vector::Character(
2760 vec![Some("data.frame".to_string())].into(),
2761 )),
2762 );
2763 result.set_attr(
2764 "names".to_string(),
2765 RValue::vec(Vector::Character(col_names.into())),
2766 );
2767 let row_names: Vec<Option<i64>> = (1..=i64::try_from(nrow)?).map(Some).collect();
2768 result.set_attr(
2769 "row.names".to_string(),
2770 RValue::vec(Vector::Integer(row_names.into())),
2771 );
2772
2773 Ok(RValue::List(result))
2774}
2775
2776fn empty_expand_grid() -> RValue {
2778 let mut result = RList::new(Vec::new());
2779 result.set_attr(
2780 "class".to_string(),
2781 RValue::vec(Vector::Character(
2782 vec![Some("data.frame".to_string())].into(),
2783 )),
2784 );
2785 result.set_attr(
2786 "names".to_string(),
2787 RValue::vec(Vector::Character(Vec::<Option<String>>::new().into())),
2788 );
2789 result.set_attr(
2790 "row.names".to_string(),
2791 RValue::vec(Vector::Integer(Vec::<Option<i64>>::new().into())),
2792 );
2793 RValue::List(result)
2794}
2795
2796fn vector_to_items(x: &RValue) -> Vec<RValue> {
2798 match x {
2799 RValue::Vector(rv) => match &rv.inner {
2800 Vector::Double(vals) => vals
2801 .iter_opt()
2802 .map(|v| RValue::vec(Vector::Double(vec![v].into())))
2803 .collect(),
2804 Vector::Integer(vals) => vals
2805 .iter_opt()
2806 .map(|v| RValue::vec(Vector::Integer(vec![v].into())))
2807 .collect(),
2808 Vector::Logical(vals) => vals
2809 .iter()
2810 .map(|v| RValue::vec(Vector::Logical(vec![*v].into())))
2811 .collect(),
2812 Vector::Character(vals) => vals
2813 .iter()
2814 .map(|v| RValue::vec(Vector::Character(vec![v.clone()].into())))
2815 .collect(),
2816 Vector::Complex(vals) => vals
2817 .iter()
2818 .map(|v| RValue::vec(Vector::Complex(vec![*v].into())))
2819 .collect(),
2820 Vector::Raw(vals) => vals
2821 .iter()
2822 .map(|v| RValue::vec(Vector::Raw(vec![*v])))
2823 .collect(),
2824 },
2825 RValue::List(l) => l.values.iter().map(|(_, v)| v.clone()).collect(),
2826 RValue::Null => Vec::new(),
2827 other => vec![other.clone()],
2828 }
2829}
2830
2831fn combine_expand_grid_column(items: &[RValue]) -> RValue {
2833 if items.is_empty() {
2834 return RValue::Null;
2835 }
2836
2837 let first_type = items[0].type_name();
2839 let all_same = items.iter().all(|i| i.type_name() == first_type);
2840
2841 if all_same {
2842 match first_type {
2843 "double" => {
2844 let vals: Vec<Option<f64>> = items
2845 .iter()
2846 .map(|i| {
2847 i.as_vector()
2848 .and_then(|v| v.to_doubles().into_iter().next())
2849 .flatten()
2850 })
2851 .collect();
2852 RValue::vec(Vector::Double(vals.into()))
2853 }
2854 "integer" => {
2855 let vals: Vec<Option<i64>> = items
2856 .iter()
2857 .map(|i| {
2858 i.as_vector()
2859 .and_then(|v| v.to_integers().into_iter().next())
2860 .flatten()
2861 })
2862 .collect();
2863 RValue::vec(Vector::Integer(vals.into()))
2864 }
2865 "logical" => {
2866 let vals: Vec<Option<bool>> = items
2867 .iter()
2868 .map(|i| {
2869 i.as_vector()
2870 .and_then(|v| v.to_logicals().into_iter().next())
2871 .flatten()
2872 })
2873 .collect();
2874 RValue::vec(Vector::Logical(vals.into()))
2875 }
2876 "character" => {
2877 let vals: Vec<Option<String>> = items
2878 .iter()
2879 .map(|i| {
2880 i.as_vector()
2881 .and_then(|v| v.to_characters().into_iter().next())
2882 .flatten()
2883 })
2884 .collect();
2885 RValue::vec(Vector::Character(vals.into()))
2886 }
2887 _ => {
2888 let entries: Vec<(Option<String>, RValue)> =
2890 items.iter().map(|v| (None, v.clone())).collect();
2891 RValue::List(RList::new(entries))
2892 }
2893 }
2894 } else {
2895 let vals: Vec<Option<String>> = items
2897 .iter()
2898 .map(|i| {
2899 i.as_vector()
2900 .and_then(|v| v.to_characters().into_iter().next())
2901 .flatten()
2902 })
2903 .collect();
2904 RValue::vec(Vector::Character(vals.into()))
2905 }
2906}
2907
2908#[builtin(min_args = 1)]
2914fn builtin_vector(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
2915 let mode = args
2916 .first()
2917 .and_then(|v| v.as_vector()?.as_character_scalar())
2918 .unwrap_or_else(|| "logical".to_string());
2919 let length = args
2920 .get(1)
2921 .and_then(|v| v.as_vector()?.as_integer_scalar())
2922 .unwrap_or(0);
2923 let length = usize::try_from(length).unwrap_or(0);
2924 match mode.as_str() {
2925 "numeric" | "double" => Ok(RValue::vec(Vector::Double(vec![Some(0.0); length].into()))),
2926 "integer" => Ok(RValue::vec(Vector::Integer(vec![Some(0); length].into()))),
2927 "character" => Ok(RValue::vec(Vector::Character(
2928 vec![Some(String::new()); length].into(),
2929 ))),
2930 "logical" => Ok(RValue::vec(Vector::Logical(
2931 vec![Some(false); length].into(),
2932 ))),
2933 "list" => Ok(RValue::List(RList::new(vec![(None, RValue::Null); length]))),
2934 "raw" => Ok(RValue::vec(Vector::Raw(vec![0u8; length]))),
2935 "complex" => Ok(RValue::vec(Vector::Complex(
2936 vec![Some(num_complex::Complex64::new(0.0, 0.0)); length].into(),
2937 ))),
2938 _ => Ok(RValue::vec(Vector::Logical(
2939 vec![Some(false); length].into(),
2940 ))),
2941 }
2942}
2943
2944#[builtin(min_args = 1)]
2954fn builtin_unlist(args: &[RValue], named: &[(String, RValue)]) -> Result<RValue, RError> {
2955 let recursive = named
2956 .iter()
2957 .find(|(k, _)| k == "recursive")
2958 .and_then(|(_, v)| v.as_vector()?.as_logical_scalar())
2959 .unwrap_or(true);
2960
2961 match args.first() {
2962 Some(RValue::List(l)) => {
2963 let mut all_vals = Vec::new();
2964 if recursive {
2965 collect_list_elements_recursive(l, &mut all_vals);
2966 } else {
2967 for (_, v) in &l.values {
2970 match v {
2971 RValue::List(inner) => {
2972 for (_, elem) in &inner.values {
2973 all_vals.push(elem.clone());
2974 }
2975 }
2976 other => all_vals.push(other.clone()),
2977 }
2978 }
2979 }
2980 all_vals.retain(|v| !matches!(v, RValue::Null));
2982 if all_vals.is_empty() {
2983 return Ok(RValue::Null);
2984 }
2985 builtin_c(&all_vals, &[])
2986 }
2987 Some(other) => Ok(other.clone()),
2988 None => Ok(RValue::Null),
2989 }
2990}
2991
2992fn collect_list_elements_recursive(list: &RList, out: &mut Vec<RValue>) {
2994 for (_, v) in &list.values {
2995 match v {
2996 RValue::List(inner) => collect_list_elements_recursive(inner, out),
2997 other => out.push(other.clone()),
2998 }
2999 }
3000}
3001
3002#[builtin(name = "force", min_args = 1)]
3009fn builtin_force(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
3010 Ok(args[0].clone())
3011}
3012
3013#[builtin(name = "identity", min_args = 1)]
3017fn builtin_identity(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
3018 Ok(args[0].clone())
3019}
3020
3021#[builtin(name = "anyDuplicated", min_args = 1)]
3027fn builtin_any_duplicated(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
3028 let chars = match &args[0] {
3029 RValue::Vector(rv) => rv.inner.to_characters(),
3030 RValue::List(list) => list
3031 .values
3032 .iter()
3033 .map(|(_, v)| match v {
3034 RValue::Vector(rv) => rv.inner.as_character_scalar(),
3035 RValue::Null => Some("NULL".to_string()),
3036 _ => Some(format!("{:?}", v)),
3037 })
3038 .collect(),
3039 _ => vec![],
3040 };
3041 let mut seen = std::collections::HashSet::new();
3042 for (i, s) in chars.iter().enumerate() {
3043 let key = s.as_deref().unwrap_or("NA");
3044 if !seen.insert(key.to_string()) {
3045 return Ok(RValue::vec(Vector::Integer(
3046 vec![Some(i64::try_from(i + 1).unwrap_or(0))].into(),
3047 )));
3048 }
3049 }
3050 Ok(RValue::vec(Vector::Integer(vec![Some(0)].into())))
3051}
3052
3053#[builtin(name = "as.function", min_args = 1)]
3063fn builtin_as_function(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
3064 as_function_impl(args)
3065}
3066
3067#[builtin(name = "as.function.default", min_args = 1)]
3069fn builtin_as_function_default(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
3070 as_function_impl(args)
3071}
3072
3073fn as_function_impl(args: &[RValue]) -> Result<RValue, RError> {
3074 let list = match &args[0] {
3075 RValue::List(l) => l,
3076 RValue::Null => {
3077 return Ok(RValue::Function(RFunction::Closure {
3079 params: vec![],
3080 body: Expr::Null,
3081 env: crate::interpreter::environment::Environment::new_empty(),
3082 }));
3083 }
3084 _ => {
3085 return Err(RError::new(
3086 RErrorKind::Type,
3087 "cannot coerce to function — argument must be a list",
3088 ))
3089 }
3090 };
3091
3092 if list.values.is_empty() {
3093 return Ok(RValue::Function(RFunction::Closure {
3094 params: vec![],
3095 body: Expr::Null,
3096 env: crate::interpreter::environment::Environment::new_empty(),
3097 }));
3098 }
3099
3100 let n = list.values.len();
3102 let mut params = Vec::new();
3103 for (name, val) in &list.values[..n - 1] {
3104 let param_name = name.clone().unwrap_or_default();
3105 if param_name == "..." {
3106 params.push(Param {
3107 name: "...".to_string(),
3108 default: None,
3109 is_dots: true,
3110 });
3111 } else {
3112 let default = match val {
3114 RValue::Language(lang) => Some((*lang.inner).clone()),
3115 RValue::Vector(_) => Some(crate::interpreter::value::rvalue_to_expr(val)),
3116 RValue::Null => None, _ => None,
3118 };
3119 params.push(Param {
3120 name: param_name,
3121 default,
3122 is_dots: false,
3123 });
3124 }
3125 }
3126
3127 let body_val = &list.values[n - 1].1;
3129 let body = match body_val {
3130 RValue::Language(lang) => (*lang.inner).clone(),
3131 _ => crate::interpreter::value::rvalue_to_expr(body_val),
3132 };
3133
3134 let env = if args.len() > 1 {
3137 match &args[1] {
3138 RValue::Environment(e) => e.clone(),
3139 _ => crate::interpreter::environment::Environment::new_empty(),
3140 }
3141 } else {
3142 crate::interpreter::environment::Environment::new_empty()
3143 };
3144
3145 Ok(RValue::Function(RFunction::Closure { params, body, env }))
3146}
3147
3148#[builtin(name = "I", min_args = 1)]
3157fn builtin_asis(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
3158 let mut val = args[0].clone();
3159 let existing: Vec<String> = match &val {
3161 RValue::Vector(rv) => rv.class().unwrap_or_default(),
3162 RValue::List(l) => l.class().unwrap_or_default(),
3163 _ => vec![],
3164 };
3165 let mut new_class: Vec<Option<String>> = vec![Some("AsIs".to_string())];
3166 new_class.extend(existing.into_iter().map(Some));
3167 let class_val = RValue::vec(Vector::Character(new_class.into()));
3168 match &mut val {
3169 RValue::Vector(rv) => rv.set_attr("class".to_string(), class_val),
3170 RValue::List(list) => list.set_attr("class".to_string(), class_val),
3171 RValue::Language(lang) => lang.set_attr("class".to_string(), class_val),
3172 _ => return Ok(val),
3176 }
3177 Ok(val)
3178}
3179
3180#[builtin(name = "pairlist")]
3189fn builtin_pairlist(args: &[RValue], named: &[(String, RValue)]) -> Result<RValue, RError> {
3190 let mut entries: Vec<(Option<String>, RValue)> = Vec::new();
3191 for arg in args {
3193 entries.push((None, arg.clone()));
3194 }
3195 for (name, val) in named {
3197 entries.push((Some(name.clone()), val.clone()));
3198 }
3199 Ok(RValue::List(RList::new(entries)))
3200}
3201
3202#[builtin(name = "modifyList", min_args = 2)]
3213fn builtin_modify_list(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
3214 let x = match args.first() {
3215 Some(RValue::List(l)) => l.clone(),
3216 Some(_) => {
3217 return Err(RError::new(
3218 RErrorKind::Type,
3219 "modifyList: first argument must be a list".to_string(),
3220 ))
3221 }
3222 None => return Ok(RValue::Null),
3223 };
3224 let val = match args.get(1) {
3225 Some(RValue::List(l)) => l,
3226 Some(RValue::Null) => return Ok(RValue::List(x)),
3227 _ => return Ok(RValue::List(x)),
3228 };
3229
3230 let mut result = x;
3231 for (name, value) in &val.values {
3232 if let Some(name) = name {
3233 if value.is_null() {
3234 result
3236 .values
3237 .retain(|(n, _)| n.as_deref() != Some(name.as_str()));
3238 } else if let Some(entry) = result
3239 .values
3240 .iter_mut()
3241 .find(|(n, _)| n.as_deref() == Some(name.as_str()))
3242 {
3243 entry.1 = value.clone();
3245 } else {
3246 result.values.push((Some(name.clone()), value.clone()));
3248 }
3249 }
3250 }
3251 Ok(RValue::List(result))
3252}
3253
3254#[builtin(name = "oldClass", min_args = 1)]
3259fn builtin_old_class(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
3260 match args.first() {
3261 Some(RValue::Vector(rv)) => match rv.get_attr("class") {
3262 Some(cls) => Ok(cls.clone()),
3263 None => Ok(RValue::Null),
3264 },
3265 Some(RValue::List(l)) => match l.get_attr("class") {
3266 Some(cls) => Ok(cls.clone()),
3267 None => Ok(RValue::Null),
3268 },
3269 _ => Ok(RValue::Null),
3270 }
3271}
3272
3273#[builtin(min_args = 3)]
3282fn builtin_ifelse(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
3283 if args.len() < 3 {
3284 return Err(RError::new(
3285 RErrorKind::Argument,
3286 "need 3 arguments".to_string(),
3287 ));
3288 }
3289 let test_vec = args[0]
3290 .as_vector()
3291 .ok_or_else(|| RError::new(RErrorKind::Argument, "test must be a vector".to_string()))?;
3292 let test_logicals = test_vec.to_logicals();
3293 let n = test_logicals.len();
3294
3295 let yes_vec = args[1]
3296 .as_vector()
3297 .ok_or_else(|| RError::new(RErrorKind::Argument, "yes must be a vector".to_string()))?;
3298 let no_vec = args[2]
3299 .as_vector()
3300 .ok_or_else(|| RError::new(RErrorKind::Argument, "no must be a vector".to_string()))?;
3301
3302 let is_character =
3304 matches!(yes_vec, Vector::Character(_)) || matches!(no_vec, Vector::Character(_));
3305 let is_logical = matches!(yes_vec, Vector::Logical(_)) && matches!(no_vec, Vector::Logical(_));
3306 let is_integer = !is_character
3307 && (matches!(yes_vec, Vector::Integer(_) | Vector::Logical(_)))
3308 && (matches!(no_vec, Vector::Integer(_) | Vector::Logical(_)));
3309
3310 if is_character {
3311 let yes_chars = yes_vec.to_characters();
3312 let no_chars = no_vec.to_characters();
3313 let result: Vec<Option<String>> = (0..n)
3314 .map(|i| match test_logicals[i] {
3315 Some(true) => yes_chars[i % yes_chars.len()].clone(),
3316 Some(false) => no_chars[i % no_chars.len()].clone(),
3317 None => None,
3318 })
3319 .collect();
3320 Ok(RValue::vec(Vector::Character(result.into())))
3321 } else if is_logical {
3322 let yes_bools = yes_vec.to_logicals();
3323 let no_bools = no_vec.to_logicals();
3324 let result: Vec<Option<bool>> = (0..n)
3325 .map(|i| match test_logicals[i] {
3326 Some(true) => yes_bools[i % yes_bools.len()],
3327 Some(false) => no_bools[i % no_bools.len()],
3328 None => None,
3329 })
3330 .collect();
3331 Ok(RValue::vec(Vector::Logical(result.into())))
3332 } else if is_integer {
3333 let yes_ints = yes_vec.to_integers();
3334 let no_ints = no_vec.to_integers();
3335 let result: Vec<Option<i64>> = (0..n)
3336 .map(|i| match test_logicals[i] {
3337 Some(true) => yes_ints[i % yes_ints.len()],
3338 Some(false) => no_ints[i % no_ints.len()],
3339 None => None,
3340 })
3341 .collect();
3342 Ok(RValue::vec(Vector::Integer(result.into())))
3343 } else {
3344 let yes_doubles = yes_vec.to_doubles();
3345 let no_doubles = no_vec.to_doubles();
3346 let result: Vec<Option<f64>> = (0..n)
3347 .map(|i| match test_logicals[i] {
3348 Some(true) => yes_doubles[i % yes_doubles.len()],
3349 Some(false) => no_doubles[i % no_doubles.len()],
3350 None => None,
3351 })
3352 .collect();
3353 Ok(RValue::vec(Vector::Double(result.into())))
3354 }
3355}
3356
3357#[builtin(min_args = 2)]
3367fn builtin_match(args: &[RValue], named: &[(String, RValue)]) -> Result<RValue, RError> {
3368 if args.len() < 2 {
3369 return Err(RError::new(
3370 RErrorKind::Argument,
3371 "need 2 arguments".to_string(),
3372 ));
3373 }
3374
3375 let ignore_case = named
3376 .iter()
3377 .find(|(k, _)| k == "ignore.case")
3378 .and_then(|(_, v)| match v {
3379 RValue::Vector(rv) => rv.inner.as_logical_scalar(),
3380 _ => None,
3381 })
3382 .unwrap_or(false);
3383
3384 let x = match &args[0] {
3385 RValue::Vector(v) => v.to_characters(),
3386 _ => return Ok(RValue::vec(Vector::Integer(vec![None].into()))),
3387 };
3388 let table = match &args[1] {
3389 RValue::Vector(v) => v.to_characters(),
3390 _ => return Ok(RValue::vec(Vector::Integer(vec![None].into()))),
3391 };
3392
3393 let result: Vec<Option<i64>> = if ignore_case {
3394 x.iter()
3395 .map(|xi| {
3396 xi.as_ref().and_then(|xi| {
3397 let key = unicase::UniCase::new(xi.as_str());
3398 table
3399 .iter()
3400 .position(|t| t.as_deref().map(unicase::UniCase::new) == Some(key))
3401 .map(|p| i64::try_from(p).map(|v| v + 1).unwrap_or(0))
3402 })
3403 })
3404 .collect()
3405 } else {
3406 x.iter()
3407 .map(|xi| {
3408 xi.as_ref().and_then(|xi| {
3409 table
3410 .iter()
3411 .position(|t| t.as_ref() == Some(xi))
3412 .map(|p| i64::try_from(p).map(|v| v + 1).unwrap_or(0))
3413 })
3414 })
3415 .collect()
3416 };
3417 Ok(RValue::vec(Vector::Integer(result.into())))
3418}
3419
3420#[builtin(min_args = 2)]
3430fn builtin_pmatch(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
3431 let x = match args.first() {
3432 Some(RValue::Vector(v)) => v.to_characters(),
3433 _ => return Ok(RValue::vec(Vector::Integer(vec![None].into()))),
3434 };
3435 let table = match args.get(1) {
3436 Some(RValue::Vector(v)) => v.to_characters(),
3437 _ => return Ok(RValue::vec(Vector::Integer(vec![None].into()))),
3438 };
3439
3440 let result: Vec<Option<i64>> = x
3441 .iter()
3442 .map(|xi| {
3443 xi.as_ref().and_then(|xi| {
3444 if let Some(pos) = table.iter().position(|t| t.as_deref() == Some(xi.as_str())) {
3446 return Some(i64::try_from(pos).map(|v| v + 1).unwrap_or(0));
3447 }
3448 let matches: Vec<usize> = table
3450 .iter()
3451 .enumerate()
3452 .filter(|(_, t)| {
3453 t.as_ref()
3454 .map(|t| t.starts_with(xi.as_str()))
3455 .unwrap_or(false)
3456 })
3457 .map(|(i, _)| i)
3458 .collect();
3459 if matches.len() == 1 {
3460 Some(i64::try_from(matches[0]).map(|v| v + 1).unwrap_or(0))
3461 } else {
3462 None }
3464 })
3465 })
3466 .collect();
3467 Ok(RValue::vec(Vector::Integer(result.into())))
3468}
3469
3470#[builtin(min_args = 2)]
3479fn builtin_charmatch(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
3480 let x = match args.first() {
3481 Some(RValue::Vector(v)) => v.to_characters(),
3482 _ => return Ok(RValue::vec(Vector::Integer(vec![None].into()))),
3483 };
3484 let table = match args.get(1) {
3485 Some(RValue::Vector(v)) => v.to_characters(),
3486 _ => return Ok(RValue::vec(Vector::Integer(vec![None].into()))),
3487 };
3488
3489 let result: Vec<Option<i64>> = x
3490 .iter()
3491 .map(|xi| {
3492 xi.as_ref().and_then(|xi| {
3493 if let Some(pos) = table.iter().position(|t| t.as_deref() == Some(xi.as_str())) {
3495 return Some(i64::try_from(pos).map(|v| v + 1).unwrap_or(0));
3496 }
3497 let matches: Vec<usize> = table
3499 .iter()
3500 .enumerate()
3501 .filter(|(_, t)| {
3502 t.as_ref()
3503 .map(|t| t.starts_with(xi.as_str()))
3504 .unwrap_or(false)
3505 })
3506 .map(|(i, _)| i)
3507 .collect();
3508 match matches.len() {
3509 0 => None, 1 => Some(i64::try_from(matches[0]).map(|v| v + 1).unwrap_or(0)), _ => Some(0), }
3513 })
3514 })
3515 .collect();
3516 Ok(RValue::vec(Vector::Integer(result.into())))
3517}
3518
3519#[builtin(min_args = 3)]
3529fn builtin_replace(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
3530 if args.len() < 3 {
3531 return Err(RError::new(
3532 RErrorKind::Argument,
3533 "need 3 arguments".to_string(),
3534 ));
3535 }
3536 match &args[0] {
3537 RValue::Vector(v) => {
3538 let indices = args[1]
3539 .as_vector()
3540 .map(|v| v.to_integers())
3541 .unwrap_or_default();
3542 let vals_vec = args[2]
3543 .as_vector()
3544 .cloned()
3545 .unwrap_or(Vector::Logical(vec![None].into()));
3546
3547 match &v.inner {
3548 Vector::Character(_) => {
3549 let mut data = v.to_characters();
3550 let vals = vals_vec.to_characters();
3551 if vals.is_empty() {
3552 return Ok(RValue::vec(Vector::Character(data.into())));
3553 }
3554 for (i, idx) in indices.iter().enumerate() {
3555 if let Some(idx) = idx {
3556 let idx = usize::try_from(*idx)? - 1;
3557 if idx < data.len() {
3558 data[idx] = vals[i % vals.len()].clone();
3559 }
3560 }
3561 }
3562 Ok(RValue::vec(Vector::Character(data.into())))
3563 }
3564 Vector::Integer(_) => {
3565 let mut data = v.to_integers();
3566 let vals = vals_vec.to_integers();
3567 if vals.is_empty() {
3568 return Ok(RValue::vec(Vector::Integer(data.into())));
3569 }
3570 for (i, idx) in indices.iter().enumerate() {
3571 if let Some(idx) = idx {
3572 let idx = usize::try_from(*idx)? - 1;
3573 if idx < data.len() {
3574 data[idx] = vals[i % vals.len()];
3575 }
3576 }
3577 }
3578 Ok(RValue::vec(Vector::Integer(data.into())))
3579 }
3580 Vector::Logical(_) => {
3581 let mut data = v.to_logicals();
3582 let vals = vals_vec.to_logicals();
3583 if vals.is_empty() {
3584 return Ok(RValue::vec(Vector::Logical(data.into())));
3585 }
3586 for (i, idx) in indices.iter().enumerate() {
3587 if let Some(idx) = idx {
3588 let idx = usize::try_from(*idx)? - 1;
3589 if idx < data.len() {
3590 data[idx] = vals[i % vals.len()];
3591 }
3592 }
3593 }
3594 Ok(RValue::vec(Vector::Logical(data.into())))
3595 }
3596 Vector::Complex(_) => {
3597 let mut data = v.to_complex();
3598 let vals = vals_vec.to_complex();
3599 if vals.is_empty() {
3600 return Ok(RValue::vec(Vector::Complex(data.into())));
3601 }
3602 for (i, idx) in indices.iter().enumerate() {
3603 if let Some(idx) = idx {
3604 let idx = usize::try_from(*idx)? - 1;
3605 if idx < data.len() {
3606 data[idx] = vals[i % vals.len()];
3607 }
3608 }
3609 }
3610 Ok(RValue::vec(Vector::Complex(data.into())))
3611 }
3612 _ => {
3613 let mut data = v.to_doubles();
3615 let vals = vals_vec.to_doubles();
3616 if vals.is_empty() {
3617 return Ok(RValue::vec(Vector::Double(data.into())));
3618 }
3619 for (i, idx) in indices.iter().enumerate() {
3620 if let Some(idx) = idx {
3621 let idx = usize::try_from(*idx)? - 1;
3622 if idx < data.len() {
3623 data[idx] = vals[i % vals.len()];
3624 }
3625 }
3626 }
3627 Ok(RValue::vec(Vector::Double(data.into())))
3628 }
3629 }
3630 }
3631 _ => Ok(args[0].clone()),
3632 }
3633}
3634
3635#[interpreter_builtin]
3644fn interp_readline(
3645 args: &[RValue],
3646 _named: &[(String, RValue)],
3647 context: &BuiltinContext,
3648) -> Result<RValue, RError> {
3649 let prompt = args
3650 .first()
3651 .and_then(|v| v.as_vector()?.as_character_scalar())
3652 .unwrap_or_default();
3653 context.write(&prompt);
3654 let mut input = String::new();
3655 std::io::stdin().read_line(&mut input).ok();
3656 Ok(RValue::vec(Vector::Character(
3657 vec![Some(input.trim_end().to_string())].into(),
3658 )))
3659}
3660
3661#[interpreter_builtin(name = "Sys.getenv")]
3669fn interp_sys_getenv(
3670 args: &[RValue],
3671 named: &[(String, RValue)],
3672 context: &BuiltinContext,
3673) -> Result<RValue, RError> {
3674 let unset: Option<String> = match named.iter().find(|(n, _)| n == "unset") {
3678 None => Some(String::new()), Some((_, v)) => {
3680 if let Some(vec) = v.as_vector() {
3682 let chars = vec.to_characters();
3683 if chars.len() == 1 && chars[0].is_none() {
3684 None } else {
3686 Some(chars.into_iter().next().flatten().unwrap_or_default())
3687 }
3688 } else {
3689 Some(String::new())
3690 }
3691 }
3692 };
3693
3694 let use_names = named
3695 .iter()
3696 .find(|(n, _)| n == "names")
3697 .and_then(|(_, v)| v.as_vector()?.as_logical_scalar())
3698 .unwrap_or(true);
3699
3700 let first_arg = args.first();
3702 if first_arg.is_none() {
3703 let snapshot = context.with_interpreter(|interp| interp.env_vars_snapshot());
3704 let mut pairs: Vec<(String, String)> = snapshot.into_iter().collect();
3705 pairs.sort_by(|a, b| a.0.cmp(&b.0));
3706 let names_vec: Vec<Option<String>> = pairs.iter().map(|(n, _)| Some(n.clone())).collect();
3707 let vals: Vec<Option<String>> = pairs.into_iter().map(|(_, v)| Some(v)).collect();
3708 let mut rv = RVector::from(Vector::Character(vals.into()));
3709 rv.set_attr(
3710 "names".to_string(),
3711 RValue::vec(Vector::Character(names_vec.into())),
3712 );
3713 return Ok(RValue::Vector(rv));
3714 }
3715
3716 let var_names: Vec<Option<String>> = first_arg
3718 .and_then(|v| v.as_vector())
3719 .map(|v| v.to_characters())
3720 .unwrap_or_default();
3721
3722 let values: Vec<Option<String>> = var_names
3723 .iter()
3724 .map(|name_opt| {
3725 let name = name_opt.as_deref().unwrap_or("");
3726 let val = context.with_interpreter(|interp| interp.get_env_var(name));
3727 match val {
3728 Some(v) => Some(v),
3729 None => unset.clone(), }
3731 })
3732 .collect();
3733
3734 if use_names && var_names.len() > 1 {
3735 let names_vec: Vec<Option<String>> = var_names.clone();
3736 let mut rv = RVector::from(Vector::Character(values.into()));
3737 rv.set_attr(
3738 "names".to_string(),
3739 RValue::vec(Vector::Character(names_vec.into())),
3740 );
3741 Ok(RValue::Vector(rv))
3742 } else if use_names && var_names.len() == 1 {
3743 let mut rv = RVector::from(Vector::Character(values.into()));
3744 rv.set_attr(
3745 "names".to_string(),
3746 RValue::vec(Vector::Character(var_names.into())),
3747 );
3748 Ok(RValue::Vector(rv))
3749 } else {
3750 Ok(RValue::vec(Vector::Character(values.into())))
3751 }
3752}
3753
3754#[interpreter_builtin(name = "loadNamespace", min_args = 1)]
3767fn interp_load_namespace(
3768 args: &[RValue],
3769 _named: &[(String, RValue)],
3770 context: &BuiltinContext,
3771) -> Result<RValue, RError> {
3772 let pkg = args
3773 .first()
3774 .and_then(|v| v.as_vector()?.as_character_scalar())
3775 .ok_or_else(|| RError::new(RErrorKind::Argument, "invalid package name".to_string()))?;
3776
3777 let env = context.with_interpreter(|interp| interp.load_namespace(&pkg))?;
3778 Ok(RValue::Environment(env))
3779}
3780
3781#[interpreter_builtin(name = "requireNamespace", min_args = 1)]
3790fn interp_require_namespace(
3791 args: &[RValue],
3792 named: &[(String, RValue)],
3793 context: &BuiltinContext,
3794) -> Result<RValue, RError> {
3795 let pkg = args
3796 .first()
3797 .and_then(|v| v.as_vector()?.as_character_scalar())
3798 .ok_or_else(|| RError::new(RErrorKind::Argument, "invalid package name".to_string()))?;
3799
3800 let quietly = named
3801 .iter()
3802 .find(|(n, _)| n == "quietly")
3803 .and_then(|(_, v)| v.as_vector()?.as_logical_scalar())
3804 .unwrap_or(true);
3805
3806 let result = context.with_interpreter(|interp| interp.load_namespace(&pkg));
3807 match result {
3808 Ok(_) => Ok(RValue::vec(Vector::Logical(vec![Some(true)].into()))),
3809 Err(_) => {
3810 if !quietly {
3811 context.write_err(&format!(
3812 "Warning message:\nthere is no package called '{}'\n",
3813 pkg
3814 ));
3815 }
3816 Ok(RValue::vec(Vector::Logical(vec![Some(false)].into())))
3817 }
3818 }
3819}
3820
3821#[interpreter_builtin(name = "detach", min_args = 1)]
3826fn interp_detach(
3827 args: &[RValue],
3828 named: &[(String, RValue)],
3829 context: &BuiltinContext,
3830) -> Result<RValue, RError> {
3831 let name = named
3832 .iter()
3833 .find(|(n, _)| n == "name")
3834 .map(|(_, v)| v)
3835 .or_else(|| args.first())
3836 .and_then(|v| v.as_vector()?.as_character_scalar())
3837 .ok_or_else(|| RError::new(RErrorKind::Argument, "invalid 'name' argument".to_string()))?;
3838
3839 let entry_name = if name.starts_with("package:") {
3841 name
3842 } else {
3843 format!("package:{}", name)
3844 };
3845
3846 context.with_interpreter(|interp| interp.detach_package(&entry_name))?;
3847 Ok(RValue::Null)
3848}
3849
3850#[builtin(name = "R.Version", names = ["version"])]
3856fn builtin_r_version(_args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
3857 Ok(RValue::List(RList::new(vec![
3858 (
3859 Some("major".to_string()),
3860 RValue::vec(Vector::Character(vec![Some("0".to_string())].into())),
3861 ),
3862 (
3863 Some("minor".to_string()),
3864 RValue::vec(Vector::Character(vec![Some("1.0".to_string())].into())),
3865 ),
3866 (
3867 Some("language".to_string()),
3868 RValue::vec(Vector::Character(vec![Some("R".to_string())].into())),
3869 ),
3870 (
3871 Some("engine".to_string()),
3872 RValue::vec(Vector::Character(
3873 vec![Some("miniR (Rust)".to_string())].into(),
3874 )),
3875 ),
3876 ])))
3877}
3878
3879fn set_key(val: &Option<String>) -> String {
3881 match val {
3882 Some(s) => s.clone(),
3883 None => "NA".to_string(),
3884 }
3885}
3886
3887fn set_op_extract(
3890 x: &RValue,
3891 y: &RValue,
3892) -> (
3893 Vec<Option<String>>,
3894 Vec<Option<String>>,
3895 bool, ) {
3897 let x_vec = x.as_vector();
3898 let y_vec = y.as_vector();
3899 let is_numeric = matches!(
3900 (x_vec, y_vec),
3901 (
3902 Some(Vector::Integer(_) | Vector::Double(_)),
3903 Some(Vector::Integer(_) | Vector::Double(_))
3904 )
3905 );
3906 let xc = x_vec.map(|v| v.to_characters()).unwrap_or_default();
3907 let yc = y_vec.map(|v| v.to_characters()).unwrap_or_default();
3908 (xc, yc, is_numeric)
3909}
3910
3911fn set_result_numeric(chars: Vec<Option<String>>) -> RValue {
3913 let as_ints: Option<Vec<Option<i64>>> = chars
3915 .iter()
3916 .map(|c| match c {
3917 None => Some(None),
3918 Some(s) => s.parse::<i64>().ok().map(Some),
3919 })
3920 .collect();
3921 if let Some(ints) = as_ints {
3922 return RValue::vec(Vector::Integer(ints.into()));
3923 }
3924 let doubles: Vec<Option<f64>> = chars
3925 .iter()
3926 .map(|c| c.as_ref().and_then(|s| s.parse::<f64>().ok()))
3927 .collect();
3928 RValue::vec(Vector::Double(doubles.into()))
3929}
3930
3931#[builtin(min_args = 2)]
3940fn builtin_setdiff(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
3941 let (x, y, numeric) = set_op_extract(&args[0], &args[1]);
3942 let y_keys: std::collections::HashSet<String> = y.iter().map(set_key).collect();
3943 let result: Vec<Option<String>> = x
3944 .into_iter()
3945 .filter(|xi| !y_keys.contains(&set_key(xi)))
3946 .collect();
3947 if numeric {
3948 Ok(set_result_numeric(result))
3949 } else {
3950 Ok(RValue::vec(Vector::Character(result.into())))
3951 }
3952}
3953
3954#[builtin(min_args = 2)]
3963fn builtin_intersect(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
3964 let (x, y, numeric) = set_op_extract(&args[0], &args[1]);
3965 let y_keys: std::collections::HashSet<String> = y.iter().map(set_key).collect();
3966 let result: Vec<Option<String>> = x
3967 .into_iter()
3968 .filter(|xi| y_keys.contains(&set_key(xi)))
3969 .collect();
3970 if numeric {
3971 Ok(set_result_numeric(result))
3972 } else {
3973 Ok(RValue::vec(Vector::Character(result.into())))
3974 }
3975}
3976
3977#[builtin(min_args = 2)]
3986fn builtin_union(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
3987 let (x, y, numeric) = set_op_extract(&args[0], &args[1]);
3988 let mut seen = std::collections::HashSet::new();
3989 let mut result = Vec::new();
3990 for xi in x.into_iter().chain(y) {
3991 let key = set_key(&xi);
3992 if seen.insert(key) {
3993 result.push(xi);
3994 }
3995 }
3996 if numeric {
3997 Ok(set_result_numeric(result))
3998 } else {
3999 Ok(RValue::vec(Vector::Character(result.into())))
4000 }
4001}
4002
4003#[builtin(min_args = 2)]
4012fn builtin_cut(args: &[RValue], named: &[(String, RValue)]) -> Result<RValue, RError> {
4013 let ca = CallArgs::new(args, named);
4014
4015 let x_vals = ca
4016 .value("x", 0)
4017 .and_then(|v| v.as_vector().map(|v| v.to_doubles()))
4018 .ok_or_else(|| {
4019 RError::new(
4020 RErrorKind::Argument,
4021 "'x' must be a numeric vector".to_string(),
4022 )
4023 })?;
4024 let breaks = ca
4025 .value("breaks", 1)
4026 .and_then(|v| v.as_vector().map(|v| v.to_doubles()))
4027 .ok_or_else(|| {
4028 RError::new(
4029 RErrorKind::Argument,
4030 "'breaks' must be a numeric vector".to_string(),
4031 )
4032 })?;
4033
4034 let breaks: Vec<f64> = breaks.into_iter().flatten().collect();
4035 if breaks.len() < 2 {
4036 return Err(RError::new(
4037 RErrorKind::Argument,
4038 "'breaks' must have at least 2 values".to_string(),
4039 ));
4040 }
4041
4042 let right = ca.logical_flag("right", 4, true);
4043 let include_lowest = ca.logical_flag("include.lowest", 5, false);
4044
4045 let custom_labels: Option<Vec<String>> = ca.value("labels", 2).and_then(|v| {
4046 v.as_vector().and_then(|vec| {
4047 let chars = vec.to_characters();
4048 chars.into_iter().collect::<Option<Vec<String>>>()
4049 })
4050 });
4051
4052 let n_intervals = breaks.len() - 1;
4053
4054 let labels: Vec<String> = if let Some(ref cl) = custom_labels {
4056 if cl.len() != n_intervals {
4057 return Err(RError::new(
4058 RErrorKind::Argument,
4059 format!(
4060 "lengths of 'breaks' and 'labels' differ: {} breaks produce {} intervals but {} labels given",
4061 breaks.len(),
4062 n_intervals,
4063 cl.len()
4064 ),
4065 ));
4066 }
4067 cl.clone()
4068 } else {
4069 (0..n_intervals)
4070 .map(|i| {
4071 let lo = breaks[i];
4072 let hi = breaks[i + 1];
4073 if right {
4074 format!("({},{}]", format_r_double_cut(lo), format_r_double_cut(hi))
4075 } else {
4076 format!("[{},{})", format_r_double_cut(lo), format_r_double_cut(hi))
4077 }
4078 })
4079 .collect()
4080 };
4081
4082 let codes: Vec<Option<i64>> = x_vals
4084 .iter()
4085 .map(|x| {
4086 let val = match x {
4087 Some(v) if v.is_finite() => *v,
4088 _ => return None, };
4090 for i in 0..n_intervals {
4091 let lo = breaks[i];
4092 let hi = breaks[i + 1];
4093 let in_bin = if right {
4094 let lower_ok = if include_lowest && i == 0 {
4095 val >= lo
4096 } else {
4097 val > lo
4098 };
4099 lower_ok && val <= hi
4100 } else {
4101 let upper_ok = if include_lowest && i == n_intervals - 1 {
4102 val <= hi
4103 } else {
4104 val < hi
4105 };
4106 val >= lo && upper_ok
4107 };
4108 if in_bin {
4109 return Some(i64::try_from(i + 1).unwrap_or(0));
4110 }
4111 }
4112 None })
4114 .collect();
4115
4116 let mut rv = RVector::from(Vector::Integer(codes.into()));
4117 rv.set_attr(
4118 "levels".to_string(),
4119 RValue::vec(Vector::Character(
4120 labels.into_iter().map(Some).collect::<Vec<_>>().into(),
4121 )),
4122 );
4123 rv.set_attr(
4124 "class".to_string(),
4125 RValue::vec(Vector::Character(vec![Some("factor".to_string())].into())),
4126 );
4127 Ok(RValue::Vector(rv))
4128}
4129
4130fn format_r_double_cut(x: f64) -> String {
4132 if x == x.floor() && x.abs() < 1e15 {
4133 format!("{}", x as i64)
4134 } else {
4135 format!("{}", x)
4136 }
4137}
4138
4139#[builtin(name = "findInterval", min_args = 2)]
4149fn builtin_find_interval(args: &[RValue], named: &[(String, RValue)]) -> Result<RValue, RError> {
4150 let ca = CallArgs::new(args, named);
4151
4152 let x_vals = ca
4153 .value("x", 0)
4154 .and_then(|v| v.as_vector().map(|v| v.to_doubles()))
4155 .ok_or_else(|| {
4156 RError::new(
4157 RErrorKind::Argument,
4158 "'x' must be a numeric vector".to_string(),
4159 )
4160 })?;
4161 let vec_vals: Vec<f64> = ca
4162 .value("vec", 1)
4163 .and_then(|v| v.as_vector().map(|v| v.to_doubles()))
4164 .ok_or_else(|| {
4165 RError::new(
4166 RErrorKind::Argument,
4167 "'vec' must be a numeric vector".to_string(),
4168 )
4169 })?
4170 .into_iter()
4171 .flatten()
4172 .collect();
4173
4174 let result: Vec<Option<i64>> = x_vals
4175 .iter()
4176 .map(|x| {
4177 let val = (*x)?;
4178 let mut lo = 0usize;
4180 let mut hi = vec_vals.len();
4181 while lo < hi {
4182 let mid = lo + (hi - lo) / 2;
4183 if vec_vals[mid] <= val {
4184 lo = mid + 1;
4185 } else {
4186 hi = mid;
4187 }
4188 }
4189 Some(i64::try_from(lo).unwrap_or(0))
4190 })
4191 .collect();
4192 Ok(RValue::vec(Vector::Integer(result.into())))
4193}
4194
4195#[builtin(min_args = 1)]
4202fn builtin_duplicated(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
4203 match args.first() {
4204 Some(RValue::Vector(v)) => {
4205 let chars = v.to_characters();
4206 let mut seen = Vec::new();
4207 let result: Vec<Option<bool>> = chars
4208 .iter()
4209 .map(|x| {
4210 let key = format!("{:?}", x);
4211 if seen.contains(&key) {
4212 Some(true)
4213 } else {
4214 seen.push(key);
4215 Some(false)
4216 }
4217 })
4218 .collect();
4219 Ok(RValue::vec(Vector::Logical(result.into())))
4220 }
4221 _ => Ok(RValue::vec(Vector::Logical(vec![].into()))),
4222 }
4223}
4224
4225#[interpreter_builtin]
4229fn interp_getwd(
4230 _args: &[RValue],
4231 _: &[(String, RValue)],
4232 context: &BuiltinContext,
4233) -> Result<RValue, RError> {
4234 let cwd =
4235 context.with_interpreter(|interp| interp.get_working_dir().to_string_lossy().to_string());
4236 Ok(RValue::vec(Vector::Character(vec![Some(cwd)].into())))
4237}
4238
4239#[builtin(names = ["double"])]
4246fn builtin_numeric(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
4247 let n = args
4248 .first()
4249 .and_then(|v| v.as_vector()?.as_integer_scalar())
4250 .map(usize::try_from)
4251 .transpose()?
4252 .unwrap_or(0);
4253 Ok(RValue::vec(Vector::Double(vec![Some(0.0); n].into())))
4254}
4255
4256#[builtin]
4261fn builtin_integer(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
4262 let n = args
4263 .first()
4264 .and_then(|v| v.as_vector()?.as_integer_scalar())
4265 .map(usize::try_from)
4266 .transpose()?
4267 .unwrap_or(0);
4268 Ok(RValue::vec(Vector::Integer(vec![Some(0); n].into())))
4269}
4270
4271#[builtin]
4276fn builtin_logical(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
4277 let n = args
4278 .first()
4279 .and_then(|v| v.as_vector()?.as_integer_scalar())
4280 .map(usize::try_from)
4281 .transpose()?
4282 .unwrap_or(0);
4283 Ok(RValue::vec(Vector::Logical(vec![Some(false); n].into())))
4284}
4285
4286#[builtin]
4291fn builtin_character(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
4292 let n = args
4293 .first()
4294 .and_then(|v| v.as_vector()?.as_integer_scalar())
4295 .map(usize::try_from)
4296 .transpose()?
4297 .unwrap_or(0);
4298 Ok(RValue::vec(Vector::Character(
4299 vec![Some(String::new()); n].into(),
4300 )))
4301}
4302
4303#[builtin]
4314fn builtin_matrix(args: &[RValue], named: &[(String, RValue)]) -> Result<RValue, RError> {
4315 let data = args
4316 .first()
4317 .cloned()
4318 .unwrap_or(RValue::vec(Vector::Double(vec![Some(f64::NAN)].into())));
4319 let nrow_arg = named
4320 .iter()
4321 .find(|(n, _)| n == "nrow")
4322 .map(|(_, v)| v)
4323 .or(args.get(1))
4324 .and_then(|v| v.as_vector()?.as_integer_scalar());
4325 let ncol_arg = named
4326 .iter()
4327 .find(|(n, _)| n == "ncol")
4328 .map(|(_, v)| v)
4329 .or(args.get(2))
4330 .and_then(|v| v.as_vector()?.as_integer_scalar());
4331 let byrow = named
4332 .iter()
4333 .find(|(n, _)| n == "byrow")
4334 .map(|(_, v)| v)
4335 .or(args.get(3))
4336 .and_then(|v| v.as_vector()?.as_logical_scalar())
4337 .unwrap_or(false);
4338 let dimnames = named
4339 .iter()
4340 .find(|(n, _)| n == "dimnames")
4341 .map(|(_, v)| v)
4342 .or(args.get(4));
4343
4344 let data_inner = match &data {
4345 RValue::Vector(v) => &v.inner,
4346 _ => {
4347 return Err(RError::new(
4348 RErrorKind::Type,
4349 "data must be a vector".to_string(),
4350 ));
4351 }
4352 };
4353 let data_len = data_inner.len();
4354
4355 let (nrow, ncol) = match (nrow_arg, ncol_arg) {
4356 (Some(r), Some(c)) => (usize::try_from(r)?, usize::try_from(c)?),
4357 (Some(r), None) => {
4358 let r = usize::try_from(r)?;
4359 (r, if r > 0 { data_len.div_ceil(r) } else { 0 })
4360 }
4361 (None, Some(c)) => {
4362 let c = usize::try_from(c)?;
4363 (if c > 0 { data_len.div_ceil(c) } else { 0 }, c)
4364 }
4365 (None, None) => (data_len, 1),
4366 };
4367
4368 let total = nrow * ncol;
4369 let indices: Vec<usize> = if byrow {
4371 (0..nrow)
4372 .flat_map(|i| (0..ncol).map(move |j| (i * ncol + j) % data_len))
4373 .collect()
4374 } else {
4375 (0..total).map(|idx| idx % data_len).collect()
4376 };
4377
4378 let mat_vec = data_inner.select_indices(&indices);
4379 let mut rv = RVector::from(mat_vec);
4380 rv.set_attr(
4381 "class".to_string(),
4382 RValue::vec(Vector::Character(
4383 vec![Some("matrix".to_string()), Some("array".to_string())].into(),
4384 )),
4385 );
4386 rv.set_attr(
4387 "dim".to_string(),
4388 RValue::vec(Vector::Integer(
4389 vec![Some(i64::try_from(nrow)?), Some(i64::try_from(ncol)?)].into(),
4390 )),
4391 );
4392 if let Some(dimnames) = dimnames {
4393 if !dimnames.is_null() {
4394 rv.set_attr("dimnames".to_string(), dimnames.clone());
4395 }
4396 }
4397 Ok(RValue::Vector(rv))
4398}
4399
4400#[builtin(min_args = 1)]
4405fn builtin_dim(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
4406 match args.first() {
4407 Some(RValue::Vector(rv)) => Ok(rv.get_attr("dim").cloned().unwrap_or(RValue::Null)),
4408 Some(value @ RValue::List(l)) if has_class(value, "data.frame") => {
4409 Ok(RValue::vec(Vector::Integer(
4410 vec![
4411 Some(i64::try_from(data_frame_row_count(l))?),
4412 Some(i64::try_from(l.values.len())?),
4413 ]
4414 .into(),
4415 )))
4416 }
4417 Some(RValue::List(l)) => Ok(l.get_attr("dim").cloned().unwrap_or(RValue::Null)),
4418 _ => Ok(RValue::Null),
4419 }
4420}
4421
4422#[builtin(name = "dim<-", min_args = 2)]
4428fn builtin_dim_set(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
4429 let dim_val = args.get(1).cloned().unwrap_or(RValue::Null);
4430 match args.first() {
4431 Some(RValue::Vector(rv)) => {
4432 let mut rv = rv.clone();
4433 if dim_val.is_null() {
4434 rv.attrs.as_mut().map(|a| a.shift_remove("dim"));
4435 rv.attrs.as_mut().map(|a| a.shift_remove("class"));
4436 } else {
4437 rv.set_attr("dim".to_string(), dim_val);
4438 rv.set_attr(
4439 "class".to_string(),
4440 RValue::vec(Vector::Character(
4441 vec![Some("matrix".to_string()), Some("array".to_string())].into(),
4442 )),
4443 );
4444 }
4445 Ok(RValue::Vector(rv))
4446 }
4447 other => Ok(other.cloned().unwrap_or(RValue::Null)),
4448 }
4449}
4450
4451#[builtin(min_args = 1)]
4456fn builtin_nrow(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
4457 match args.first() {
4458 Some(RValue::Vector(rv)) => {
4459 if let Some(dims) = get_dim_ints(rv.get_attr("dim")) {
4460 if !dims.is_empty() {
4461 return Ok(RValue::vec(Vector::Integer(vec![dims[0]].into())));
4462 }
4463 }
4464 Ok(RValue::Null)
4465 }
4466 Some(RValue::List(l)) => {
4467 if let Some(dims) = get_dim_ints(l.get_attr("dim")) {
4468 if !dims.is_empty() {
4469 return Ok(RValue::vec(Vector::Integer(vec![dims[0]].into())));
4470 }
4471 }
4472 if has_class(&args[0], "data.frame") {
4473 if let Some(rn) = l.get_attr("row.names") {
4474 return Ok(RValue::vec(Vector::Integer(
4475 vec![Some(i64::try_from(rn.length())?)].into(),
4476 )));
4477 }
4478 let n = l.values.first().map(|(_, v)| v.length()).unwrap_or(0);
4480 return Ok(RValue::vec(Vector::Integer(
4481 vec![Some(i64::try_from(n)?)].into(),
4482 )));
4483 }
4484 Ok(RValue::Null)
4485 }
4486 _ => Ok(RValue::Null),
4487 }
4488}
4489
4490#[builtin(min_args = 1)]
4495fn builtin_ncol(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
4496 match args.first() {
4497 Some(RValue::Vector(rv)) => {
4498 if let Some(dims) = get_dim_ints(rv.get_attr("dim")) {
4499 if dims.len() >= 2 {
4500 return Ok(RValue::vec(Vector::Integer(vec![dims[1]].into())));
4501 }
4502 }
4503 Ok(RValue::Null)
4504 }
4505 Some(RValue::List(l)) => {
4506 if let Some(dims) = get_dim_ints(l.get_attr("dim")) {
4507 if dims.len() >= 2 {
4508 return Ok(RValue::vec(Vector::Integer(vec![dims[1]].into())));
4509 }
4510 }
4511 if has_class(
4512 args.first().expect("min_args = 1 guarantees first arg"),
4513 "data.frame",
4514 ) {
4515 return Ok(RValue::vec(Vector::Integer(
4516 vec![Some(i64::try_from(l.values.len())?)].into(),
4517 )));
4518 }
4519 Ok(RValue::Null)
4520 }
4521 _ => Ok(RValue::Null),
4522 }
4523}
4524
4525#[builtin(name = "NROW", min_args = 1)]
4532fn builtin_nrow_safe(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
4533 match args.first() {
4534 Some(RValue::Vector(rv)) => {
4535 if let Some(dims) = get_dim_ints(rv.get_attr("dim")) {
4536 if !dims.is_empty() {
4537 return Ok(RValue::vec(Vector::Integer(vec![dims[0]].into())));
4538 }
4539 }
4540 Ok(RValue::vec(Vector::Integer(
4541 vec![Some(i64::try_from(rv.len())?)].into(),
4542 )))
4543 }
4544 Some(RValue::List(l)) => {
4545 if let Some(dims) = get_dim_ints(l.get_attr("dim")) {
4546 if !dims.is_empty() {
4547 return Ok(RValue::vec(Vector::Integer(vec![dims[0]].into())));
4548 }
4549 }
4550 if has_class(
4552 args.first().expect("min_args = 1 guarantees first arg"),
4553 "data.frame",
4554 ) {
4555 if let Some(rn) = l.get_attr("row.names") {
4556 return Ok(RValue::vec(Vector::Integer(
4557 vec![Some(i64::try_from(rn.length())?)].into(),
4558 )));
4559 }
4560 let n = l.values.first().map(|(_, v)| v.length()).unwrap_or(0);
4561 return Ok(RValue::vec(Vector::Integer(
4562 vec![Some(i64::try_from(n)?)].into(),
4563 )));
4564 }
4565 Ok(RValue::vec(Vector::Integer(
4566 vec![Some(i64::try_from(l.values.len())?)].into(),
4567 )))
4568 }
4569 Some(RValue::Null) => Ok(RValue::vec(Vector::Integer(vec![Some(0)].into()))),
4570 _ => Ok(RValue::vec(Vector::Integer(vec![Some(1)].into()))),
4571 }
4572}
4573
4574#[builtin(name = "NCOL", min_args = 1)]
4581fn builtin_ncol_safe(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
4582 match args.first() {
4583 Some(RValue::Vector(rv)) => {
4584 if let Some(dims) = get_dim_ints(rv.get_attr("dim")) {
4585 if dims.len() >= 2 {
4586 return Ok(RValue::vec(Vector::Integer(vec![dims[1]].into())));
4587 }
4588 }
4589 Ok(RValue::vec(Vector::Integer(vec![Some(1)].into())))
4590 }
4591 Some(RValue::List(l)) => {
4592 if let Some(dims) = get_dim_ints(l.get_attr("dim")) {
4593 if dims.len() >= 2 {
4594 return Ok(RValue::vec(Vector::Integer(vec![dims[1]].into())));
4595 }
4596 }
4597 if has_class(
4598 args.first().expect("min_args = 1 guarantees first arg"),
4599 "data.frame",
4600 ) {
4601 return Ok(RValue::vec(Vector::Integer(
4602 vec![Some(i64::try_from(l.values.len())?)].into(),
4603 )));
4604 }
4605 Ok(RValue::vec(Vector::Integer(vec![Some(1)].into())))
4606 }
4607 Some(RValue::Null) => Ok(RValue::vec(Vector::Integer(vec![Some(0)].into()))),
4608 _ => Ok(RValue::vec(Vector::Integer(vec![Some(1)].into()))),
4609 }
4610}
4611
4612#[builtin(min_args = 1)]
4619fn builtin_unname(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
4620 match args.first() {
4621 Some(RValue::Vector(rv)) => {
4622 let mut rv = rv.clone();
4623 rv.attrs.as_mut().map(|a| a.shift_remove("names"));
4624 rv.attrs.as_mut().map(|a| a.shift_remove("dimnames"));
4625 Ok(RValue::Vector(rv))
4626 }
4627 Some(RValue::List(l)) => {
4628 let mut l = l.clone();
4629 for entry in &mut l.values {
4630 entry.0 = None;
4631 }
4632 l.attrs.as_mut().map(|a| a.shift_remove("names"));
4633 l.attrs.as_mut().map(|a| a.shift_remove("dimnames"));
4634 Ok(RValue::List(l))
4635 }
4636 other => Ok(other.cloned().unwrap_or(RValue::Null)),
4637 }
4638}
4639
4640#[builtin(min_args = 1)]
4645fn builtin_dimnames(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
4646 match args.first() {
4647 Some(value @ RValue::List(list)) if has_class(value, "data.frame") => {
4648 data_frame_dimnames_value(list)
4649 }
4650 Some(RValue::Vector(rv)) => Ok(rv.get_attr("dimnames").cloned().unwrap_or(RValue::Null)),
4651 Some(RValue::List(l)) => Ok(l.get_attr("dimnames").cloned().unwrap_or(RValue::Null)),
4652 _ => Ok(RValue::Null),
4653 }
4654}
4655
4656#[builtin(name = "dimnames<-", min_args = 2)]
4662fn builtin_dimnames_set(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
4663 let dimnames_val = args.get(1).cloned().unwrap_or(RValue::Null);
4664 match args.first() {
4665 Some(RValue::Vector(rv)) => {
4666 let mut rv = rv.clone();
4667 if dimnames_val.is_null() {
4668 rv.attrs.as_mut().map(|a| a.shift_remove("dimnames"));
4669 } else {
4670 rv.set_attr("dimnames".to_string(), dimnames_val);
4671 }
4672 Ok(RValue::Vector(rv))
4673 }
4674 Some(value @ RValue::List(l)) if has_class(value, "data.frame") => {
4675 let mut l = l.clone();
4676 set_data_frame_dimnames(&mut l, &dimnames_val)?;
4677 Ok(RValue::List(l))
4678 }
4679 Some(RValue::List(l)) => {
4680 let mut l = l.clone();
4681 if dimnames_val.is_null() {
4682 l.attrs.as_mut().map(|a| a.shift_remove("dimnames"));
4683 } else {
4684 l.set_attr("dimnames".to_string(), dimnames_val);
4685 }
4686 Ok(RValue::List(l))
4687 }
4688 other => Ok(other.cloned().unwrap_or(RValue::Null)),
4689 }
4690}
4691
4692#[builtin]
4699fn builtin_array(args: &[RValue], named: &[(String, RValue)]) -> Result<RValue, RError> {
4700 let data = args
4702 .first()
4703 .cloned()
4704 .unwrap_or(RValue::vec(Vector::Logical(vec![None].into())));
4705 let dim_arg = named
4706 .iter()
4707 .find(|(n, _)| n == "dim")
4708 .map(|(_, v)| v)
4709 .or(args.get(1));
4710 let dimnames_arg = named
4711 .iter()
4712 .find(|(n, _)| n == "dimnames")
4713 .map(|(_, v)| v)
4714 .or(args.get(2));
4715
4716 let data_vec = match &data {
4717 RValue::Vector(v) => v.to_doubles(),
4718 RValue::Null => vec![],
4719 _ => vec![Some(f64::NAN)],
4720 };
4721
4722 let dims: Vec<usize> = match dim_arg {
4724 Some(val) => {
4725 let ints = match val.as_vector() {
4726 Some(v) => v.to_integers(),
4727 None => {
4728 return Err(RError::new(
4729 RErrorKind::Argument,
4730 "'dim' must be a numeric vector".to_string(),
4731 ))
4732 }
4733 };
4734 ints.iter()
4735 .map(|x| usize::try_from(x.unwrap_or(0)))
4736 .collect::<Result<Vec<_>, _>>()?
4737 }
4738 None => vec![data_vec.len()],
4739 };
4740
4741 let total: usize = dims.iter().product();
4743
4744 let mut mat = Vec::with_capacity(total);
4746 if data_vec.is_empty() {
4747 mat.resize(total, None);
4748 } else {
4749 for i in 0..total {
4750 mat.push(data_vec[i % data_vec.len()]);
4751 }
4752 }
4753
4754 let mut rv = RVector::from(Vector::Double(mat.into()));
4755
4756 if dims.len() == 2 {
4758 rv.set_attr(
4759 "class".to_string(),
4760 RValue::vec(Vector::Character(
4761 vec![Some("matrix".to_string()), Some("array".to_string())].into(),
4762 )),
4763 );
4764 } else {
4765 rv.set_attr(
4766 "class".to_string(),
4767 RValue::vec(Vector::Character(vec![Some("array".to_string())].into())),
4768 );
4769 }
4770
4771 rv.set_attr(
4773 "dim".to_string(),
4774 RValue::vec(Vector::Integer(
4775 dims.iter()
4776 .map(|&d| i64::try_from(d).map(Some))
4777 .collect::<Result<Vec<_>, _>>()?
4778 .into(),
4779 )),
4780 );
4781
4782 if let Some(dn) = dimnames_arg {
4784 if !dn.is_null() {
4785 rv.set_attr("dimnames".to_string(), dn.clone());
4786 }
4787 }
4788
4789 Ok(RValue::Vector(rv))
4790}
4791
4792#[builtin(min_args = 1)]
4803fn builtin_aperm(args: &[RValue], named: &[(String, RValue)]) -> Result<RValue, RError> {
4804 let x = args.first().ok_or_else(|| {
4805 RError::new(
4806 RErrorKind::Argument,
4807 "aperm() requires an array argument".to_string(),
4808 )
4809 })?;
4810
4811 let rv = match x {
4812 RValue::Vector(rv) => rv,
4813 _ => {
4814 return Err(RError::new(
4815 RErrorKind::Type,
4816 "aperm() requires an array (a vector with dim attribute)".to_string(),
4817 ))
4818 }
4819 };
4820
4821 let dims: Vec<usize> = match get_dim_ints(rv.get_attr("dim")) {
4823 Some(dim_ints) => dim_ints
4824 .iter()
4825 .map(|x| usize::try_from(x.unwrap_or(0)))
4826 .collect::<Result<Vec<_>, _>>()?,
4827 None => {
4828 return Err(RError::new(
4829 RErrorKind::Argument,
4830 "aperm() requires an array with a 'dim' attribute".to_string(),
4831 ))
4832 }
4833 };
4834
4835 let ndim = dims.len();
4836
4837 let perm_arg = named
4839 .iter()
4840 .find(|(n, _)| n == "perm")
4841 .map(|(_, v)| v)
4842 .or(args.get(1));
4843
4844 let perm: Vec<usize> = match perm_arg {
4846 Some(val) => {
4847 let ints = match val.as_vector() {
4848 Some(v) => v.to_integers(),
4849 None => {
4850 return Err(RError::new(
4851 RErrorKind::Argument,
4852 "'perm' must be a numeric vector".to_string(),
4853 ))
4854 }
4855 };
4856 if ints.len() != ndim {
4857 return Err(RError::new(
4858 RErrorKind::Argument,
4859 format!(
4860 "'perm' must have length {} (matching the number of dimensions), got {}",
4861 ndim,
4862 ints.len()
4863 ),
4864 ));
4865 }
4866 let mut p = Vec::with_capacity(ndim);
4867 for &v in &ints {
4868 let idx = usize::try_from(v.unwrap_or(0))?;
4869 if idx < 1 || idx > ndim {
4870 return Err(RError::new(
4871 RErrorKind::Argument,
4872 format!("perm values must be between 1 and {}, got {}", ndim, idx),
4873 ));
4874 }
4875 p.push(idx - 1);
4876 }
4877 p
4878 }
4879 None => {
4880 (0..ndim).rev().collect()
4882 }
4883 };
4884
4885 let mut seen = vec![false; ndim];
4887 for &p in &perm {
4888 if seen[p] {
4889 return Err(RError::new(
4890 RErrorKind::Argument,
4891 "perm must be a permutation of 1:n where n is the number of dimensions".to_string(),
4892 ));
4893 }
4894 seen[p] = true;
4895 }
4896
4897 let total: usize = dims.iter().product();
4898 let data = rv.to_doubles();
4899
4900 let new_dims: Vec<usize> = perm.iter().map(|&p| dims[p]).collect();
4902
4903 let mut old_strides = vec![1usize; ndim];
4905 for d in 1..ndim {
4906 old_strides[d] = old_strides[d - 1] * dims[d - 1];
4907 }
4908
4909 let mut new_strides = vec![1usize; ndim];
4911 for d in 1..ndim {
4912 new_strides[d] = new_strides[d - 1] * new_dims[d - 1];
4913 }
4914
4915 let mut result = vec![None; total];
4918 for (new_flat, slot) in result.iter_mut().enumerate() {
4919 let mut remainder = new_flat;
4921 let mut new_idx = vec![0usize; ndim];
4922 for d in (0..ndim).rev() {
4923 new_idx[d] = remainder / new_strides[d];
4924 remainder %= new_strides[d];
4925 }
4926
4927 let mut old_flat = 0;
4929 for d in 0..ndim {
4930 old_flat += new_idx[d] * old_strides[perm[d]];
4931 }
4932
4933 *slot = data[old_flat];
4934 }
4935
4936 let mut out = RVector::from(Vector::Double(result.into()));
4937
4938 out.set_attr(
4940 "dim".to_string(),
4941 RValue::vec(Vector::Integer(
4942 new_dims
4943 .iter()
4944 .map(|&d| i64::try_from(d).map(Some))
4945 .collect::<Result<Vec<_>, _>>()?
4946 .into(),
4947 )),
4948 );
4949
4950 if new_dims.len() == 2 {
4952 out.set_attr(
4953 "class".to_string(),
4954 RValue::vec(Vector::Character(
4955 vec![Some("matrix".to_string()), Some("array".to_string())].into(),
4956 )),
4957 );
4958 } else {
4959 out.set_attr(
4960 "class".to_string(),
4961 RValue::vec(Vector::Character(vec![Some("array".to_string())].into())),
4962 );
4963 }
4964
4965 if let Some(RValue::List(dimnames_list)) = rv.get_attr("dimnames") {
4967 let mut new_dimnames_vals = Vec::with_capacity(ndim);
4968 for &p in &perm {
4969 if p < dimnames_list.values.len() {
4970 new_dimnames_vals.push(dimnames_list.values[p].clone());
4971 } else {
4972 new_dimnames_vals.push((None, RValue::Null));
4973 }
4974 }
4975 out.set_attr(
4976 "dimnames".to_string(),
4977 RValue::List(RList::new(new_dimnames_vals)),
4978 );
4979 }
4980
4981 Ok(RValue::Vector(out))
4982}
4983
4984#[builtin(min_args = 1)]
4992fn builtin_rbind(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
4993 if args.is_empty() {
4994 return Ok(RValue::Null);
4995 }
4996
4997 let has_df = args
4999 .iter()
5000 .any(|a| matches!(a, RValue::List(_)) && has_class(a, "data.frame"));
5001 if has_df {
5002 return rbind_data_frames(args);
5003 }
5004
5005 let mut inputs = Vec::new();
5006 for arg in args {
5007 match arg {
5008 RValue::Vector(rv) => {
5009 let data = rv.to_doubles();
5010 if let Some(dims) = get_dim_ints(rv.get_attr("dim")) {
5011 if dims.len() >= 2 {
5012 let nr = usize::try_from(dims[0].unwrap_or(0))?;
5013 let nc = usize::try_from(dims[1].unwrap_or(0))?;
5014 inputs.push(BindInput {
5015 data,
5016 nrow: nr,
5017 ncol: nc,
5018 row_names: dimnames_component(rv.get_attr("dimnames"), 0),
5019 col_names: dimnames_component(rv.get_attr("dimnames"), 1),
5020 });
5021 continue;
5022 }
5023 }
5024 let len = data.len();
5026 inputs.push(BindInput {
5027 data,
5028 nrow: 1,
5029 ncol: len,
5030 row_names: None,
5031 col_names: rv.get_attr("names").and_then(coerce_name_values),
5032 });
5033 }
5034 RValue::Null => continue,
5035 _ => {
5036 return Err(RError::new(
5037 RErrorKind::Argument,
5038 "cannot rbind non-vector/matrix arguments".to_string(),
5039 ))
5040 }
5041 }
5042 }
5043
5044 if inputs.is_empty() {
5045 return Ok(RValue::Null);
5046 }
5047
5048 let max_ncol = inputs.iter().map(|input| input.ncol).max().unwrap_or(0);
5050 if max_ncol == 0 {
5051 return Ok(RValue::Null);
5052 }
5053
5054 for input in &inputs {
5056 if input.ncol != max_ncol && max_ncol % input.ncol != 0 && input.ncol % max_ncol != 0 {
5057 return Err(RError::new(
5058 RErrorKind::Argument,
5059 "number of columns of arguments do not match".to_string(),
5060 ));
5061 }
5062 }
5063
5064 let total_nrow: usize = inputs.iter().map(|input| input.nrow).sum();
5066
5067 let mut result = Vec::with_capacity(total_nrow * max_ncol);
5069 for j in 0..max_ncol {
5070 for input in &inputs {
5071 let actual_j = j % input.ncol;
5072 for i in 0..input.nrow {
5073 let idx = actual_j * input.nrow + i;
5075 result.push(if idx < input.data.len() {
5076 input.data[idx]
5077 } else {
5078 None
5079 });
5080 }
5081 }
5082 }
5083
5084 let mut row_names = Vec::new();
5085 let has_any_row_names = inputs.iter().any(|input| input.row_names.is_some());
5086 if has_any_row_names {
5087 for input in &inputs {
5088 if let Some(names) = &input.row_names {
5089 row_names.extend(
5090 (0..input.nrow)
5091 .map(|idx| names.get(idx).cloned().unwrap_or(None))
5092 .collect::<Vec<_>>(),
5093 );
5094 } else {
5095 row_names.extend(std::iter::repeat_n(None, input.nrow));
5096 }
5097 }
5098 }
5099
5100 let mut col_names = Vec::new();
5101 if let Some(source_names) = inputs.iter().find_map(|input| input.col_names.clone()) {
5102 col_names.extend(
5103 (0..max_ncol)
5104 .map(|idx| {
5105 source_names
5106 .get(idx % source_names.len())
5107 .cloned()
5108 .unwrap_or(None)
5109 })
5110 .collect::<Vec<_>>(),
5111 );
5112 }
5113
5114 let mut rv = RVector::from(Vector::Double(result.into()));
5115 rv.set_attr(
5116 "class".to_string(),
5117 RValue::vec(Vector::Character(
5118 vec![Some("matrix".to_string()), Some("array".to_string())].into(),
5119 )),
5120 );
5121 rv.set_attr(
5122 "dim".to_string(),
5123 RValue::vec(Vector::Integer(
5124 vec![
5125 Some(i64::try_from(total_nrow)?),
5126 Some(i64::try_from(max_ncol)?),
5127 ]
5128 .into(),
5129 )),
5130 );
5131 if let Some(dimnames) = bind_dimnames_value(row_names, col_names) {
5132 rv.set_attr("dimnames".to_string(), dimnames);
5133 }
5134 Ok(RValue::Vector(rv))
5135}
5136
5137fn rbind_data_frames(args: &[RValue]) -> Result<RValue, RError> {
5139 let mut all_col_names: Vec<String> = Vec::new();
5141 let mut seen = std::collections::HashSet::new();
5142 let mut dfs: Vec<&RList> = Vec::new();
5143
5144 for arg in args {
5145 match arg {
5146 RValue::List(list) if has_class(arg, "data.frame") => {
5147 let names = dataframes::df_col_names(list);
5148 for name in names.into_iter().flatten() {
5149 if seen.insert(name.clone()) {
5150 all_col_names.push(name);
5151 }
5152 }
5153 dfs.push(list);
5154 }
5155 RValue::Null => continue,
5156 _ => {
5157 return Err(RError::new(
5158 RErrorKind::Argument,
5159 "rbind() with data frames requires all arguments to be data frames".to_string(),
5160 ))
5161 }
5162 }
5163 }
5164
5165 if dfs.is_empty() {
5166 return Ok(RValue::Null);
5167 }
5168
5169 let total_nrow: usize = dfs.iter().map(|df| dataframes::df_nrow(df)).sum();
5170
5171 let mut output_columns: Vec<(Option<String>, RValue)> = Vec::new();
5173 for col_name in &all_col_names {
5174 let mut parts: Vec<RValue> = Vec::new();
5175 for df in &dfs {
5176 let col_idx = dataframes::df_col_index(df, col_name);
5177 let nrow = dataframes::df_nrow(df);
5178 if let Some(idx) = col_idx {
5179 parts.push(df.values[idx].1.clone());
5180 } else {
5181 parts.push(RValue::vec(Vector::Logical(vec![None; nrow].into())));
5183 }
5184 }
5185 let combined = concat_column_values(&parts)?;
5186 output_columns.push((Some(col_name.clone()), combined));
5187 }
5188
5189 dataframes::build_data_frame(output_columns, total_nrow)
5190}
5191
5192fn concat_column_values(parts: &[RValue]) -> Result<RValue, RError> {
5194 let mut has_character = false;
5196 let mut has_double = false;
5197 let mut has_integer = false;
5198 let mut has_logical = false;
5199
5200 for part in parts {
5201 if let RValue::Vector(rv) = part {
5202 match &rv.inner {
5203 Vector::Character(_) => has_character = true,
5204 Vector::Double(_) => has_double = true,
5205 Vector::Integer(_) => has_integer = true,
5206 Vector::Logical(_) => has_logical = true,
5207 _ => {}
5208 }
5209 }
5210 }
5211
5212 if has_character {
5213 let mut result: Vec<Option<String>> = Vec::new();
5214 for part in parts {
5215 if let RValue::Vector(rv) = part {
5216 result.extend(rv.inner.to_characters());
5217 }
5218 }
5219 Ok(RValue::vec(Vector::Character(result.into())))
5220 } else if has_double {
5221 let mut result: Vec<Option<f64>> = Vec::new();
5222 for part in parts {
5223 if let RValue::Vector(rv) = part {
5224 result.extend(rv.to_doubles());
5225 }
5226 }
5227 Ok(RValue::vec(Vector::Double(result.into())))
5228 } else if has_integer {
5229 let mut result: Vec<Option<i64>> = Vec::new();
5230 for part in parts {
5231 if let RValue::Vector(rv) = part {
5232 result.extend(rv.inner.to_integers());
5233 }
5234 }
5235 Ok(RValue::vec(Vector::Integer(result.into())))
5236 } else if has_logical {
5237 let mut result: Vec<Option<bool>> = Vec::new();
5238 for part in parts {
5239 if let RValue::Vector(rv) = part {
5240 result.extend(rv.inner.to_logicals());
5241 }
5242 }
5243 Ok(RValue::vec(Vector::Logical(result.into())))
5244 } else {
5245 Ok(RValue::Null)
5246 }
5247}
5248
5249#[builtin(min_args = 1)]
5257fn builtin_cbind(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
5258 if args.is_empty() {
5259 return Ok(RValue::Null);
5260 }
5261
5262 let has_df = args
5264 .iter()
5265 .any(|a| matches!(a, RValue::List(_)) && has_class(a, "data.frame"));
5266 if has_df {
5267 return cbind_data_frames(args);
5268 }
5269
5270 let mut inputs = Vec::new();
5271 for arg in args {
5272 match arg {
5273 RValue::Vector(rv) => {
5274 let data = rv.to_doubles();
5275 if let Some(dims) = get_dim_ints(rv.get_attr("dim")) {
5276 if dims.len() >= 2 {
5277 let nr = usize::try_from(dims[0].unwrap_or(0))?;
5278 let nc = usize::try_from(dims[1].unwrap_or(0))?;
5279 inputs.push(BindInput {
5280 data,
5281 nrow: nr,
5282 ncol: nc,
5283 row_names: dimnames_component(rv.get_attr("dimnames"), 0),
5284 col_names: dimnames_component(rv.get_attr("dimnames"), 1),
5285 });
5286 continue;
5287 }
5288 }
5289 let len = data.len();
5291 inputs.push(BindInput {
5292 data,
5293 nrow: len,
5294 ncol: 1,
5295 row_names: rv.get_attr("names").and_then(coerce_name_values),
5296 col_names: None,
5297 });
5298 }
5299 RValue::Null => continue,
5300 _ => {
5301 return Err(RError::new(
5302 RErrorKind::Argument,
5303 "cannot cbind non-vector/matrix arguments".to_string(),
5304 ))
5305 }
5306 }
5307 }
5308
5309 if inputs.is_empty() {
5310 return Ok(RValue::Null);
5311 }
5312
5313 let max_nrow = inputs.iter().map(|input| input.nrow).max().unwrap_or(0);
5315 if max_nrow == 0 {
5316 return Ok(RValue::Null);
5317 }
5318
5319 for input in &inputs {
5321 if input.nrow != max_nrow && max_nrow % input.nrow != 0 && input.nrow % max_nrow != 0 {
5322 return Err(RError::new(
5323 RErrorKind::Argument,
5324 "number of rows of arguments do not match".to_string(),
5325 ));
5326 }
5327 }
5328
5329 let total_ncol: usize = inputs.iter().map(|input| input.ncol).sum();
5331
5332 let mut result = Vec::with_capacity(max_nrow * total_ncol);
5334 for input in &inputs {
5335 for j in 0..input.ncol {
5336 for i in 0..max_nrow {
5337 let actual_i = i % input.nrow;
5339 let idx = j * input.nrow + actual_i;
5340 result.push(if idx < input.data.len() {
5341 input.data[idx]
5342 } else {
5343 None
5344 });
5345 }
5346 }
5347 }
5348
5349 let row_names =
5350 if let Some(source_names) = inputs.iter().find_map(|input| input.row_names.clone()) {
5351 (0..max_nrow)
5352 .map(|idx| {
5353 source_names
5354 .get(idx % source_names.len())
5355 .cloned()
5356 .unwrap_or(None)
5357 })
5358 .collect::<Vec<_>>()
5359 } else {
5360 Vec::new()
5361 };
5362
5363 let has_any_col_names = inputs.iter().any(|input| input.col_names.is_some());
5364 let mut col_names = Vec::new();
5365 if has_any_col_names {
5366 for input in &inputs {
5367 if let Some(names) = &input.col_names {
5368 col_names.extend(
5369 (0..input.ncol)
5370 .map(|idx| names.get(idx).cloned().unwrap_or(None))
5371 .collect::<Vec<_>>(),
5372 );
5373 } else {
5374 col_names.extend(std::iter::repeat_n(None, input.ncol));
5375 }
5376 }
5377 }
5378
5379 let mut rv = RVector::from(Vector::Double(result.into()));
5380 rv.set_attr(
5381 "class".to_string(),
5382 RValue::vec(Vector::Character(
5383 vec![Some("matrix".to_string()), Some("array".to_string())].into(),
5384 )),
5385 );
5386 rv.set_attr(
5387 "dim".to_string(),
5388 RValue::vec(Vector::Integer(
5389 vec![
5390 Some(i64::try_from(max_nrow)?),
5391 Some(i64::try_from(total_ncol)?),
5392 ]
5393 .into(),
5394 )),
5395 );
5396 if let Some(dimnames) = bind_dimnames_value(row_names, col_names) {
5397 rv.set_attr("dimnames".to_string(), dimnames);
5398 }
5399 Ok(RValue::Vector(rv))
5400}
5401
5402fn cbind_data_frames(args: &[RValue]) -> Result<RValue, RError> {
5404 let mut output_columns: Vec<(Option<String>, RValue)> = Vec::new();
5405 let mut target_nrow: Option<usize> = None;
5406
5407 for arg in args {
5408 match arg {
5409 RValue::List(list) if has_class(arg, "data.frame") => {
5410 let nrow = dataframes::df_nrow(list);
5411 if let Some(expected) = target_nrow {
5412 if nrow != expected {
5413 return Err(RError::new(
5414 RErrorKind::Argument,
5415 format!(
5416 "cbind() arguments have different row counts: {} vs {}",
5417 expected, nrow
5418 ),
5419 ));
5420 }
5421 } else {
5422 target_nrow = Some(nrow);
5423 }
5424 for (name, val) in &list.values {
5425 output_columns.push((name.clone(), val.clone()));
5426 }
5427 }
5428 RValue::Vector(rv) => {
5429 let len = rv.inner.len();
5430 if let Some(expected) = target_nrow {
5431 if len != expected && len != 1 {
5432 return Err(RError::new(
5433 RErrorKind::Argument,
5434 format!(
5435 "cbind() arguments have different row counts: {} vs {}",
5436 expected, len
5437 ),
5438 ));
5439 }
5440 } else {
5441 target_nrow = Some(len);
5442 }
5443 let col_name = rv
5445 .get_attr("names")
5446 .and_then(|v| v.as_vector()?.as_character_scalar());
5447 output_columns.push((col_name, RValue::Vector(rv.clone())));
5448 }
5449 RValue::Null => continue,
5450 _ => {
5451 return Err(RError::new(
5452 RErrorKind::Argument,
5453 "cbind() requires data frames or vectors".to_string(),
5454 ))
5455 }
5456 }
5457 }
5458
5459 let nrow = target_nrow.unwrap_or(0);
5460 dataframes::build_data_frame(output_columns, nrow)
5461}
5462
5463#[builtin(min_args = 2)]
5469fn builtin_attr(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
5470 let which = args
5471 .get(1)
5472 .and_then(|v| v.as_vector())
5473 .and_then(|v| v.as_character_scalar())
5474 .ok_or_else(|| {
5475 RError::new(
5476 RErrorKind::Argument,
5477 "'which' must be a character string".to_string(),
5478 )
5479 })?;
5480 match args.first() {
5481 Some(RValue::Vector(rv)) => Ok(rv.get_attr(&which).cloned().unwrap_or(RValue::Null)),
5482 Some(RValue::List(l)) => Ok(l.get_attr(&which).cloned().unwrap_or(RValue::Null)),
5483 Some(RValue::Language(lang)) => Ok(lang.get_attr(&which).cloned().unwrap_or(RValue::Null)),
5484 _ => Ok(RValue::Null),
5485 }
5486}
5487
5488#[builtin(name = "attr<-", min_args = 3)]
5495fn builtin_attr_set(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
5496 let which = args
5497 .get(1)
5498 .and_then(|v| v.as_vector())
5499 .and_then(|v| v.as_character_scalar())
5500 .ok_or_else(|| {
5501 RError::new(
5502 RErrorKind::Argument,
5503 "'which' must be a character string".to_string(),
5504 )
5505 })?;
5506 let value = args.get(2).cloned().unwrap_or(RValue::Null);
5507 match args.first() {
5508 Some(RValue::Vector(rv)) => {
5509 let mut rv = rv.clone();
5510 if value.is_null() {
5511 rv.attrs.as_mut().map(|a| a.shift_remove(&which));
5512 } else {
5513 rv.set_attr(which, value);
5514 }
5515 Ok(RValue::Vector(rv))
5516 }
5517 Some(RValue::List(l)) => {
5518 let mut l = l.clone();
5519 if value.is_null() {
5520 l.attrs.as_mut().map(|a| a.shift_remove(&which));
5521 } else {
5522 l.set_attr(which, value);
5523 }
5524 Ok(RValue::List(l))
5525 }
5526 Some(RValue::Language(lang)) => {
5527 let mut lang = lang.clone();
5528 if value.is_null() {
5529 lang.attrs.as_mut().map(|a| a.shift_remove(&which));
5530 } else {
5531 lang.set_attr(which, value);
5532 }
5533 Ok(RValue::Language(lang))
5534 }
5535 other => Ok(other.cloned().unwrap_or(RValue::Null)),
5536 }
5537}
5538
5539#[builtin(min_args = 1)]
5544fn builtin_attributes(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
5545 let attrs = match args.first() {
5546 Some(RValue::Vector(rv)) => rv.attrs.as_deref(),
5547 Some(RValue::List(l)) => l.attrs.as_deref(),
5548 Some(RValue::Language(lang)) => lang.attrs.as_deref(),
5549 _ => None,
5550 };
5551 match attrs {
5552 Some(a) if !a.is_empty() => {
5553 let values: Vec<(Option<String>, RValue)> = a
5554 .iter()
5555 .map(|(k, v)| (Some(k.clone()), v.clone()))
5556 .collect();
5557 Ok(RValue::List(RList::new(values)))
5558 }
5559 _ => Ok(RValue::Null),
5560 }
5561}
5562
5563#[builtin(min_args = 1)]
5572fn builtin_structure(args: &[RValue], named: &[(String, RValue)]) -> Result<RValue, RError> {
5573 let base = args.first().cloned().unwrap_or(RValue::Null);
5574 if named.is_empty() {
5575 return Ok(base);
5576 }
5577 match base {
5578 RValue::List(mut l) => {
5579 for (name, value) in named {
5580 if name == ".Names" || name == "names" {
5581 if let RValue::Vector(rv) = value {
5582 if let Vector::Character(names) = &rv.inner {
5583 for (i, n) in names.iter().enumerate() {
5584 if i < l.values.len() {
5585 l.values[i].0 = n.clone();
5586 }
5587 }
5588 }
5589 }
5590 } else {
5591 l.set_attr(name.clone(), value.clone());
5592 }
5593 }
5594 Ok(RValue::List(l))
5595 }
5596 RValue::Vector(mut rv) => {
5597 for (name, value) in named {
5598 if name == ".Names" || name == "names" {
5599 rv.set_attr("names".to_string(), value.clone());
5600 } else {
5601 rv.set_attr(name.clone(), value.clone());
5602 }
5603 }
5604 Ok(RValue::Vector(rv))
5605 }
5606 RValue::Language(mut lang) => {
5607 for (name, value) in named {
5608 lang.set_attr(name.clone(), value.clone());
5609 }
5610 Ok(RValue::Language(lang))
5611 }
5612 other => Ok(other),
5613 }
5614}
5615
5616#[builtin(min_args = 2)]
5624fn builtin_inherits(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
5625 let what = args
5626 .get(1)
5627 .and_then(|v| v.as_vector())
5628 .map(|v| v.to_characters())
5629 .unwrap_or_default();
5630
5631 let classes = match args.first() {
5632 Some(RValue::List(l)) => {
5633 if let Some(RValue::Vector(rv)) = l.get_attr("class") {
5634 if let Vector::Character(cls) = &rv.inner {
5635 cls.iter().filter_map(|s| s.clone()).collect::<Vec<_>>()
5636 } else {
5637 vec!["list".to_string()]
5638 }
5639 } else {
5640 vec!["list".to_string()]
5641 }
5642 }
5643 Some(RValue::Vector(rv)) => {
5644 if let Some(cls) = rv.class() {
5645 cls
5646 } else {
5647 match &rv.inner {
5648 Vector::Raw(_) => vec!["raw".to_string()],
5649 Vector::Logical(_) => vec!["logical".to_string()],
5650 Vector::Integer(_) => vec!["integer".to_string()],
5651 Vector::Double(_) => vec!["numeric".to_string()],
5652 Vector::Complex(_) => vec!["complex".to_string()],
5653 Vector::Character(_) => vec!["character".to_string()],
5654 }
5655 }
5656 }
5657 Some(RValue::Function(_)) => vec!["function".to_string()],
5658 Some(RValue::Language(lang)) => lang.class().unwrap_or_default(),
5659 _ => vec![],
5660 };
5661
5662 let result = what
5663 .iter()
5664 .any(|w| w.as_ref().is_some_and(|w| classes.iter().any(|c| c == w)));
5665 Ok(RValue::vec(Vector::Logical(vec![Some(result)].into())))
5666}
5667
5668pub(crate) fn get_dim_ints(dim_attr: Option<&RValue>) -> Option<Vec<Option<i64>>> {
5670 match dim_attr {
5671 Some(RValue::Vector(rv)) => match &rv.inner {
5672 Vector::Integer(dims) => Some(dims.iter_opt().collect()),
5673 _ => None,
5674 },
5675 _ => None,
5676 }
5677}
5678
5679pub(crate) fn has_class(val: &RValue, class_name: &str) -> bool {
5680 let class_attr = match val {
5681 RValue::Vector(rv) => rv.get_attr("class"),
5682 RValue::List(l) => l.get_attr("class"),
5683 RValue::Language(lang) => lang.get_attr("class"),
5684 _ => None,
5685 };
5686 if let Some(RValue::Vector(rv)) = class_attr {
5687 if let Vector::Character(cls) = &rv.inner {
5688 return cls.iter().any(|c| c.as_deref() == Some(class_name));
5689 }
5690 }
5691 false
5692}
5693
5694#[builtin(name = "new.env")]
5703fn builtin_new_env(args: &[RValue], named: &[(String, RValue)]) -> Result<RValue, RError> {
5704 let named_hash = named.iter().find(|(n, _)| n == "hash").map(|(_, v)| v);
5709 let named_parent = named.iter().find(|(n, _)| n == "parent").map(|(_, v)| v);
5710 let named_size = named.iter().find(|(n, _)| n == "size").map(|(_, v)| v);
5711
5712 let mut positional_iter = args.iter();
5714 let _hash_val = named_hash.or_else(|| positional_iter.next());
5715 let parent_val = named_parent.or_else(|| positional_iter.next());
5717 let _size_val = named_size.or_else(|| positional_iter.next());
5718 let parent = parent_val.and_then(|v| {
5721 if let RValue::Environment(e) = v {
5722 Some(e.clone())
5723 } else {
5724 None
5725 }
5726 });
5727 match parent {
5728 Some(p) => Ok(RValue::Environment(Environment::new_child(&p))),
5729 None => Ok(RValue::Environment(Environment::new_empty())),
5730 }
5731}
5732
5733#[builtin(name = "environmentName", min_args = 1)]
5738fn builtin_environment_name(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
5739 let name = match args.first() {
5740 Some(RValue::Environment(e)) => e.name().unwrap_or_default(),
5741 _ => String::new(),
5742 };
5743 Ok(RValue::vec(Vector::Character(vec![Some(name)].into())))
5744}
5745
5746#[builtin(name = "parent.env", min_args = 1)]
5751fn builtin_parent_env(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
5752 match args.first() {
5753 Some(RValue::Environment(e)) => match e.parent() {
5754 Some(p) => Ok(RValue::Environment(p)),
5755 None => Ok(RValue::Null),
5756 },
5757 _ => Err(RError::new(
5758 RErrorKind::Argument,
5759 "not an environment".to_string(),
5760 )),
5761 }
5762}
5763
5764#[builtin(name = "parent.env<-", min_args = 2)]
5773fn builtin_parent_env_set(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
5774 let env = match args.first() {
5775 Some(RValue::Environment(e)) => e.clone(),
5776 _ => {
5777 return Err(RError::new(
5778 RErrorKind::Argument,
5779 "not an environment".to_string(),
5780 ))
5781 }
5782 };
5783 let new_parent = match args.get(1) {
5784 Some(RValue::Environment(p)) => Some(p.clone()),
5785 Some(RValue::Null) => None,
5786 _ => {
5787 return Err(RError::new(
5788 RErrorKind::Argument,
5789 "'value' must be an environment or NULL".to_string(),
5790 ))
5791 }
5792 };
5793 env.set_parent(new_parent);
5794 Ok(RValue::Environment(env))
5795}
5796
5797#[builtin]
5805fn builtin_stopifnot(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
5806 for (i, arg) in args.iter().enumerate() {
5807 match arg {
5808 RValue::Vector(rv) if matches!(rv.inner, Vector::Logical(_)) => {
5809 let Vector::Logical(v) = &rv.inner else {
5810 unreachable!()
5811 };
5812 for (j, val) in v.iter().enumerate() {
5813 match val {
5814 Some(true) => {}
5815 Some(false) => {
5816 return Err(RError::other(format!(
5817 "not all are TRUE (element {} of argument {})",
5818 j + 1,
5819 i + 1
5820 )));
5821 }
5822 None => {
5823 return Err(RError::other(format!(
5824 "missing value where TRUE/FALSE needed (argument {})",
5825 i + 1
5826 )));
5827 }
5828 }
5829 }
5830 }
5831 RValue::Vector(v) => {
5832 if let Some(b) = v.as_logical_scalar() {
5833 if !b {
5834 return Err(RError::other(format!("argument {} is not TRUE", i + 1)));
5835 }
5836 }
5837 }
5838 _ => {
5839 return Err(RError::other(format!(
5840 "argument {} is not a logical value",
5841 i + 1
5842 )));
5843 }
5844 }
5845 }
5846 Ok(RValue::Null)
5847}
5848
5849#[builtin(min_args = 1)]
5854fn builtin_unclass(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
5855 match args.first() {
5856 Some(RValue::Vector(rv)) => {
5857 let mut rv = rv.clone();
5858 rv.attrs.as_mut().map(|a| a.shift_remove("class"));
5859 Ok(RValue::Vector(rv))
5860 }
5861 Some(RValue::List(l)) => {
5862 let mut l = l.clone();
5863 l.attrs.as_mut().map(|a| a.shift_remove("class"));
5864 Ok(RValue::List(l))
5865 }
5866 Some(RValue::Language(lang)) => {
5867 let mut lang = lang.clone();
5868 lang.attrs.as_mut().map(|a| a.shift_remove("class"));
5869 Ok(RValue::Language(lang))
5870 }
5871 other => Ok(other.cloned().unwrap_or(RValue::Null)),
5872 }
5873}
5874
5875#[builtin(name = "match.arg", min_args = 1)]
5887fn builtin_match_arg(args: &[RValue], named: &[(String, RValue)]) -> Result<RValue, RError> {
5888 let arg = args.first().cloned().unwrap_or(RValue::Null);
5889 let choices = args
5890 .get(1)
5891 .or_else(|| named.iter().find(|(n, _)| n == "choices").map(|(_, v)| v));
5892
5893 let several_ok = args
5894 .get(2)
5895 .or_else(|| {
5896 named
5897 .iter()
5898 .find(|(n, _)| n == "several.ok")
5899 .map(|(_, v)| v)
5900 })
5901 .and_then(|v| match v {
5902 RValue::Vector(rv) => rv.as_logical_scalar(),
5903 _ => None,
5904 })
5905 .unwrap_or(false);
5906
5907 let choices_vec = match choices {
5908 Some(RValue::Vector(rv)) if matches!(rv.inner, Vector::Character(_)) => {
5909 let Vector::Character(v) = &rv.inner else {
5910 unreachable!()
5911 };
5912 v.iter().filter_map(|s| s.clone()).collect::<Vec<_>>()
5913 }
5914 Some(RValue::Null) | None => {
5915 match &arg {
5922 RValue::Vector(rv) if matches!(rv.inner, Vector::Character(_)) => {
5923 let Vector::Character(v) = &rv.inner else {
5924 unreachable!()
5925 };
5926 let strings: Vec<String> =
5927 v.iter().filter_map(|s| s.clone()).collect::<Vec<_>>();
5928 if strings.len() > 1 && !several_ok {
5929 return Ok(RValue::vec(Vector::Character(
5931 vec![Some(strings[0].clone())].into(),
5932 )));
5933 } else if strings.len() == 1 {
5934 return Ok(arg);
5936 } else if strings.is_empty() {
5937 return Ok(arg);
5938 }
5939 return Ok(arg);
5941 }
5942 RValue::Null => {
5943 return Ok(RValue::Null);
5945 }
5946 _ => return Ok(arg),
5947 }
5948 }
5949 _ => return Ok(arg),
5950 };
5951
5952 if choices_vec.is_empty() {
5953 return Ok(arg);
5954 }
5955
5956 let arg_strings: Vec<Option<String>> = match &arg {
5958 RValue::Vector(rv) => match &rv.inner {
5959 Vector::Character(v) => v.iter().cloned().collect(),
5960 _ => vec![None],
5961 },
5962 RValue::Null => vec![],
5963 _ => vec![None],
5964 };
5965
5966 if arg_strings.is_empty() {
5968 return Ok(RValue::vec(Vector::Character(
5969 vec![Some(choices_vec[0].clone())].into(),
5970 )));
5971 }
5972
5973 if !several_ok && arg_strings.len() > 1 && arg_strings.len() == choices_vec.len() {
5975 let all_match = arg_strings
5976 .iter()
5977 .zip(choices_vec.iter())
5978 .all(|(a, c)| a.as_deref() == Some(c.as_str()));
5979 if all_match {
5980 return Ok(RValue::vec(Vector::Character(
5981 vec![Some(choices_vec[0].clone())].into(),
5982 )));
5983 }
5984 }
5985
5986 if !several_ok && arg_strings.len() > 1 {
5988 return Err(RError::new(
5989 RErrorKind::Argument,
5990 format!(
5991 "'arg' should be one of {}, not a vector of length {}",
5992 choices_vec.iter().map(|c| format!("'{c}'")).join(", "),
5993 arg_strings.len()
5994 ),
5995 ));
5996 }
5997
5998 let mut matched = Vec::with_capacity(arg_strings.len());
6000 for s_opt in &arg_strings {
6001 let s = match s_opt {
6002 Some(s) => s,
6003 None => {
6004 return Err(RError::new(
6005 RErrorKind::Argument,
6006 "'arg' should be one of the choices".to_string(),
6007 ))
6008 }
6009 };
6010
6011 if choices_vec.contains(s) {
6013 matched.push(Some(s.clone()));
6014 continue;
6015 }
6016 let partial: Vec<&String> = choices_vec
6018 .iter()
6019 .filter(|c| c.starts_with(s.as_str()))
6020 .collect();
6021 match partial.len() {
6022 1 => matched.push(Some(partial[0].clone())),
6023 0 => {
6024 return Err(RError::new(
6025 RErrorKind::Argument,
6026 format!(
6027 "'arg' should be one of {}",
6028 choices_vec.iter().map(|c| format!("'{c}'")).join(", ")
6029 ),
6030 ))
6031 }
6032 _ => {
6033 return Err(RError::new(
6034 RErrorKind::Argument,
6035 format!(
6036 "'arg' should be one of {}",
6037 choices_vec.iter().map(|c| format!("'{c}'")).join(", ")
6038 ),
6039 ))
6040 }
6041 }
6042 }
6043
6044 Ok(RValue::vec(Vector::Character(matched.into())))
6045}
6046
6047#[builtin(names = ["quit"])]
6051fn builtin_q(_args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
6052 std::process::exit(0);
6053}
6054
6055use crate::parser::ast::Expr;
6058
6059#[builtin(min_args = 1)]
6064fn builtin_formals(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
6065 match args.first() {
6066 Some(RValue::Function(RFunction::Closure { params, .. })) => {
6067 if params.is_empty() {
6068 return Ok(RValue::Null);
6069 }
6070 let entries: Vec<(Option<String>, RValue)> = params
6071 .iter()
6072 .map(|p| {
6073 let name = if p.is_dots {
6074 "...".to_string()
6075 } else {
6076 p.name.clone()
6077 };
6078 let value = match &p.default {
6079 Some(expr) => RValue::Language(Language::new(expr.clone())),
6080 None => RValue::Null,
6081 };
6082 (Some(name), value)
6083 })
6084 .collect();
6085 Ok(RValue::List(RList::new(entries)))
6086 }
6087 Some(RValue::Function(RFunction::Builtin { name, .. })) => {
6088 if let Some(descriptor) = find_builtin(name) {
6089 let param_names = extract_param_names_from_doc(descriptor.doc);
6090 if !param_names.is_empty() {
6091 let entries: Vec<(Option<String>, RValue)> = param_names
6092 .into_iter()
6093 .map(|n| (Some(n), RValue::Null))
6094 .collect();
6095 return Ok(RValue::List(RList::new(entries)));
6096 }
6097 }
6098 Ok(RValue::Null)
6099 }
6100 _ => Err(RError::new(
6101 RErrorKind::Argument,
6102 "'fn' is not a function — formals() requires a function argument".to_string(),
6103 )),
6104 }
6105}
6106
6107#[builtin(min_args = 1)]
6110fn builtin_body(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
6111 match args.first() {
6112 Some(RValue::Function(RFunction::Closure { body, .. })) => {
6113 Ok(RValue::Language(Language::new(body.clone())))
6114 }
6115 Some(RValue::Function(RFunction::Builtin { .. })) => Ok(RValue::Null),
6116 _ => Err(RError::new(
6117 RErrorKind::Argument,
6118 "'fn' is not a function — body() requires a function argument".to_string(),
6119 )),
6120 }
6121}
6122
6123#[builtin(name = "body<-", min_args = 2)]
6130fn builtin_body_set(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
6131 match args.first() {
6132 Some(RValue::Function(RFunction::Closure { params, env, .. })) => {
6133 let new_body = match args.get(1) {
6134 Some(RValue::Language(lang)) => (*lang.inner).clone(),
6135 Some(RValue::Null) => crate::parser::ast::Expr::Null,
6136 _ => crate::parser::ast::Expr::Null,
6137 };
6138 Ok(RValue::Function(RFunction::Closure {
6139 params: params.clone(),
6140 body: new_body,
6141 env: env.clone(),
6142 }))
6143 }
6144 _ => Err(RError::new(
6145 RErrorKind::Argument,
6146 "body<- requires a function".to_string(),
6147 )),
6148 }
6149}
6150
6151#[builtin(name = "formals<-", min_args = 2)]
6158fn builtin_formals_set(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
6159 match args.first() {
6160 Some(RValue::Function(RFunction::Closure { body, env, .. })) => {
6161 let new_params = match args.get(1) {
6162 Some(RValue::List(list)) => list
6163 .values
6164 .iter()
6165 .map(|(name, val)| {
6166 let param_name = name.clone().unwrap_or_default();
6167 let default = if matches!(val, RValue::Null) {
6168 None
6169 } else {
6170 None
6172 };
6173 crate::parser::ast::Param {
6174 name: param_name,
6175 default,
6176 is_dots: name.as_deref() == Some("..."),
6177 }
6178 })
6179 .collect(),
6180 _ => vec![],
6181 };
6182 Ok(RValue::Function(RFunction::Closure {
6183 params: new_params,
6184 body: body.clone(),
6185 env: env.clone(),
6186 }))
6187 }
6188 _ => Err(RError::new(
6189 RErrorKind::Argument,
6190 "formals<- requires a function".to_string(),
6191 )),
6192 }
6193}
6194
6195#[builtin(name = "environment<-", min_args = 2)]
6202fn builtin_environment_set(args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
6203 match args.first() {
6204 Some(RValue::Function(RFunction::Closure { params, body, .. })) => {
6205 let new_env = match args.get(1) {
6206 Some(RValue::Environment(e)) => e.clone(),
6207 _ => {
6208 return Err(RError::new(
6209 RErrorKind::Argument,
6210 "replacement environment must be an environment".to_string(),
6211 ))
6212 }
6213 };
6214 Ok(RValue::Function(RFunction::Closure {
6215 params: params.clone(),
6216 body: body.clone(),
6217 env: new_env,
6218 }))
6219 }
6220 _ => Err(RError::new(
6221 RErrorKind::Argument,
6222 "environment<- requires a function".to_string(),
6223 )),
6224 }
6225}
6226
6227#[builtin(min_args = 1)]
6231fn builtin_args(args: &[RValue], _named: &[(String, RValue)]) -> Result<RValue, RError> {
6232 let f = args
6235 .first()
6236 .ok_or_else(|| RError::new(RErrorKind::Argument, "args() requires a function argument"))?;
6237 match f {
6238 RValue::Function(func) => match func {
6239 RFunction::Closure { params, env, .. } => Ok(RValue::Function(RFunction::Closure {
6240 params: params.clone(),
6241 body: Expr::Null,
6242 env: env.clone(),
6243 })),
6244 RFunction::Builtin { formals, .. } => {
6245 let params: Vec<Param> = formals
6246 .iter()
6247 .map(|&s| Param {
6248 name: s.to_string(),
6249 default: None,
6250 is_dots: s == "...",
6251 })
6252 .collect();
6253 Ok(RValue::Function(RFunction::Closure {
6254 params,
6255 body: Expr::Null,
6256 env: crate::interpreter::environment::Environment::new_empty(),
6257 }))
6258 }
6259 },
6260 RValue::Null => Ok(RValue::Null),
6261 _ => Ok(RValue::Null), }
6263}
6264
6265#[builtin(name = "call", min_args = 1)]
6268fn builtin_call(args: &[RValue], named: &[(String, RValue)]) -> Result<RValue, RError> {
6269 let func_name = args
6270 .first()
6271 .and_then(|v| v.as_vector()?.as_character_scalar())
6272 .ok_or_else(|| {
6273 RError::new(
6274 RErrorKind::Argument,
6275 "first argument must be a character string naming the function to call".to_string(),
6276 )
6277 })?;
6278
6279 let mut call_args: Vec<crate::parser::ast::Arg> = Vec::new();
6281
6282 for val in args.iter().skip(1) {
6283 call_args.push(Arg {
6284 name: None,
6285 value: Some(rvalue_to_expr(val)),
6286 });
6287 }
6288
6289 for (name, val) in named {
6290 call_args.push(Arg {
6291 name: Some(name.clone()),
6292 value: Some(rvalue_to_expr(val)),
6293 });
6294 }
6295
6296 let expr = Expr::Call {
6297 func: Box::new(Expr::Symbol(func_name)),
6298 args: call_args,
6299 span: None,
6300 };
6301
6302 Ok(RValue::Language(Language::new(expr)))
6303}
6304
6305#[builtin(name = "UseMethod", min_args = 1)]
6308fn builtin_use_method(_args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
6309 Err(RError::other(
6310 "internal error: UseMethod() should be intercepted during evaluation",
6311 ))
6312}
6313
6314#[builtin(name = "Sys.localeconv")]
6327fn builtin_sys_localeconv(_args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
6328 let names = vec![
6329 "decimal_point",
6330 "thousands_sep",
6331 "grouping",
6332 "int_curr_symbol",
6333 "currency_symbol",
6334 "mon_decimal_point",
6335 "mon_thousands_sep",
6336 "mon_grouping",
6337 "positive_sign",
6338 "negative_sign",
6339 "int_frac_digits",
6340 "frac_digits",
6341 "p_cs_precedes",
6342 "p_sep_by_space",
6343 "n_cs_precedes",
6344 "n_sep_by_space",
6345 "p_sign_posn",
6346 "n_sign_posn",
6347 ];
6348 let values: Vec<Option<String>> = vec![
6349 Some(".".to_string()), Some(String::new()), Some(String::new()), Some(String::new()), Some(String::new()), Some(String::new()), Some(String::new()), Some(String::new()), Some(String::new()), Some(String::new()), Some("127".to_string()), Some("127".to_string()), Some("127".to_string()), Some("127".to_string()), Some("127".to_string()), Some("127".to_string()), Some("127".to_string()), Some("127".to_string()), ];
6368 let mut rv = RVector::from(Vector::Character(values.into()));
6369 rv.set_attr(
6370 "names".to_string(),
6371 RValue::vec(Vector::Character(
6372 names
6373 .into_iter()
6374 .map(|s| Some(s.to_string()))
6375 .collect::<Vec<_>>()
6376 .into(),
6377 )),
6378 );
6379 Ok(RValue::Vector(rv))
6380}
6381
6382#[builtin]
6392fn builtin_gc(_args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
6393 Ok(RValue::Null)
6397}
6398
6399#[builtin]
6406fn builtin_gcinfo(_args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
6407 Ok(RValue::vec(Vector::Logical(vec![Some(false)].into())))
6408}
6409
6410#[interpreter_builtin(names = ["traceBack"])]
6418fn interp_traceback(
6419 _args: &[RValue],
6420 _named: &[(String, RValue)],
6421 context: &BuiltinContext,
6422) -> Result<RValue, RError> {
6423 context.with_interpreter(|interp| {
6424 let tb = interp.last_traceback.borrow();
6425 if tb.is_empty() {
6426 context.write("No traceback available\n");
6427 interp.set_invisible();
6428 return Ok(RValue::Null);
6429 }
6430 let mut lines = Vec::with_capacity(tb.len());
6431 for (i, entry) in tb.iter().enumerate().rev() {
6432 let call_str = match &entry.call {
6433 Some(expr) => crate::interpreter::value::deparse_expr(expr),
6434 None => "<anonymous>".to_string(),
6435 };
6436 let line = format!("{}: {}", i + 1, call_str);
6437 context.write(&format!("{}\n", line));
6438 lines.push(Some(line));
6439 }
6440 interp.set_invisible();
6441 Ok(RValue::vec(Vector::Character(lines.into())))
6442 })
6443}
6444
6445#[interpreter_builtin]
6452fn interp_debug(
6453 _args: &[RValue],
6454 _named: &[(String, RValue)],
6455 context: &BuiltinContext,
6456) -> Result<RValue, RError> {
6457 context
6458 .write_err("debug() is not supported in miniR — interactive debugging is not available.\n");
6459 Ok(RValue::Null)
6460}
6461
6462#[builtin]
6467fn builtin_undebug(_args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
6468 Ok(RValue::Null)
6469}
6470
6471#[builtin(name = "isdebugged")]
6476fn builtin_isdebugged(_args: &[RValue], _: &[(String, RValue)]) -> Result<RValue, RError> {
6477 Ok(RValue::vec(Vector::Logical(vec![Some(false)].into())))
6478}
6479
6480#[interpreter_builtin]
6486fn interp_browser(
6487 _args: &[RValue],
6488 _named: &[(String, RValue)],
6489 context: &BuiltinContext,
6490) -> Result<RValue, RError> {
6491 context.write_err(
6492 "browser() is not supported in miniR — interactive debugging is not available.\n",
6493 );
6494 Ok(RValue::Null)
6495}
6496
6497fn rvalue_to_expr(val: &RValue) -> Expr {
6501 match val {
6502 RValue::Language(expr) => *expr.inner.clone(),
6503 RValue::Null => Expr::Null,
6504 RValue::Vector(rv) => match &rv.inner {
6505 Vector::Double(d) if d.len() == 1 => match d.get_opt(0) {
6506 Some(v) if v.is_infinite() && v > 0.0 => Expr::Inf,
6507 Some(v) if v.is_nan() => Expr::NaN,
6508 Some(v) => Expr::Double(v),
6509 None => Expr::Na(crate::parser::ast::NaType::Real),
6510 },
6511 Vector::Integer(i) if i.len() == 1 => match i.get_opt(0) {
6512 Some(v) => Expr::Integer(v),
6513 None => Expr::Na(crate::parser::ast::NaType::Integer),
6514 },
6515 Vector::Logical(l) if l.len() == 1 => match l[0] {
6516 Some(v) => Expr::Bool(v),
6517 None => Expr::Na(crate::parser::ast::NaType::Logical),
6518 },
6519 Vector::Character(c) if c.len() == 1 => match &c[0] {
6520 Some(v) => Expr::String(v.clone()),
6521 None => Expr::Na(crate::parser::ast::NaType::Character),
6522 },
6523 _ => Expr::Symbol(format!("{}", val)),
6524 },
6525 _ => Expr::Symbol(format!("{}", val)),
6526 }
6527}