1mod arguments;
2mod assignment;
3pub mod builtins;
4pub mod call;
5mod call_eval;
6pub mod coerce;
7mod control_flow;
8pub mod environment;
9pub mod graphics;
10pub mod grid;
11pub(crate) mod indexing;
12#[cfg(feature = "native")]
13pub mod native;
14mod ops;
15pub mod packages;
16mod s3;
17pub mod value;
18
19use std::cell::RefCell;
20use std::io::Write;
21use std::sync::atomic::{AtomicBool, Ordering};
22use std::sync::Arc;
23
24use tracing::{debug, info, trace};
25
26use crate::parser::ast::*;
27pub use call::BuiltinContext;
28pub(crate) use call::{CallFrame, S3DispatchContext};
29pub use call::{NativeBacktrace, TraceEntry};
30use environment::Environment;
31use value::*;
32
33type ForcedArgs = (Vec<RValue>, Vec<(String, RValue)>);
35
36#[cfg(feature = "random")]
45pub(crate) enum InterpreterRng {
46 Fast(rand::rngs::SmallRng),
47 Deterministic(Box<rand_chacha::ChaCha20Rng>),
48}
49
50#[cfg(feature = "random")]
51impl rand::TryRng for InterpreterRng {
52 type Error = std::convert::Infallible;
53
54 fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
55 match self {
56 InterpreterRng::Fast(rng) => rng.try_next_u32(),
57 InterpreterRng::Deterministic(rng) => rng.try_next_u32(),
58 }
59 }
60
61 fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
62 match self {
63 InterpreterRng::Fast(rng) => rng.try_next_u64(),
64 InterpreterRng::Deterministic(rng) => rng.try_next_u64(),
65 }
66 }
67
68 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> {
69 match self {
70 InterpreterRng::Fast(rng) => rng.try_fill_bytes(dest),
71 InterpreterRng::Deterministic(rng) => rng.try_fill_bytes(dest),
72 }
73 }
74}
75
76#[cfg(feature = "random")]
78#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79pub(crate) enum RngKind {
80 Xoshiro,
81 ChaCha20,
82}
83
84#[cfg(feature = "random")]
85impl std::fmt::Display for RngKind {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 match self {
88 RngKind::Xoshiro => write!(f, "Xoshiro"),
89 RngKind::ChaCha20 => write!(f, "ChaCha20"),
90 }
91 }
92}
93
94thread_local! {
97 static INTERPRETER: RefCell<Interpreter> = RefCell::new(Interpreter::new());
98}
99
100pub fn with_interpreter<F, R>(f: F) -> R
103where
104 F: FnOnce(&Interpreter) -> R,
105{
106 INTERPRETER.with(|cell| f(&cell.borrow()))
107}
108
109pub fn with_interpreter_state<F, R>(state: &mut Interpreter, f: F) -> R
113where
114 F: FnOnce(&Interpreter) -> R,
115{
116 INTERPRETER.with(|cell| {
117 {
118 let mut installed = cell.borrow_mut();
119 std::mem::swap(&mut *installed, state);
120 }
121
122 struct Restore<'a> {
123 cell: &'a RefCell<Interpreter>,
124 state: &'a mut Interpreter,
125 }
126
127 impl Drop for Restore<'_> {
128 fn drop(&mut self) {
129 let mut installed = self.cell.borrow_mut();
130 std::mem::swap(&mut *installed, self.state);
131 }
132 }
133
134 let _restore = Restore { cell, state };
135 let installed = cell.borrow();
136 f(&installed)
137 })
138}
139
140fn formula_value(expr: Expr, env: &Environment) -> RValue {
141 let mut lang = Language::new(expr);
142 lang.set_attr(
143 "class".to_string(),
144 RValue::vec(Vector::Character(vec![Some("formula".to_string())].into())),
145 );
146 lang.set_attr(".Environment".to_string(), RValue::Environment(env.clone()));
147 RValue::Language(lang)
148}
149
150#[derive(Clone)]
152pub(crate) struct ConditionHandler {
153 pub class: String,
154 pub handler: RValue,
155 #[allow(dead_code)]
156 pub env: Environment,
157}
158
159#[derive(Debug, Clone, Copy, PartialEq, Eq)]
165pub enum DiagnosticStyle {
166 Error,
168 Warning,
170 Message,
172}
173
174pub struct Interpreter {
175 pub global_env: Environment,
176 pub(crate) stdout: RefCell<Box<dyn Write>>,
179 pub(crate) stderr: RefCell<Box<dyn Write>>,
181 color_stderr: bool,
185 s3_dispatch_stack: RefCell<Vec<S3DispatchContext>>,
186 call_stack: RefCell<Vec<CallFrame>>,
187 pub(crate) last_traceback: RefCell<Vec<TraceEntry>>,
191 pub(crate) source_stack: RefCell<Vec<(String, String)>>,
195 traceback_generation: std::cell::Cell<u64>,
199 traceback_captured_generation: std::cell::Cell<u64>,
201 #[cfg(feature = "native")]
204 pub(crate) pending_native_backtrace: RefCell<Option<NativeBacktrace>>,
205 pub(crate) condition_handlers: RefCell<Vec<Vec<ConditionHandler>>>,
207 #[cfg(feature = "random")]
218 rng: RefCell<InterpreterRng>,
219 #[cfg(feature = "random")]
221 pub(crate) rng_kind: std::cell::Cell<RngKind>,
222 pub(crate) temp_dir: temp_dir::TempDir,
224 pub(crate) temp_counter: std::cell::Cell<u64>,
226 pub(crate) env_vars: RefCell<std::collections::HashMap<String, String>>,
229 pub(crate) working_dir: RefCell<std::path::PathBuf>,
232 pub(crate) start_instant: std::time::Instant,
234 #[cfg(feature = "collections")]
237 pub(crate) collections: RefCell<Vec<builtins::collections::CollectionObject>>,
238 pub(crate) connections: RefCell<Vec<builtins::connections::ConnectionInfo>>,
240 pub(crate) tcp_streams: RefCell<std::collections::HashMap<usize, std::net::TcpStream>>,
243 #[cfg(feature = "tls")]
247 pub(crate) url_bodies: RefCell<std::collections::HashMap<usize, Vec<u8>>>,
248 pub(crate) finalizers: RefCell<Vec<RValue>>,
251 interrupted: Arc<AtomicBool>,
254 pub(crate) options: RefCell<std::collections::HashMap<String, value::RValue>>,
256 pub(crate) rd_help_index: RefCell<packages::rd::RdHelpIndex>,
258 pub(crate) last_value_invisible: std::cell::Cell<bool>,
260 eval_depth: std::cell::Cell<usize>,
262 max_eval_depth: usize,
265 stack_base: usize,
267 pub(crate) s4_classes: RefCell<std::collections::HashMap<String, S4ClassDef>>,
269 pub(crate) s4_generics: RefCell<std::collections::HashMap<String, S4GenericDef>>,
271 pub(crate) s4_methods: RefCell<std::collections::HashMap<S4MethodKey, value::RValue>>,
273 pub(crate) loaded_namespaces:
275 RefCell<std::collections::HashMap<String, packages::LoadedNamespace>>,
276 pub(crate) search_path: RefCell<Vec<packages::SearchPathEntry>>,
278 pub(crate) s3_method_registry:
282 RefCell<std::collections::HashMap<(String, String), value::RValue>>,
283 #[cfg(feature = "progress")]
285 pub(crate) progress_bars: RefCell<Vec<Option<builtins::progress::ProgressBarState>>>,
286 pub(crate) par_state: RefCell<graphics::par::ParState>,
288 pub(crate) grid_display_list: RefCell<Vec<RValue>>,
290 pub(crate) grid_viewport_stack: RefCell<Vec<RValue>>,
292 pub(crate) grid_grob_store: RefCell<grid::grob::GrobStore>,
294 pub(crate) grid_rust_display_list: RefCell<grid::display::DisplayList>,
296 pub(crate) grid_rust_viewport_stack: RefCell<grid::viewport::ViewportStack>,
298 pub(crate) color_palette: RefCell<Vec<graphics::color::RColor>>,
300 pub(crate) current_plot: RefCell<Option<graphics::plot_data::PlotState>>,
302 pub(crate) file_device: RefCell<Option<graphics::FileDevice>>,
304 #[cfg(feature = "native")]
306 pub(crate) loaded_dlls: RefCell<Vec<native::dll::LoadedDll>>,
307 #[cfg(feature = "plot")]
309 pub(crate) plot_tx: RefCell<Option<graphics::egui_device::PlotSender>>,
310}
311
312#[derive(Debug, Clone)]
314pub struct S4ClassDef {
315 pub name: String,
316 pub slots: Vec<(String, String)>,
317 pub contains: Vec<String>,
318 pub prototype: Vec<(String, value::RValue)>,
319 pub is_virtual: bool,
320 pub validity: Option<value::RValue>,
321}
322
323pub(crate) type S4MethodKey = (String, Vec<String>);
325
326#[derive(Debug, Clone)]
328#[allow(dead_code)]
329pub(crate) struct S4GenericDef {
330 pub name: String,
331 pub default: Option<value::RValue>,
332}
333
334impl Default for Interpreter {
335 fn default() -> Self {
336 Self::new()
337 }
338}
339
340impl Drop for Interpreter {
341 fn drop(&mut self) {
342 let finalizers: Vec<RValue> = self.finalizers.borrow_mut().drain(..).collect();
343 if finalizers.is_empty() {
344 return;
345 }
346 let env = self.global_env.clone();
347 for f in &finalizers {
348 self.call_function(f, &[RValue::Environment(env.clone())], &[], &env)
351 .ok();
352 }
353 }
354}
355
356impl Interpreter {
357 fn ensure_builtin_min_arity(
358 name: &str,
359 min_args: usize,
360 actual_args: usize,
361 ) -> Result<(), RError> {
362 if min_args == 0 || actual_args >= min_args {
363 return Ok(());
364 }
365
366 let expectation = match min_args {
367 1 => "requires at least 1 argument".to_string(),
368 n => format!("requires at least {n} arguments"),
369 };
370 let suffix = if actual_args == 1 { "" } else { "s" };
371
372 Err(RError::new(
373 RErrorKind::Argument,
374 format!("{name}() {expectation}, got {actual_args} argument{suffix}"),
375 ))
376 }
377
378 fn ensure_builtin_max_arity(
379 name: &str,
380 max_args: Option<usize>,
381 actual_args: usize,
382 ) -> Result<(), RError> {
383 let Some(max_args) = max_args else {
384 return Ok(());
385 };
386
387 if actual_args <= max_args {
388 return Ok(());
389 }
390
391 let expectation = match max_args {
392 0 => "takes no arguments".to_string(),
393 1 => "takes at most 1 argument".to_string(),
394 n => format!("takes at most {n} arguments"),
395 };
396 let suffix = if actual_args == 1 { "" } else { "s" };
397
398 Err(RError::new(
399 RErrorKind::Argument,
400 format!("{name}() {expectation}, got {actual_args} argument{suffix}"),
401 ))
402 }
403
404 pub fn new() -> Self {
405 info!("creating new R interpreter");
406 #[cfg(feature = "native")]
408 native::runtime::init_globals();
409
410 let base_env = Environment::new_global();
411 base_env.set_name("base".to_string());
412 builtins::register_builtins(&base_env);
413 let global_env = Environment::new_child(&base_env);
414 global_env.set_name("R_GlobalEnv".to_string());
415
416 base_env.set(
418 ".GlobalEnv".to_string(),
419 value::RValue::Environment(global_env.clone()),
420 );
421 base_env.set(
422 ".BaseNamespaceEnv".to_string(),
423 value::RValue::Environment(base_env.clone()),
424 );
425
426 let color_stderr = {
427 use std::io::IsTerminal;
428 std::io::stderr().is_terminal()
429 };
430 let interp = Interpreter {
431 global_env,
432 stdout: RefCell::new(Box::new(std::io::stdout())),
433 stderr: RefCell::new(Box::new(std::io::stderr())),
434 color_stderr,
435 s3_dispatch_stack: RefCell::new(Vec::new()),
436 call_stack: RefCell::new(Vec::new()),
437 last_traceback: RefCell::new(Vec::new()),
438 source_stack: RefCell::new(Vec::new()),
439 traceback_generation: std::cell::Cell::new(0),
440 traceback_captured_generation: std::cell::Cell::new(0),
441 #[cfg(feature = "native")]
442 pending_native_backtrace: RefCell::new(None),
443 condition_handlers: RefCell::new(Vec::new()),
444 #[cfg(feature = "random")]
445 rng: RefCell::new({
446 use rand::SeedableRng;
447 let mut thread_rng = rand::rng();
448 InterpreterRng::Fast(rand::rngs::SmallRng::from_rng(&mut thread_rng))
449 }),
450 #[cfg(feature = "random")]
451 rng_kind: std::cell::Cell::new(RngKind::Xoshiro),
452 temp_dir: temp_dir::TempDir::new().expect("failed to create session temp directory"),
453 temp_counter: std::cell::Cell::new(0),
454 env_vars: RefCell::new(std::env::vars().collect()),
455 working_dir: RefCell::new(
456 std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from(".")),
457 ),
458 start_instant: std::time::Instant::now(),
459 #[cfg(feature = "collections")]
460 collections: RefCell::new(Vec::new()),
461 connections: RefCell::new(Vec::new()),
462 tcp_streams: RefCell::new(std::collections::HashMap::new()),
463 #[cfg(feature = "tls")]
464 url_bodies: RefCell::new(std::collections::HashMap::new()),
465 finalizers: RefCell::new(Vec::new()),
466 interrupted: Arc::new(AtomicBool::new(false)),
467 options: RefCell::new(Self::default_options()),
468 rd_help_index: RefCell::new(packages::rd::RdHelpIndex::new()),
469 last_value_invisible: std::cell::Cell::new(false),
470 eval_depth: std::cell::Cell::new(0),
471 max_eval_depth: Self::compute_max_eval_depth(),
472 stack_base: Self::current_stack_addr(),
473 s4_classes: RefCell::new(std::collections::HashMap::new()),
474 s4_generics: RefCell::new(std::collections::HashMap::new()),
475 s4_methods: RefCell::new(std::collections::HashMap::new()),
476 loaded_namespaces: RefCell::new(std::collections::HashMap::new()),
477 search_path: RefCell::new(Vec::new()),
478 s3_method_registry: RefCell::new(std::collections::HashMap::new()),
479 #[cfg(feature = "progress")]
480 progress_bars: RefCell::new(Vec::new()),
481 par_state: RefCell::new(graphics::par::ParState::default()),
482 grid_display_list: RefCell::new(Vec::new()),
483 grid_viewport_stack: RefCell::new(Vec::new()),
484 grid_grob_store: RefCell::new(grid::grob::GrobStore::new()),
485 grid_rust_display_list: RefCell::new(grid::display::DisplayList::new()),
486 grid_rust_viewport_stack: RefCell::new(grid::viewport::ViewportStack::new(
487 17.78, 17.78,
488 )),
489 color_palette: RefCell::new(graphics::color::default_palette()),
490 current_plot: RefCell::new(None),
491 file_device: RefCell::new(None),
492 #[cfg(feature = "native")]
493 loaded_dlls: RefCell::new(Vec::new()),
494 #[cfg(feature = "plot")]
495 plot_tx: RefCell::new(None),
496 };
497
498 builtins::synthesize_builtin_help(&mut interp.rd_help_index.borrow_mut());
501
502 interp
503 }
504
505 pub fn index_package_help(&self, package_name: &str, man_dir: &std::path::Path) {
507 self.rd_help_index
508 .borrow_mut()
509 .index_package_dir(package_name, man_dir);
510 }
511
512 pub(crate) fn set_invisible(&self) {
514 self.last_value_invisible.set(true);
515 }
516
517 pub(crate) fn take_invisible(&self) -> bool {
520 self.last_value_invisible.replace(false)
521 }
522
523 pub fn interrupt_flag(&self) -> Arc<AtomicBool> {
525 Arc::clone(&self.interrupted)
526 }
527
528 pub(crate) fn check_interrupt(&self) -> Result<(), RFlow> {
530 if self.interrupted.load(Ordering::Relaxed) {
531 self.interrupted.store(false, Ordering::Relaxed);
532 debug!("SIGINT interrupt detected");
533 Err(RFlow::Error(RError::interrupt()))
534 } else {
535 Ok(())
536 }
537 }
538
539 pub(crate) fn signal_condition(
543 &self,
544 condition: &RValue,
545 env: &Environment,
546 ) -> Result<bool, RError> {
547 let classes = value::get_class(condition);
548 let handler_stack: Vec<Vec<ConditionHandler>> = self.condition_handlers.borrow().clone();
550 for handler_set in handler_stack.iter().rev() {
552 for handler in handler_set {
553 if classes.iter().any(|c| c == &handler.class) {
554 let result = self.call_function(
556 &handler.handler,
557 std::slice::from_ref(condition),
558 &[],
559 env,
560 );
561 match &result {
562 Err(RFlow::Error(RError::Standard { message: msg, .. }))
563 if msg == "muffleWarning" || msg == "muffleMessage" =>
564 {
565 return Ok(true);
566 }
567 Err(e) => return Err(RError::from(e.clone())),
568 Ok(_) => {} }
570 }
571 }
572 }
573 Ok(false)
574 }
575
576 fn default_options() -> std::collections::HashMap<String, value::RValue> {
578 use value::{RValue, Vector};
579 let mut opts = std::collections::HashMap::new();
580 opts.insert(
581 "digits".to_string(),
582 RValue::vec(Vector::Integer(vec![Some(7)].into())),
583 );
584 opts.insert(
585 "warn".to_string(),
586 RValue::vec(Vector::Integer(vec![Some(0)].into())),
587 );
588 opts.insert(
589 "OutDec".to_string(),
590 RValue::vec(Vector::Character(vec![Some(".".to_string())].into())),
591 );
592 opts.insert(
593 "scipen".to_string(),
594 RValue::vec(Vector::Integer(vec![Some(0)].into())),
595 );
596 opts.insert(
597 "max.print".to_string(),
598 RValue::vec(Vector::Integer(vec![Some(99999)].into())),
599 );
600 opts.insert(
601 "width".to_string(),
602 RValue::vec(Vector::Integer(vec![Some(80)].into())),
603 );
604 opts.insert(
605 "warning.length".to_string(),
606 RValue::vec(Vector::Integer(vec![Some(1000)].into())),
607 );
608 opts.insert(
609 "prompt".to_string(),
610 RValue::vec(Vector::Character(vec![Some("> ".to_string())].into())),
611 );
612 opts.insert(
613 "continue".to_string(),
614 RValue::vec(Vector::Character(vec![Some("+ ".to_string())].into())),
615 );
616 opts.insert(
617 "encoding".to_string(),
618 RValue::vec(Vector::Character(
619 vec![Some("native.enc".to_string())].into(),
620 )),
621 );
622 opts.insert(
623 "stringsAsFactors".to_string(),
624 RValue::vec(Vector::Logical(vec![Some(false)].into())),
625 );
626 opts
627 }
628
629 #[cfg(feature = "random")]
630 pub(crate) fn rng(&self) -> &RefCell<InterpreterRng> {
631 &self.rng
632 }
633
634 pub(crate) fn get_env_var(&self, name: &str) -> Option<String> {
636 self.env_vars.borrow().get(name).cloned()
637 }
638
639 pub(crate) fn env_vars_snapshot(&self) -> std::collections::HashMap<String, String> {
641 self.env_vars.borrow().clone()
642 }
643
644 pub(crate) fn set_env_var(&self, name: String, value: String) {
646 self.env_vars.borrow_mut().insert(name, value);
647 }
648
649 pub(crate) fn remove_env_var(&self, name: &str) {
651 self.env_vars.borrow_mut().remove(name);
652 }
653
654 pub(crate) fn register_s3_method(&self, generic: String, class: String, method: RValue) {
658 self.s3_method_registry
659 .borrow_mut()
660 .insert((generic, class), method);
661 }
662
663 pub(crate) fn lookup_s3_method(&self, generic: &str, class: &str) -> Option<RValue> {
667 self.s3_method_registry
668 .borrow()
669 .get(&(generic.to_string(), class.to_string()))
670 .cloned()
671 }
672
673 pub(crate) fn get_working_dir(&self) -> std::path::PathBuf {
675 self.working_dir.borrow().clone()
676 }
677
678 pub(crate) fn set_working_dir(&self, path: std::path::PathBuf) {
680 *self.working_dir.borrow_mut() = path;
681 }
682
683 pub(crate) fn resolve_path(&self, path: impl AsRef<std::path::Path>) -> std::path::PathBuf {
685 let path = path.as_ref();
686 if path.is_absolute() {
687 path.to_path_buf()
688 } else {
689 self.get_working_dir().join(path)
690 }
691 }
692
693 pub(crate) fn write_stdout(&self, msg: &str) {
695 if self.stdout.borrow_mut().write_all(msg.as_bytes()).is_err() {}
698 }
699
700 pub(crate) fn write_stderr(&self, msg: &str) {
702 if self.stderr.borrow_mut().write_all(msg.as_bytes()).is_err() {}
703 }
704
705 pub fn color_stderr(&self) -> bool {
707 self.color_stderr
708 }
709
710 pub fn set_color_stderr(&mut self, enabled: bool) {
712 self.color_stderr = enabled;
713 }
714
715 pub(crate) fn write_stderr_colored(&self, msg: &str, style: DiagnosticStyle) {
721 if self.try_write_colored(msg, style) {
722 return;
723 }
724 self.write_stderr(msg);
726 }
727
728 #[cfg(feature = "repl")]
731 fn try_write_colored(&self, msg: &str, style: DiagnosticStyle) -> bool {
732 if !self.color_stderr {
733 return false;
734 }
735 use crossterm::style::{Attribute, Color, Stylize};
736 use std::io::Write as _;
737
738 let (color, bold) = match style {
739 DiagnosticStyle::Error => (Color::Red, true),
740 DiagnosticStyle::Warning => (Color::Yellow, true),
741 DiagnosticStyle::Message => (Color::Cyan, false),
742 };
743
744 let styled = if bold {
746 format!("{}", msg.with(color).attribute(Attribute::Bold))
747 } else {
748 format!("{}", msg.with(color))
749 };
750 self.stderr.borrow_mut().write_all(styled.as_bytes()).ok();
751 true
752 }
753
754 #[cfg(not(feature = "repl"))]
756 fn try_write_colored(&self, _msg: &str, _style: DiagnosticStyle) -> bool {
757 false
758 }
759
760 pub fn force_value(&self, value: RValue) -> Result<RValue, RFlow> {
766 match value {
767 RValue::Promise(ref p) => {
768 {
770 let inner = p.borrow();
771 if let Some(ref cached) = inner.value {
772 return Ok(cached.clone());
773 }
774 if inner.forcing {
775 return Err(RError::other(
776 "promise already under evaluation: recursive default argument reference or earlier problems?"
777 .to_string(),
778 )
779 .into());
780 }
781 }
782
783 p.borrow_mut().forcing = true;
785
786 let (expr, env) = {
788 let inner = p.borrow();
789 (inner.expr.clone(), inner.env.clone())
790 };
791
792 let result = self.eval_in(&expr, &env);
793
794 match result {
795 Ok(val) => {
796 let forced = self.force_value(val)?;
798 let mut inner = p.borrow_mut();
799 inner.value = Some(forced.clone());
800 inner.forcing = false;
801 Ok(forced)
802 }
803 Err(e) => {
804 p.borrow_mut().forcing = false;
805 Err(e)
806 }
807 }
808 }
809 other => Ok(other),
810 }
811 }
812
813 pub fn force_args(
816 &self,
817 positional: &[RValue],
818 named: &[(String, RValue)],
819 ) -> Result<ForcedArgs, RFlow> {
820 let forced_pos: Vec<RValue> = positional
821 .iter()
822 .map(|v| self.force_value(v.clone()))
823 .collect::<Result<_, _>>()?;
824 let forced_named: Vec<(String, RValue)> = named
825 .iter()
826 .map(|(n, v)| Ok((n.clone(), self.force_value(v.clone())?)))
827 .collect::<Result<_, RFlow>>()?;
828 Ok((forced_pos, forced_named))
829 }
830
831 pub fn eval(&self, expr: &Expr) -> Result<RValue, RFlow> {
832 self.traceback_generation
835 .set(self.traceback_generation.get().wrapping_add(1));
836 self.eval_in(expr, &self.global_env)
837 }
838
839 const DEFAULT_STACK_SIZE: usize = 8 * 1024 * 1024;
846 const STACK_RESERVED_BYTES: usize = 4 * 1024 * 1024;
847
848 fn stack_bytes_per_eval_frame() -> usize {
859 let rvalue = std::mem::size_of::<value::RValue>();
860 let expr = std::mem::size_of::<crate::parser::ast::Expr>();
861 let env = std::mem::size_of::<environment::Environment>();
862 let call_frame = std::mem::size_of::<call::CallFrame>();
863 let frame_cost = (rvalue * 8 + expr * 2 + env * 2 + call_frame) * 3;
867 frame_cost.max(4096)
869 }
870
871 fn compute_max_eval_depth() -> usize {
873 let stack_size = 8 * 1024 * 1024_usize;
875 let usable = stack_size.saturating_sub(Self::STACK_RESERVED_BYTES);
876 let frame_cost = Self::stack_bytes_per_eval_frame();
877 let depth = usable / frame_cost;
878 depth.clamp(50, 5000)
879 }
880
881 #[inline(never)]
883 fn current_stack_addr() -> usize {
884 let local = 0u8;
885 std::ptr::addr_of!(local) as usize
886 }
887
888 #[inline]
892 fn stack_is_low(&self) -> bool {
893 let current = Self::current_stack_addr();
894 let used = self.stack_base.saturating_sub(current);
896 let limit = Self::DEFAULT_STACK_SIZE.saturating_sub(Self::STACK_RESERVED_BYTES);
897 used > limit
898 }
899
900 #[tracing::instrument(level = "trace", skip(self, env))]
901 pub fn eval_in(&self, expr: &Expr, env: &Environment) -> Result<RValue, RFlow> {
902 let depth = self.eval_depth.get();
903 if depth >= self.max_eval_depth || self.stack_is_low() {
904 let frames = self.call_stack.borrow();
906 if !frames.is_empty() {
907 self.write_stderr("Traceback (most recent call last):\n");
908 for (i, frame) in frames.iter().rev().enumerate().take(20) {
909 let name = match &frame.call {
910 Some(call_expr) => format!(
911 "{}",
912 crate::interpreter::value::RValue::Language(
913 crate::interpreter::value::Language::new(call_expr.clone())
914 )
915 ),
916 None => "<anonymous>".to_string(),
917 };
918 self.write_stderr(&format!("{}: {}\n", i + 1, name));
919 }
920 }
921 return Err(RFlow::Error(value::RError::other(
922 "evaluation nested too deeply: infinite recursion / options(expressions=) ?"
923 .to_string(),
924 )));
925 }
926 self.eval_depth.set(depth + 1);
927 let result = self.eval_in_inner(expr, env);
928 self.eval_depth.set(depth);
929 result
930 }
931
932 fn eval_in_inner(&self, expr: &Expr, env: &Environment) -> Result<RValue, RFlow> {
933 match expr {
934 Expr::Null => Ok(RValue::Null),
935 Expr::Na(na_type) => Ok(match na_type {
936 NaType::Logical => RValue::vec(Vector::Logical(vec![None].into())),
937 NaType::Integer => RValue::vec(Vector::Integer(vec![None].into())),
938 NaType::Real => RValue::vec(Vector::Double(vec![None].into())),
939 NaType::Character => RValue::vec(Vector::Character(vec![None].into())),
940 NaType::Complex => RValue::vec(Vector::Double(vec![None].into())),
941 }),
942 Expr::Inf => Ok(RValue::vec(Vector::Double(
943 vec![Some(f64::INFINITY)].into(),
944 ))),
945 Expr::NaN => Ok(RValue::vec(Vector::Double(vec![Some(f64::NAN)].into()))),
946 Expr::Bool(b) => Ok(RValue::vec(Vector::Logical(vec![Some(*b)].into()))),
947 Expr::Integer(i) => Ok(RValue::vec(Vector::Integer(vec![Some(*i)].into()))),
948 Expr::Double(f) => Ok(RValue::vec(Vector::Double(vec![Some(*f)].into()))),
949 Expr::String(s) => Ok(RValue::vec(Vector::Character(vec![Some(s.clone())].into()))),
950 Expr::Complex(f) => Ok(RValue::vec(Vector::Complex(
951 vec![Some(num_complex::Complex64::new(0.0, *f))].into(),
952 ))),
953 Expr::Symbol(name) => {
954 if let Some(fun) = env.get_active_binding(name) {
956 return self.call_function(&fun, &[], &[], env);
957 }
958 let val = env.get(name).ok_or_else(|| {
959 debug!(symbol = name.as_str(), "symbol not found");
960 RFlow::from(RError::new(RErrorKind::Name, name.clone()))
961 })?;
962 self.force_value(val)
964 }
965 Expr::Dots => {
966 env.get("...").ok_or_else(|| {
968 RError::other("'...' used in incorrect context".to_string()).into()
969 })
970 }
971 Expr::DotDot(n) => {
972 if *n == 0 {
973 return Err(RError::other(
974 "..0 is not valid — R uses 1-based indexing for ... arguments.\n \
975 Did you mean ..1? (..1 is the first element, ..2 is the second, etc.)",
976 )
977 .into());
978 }
979 let dots = env
981 .get("...")
982 .ok_or_else(|| RError::other(format!("'..{}' used in incorrect context", n)))?;
983 match dots {
984 RValue::List(list) => {
985 let idx = usize::try_from(i64::from(*n))?.saturating_sub(1);
986 let val =
987 list.values
988 .get(idx)
989 .map(|(_, v)| v.clone())
990 .ok_or_else(|| {
991 RFlow::from(RError::other(format!(
992 "the ... list does not contain {} elements",
993 n
994 )))
995 })?;
996 self.force_value(val)
998 }
999 _ => Err(RError::other(format!("'..{}' used in incorrect context", n)).into()),
1000 }
1001 }
1002
1003 Expr::UnaryOp { op, operand } => {
1004 let val = self.eval_in(operand, env)?;
1005 self.eval_unary(*op, &val)
1006 }
1007 Expr::BinaryOp { op, lhs, rhs } => {
1008 match op {
1010 BinaryOp::Special(SpecialOp::Walrus) => {
1012 let val = self.eval_in(rhs, env)?;
1013 return self.eval_assign(
1014 &crate::parser::ast::AssignOp::LeftAssign,
1015 lhs,
1016 val,
1017 env,
1018 );
1019 }
1020 BinaryOp::Pipe => return self.eval_pipe(lhs, rhs, env),
1021 BinaryOp::AssignPipe => {
1022 let result = self.eval_pipe(lhs, rhs, env)?;
1024 self.eval_assign(
1025 &crate::parser::ast::AssignOp::LeftAssign,
1026 lhs,
1027 result.clone(),
1028 env,
1029 )?;
1030 return Ok(result);
1031 }
1032 BinaryOp::TeePipe => {
1033 let left_val = self.eval_in(lhs, env)?;
1037 let _ = self.eval_pipe(lhs, rhs, env);
1038 return Ok(left_val);
1039 }
1040 BinaryOp::ExpoPipe => {
1041 let left_val = self.eval_in(lhs, env)?;
1043 let child_env =
1044 crate::interpreter::environment::Environment::new_child(env);
1045 if let RValue::List(list) = &left_val {
1047 for (name, val) in &list.values {
1048 if let Some(n) = name {
1049 child_env.set(n.clone(), val.clone());
1050 }
1051 }
1052 }
1053 return self.eval_in(rhs, &child_env);
1054 }
1055 BinaryOp::AndScalar => {
1057 let left = self.eval_in(lhs, env)?;
1058 let a = left.as_vector().and_then(|v| v.as_logical_scalar());
1059 if a == Some(false) {
1060 return Ok(RValue::vec(Vector::Logical(vec![Some(false)].into())));
1061 }
1062 let right = self.eval_in(rhs, env)?;
1063 let b = right.as_vector().and_then(|v| v.as_logical_scalar());
1064 return match (a, b) {
1065 (Some(true), Some(true)) => {
1066 Ok(RValue::vec(Vector::Logical(vec![Some(true)].into())))
1067 }
1068 (Some(false), _) | (_, Some(false)) => {
1069 Ok(RValue::vec(Vector::Logical(vec![Some(false)].into())))
1070 }
1071 _ => Ok(RValue::vec(Vector::Logical(vec![None].into()))),
1072 };
1073 }
1074 BinaryOp::OrScalar => {
1075 let left = self.eval_in(lhs, env)?;
1076 let a = left.as_vector().and_then(|v| v.as_logical_scalar());
1077 if a == Some(true) {
1078 return Ok(RValue::vec(Vector::Logical(vec![Some(true)].into())));
1079 }
1080 let right = self.eval_in(rhs, env)?;
1081 let b = right.as_vector().and_then(|v| v.as_logical_scalar());
1082 return match (a, b) {
1083 (Some(true), _) | (_, Some(true)) => {
1084 Ok(RValue::vec(Vector::Logical(vec![Some(true)].into())))
1085 }
1086 (Some(false), Some(false)) => {
1087 Ok(RValue::vec(Vector::Logical(vec![Some(false)].into())))
1088 }
1089 _ => Ok(RValue::vec(Vector::Logical(vec![None].into()))),
1090 };
1091 }
1092 _ => {}
1093 }
1094 let left = self.eval_in(lhs, env)?;
1095 let right = self.eval_in(rhs, env)?;
1096 if let BinaryOp::Special(SpecialOp::Other(ref name)) = op {
1098 if let Some(func) = env.get(name) {
1099 return self.call_function(&func, &[left, right], &[], env);
1100 }
1101 return Err(RError::new(
1102 RErrorKind::Other,
1103 format!("could not find function \"{}\"", name),
1104 )
1105 .into());
1106 }
1107 self.eval_binary(op.clone(), &left, &right, env)
1108 }
1109 Expr::Assign { op, target, value } => {
1110 let val = self.eval_in(value, env)?;
1111 self.eval_assign(op, target, val, env)
1112 }
1113
1114 Expr::Call {
1115 func, args, span, ..
1116 } => self.eval_call(func, args, *span, env),
1117 Expr::Index { object, indices } => self.eval_index(object, indices, env),
1118 Expr::IndexDouble { object, indices } => self.eval_index_double(object, indices, env),
1119 Expr::Dollar { object, member } => self.eval_dollar(object, member, env),
1120 Expr::Slot { object, member } => self.eval_dollar(object, member, env), Expr::NsGet { namespace, name } => self.eval_ns_get(namespace, name, env),
1122 Expr::NsGetInt { namespace, name } => self.eval_ns_get(namespace, name, env),
1123
1124 Expr::Formula { .. } => Ok(formula_value(expr.clone(), env)),
1125
1126 Expr::If {
1127 condition,
1128 then_body,
1129 else_body,
1130 } => {
1131 trace!("eval if");
1132 self.eval_if(condition, then_body, else_body.as_deref(), env)
1133 }
1134
1135 Expr::For { var, iter, body } => {
1136 trace!(var = var.as_str(), "eval for");
1137 let iter_val = self.eval_in(iter, env)?;
1138 self.eval_for(var, &iter_val, body, env)
1139 }
1140
1141 Expr::While { condition, body } => {
1142 trace!("eval while");
1143 self.eval_while(condition, body, env)
1144 }
1145
1146 Expr::Repeat { body } => self.eval_repeat(body, env),
1147
1148 Expr::Break => Err(RFlow::Signal(RSignal::Break)),
1149 Expr::Next => Err(RFlow::Signal(RSignal::Next)),
1150 Expr::Return(val) => {
1151 let ret_val = match val {
1152 Some(expr) => self.eval_in(expr, env)?,
1153 None => RValue::Null,
1154 };
1155 Err(RFlow::Signal(RSignal::Return(ret_val)))
1156 }
1157
1158 Expr::Block(exprs) => {
1159 let mut result = RValue::Null;
1160 for expr in exprs {
1161 self.check_interrupt()?;
1162 result = self.eval_in(expr, env)?;
1163 }
1164 Ok(result)
1165 }
1166
1167 Expr::Function { params, body } => Ok(RValue::Function(RFunction::Closure {
1168 params: params.clone(),
1169 body: (**body).clone(),
1170 env: env.clone(),
1171 })),
1172
1173 Expr::Program(exprs) => {
1174 let mut result = RValue::Null;
1175 for expr in exprs {
1176 self.check_interrupt()?;
1177 result = self.eval_in(expr, env)?;
1178 }
1179 Ok(result)
1180 }
1181 }
1182 }
1183}