1use crate::ast::{BinOp, Expr, Program, Stmt, UnaryOp};
5use crate::builtins::BuiltInRegistry;
6use crate::environment::Environment;
7use crate::module_system::{
8 DisabledModuleResolver, ModuleContext, ModuleResolveError, ModuleResolver, ResolvedModule,
9};
10use crate::value::{GeneratorState, Value};
11use serde_json::{Value as JsonValue, json};
12use std::cell::RefCell;
13use std::collections::HashMap;
14use std::collections::VecDeque;
15use std::rc::Rc;
16
17#[derive(Debug, Clone, PartialEq)]
18pub struct CallFrame {
19 pub name: String,
20 pub signature: String,
21}
22
23#[derive(Debug, Clone, PartialEq)]
24pub enum ImportErrorKind {
25 ImportDisabled,
26 InvalidSpecifier,
27 NoBaseDir,
28 NotFound,
29 AccessDenied,
30 IoError,
31 NotExported,
32 CircularImport,
33 ParseFailed,
34}
35
36#[derive(Debug, Clone, PartialEq)]
37pub struct ImportError {
38 pub kind: ImportErrorKind,
39 pub specifier: String,
40 pub detail: Option<String>,
41 pub symbol: Option<String>,
42 pub module_id: Option<String>,
43 pub import_chain: Vec<String>,
44 pub cycle: Option<Vec<String>>,
45}
46
47impl ImportError {
48 fn from_resolve_error(
49 specifier: &str,
50 err: ModuleResolveError,
51 import_chain: Vec<String>,
52 ) -> Self {
53 match err {
54 ModuleResolveError::ImportDisabled => ImportError {
55 kind: ImportErrorKind::ImportDisabled,
56 specifier: specifier.to_string(),
57 detail: None,
58 symbol: None,
59 module_id: None,
60 import_chain,
61 cycle: None,
62 },
63 ModuleResolveError::InvalidSpecifier(s) => ImportError {
64 kind: ImportErrorKind::InvalidSpecifier,
65 specifier: specifier.to_string(),
66 detail: Some(s),
67 symbol: None,
68 module_id: None,
69 import_chain,
70 cycle: None,
71 },
72 ModuleResolveError::NoBaseDir(s) => ImportError {
73 kind: ImportErrorKind::NoBaseDir,
74 specifier: specifier.to_string(),
75 detail: Some(s),
76 symbol: None,
77 module_id: None,
78 import_chain,
79 cycle: None,
80 },
81 ModuleResolveError::NotFound(s) => ImportError {
82 kind: ImportErrorKind::NotFound,
83 specifier: specifier.to_string(),
84 detail: Some(s),
85 symbol: None,
86 module_id: None,
87 import_chain,
88 cycle: None,
89 },
90 ModuleResolveError::AccessDenied(s) => ImportError {
91 kind: ImportErrorKind::AccessDenied,
92 specifier: specifier.to_string(),
93 detail: Some(s),
94 symbol: None,
95 module_id: None,
96 import_chain,
97 cycle: None,
98 },
99 ModuleResolveError::IoError(s) => ImportError {
100 kind: ImportErrorKind::IoError,
101 specifier: specifier.to_string(),
102 detail: Some(s),
103 symbol: None,
104 module_id: None,
105 import_chain,
106 cycle: None,
107 },
108 }
109 }
110
111 fn not_exported(specifier: &str, symbol: &str, import_chain: Vec<String>) -> Self {
112 ImportError {
113 kind: ImportErrorKind::NotExported,
114 specifier: specifier.to_string(),
115 detail: None,
116 symbol: Some(symbol.to_string()),
117 module_id: None,
118 import_chain,
119 cycle: None,
120 }
121 }
122
123 fn circular(module_id: &str, cycle: Vec<String>, import_chain: Vec<String>) -> Self {
124 ImportError {
125 kind: ImportErrorKind::CircularImport,
126 specifier: module_id.to_string(),
127 detail: None,
128 symbol: None,
129 module_id: Some(module_id.to_string()),
130 import_chain,
131 cycle: Some(cycle),
132 }
133 }
134
135 fn parse_failed(module_id: &str, detail: String, import_chain: Vec<String>) -> Self {
136 ImportError {
137 kind: ImportErrorKind::ParseFailed,
138 specifier: module_id.to_string(),
139 detail: Some(detail),
140 symbol: None,
141 module_id: Some(module_id.to_string()),
142 import_chain,
143 cycle: None,
144 }
145 }
146}
147
148#[derive(Debug, Clone, PartialEq)]
150pub enum RuntimeError {
151 UndefinedVariable(String),
153
154 TypeError(String),
156
157 TypeErrorDetailed { expected: String, got: String },
159
160 InvalidOperation(String),
162
163 DivisionByZero,
165
166 NotCallable(String),
168
169 WrongArity { expected: usize, got: usize },
171
172 Return(Value),
174
175 Yield(Value),
177
178 Break,
180
181 Continue,
183
184 Throw(Value),
186
187 ImportError(Box<ImportError>),
189
190 WithCallStack {
192 error: Box<RuntimeError>,
193 call_stack: Vec<CallFrame>,
194 },
195
196 ExecutionLimit(crate::runtime::ExecutionLimitError),
198
199 CustomError(String),
201
202 DebugPause,
204}
205
206impl std::fmt::Display for RuntimeError {
207 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
208 match self {
209 RuntimeError::UndefinedVariable(name) => write!(f, "Undefined variable: {}", name),
210 RuntimeError::TypeError(msg) => write!(f, "Type error: {}", msg),
211 RuntimeError::TypeErrorDetailed { expected, got } => {
212 write!(f, "Type error: expected {}, got {}", expected, got)
213 }
214 RuntimeError::InvalidOperation(msg) => write!(f, "Invalid operation: {}", msg),
215 RuntimeError::DivisionByZero => write!(f, "Division by zero"),
216 RuntimeError::NotCallable(name) => write!(f, "Not callable: {}", name),
217 RuntimeError::WrongArity { expected, got } => {
218 write!(
219 f,
220 "Wrong number of arguments: expected {}, got {}",
221 expected, got
222 )
223 }
224 RuntimeError::Return(val) => write!(f, "Return: {}", val),
225 RuntimeError::Yield(val) => write!(f, "Yield: {}", val),
226 RuntimeError::Break => write!(f, "Break outside of loop"),
227 RuntimeError::Continue => write!(f, "Continue outside of loop"),
228 RuntimeError::Throw(val) => write!(f, "Throw: {}", val),
229 RuntimeError::ImportError(e) => {
230 let msg = match e.kind {
231 ImportErrorKind::ImportDisabled => "Import is disabled".to_string(),
232 ImportErrorKind::InvalidSpecifier => format!(
233 "Invalid module specifier: {}",
234 e.detail.clone().unwrap_or_else(|| e.specifier.clone())
235 ),
236 ImportErrorKind::NoBaseDir => format!(
237 "No base directory to resolve specifier: {}",
238 e.detail.clone().unwrap_or_else(|| e.specifier.clone())
239 ),
240 ImportErrorKind::NotFound => format!(
241 "Module not found: {}",
242 e.detail.clone().unwrap_or_else(|| e.specifier.clone())
243 ),
244 ImportErrorKind::AccessDenied => format!(
245 "Module access denied: {}",
246 e.detail.clone().unwrap_or_else(|| e.specifier.clone())
247 ),
248 ImportErrorKind::IoError => format!(
249 "Module IO error: {}",
250 e.detail.clone().unwrap_or_else(|| e.specifier.clone())
251 ),
252 ImportErrorKind::NotExported => format!(
253 "'{}' is not exported by module {}",
254 e.symbol.clone().unwrap_or_else(|| "<unknown>".to_string()),
255 e.specifier
256 ),
257 ImportErrorKind::CircularImport => {
258 let cycle = e.cycle.clone().unwrap_or_else(|| vec![e.specifier.clone()]);
259 format!("circular import detected: {}", cycle.join(" -> "))
260 }
261 ImportErrorKind::ParseFailed => format!(
262 "parse failed for module {}: {}",
263 e.module_id.clone().unwrap_or_else(|| e.specifier.clone()),
264 e.detail.clone().unwrap_or_else(|| "<unknown>".to_string())
265 ),
266 };
267
268 write!(f, "Import error: {}", msg)?;
269 if !e.import_chain.is_empty() {
270 write!(f, "\nImport chain: {}", e.import_chain.join(" -> "))?;
271 }
272 Ok(())
273 }
274 RuntimeError::WithCallStack { error, call_stack } => {
275 write!(f, "{}", error)?;
276 if !call_stack.is_empty() {
277 let frames = call_stack
278 .iter()
279 .map(|fr| fr.signature.as_str())
280 .collect::<Vec<_>>()
281 .join(" -> ");
282 write!(f, "\nCall stack: {}", frames)?;
283 }
284 Ok(())
285 }
286 RuntimeError::CustomError(msg) => write!(f, "{}", msg),
287 RuntimeError::ExecutionLimit(e) => write!(f, "{}", e),
288 RuntimeError::DebugPause => write!(f, "Debugger pause"),
289 }
290 }
291}
292
293impl std::error::Error for RuntimeError {}
294
295pub type EvalResult = Result<Value, RuntimeError>;
296
297#[derive(Debug, Clone, PartialEq)]
302pub struct ErrorReport {
303 pub phase: String,
304 pub kind: String,
305 pub message: String,
306 pub import_chain: Vec<String>,
307 pub call_stack: Vec<CallFrame>,
308}
309
310impl ErrorReport {
311 pub fn io_error(message: impl Into<String>) -> Self {
312 ErrorReport {
313 phase: "io".to_string(),
314 kind: "IoError".to_string(),
315 message: message.into(),
316 import_chain: Vec::new(),
317 call_stack: Vec::new(),
318 }
319 }
320
321 pub fn parse_error(message: impl Into<String>) -> Self {
322 ErrorReport {
323 phase: "parse".to_string(),
324 kind: "ParseError".to_string(),
325 message: message.into(),
326 import_chain: Vec::new(),
327 call_stack: Vec::new(),
328 }
329 }
330
331 pub fn to_json_value(&self) -> JsonValue {
332 let call_stack = self
333 .call_stack
334 .iter()
335 .map(|fr| json!({"name": fr.name, "signature": fr.signature}))
336 .collect::<Vec<_>>();
337
338 json!({
339 "phase": self.phase,
340 "kind": self.kind,
341 "message": self.message,
342 "import_chain": self.import_chain,
343 "call_stack": call_stack,
344 })
345 }
346
347 pub fn to_json_pretty(&self) -> String {
348 serde_json::to_string_pretty(&self.to_json_value()).unwrap_or_else(|_| {
349 "{\n \"error\": \"failed to serialize ErrorReport\"\n}".to_string()
350 })
351 }
352}
353
354impl RuntimeError {
355 fn peel_call_stack(&self) -> (&RuntimeError, Vec<CallFrame>) {
356 let mut current = self;
357 let mut frames: Vec<CallFrame> = Vec::new();
358
359 while let RuntimeError::WithCallStack { error, call_stack } = current {
360 if frames.is_empty() {
361 frames = call_stack.clone();
362 }
363 current = error.as_ref();
364 }
365
366 (current, frames)
367 }
368
369 fn kind_name(&self) -> String {
370 match self {
371 RuntimeError::UndefinedVariable(_) => "UndefinedVariable",
372 RuntimeError::TypeError(_) | RuntimeError::TypeErrorDetailed { .. } => "TypeError",
373 RuntimeError::InvalidOperation(_) => "InvalidOperation",
374 RuntimeError::DivisionByZero => "DivisionByZero",
375 RuntimeError::NotCallable(_) => "NotCallable",
376 RuntimeError::WrongArity { .. } => "WrongArity",
377 RuntimeError::Return(_) => "Return",
378 RuntimeError::Yield(_) => "Yield",
379 RuntimeError::Break => "Break",
380 RuntimeError::Continue => "Continue",
381 RuntimeError::Throw(_) => "Throw",
382 RuntimeError::ImportError(e) => match e.kind {
383 ImportErrorKind::ImportDisabled => "ImportDisabled",
384 ImportErrorKind::InvalidSpecifier => "InvalidSpecifier",
385 ImportErrorKind::NoBaseDir => "NoBaseDir",
386 ImportErrorKind::NotFound => "NotFound",
387 ImportErrorKind::AccessDenied => "AccessDenied",
388 ImportErrorKind::IoError => "IoError",
389 ImportErrorKind::NotExported => "NotExported",
390 ImportErrorKind::CircularImport => "CircularImport",
391 ImportErrorKind::ParseFailed => "ParseFailed",
392 },
393 RuntimeError::WithCallStack { .. } => "WithCallStack",
394 RuntimeError::ExecutionLimit(_) => "ExecutionLimit",
395 RuntimeError::CustomError(_) => "CustomError",
396 RuntimeError::DebugPause => "DebugPause",
397 }
398 .to_string()
399 }
400
401 fn base_message(&self) -> String {
402 match self {
403 RuntimeError::WithCallStack { error, .. } => error.base_message(),
404 RuntimeError::ImportError(e) => {
405 let msg = match e.kind {
406 ImportErrorKind::ImportDisabled => "Import is disabled".to_string(),
407 ImportErrorKind::InvalidSpecifier => format!(
408 "Invalid module specifier: {}",
409 e.detail.clone().unwrap_or_else(|| e.specifier.clone())
410 ),
411 ImportErrorKind::NoBaseDir => format!(
412 "No base directory to resolve specifier: {}",
413 e.detail.clone().unwrap_or_else(|| e.specifier.clone())
414 ),
415 ImportErrorKind::NotFound => format!(
416 "Module not found: {}",
417 e.detail.clone().unwrap_or_else(|| e.specifier.clone())
418 ),
419 ImportErrorKind::AccessDenied => format!(
420 "Module access denied: {}",
421 e.detail.clone().unwrap_or_else(|| e.specifier.clone())
422 ),
423 ImportErrorKind::IoError => format!(
424 "Module IO error: {}",
425 e.detail.clone().unwrap_or_else(|| e.specifier.clone())
426 ),
427 ImportErrorKind::NotExported => format!(
428 "'{}' is not exported by module {}",
429 e.symbol.clone().unwrap_or_else(|| "<unknown>".to_string()),
430 e.specifier
431 ),
432 ImportErrorKind::CircularImport => {
433 let cycle = e.cycle.clone().unwrap_or_else(|| vec![e.specifier.clone()]);
434 format!("circular import detected: {}", cycle.join(" -> "))
435 }
436 ImportErrorKind::ParseFailed => format!(
437 "parse failed for module {}: {}",
438 e.module_id.clone().unwrap_or_else(|| e.specifier.clone()),
439 e.detail.clone().unwrap_or_else(|| "<unknown>".to_string())
440 ),
441 };
442
443 format!("Import error: {msg}")
444 }
445 other => other.to_string(),
446 }
447 }
448
449 pub fn to_error_report(&self) -> ErrorReport {
450 let (base, call_stack) = self.peel_call_stack();
451
452 let import_chain = match base {
453 RuntimeError::ImportError(e) => e.import_chain.clone(),
454 _ => Vec::new(),
455 };
456
457 ErrorReport {
458 phase: "runtime".to_string(),
459 kind: base.kind_name(),
460 message: base.base_message(),
461 import_chain,
462 call_stack,
463 }
464 }
465}
466
467pub struct Evaluator {
469 env: Rc<RefCell<Environment>>,
471 registry: BuiltInRegistry,
473 trace: VecDeque<String>,
475 trace_seq: u64,
477 trace_entries: VecDeque<crate::runtime::TraceEntry>,
479 trace_buffer_size: usize,
481
482 module_resolver: Box<dyn ModuleResolver>,
484 module_cache: HashMap<String, HashMap<String, Value>>,
486 module_stack: Vec<String>,
488 export_stack: Vec<HashMap<String, Value>>,
490 import_base_stack: Vec<ModuleContext>,
492
493 call_stack: Vec<CallFrame>,
495
496 limits: crate::runtime::ExecutionLimits,
498 current_source_file: Option<String>,
500 current_line: std::cell::Cell<usize>,
502 step_counter: std::cell::Cell<usize>,
504 call_stack_depth: std::cell::Cell<usize>,
506 start_time: std::cell::Cell<Option<std::time::Instant>>,
508}
509
510impl Evaluator {
511 const DEFAULT_TRACE_BUFFER_SIZE: usize = 1024;
513
514 fn register_builtins_into_env(registry: &BuiltInRegistry, env: &mut Environment) {
515 for name in registry.names() {
516 let arity = registry.get(&name).map(|(_, a)| a).unwrap_or(0);
517 env.set(name.clone(), Value::BuiltIn { name, arity });
518 }
519 }
520
521 fn eval_step(&self) -> Result<(), RuntimeError> {
523 let steps = self.step_counter.get();
524
525 if let Some(limit) = self.limits.max_steps
526 && steps >= limit
527 {
528 return Err(RuntimeError::ExecutionLimit(
529 crate::runtime::ExecutionLimitError::StepLimitExceeded { steps, limit },
530 ));
531 }
532
533 self.step_counter.set(steps + 1);
534 Ok(())
535 }
536
537 pub fn reset_step_counter(&mut self) {
541 self.step_counter.set(0);
542 }
543
544 pub fn step_count(&self) -> usize {
548 self.step_counter.get()
549 }
550
551 pub fn set_source_file(&mut self, file: String) {
553 self.current_source_file = Some(file);
554 }
555
556 pub fn get_source_file(&self) -> Option<&str> {
558 self.current_source_file.as_deref()
559 }
560
561 pub fn set_current_line(&self, line: usize) {
563 self.current_line.set(line);
564 }
565
566 pub fn get_current_line(&self) -> usize {
568 self.current_line.get()
569 }
570
571 pub fn get_call_stack(&self) -> &[CallFrame] {
573 &self.call_stack
574 }
575
576 pub fn get_call_stack_depth(&self) -> usize {
578 self.call_stack_depth.get()
579 }
580
581 fn check_timeout(&self) -> Result<(), RuntimeError> {
583 if let Some(limit_ms) = self.limits.max_duration_ms
584 && let Some(start) = self.start_time.get()
585 {
586 let elapsed = start.elapsed().as_millis() as u64;
587 if elapsed >= limit_ms {
588 return Err(RuntimeError::ExecutionLimit(
589 crate::runtime::ExecutionLimitError::DurationExceeded {
590 duration_ms: elapsed,
591 limit: limit_ms,
592 },
593 ));
594 }
595 }
596 Ok(())
597 }
598
599 fn enter_call(&self) -> Result<(), RuntimeError> {
601 if let Some(limit) = self.limits.max_recursion_depth {
602 let depth = self.call_stack_depth.get();
603 if depth >= limit {
604 return Err(RuntimeError::ExecutionLimit(
605 crate::runtime::ExecutionLimitError::RecursionDepthExceeded { depth, limit },
606 ));
607 }
608 self.call_stack_depth.set(depth + 1);
609 }
610 Ok(())
611 }
612
613 fn exit_call(&self) {
615 if self.limits.max_recursion_depth.is_some() {
616 let depth = self.call_stack_depth.get();
617 self.call_stack_depth.set(depth.saturating_sub(1));
618 }
619 }
620
621 pub fn set_limits(&mut self, limits: crate::runtime::ExecutionLimits) {
623 self.limits = limits;
624 }
625
626 pub fn limits(&self) -> &crate::runtime::ExecutionLimits {
628 &self.limits
629 }
630
631 fn is_control_flow_error(err: &RuntimeError) -> bool {
632 matches!(
633 err,
634 RuntimeError::Return(_)
635 | RuntimeError::Yield(_)
636 | RuntimeError::Break
637 | RuntimeError::Continue
638 | RuntimeError::DebugPause
639 )
640 }
641
642 fn attach_call_stack_if_absent(&self, err: RuntimeError) -> RuntimeError {
643 if Self::is_control_flow_error(&err) {
644 return err;
645 }
646 match err {
647 RuntimeError::WithCallStack { .. } => err,
648 other => RuntimeError::WithCallStack {
649 error: Box::new(other),
650 call_stack: self.call_stack.clone(),
651 },
652 }
653 }
654
655 pub fn new() -> Self {
657 Self::with_permissions_and_trace_buffer(
658 crate::builtins::IOPermissions::default(),
659 Self::DEFAULT_TRACE_BUFFER_SIZE,
660 )
661 }
662
663 pub fn with_permissions(permissions: crate::builtins::IOPermissions) -> Self {
665 Self::with_permissions_and_trace_buffer(permissions, Self::DEFAULT_TRACE_BUFFER_SIZE)
666 }
667
668 pub fn with_permissions_and_trace_buffer(
670 permissions: crate::builtins::IOPermissions,
671 trace_buffer_size: usize,
672 ) -> Self {
673 let env = Rc::new(RefCell::new(Environment::new()));
674
675 let registry = BuiltInRegistry::with_permissions(permissions);
677 Self::register_builtins_into_env(®istry, &mut env.borrow_mut());
678
679 Evaluator {
680 env,
681 registry,
682 trace: VecDeque::new(),
683 trace_seq: 0,
684 trace_entries: VecDeque::new(),
685 trace_buffer_size,
686
687 module_resolver: Box::new(DisabledModuleResolver),
688 module_cache: HashMap::new(),
689 module_stack: Vec::new(),
690 export_stack: Vec::new(),
691 import_base_stack: Vec::new(),
692
693 call_stack: Vec::new(),
694
695 limits: crate::runtime::ExecutionLimits::default(),
696 current_source_file: None,
697 current_line: std::cell::Cell::new(0),
698 step_counter: std::cell::Cell::new(0),
699 call_stack_depth: std::cell::Cell::new(0),
700 start_time: std::cell::Cell::new(None),
701 }
702 }
703
704 pub fn with_env(env: Rc<RefCell<Environment>>) -> Self {
706 let registry = BuiltInRegistry::new();
707 Evaluator {
708 env,
709 registry,
710 trace: VecDeque::new(),
711 trace_seq: 0,
712 trace_entries: VecDeque::new(),
713 trace_buffer_size: Self::DEFAULT_TRACE_BUFFER_SIZE,
714
715 module_resolver: Box::new(DisabledModuleResolver),
716 module_cache: HashMap::new(),
717 module_stack: Vec::new(),
718 export_stack: Vec::new(),
719 import_base_stack: Vec::new(),
720
721 call_stack: Vec::new(),
722
723 limits: crate::runtime::ExecutionLimits::default(),
724 current_source_file: None,
725 current_line: std::cell::Cell::new(0),
726 step_counter: std::cell::Cell::new(0),
727 call_stack_depth: std::cell::Cell::new(0),
728 start_time: std::cell::Cell::new(None),
729 }
730 }
731
732 pub fn clear_call_stack(&mut self) {
734 self.call_stack.clear();
735 }
736
737 pub fn set_module_resolver(&mut self, resolver: Box<dyn ModuleResolver>) {
739 self.module_resolver = resolver;
740 }
741
742 pub fn push_import_base(&mut self, module_id: String, base_dir: Option<std::path::PathBuf>) {
746 self.import_base_stack.push(ModuleContext {
747 module_id,
748 base_dir,
749 });
750 }
751
752 pub fn pop_import_base(&mut self) {
754 self.import_base_stack.pop();
755 }
756
757 pub fn trace_push(&mut self, msg: String) {
759 self.trace_seq = self.trace_seq.saturating_add(1);
760 let entry = format!("#{} {}", self.trace_seq, msg);
761
762 if self.trace.len() >= self.trace_buffer_size {
763 self.trace.pop_front();
764 }
765 self.trace.push_back(entry);
766 }
767
768 fn trace_push_entry(&mut self, entry: crate::runtime::TraceEntry) {
770 self.trace_seq = self.trace_seq.saturating_add(1);
771
772 if self.trace_entries.len() >= self.trace_buffer_size {
774 self.trace_entries.pop_front();
775 }
776 self.trace_entries.push_back(entry.clone());
777
778 let formatted = entry.format();
780 let msg = format!("#{} {}", self.trace_seq, formatted);
781 if self.trace.len() >= self.trace_buffer_size {
782 self.trace.pop_front();
783 }
784 self.trace.push_back(msg);
785 }
786
787 pub fn take_trace(&mut self) -> Vec<String> {
789 std::mem::take(&mut self.trace).into_iter().collect()
790 }
791
792 pub fn trace_records(&self) -> Vec<crate::runtime::TraceEntry> {
794 self.trace_entries.iter().cloned().collect()
795 }
796
797 pub fn trace_by_level(
799 &self,
800 level: crate::runtime::TraceLevel,
801 ) -> Vec<crate::runtime::TraceEntry> {
802 self.trace_entries
803 .iter()
804 .filter(|e| e.level == level)
805 .cloned()
806 .collect()
807 }
808
809 pub fn trace_by_category(&self, category: &str) -> Vec<crate::runtime::TraceEntry> {
811 self.trace_entries
812 .iter()
813 .filter(|e| e.category == category)
814 .cloned()
815 .collect()
816 }
817
818 pub fn trace_by_label(&self, label: &str) -> Vec<crate::runtime::TraceEntry> {
820 self.trace_entries
821 .iter()
822 .filter(|e| e.label.as_deref() == Some(label))
823 .cloned()
824 .collect()
825 }
826
827 pub fn trace_since(&self, since: std::time::Instant) -> Vec<crate::runtime::TraceEntry> {
829 self.trace_entries
830 .iter()
831 .filter(|e| e.timestamp >= since)
832 .cloned()
833 .collect()
834 }
835
836 pub fn trace_filter(
838 &self,
839 filter: &crate::runtime::TraceFilter,
840 ) -> Vec<crate::runtime::TraceEntry> {
841 self.trace_entries
842 .iter()
843 .filter(|e| filter.matches(e))
844 .cloned()
845 .collect()
846 }
847
848 pub fn trace_stats(&self) -> crate::runtime::TraceStats {
850 use std::collections::HashMap;
851
852 let mut by_level = HashMap::new();
853 let mut by_category = HashMap::new();
854
855 for entry in &self.trace_entries {
856 *by_level.entry(entry.level).or_insert(0) += 1;
857 *by_category.entry(entry.category.clone()).or_insert(0) += 1;
858 }
859
860 crate::runtime::TraceStats {
861 total_entries: self.trace_entries.len(),
862 by_level,
863 by_category,
864 buffer_size: self.trace_buffer_size,
865 buffer_full: self.trace_entries.len() >= self.trace_buffer_size,
866 }
867 }
868
869 pub fn clear_trace(&mut self) {
871 self.trace.clear();
872 self.trace_entries.clear();
873 self.trace_seq = 0;
874 }
875
876 pub fn set_trace_buffer_size(&mut self, size: usize) {
881 self.trace_buffer_size = size;
882
883 while self.trace.len() > size {
885 self.trace.pop_front();
886 }
887 while self.trace_entries.len() > size {
888 self.trace_entries.pop_front();
889 }
890 }
891
892 pub fn reset_env(&mut self) {
897 self.env = Rc::new(RefCell::new(Environment::new()));
899
900 self.trace.clear();
902 self.trace_entries.clear();
903 self.trace_seq = 0;
904
905 self.import_base_stack.clear();
907 self.export_stack.clear();
908 self.module_stack.clear();
909
910 self.call_stack.clear();
912
913 Self::register_builtins_into_env(&self.registry, &mut self.env.borrow_mut());
915 }
916
917 pub fn set_global(&mut self, name: impl Into<String>, value: Value) {
919 self.env.borrow_mut().set(name.into(), value);
920 }
921
922 pub fn get_global(&self, name: &str) -> Option<Value> {
924 self.env.borrow().get(name)
925 }
926
927 pub fn enter_child_scope(&mut self) -> Rc<RefCell<Environment>> {
931 let prev = Rc::clone(&self.env);
932 let child = Rc::new(RefCell::new(Environment::with_parent(Rc::clone(&prev))));
933 self.env = child;
934 prev
935 }
936
937 pub fn restore_env(&mut self, prev: Rc<RefCell<Environment>>) {
939 self.env = prev;
940 }
941
942 pub fn eval_program(&mut self, program: &Program) -> EvalResult {
944 if self.limits.max_duration_ms.is_some() {
946 self.start_time.set(Some(std::time::Instant::now()));
947 }
948
949 let mut result = Value::Null;
950
951 for stmt in program {
952 result = self.eval_statement(stmt)?;
953 }
954
955 Ok(result)
956 }
957
958 pub fn eval_statement(&mut self, stmt: &Stmt) -> EvalResult {
960 self.eval_step()?;
962 self.check_timeout()?;
963
964 match stmt {
965 Stmt::Set { name, value } => {
966 let val = self.eval_expression(value)?;
967 self.env.borrow_mut().set(name.clone(), val.clone());
968 Ok(val)
969 }
970
971 Stmt::SetIndex {
972 object,
973 index,
974 value,
975 } => {
976 let val = self.eval_expression(value)?;
978
979 if let Expr::Identifier(name) = object.as_ref() {
981 let obj = self
983 .env
984 .borrow()
985 .get(name)
986 .ok_or_else(|| RuntimeError::UndefinedVariable(name.clone()))?;
987
988 let idx_val = self.eval_expression(index)?;
990
991 let new_obj = match (obj, idx_val) {
993 (Value::Array(mut arr), Value::Number(n)) => {
994 let idx = n as usize;
995 if idx >= arr.len() {
996 return Err(RuntimeError::InvalidOperation(format!(
997 "Index {} out of bounds (array length: {})",
998 idx,
999 arr.len()
1000 )));
1001 }
1002 arr[idx] = val.clone();
1003 Value::Array(arr)
1004 }
1005 (Value::Dict(mut dict), Value::String(key)) => {
1006 dict.insert(key, val.clone());
1007 Value::Dict(dict)
1008 }
1009 (obj, idx) => {
1010 return Err(RuntimeError::TypeError(format!(
1011 "Cannot index {} with {}",
1012 obj.type_name(),
1013 idx.type_name()
1014 )));
1015 }
1016 };
1017
1018 self.env.borrow_mut().set(name.clone(), new_obj);
1020 Ok(val)
1021 } else {
1022 Err(RuntimeError::InvalidOperation(
1024 "Can only assign to simple variable indices (e.g., dict[key], not expr[key])"
1025 .to_string(),
1026 ))
1027 }
1028 }
1029
1030 Stmt::FuncDef { name, params, body } => {
1031 let func = Value::Function {
1032 name: Some(name.clone()),
1033 params: params.clone(),
1034 body: body.clone(),
1035 env: Rc::clone(&self.env),
1036 };
1037 self.env.borrow_mut().set(name.clone(), func.clone());
1038 Ok(func)
1039 }
1040
1041 Stmt::GeneratorDef { name, params, body } => {
1042 let r#gen = Value::Generator {
1043 params: params.clone(),
1044 body: body.clone(),
1045 env: Rc::clone(&self.env),
1046 state: GeneratorState::NotStarted,
1047 };
1048 self.env.borrow_mut().set(name.clone(), r#gen.clone());
1049 Ok(r#gen)
1050 }
1051
1052 Stmt::LazyDef { name, expr } => {
1053 let lazy = Value::Lazy {
1054 expr: expr.clone(),
1055 env: Rc::clone(&self.env),
1056 cached: None,
1057 };
1058 self.env.borrow_mut().set(name.clone(), lazy.clone());
1059 Ok(lazy)
1060 }
1061
1062 Stmt::Return(expr) => {
1063 let val = self.eval_expression(expr)?;
1064 Err(RuntimeError::Return(val))
1065 }
1066
1067 Stmt::Yield(expr) => {
1068 let val = self.eval_expression(expr)?;
1069 Err(RuntimeError::Yield(val))
1070 }
1071
1072 Stmt::Break => Err(RuntimeError::Break),
1073
1074 Stmt::Continue => Err(RuntimeError::Continue),
1075
1076 Stmt::While { condition, body } => {
1077 let mut result = Value::Null;
1078
1079 loop {
1080 let cond = self.eval_expression(condition)?;
1081 if !cond.is_truthy() {
1082 break;
1083 }
1084
1085 let mut should_break = false;
1086 for stmt in body {
1087 match self.eval_statement(stmt) {
1088 Ok(val) => result = val,
1089 Err(RuntimeError::Break) => {
1090 should_break = true;
1091 break;
1092 }
1093 Err(RuntimeError::Continue) => break,
1094 Err(e) => return Err(e),
1095 }
1096 }
1097
1098 if should_break {
1099 break;
1100 }
1101 }
1102
1103 Ok(result)
1104 }
1105
1106 Stmt::For {
1107 var,
1108 iterable,
1109 body,
1110 } => {
1111 let iter_val = self.eval_expression(iterable)?;
1112 let mut result = Value::Null;
1113
1114 match iter_val {
1115 Value::Array(arr) => {
1116 let mut should_break = false;
1117 for item in arr {
1118 self.env.borrow_mut().set(var.clone(), item);
1119 for stmt in body {
1120 match self.eval_statement(stmt) {
1121 Ok(val) => result = val,
1122 Err(RuntimeError::Break) => {
1123 should_break = true;
1124 break;
1125 }
1126 Err(RuntimeError::Continue) => break,
1127 Err(e) => return Err(e),
1128 }
1129 }
1130 if should_break {
1131 break;
1132 }
1133 }
1134 }
1135 _ => {
1136 return Err(RuntimeError::TypeError(format!(
1137 "Cannot iterate over {}",
1138 iter_val.type_name()
1139 )));
1140 }
1141 }
1142
1143 Ok(result)
1144 }
1145
1146 Stmt::ForIndexed {
1147 index_var,
1148 value_var,
1149 iterable,
1150 body,
1151 } => {
1152 let iter_val = self.eval_expression(iterable)?;
1153 let mut result = Value::Null;
1154
1155 match iter_val {
1156 Value::Array(arr) => {
1157 let mut should_break = false;
1158 for (idx, item) in arr.iter().enumerate() {
1159 self.env
1160 .borrow_mut()
1161 .set(index_var.clone(), Value::Number(idx as f64));
1162 self.env.borrow_mut().set(value_var.clone(), item.clone());
1163 for stmt in body {
1164 match self.eval_statement(stmt) {
1165 Ok(val) => result = val,
1166 Err(RuntimeError::Break) => {
1167 should_break = true;
1168 break;
1169 }
1170 Err(RuntimeError::Continue) => break,
1171 Err(e) => return Err(e),
1172 }
1173 }
1174 if should_break {
1175 break;
1176 }
1177 }
1178 }
1179 _ => {
1180 return Err(RuntimeError::TypeError(format!(
1181 "Cannot iterate over {}",
1182 iter_val.type_name()
1183 )));
1184 }
1185 }
1186
1187 Ok(result)
1188 }
1189
1190 Stmt::Switch {
1191 expr,
1192 cases,
1193 default,
1194 } => {
1195 let val = self.eval_expression(expr)?;
1196
1197 for (case_expr, case_body) in cases {
1198 let case_val = self.eval_expression(case_expr)?;
1199 if val.equals(&case_val) {
1200 let mut result = Value::Null;
1201 for stmt in case_body {
1202 result = self.eval_statement(stmt)?;
1203 }
1204 return Ok(result);
1205 }
1206 }
1207
1208 if let Some(default_body) = default {
1209 let mut result = Value::Null;
1210 for stmt in default_body {
1211 result = self.eval_statement(stmt)?;
1212 }
1213 return Ok(result);
1214 }
1215
1216 Ok(Value::Null)
1217 }
1218
1219 Stmt::Import {
1220 names,
1221 path,
1222 aliases,
1223 namespace,
1224 } => self.eval_import(names, path, aliases, namespace.as_ref()),
1225
1226 Stmt::Export(name) => self.eval_export(name),
1227
1228 Stmt::Throw(expr) => {
1229 let val = self.eval_expression(expr)?;
1230 Err(RuntimeError::Throw(val))
1231 }
1232
1233 Stmt::Expression(expr) => self.eval_expression(expr),
1234 }
1235 }
1236
1237 pub fn eval_expression(&mut self, expr: &Expr) -> EvalResult {
1239 match expr {
1240 Expr::Number(n) => Ok(Value::Number(*n)),
1241
1242 Expr::BigInteger(s) => {
1243 use num_bigint::BigInt;
1245 use num_rational::Ratio;
1246
1247 match s.parse::<BigInt>() {
1248 Ok(big_int) => Ok(Value::Fraction(Ratio::new(big_int, BigInt::from(1)))),
1249 Err(_) => Err(RuntimeError::InvalidOperation(format!(
1250 "Invalid big integer: {}",
1251 s
1252 ))),
1253 }
1254 }
1255
1256 Expr::String(s) => Ok(Value::String(s.clone())),
1257
1258 Expr::Boolean(b) => Ok(Value::Boolean(*b)),
1259
1260 Expr::Null => Ok(Value::Null),
1261
1262 Expr::Identifier(name) => self
1263 .env
1264 .borrow()
1265 .get(name)
1266 .ok_or_else(|| RuntimeError::UndefinedVariable(name.clone())),
1267
1268 Expr::Binary { left, op, right } => {
1269 match op {
1271 BinOp::And => {
1272 let left_val = self.eval_expression(left)?;
1273 if !left_val.is_truthy() {
1274 Ok(left_val)
1276 } else {
1277 self.eval_expression(right)
1279 }
1280 }
1281 BinOp::Or => {
1282 let left_val = self.eval_expression(left)?;
1283 if left_val.is_truthy() {
1284 Ok(left_val)
1286 } else {
1287 self.eval_expression(right)
1289 }
1290 }
1291 _ => {
1293 let left_val = self.eval_expression(left)?;
1294 let right_val = self.eval_expression(right)?;
1295 self.eval_binary_op(&left_val, op, &right_val)
1296 }
1297 }
1298 }
1299
1300 Expr::Unary { op, expr } => {
1301 let val = self.eval_expression(expr)?;
1302 self.eval_unary_op(op, &val)
1303 }
1304
1305 Expr::Call { func, args } => {
1306 let name_hint = match func.as_ref() {
1307 Expr::Identifier(name) => Some(name.clone()),
1308 _ => None,
1309 };
1310 let func_val = self.eval_expression(func)?;
1311 let arg_vals: Result<Vec<_>, _> =
1312 args.iter().map(|arg| self.eval_expression(arg)).collect();
1313 let arg_vals = arg_vals?;
1314
1315 self.call_function(name_hint.as_deref(), &func_val, arg_vals)
1316 }
1317
1318 Expr::Array(elements) => {
1319 let vals: Result<Vec<_>, _> =
1320 elements.iter().map(|e| self.eval_expression(e)).collect();
1321 Ok(Value::Array(vals?))
1322 }
1323
1324 Expr::Dict(pairs) => {
1325 let mut map = std::collections::HashMap::new();
1326 for (key, value_expr) in pairs {
1327 let value = self.eval_expression(value_expr)?;
1328 map.insert(key.clone(), value);
1329 }
1330 Ok(Value::Dict(map))
1331 }
1332
1333 Expr::Index { object, index } => {
1334 let obj_val = self.eval_expression(object)?;
1335 let idx_val = self.eval_expression(index)?;
1336
1337 match (obj_val, idx_val) {
1338 (Value::Array(arr), Value::Number(n)) => {
1339 let idx = n as usize;
1340 arr.get(idx).cloned().ok_or_else(|| {
1341 RuntimeError::InvalidOperation(format!("Index {} out of bounds", idx))
1342 })
1343 }
1344 (Value::String(s), Value::Number(n)) => {
1345 let idx = n as usize;
1346 let chars: Vec<char> = s.chars().collect();
1347 chars
1348 .get(idx)
1349 .cloned()
1350 .map(|ch| Value::String(ch.to_string()))
1351 .ok_or_else(|| {
1352 RuntimeError::InvalidOperation(format!(
1353 "Index {} out of bounds (string length: {})",
1354 idx,
1355 chars.len()
1356 ))
1357 })
1358 }
1359 (Value::Dict(dict), Value::String(key)) => {
1360 dict.get(&key).cloned().ok_or_else(|| {
1361 RuntimeError::InvalidOperation(format!("Key '{}' not found", key))
1362 })
1363 }
1364 (obj, idx) => Err(RuntimeError::TypeError(format!(
1365 "Cannot index {} with {}",
1366 obj.type_name(),
1367 idx.type_name()
1368 ))),
1369 }
1370 }
1371
1372 Expr::If {
1373 condition,
1374 then_branch,
1375 elif_branches,
1376 else_branch,
1377 } => {
1378 let cond = self.eval_expression(condition)?;
1379
1380 if cond.is_truthy() {
1381 let mut result = Value::Null;
1382 for stmt in then_branch {
1383 result = self.eval_statement(stmt)?;
1384 }
1385 return Ok(result);
1386 }
1387
1388 for (elif_cond, elif_body) in elif_branches {
1389 let cond = self.eval_expression(elif_cond)?;
1390 if cond.is_truthy() {
1391 let mut result = Value::Null;
1392 for stmt in elif_body {
1393 result = self.eval_statement(stmt)?;
1394 }
1395 return Ok(result);
1396 }
1397 }
1398
1399 if let Some(else_body) = else_branch {
1400 let mut result = Value::Null;
1401 for stmt in else_body {
1402 result = self.eval_statement(stmt)?;
1403 }
1404 return Ok(result);
1405 }
1406
1407 Ok(Value::Null)
1408 }
1409
1410 Expr::Lambda { params, body } => {
1411 Ok(Value::Function {
1413 name: None,
1414 params: params.clone(),
1415 body: body.clone(),
1416 env: Rc::clone(&self.env),
1417 })
1418 }
1419 }
1420 }
1421
1422 fn eval_binary_op(&self, left: &Value, op: &BinOp, right: &Value) -> EvalResult {
1424 match op {
1425 BinOp::Add => match (left, right) {
1426 (Value::Number(a), Value::Number(b)) => Ok(Value::Number(a + b)),
1427 (Value::String(a), Value::String(b)) => Ok(Value::String(format!("{}{}", a, b))),
1428 (Value::Fraction(a), Value::Fraction(b)) => Ok(Value::Fraction(a + b)),
1429 (Value::Number(a), Value::Fraction(b)) | (Value::Fraction(b), Value::Number(a)) => {
1430 use num_bigint::BigInt;
1431 use num_rational::Ratio;
1432 if a.fract() == 0.0 {
1433 let a_frac = Ratio::new(BigInt::from(*a as i64), BigInt::from(1));
1434 Ok(Value::Fraction(a_frac + b))
1435 } else {
1436 use num_traits::ToPrimitive;
1438 let b_float =
1439 b.numer().to_f64().unwrap_or(0.0) / b.denom().to_f64().unwrap_or(1.0);
1440 Ok(Value::Number(a + b_float))
1441 }
1442 }
1443 _ => Err(RuntimeError::TypeError(format!(
1444 "Cannot add {} and {}",
1445 left.type_name(),
1446 right.type_name()
1447 ))),
1448 },
1449
1450 BinOp::Subtract => match (left, right) {
1451 (Value::Number(a), Value::Number(b)) => Ok(Value::Number(a - b)),
1452 (Value::Fraction(a), Value::Fraction(b)) => Ok(Value::Fraction(a - b)),
1453 (Value::Number(a), Value::Fraction(b)) => {
1454 use num_bigint::BigInt;
1455 use num_rational::Ratio;
1456 if a.fract() == 0.0 {
1457 let a_frac = Ratio::new(BigInt::from(*a as i64), BigInt::from(1));
1458 Ok(Value::Fraction(a_frac - b))
1459 } else {
1460 use num_traits::ToPrimitive;
1461 let b_float =
1462 b.numer().to_f64().unwrap_or(0.0) / b.denom().to_f64().unwrap_or(1.0);
1463 Ok(Value::Number(a - b_float))
1464 }
1465 }
1466 (Value::Fraction(a), Value::Number(b)) => {
1467 use num_bigint::BigInt;
1468 use num_rational::Ratio;
1469 if b.fract() == 0.0 {
1470 let b_frac = Ratio::new(BigInt::from(*b as i64), BigInt::from(1));
1471 Ok(Value::Fraction(a - b_frac))
1472 } else {
1473 use num_traits::ToPrimitive;
1474 let a_float =
1475 a.numer().to_f64().unwrap_or(0.0) / a.denom().to_f64().unwrap_or(1.0);
1476 Ok(Value::Number(a_float - b))
1477 }
1478 }
1479 _ => Err(RuntimeError::TypeError(format!(
1480 "Cannot subtract {} from {}",
1481 right.type_name(),
1482 left.type_name()
1483 ))),
1484 },
1485
1486 BinOp::Multiply => match (left, right) {
1487 (Value::Number(a), Value::Number(b)) => {
1488 if a.fract() == 0.0 && b.fract() == 0.0 {
1490 let max_safe = 9007199254740992.0; if a.abs() > max_safe || b.abs() > max_safe {
1493 use num_bigint::BigInt;
1495 use num_rational::Ratio;
1496
1497 let a_str = format!("{:.0}", a);
1499 let b_str = format!("{:.0}", b);
1500
1501 if let (Ok(a_big), Ok(b_big)) =
1502 (a_str.parse::<BigInt>(), b_str.parse::<BigInt>())
1503 {
1504 let result_big = a_big * b_big;
1505 let frac = Ratio::new(result_big, BigInt::from(1));
1506 return Ok(Value::Fraction(frac));
1507 }
1508 }
1509 }
1510 Ok(Value::Number(a * b))
1511 }
1512 (Value::Fraction(a), Value::Fraction(b)) => Ok(Value::Fraction(a * b)),
1513 (Value::Number(a), Value::Fraction(b)) | (Value::Fraction(b), Value::Number(a)) => {
1514 use num_bigint::BigInt;
1515 use num_rational::Ratio;
1516 if a.fract() == 0.0 {
1517 let a_frac = Ratio::new(BigInt::from(*a as i64), BigInt::from(1));
1518 Ok(Value::Fraction(a_frac * b))
1519 } else {
1520 Err(RuntimeError::TypeError(
1521 "Cannot multiply non-integer Number with Fraction".to_string(),
1522 ))
1523 }
1524 }
1525 _ => Err(RuntimeError::TypeError(format!(
1526 "Cannot multiply {} and {}",
1527 left.type_name(),
1528 right.type_name()
1529 ))),
1530 },
1531
1532 BinOp::Divide => match (left, right) {
1533 (Value::Number(a), Value::Number(b)) => {
1534 if *b == 0.0 {
1535 Err(RuntimeError::DivisionByZero)
1536 } else {
1537 Ok(Value::Number(a / b))
1538 }
1539 }
1540 (Value::Fraction(a), Value::Fraction(b)) => {
1541 use num_traits::Zero;
1542 if b.is_zero() {
1543 Err(RuntimeError::DivisionByZero)
1544 } else {
1545 Ok(Value::Fraction(a / b))
1546 }
1547 }
1548 (Value::Number(a), Value::Fraction(b)) => {
1549 use num_bigint::BigInt;
1550 use num_rational::Ratio;
1551 use num_traits::Zero;
1552 if b.is_zero() {
1553 Err(RuntimeError::DivisionByZero)
1554 } else if a.fract() == 0.0 {
1555 let a_frac = Ratio::new(BigInt::from(*a as i64), BigInt::from(1));
1556 Ok(Value::Fraction(a_frac / b))
1557 } else {
1558 use num_traits::ToPrimitive;
1559 let b_float =
1560 b.numer().to_f64().unwrap_or(0.0) / b.denom().to_f64().unwrap_or(1.0);
1561 Ok(Value::Number(a / b_float))
1562 }
1563 }
1564 (Value::Fraction(a), Value::Number(b)) => {
1565 use num_bigint::BigInt;
1566 use num_rational::Ratio;
1567 if *b == 0.0 {
1568 Err(RuntimeError::DivisionByZero)
1569 } else if b.fract() == 0.0 {
1570 let b_frac = Ratio::new(BigInt::from(*b as i64), BigInt::from(1));
1571 Ok(Value::Fraction(a / b_frac))
1572 } else {
1573 use num_traits::ToPrimitive;
1574 let a_float =
1575 a.numer().to_f64().unwrap_or(0.0) / a.denom().to_f64().unwrap_or(1.0);
1576 Ok(Value::Number(a_float / b))
1577 }
1578 }
1579 _ => Err(RuntimeError::TypeError(format!(
1580 "Cannot divide {} by {}",
1581 left.type_name(),
1582 right.type_name()
1583 ))),
1584 },
1585
1586 BinOp::Modulo => match (left, right) {
1587 (Value::Number(a), Value::Number(b)) => {
1588 if *b == 0.0 {
1589 Err(RuntimeError::DivisionByZero)
1590 } else {
1591 Ok(Value::Number(a % b))
1592 }
1593 }
1594 _ => Err(RuntimeError::TypeError(format!(
1595 "Cannot modulo {} by {}",
1596 left.type_name(),
1597 right.type_name()
1598 ))),
1599 },
1600
1601 BinOp::Equal => Ok(Value::Boolean(left.equals(right))),
1602
1603 BinOp::NotEqual => Ok(Value::Boolean(!left.equals(right))),
1604
1605 BinOp::Less => match left.compare(right) {
1606 Some(ord) => Ok(Value::Boolean(ord == std::cmp::Ordering::Less)),
1607 None => Err(RuntimeError::TypeError(format!(
1608 "Cannot compare {} and {}",
1609 left.type_name(),
1610 right.type_name()
1611 ))),
1612 },
1613
1614 BinOp::LessEqual => match left.compare(right) {
1615 Some(ord) => Ok(Value::Boolean(ord != std::cmp::Ordering::Greater)),
1616 None => Err(RuntimeError::TypeError(format!(
1617 "Cannot compare {} and {}",
1618 left.type_name(),
1619 right.type_name()
1620 ))),
1621 },
1622
1623 BinOp::Greater => match left.compare(right) {
1624 Some(ord) => Ok(Value::Boolean(ord == std::cmp::Ordering::Greater)),
1625 None => Err(RuntimeError::TypeError(format!(
1626 "Cannot compare {} and {}",
1627 left.type_name(),
1628 right.type_name()
1629 ))),
1630 },
1631
1632 BinOp::GreaterEqual => match left.compare(right) {
1633 Some(ord) => Ok(Value::Boolean(ord != std::cmp::Ordering::Less)),
1634 None => Err(RuntimeError::TypeError(format!(
1635 "Cannot compare {} and {}",
1636 left.type_name(),
1637 right.type_name()
1638 ))),
1639 },
1640
1641 BinOp::And => {
1642 if !left.is_truthy() {
1643 Ok(left.clone())
1644 } else {
1645 Ok(right.clone())
1646 }
1647 }
1648
1649 BinOp::Or => {
1650 if left.is_truthy() {
1651 Ok(left.clone())
1652 } else {
1653 Ok(right.clone())
1654 }
1655 }
1656 }
1657 }
1658
1659 fn eval_unary_op(&self, op: &UnaryOp, val: &Value) -> EvalResult {
1661 match op {
1662 UnaryOp::Minus => match val {
1663 Value::Number(n) => Ok(Value::Number(-n)),
1664 _ => Err(RuntimeError::TypeError(format!(
1665 "Cannot negate {}",
1666 val.type_name()
1667 ))),
1668 },
1669
1670 UnaryOp::Not => Ok(Value::Boolean(!val.is_truthy())),
1671 }
1672 }
1673
1674 fn call_function(
1676 &mut self,
1677 name_hint: Option<&str>,
1678 func: &Value,
1679 args: Vec<Value>,
1680 ) -> EvalResult {
1681 self.enter_call()?;
1683
1684 let frame = match func {
1685 Value::Function { name, params, .. } => {
1686 let display_name = name_hint
1687 .map(|s| s.to_string())
1688 .or_else(|| name.clone())
1689 .unwrap_or_else(|| "<lambda>".to_string());
1690 let signature = format!("{}({})", display_name, params.join(", "));
1691 CallFrame {
1692 name: display_name.clone(),
1693 signature,
1694 }
1695 }
1696 Value::BuiltIn { name, .. } => {
1697 let arity = self.registry.get(name).map(|(_, a)| a).unwrap_or(0);
1698 let params = if arity == 0 {
1699 String::new()
1700 } else {
1701 (1..=arity)
1702 .map(|i| format!("arg{}", i))
1703 .collect::<Vec<_>>()
1704 .join(", ")
1705 };
1706 let signature = format!("{}({})", name, params);
1707 CallFrame {
1708 name: name.clone(),
1709 signature,
1710 }
1711 }
1712 other => {
1713 let name = name_hint.unwrap_or("<call>").to_string();
1714 let signature = format!("{}(<{}>)", name, other.type_name());
1715 CallFrame { name, signature }
1716 }
1717 };
1718
1719 self.call_stack.push(frame);
1720
1721 match func {
1722 Value::Function {
1723 params, body, env, ..
1724 } => {
1725 if params.len() != args.len() {
1726 let err = RuntimeError::WrongArity {
1727 expected: params.len(),
1728 got: args.len(),
1729 };
1730 let err = self.attach_call_stack_if_absent(err);
1731 let _ = self.call_stack.pop();
1732 self.exit_call();
1733 return Err(err);
1734 }
1735
1736 let func_env = Rc::new(RefCell::new(Environment::with_parent(Rc::clone(env))));
1738
1739 for (param, arg) in params.iter().zip(args.iter()) {
1741 func_env.borrow_mut().set(param.clone(), arg.clone());
1742 }
1743
1744 let prev_env = Rc::clone(&self.env);
1746 self.env = func_env;
1747
1748 let mut result = Value::Null;
1749 for stmt in body {
1750 match self.eval_statement(stmt) {
1751 Ok(val) => result = val,
1752 Err(RuntimeError::Return(val)) => {
1753 result = val;
1754 break;
1755 }
1756 Err(e) => {
1757 self.env = prev_env;
1758 let e = self.attach_call_stack_if_absent(e);
1759 let _ = self.call_stack.pop();
1760 self.exit_call();
1761 return Err(e);
1762 }
1763 }
1764 }
1765
1766 self.env = prev_env;
1767 let _ = self.call_stack.pop();
1768 self.exit_call();
1769 Ok(result)
1770 }
1771
1772 Value::BuiltIn { name, .. } => {
1773 let res = match name.as_str() {
1775 "TRACE" => {
1776 if args.is_empty() {
1777 return {
1778 let err = RuntimeError::WrongArity {
1779 expected: 1,
1780 got: 0,
1781 };
1782 let err = self.attach_call_stack_if_absent(err);
1783 let _ = self.call_stack.pop();
1784 self.exit_call();
1785 Err(err)
1786 };
1787 }
1788
1789 let (label, payload_args) = if args.len() >= 2 {
1792 match &args[0] {
1793 Value::String(s) => (Some(s.as_str()), &args[1..]),
1794 _ => (None, args.as_slice()),
1795 }
1796 } else {
1797 (None, args.as_slice())
1798 };
1799
1800 let payload = payload_args
1801 .iter()
1802 .map(|v| v.to_string())
1803 .collect::<Vec<_>>()
1804 .join(" ");
1805
1806 let msg = match label {
1807 Some(l) => format!("[{}] {}", l, payload),
1808 None => payload,
1809 };
1810
1811 self.trace_push(msg);
1812 Ok(Value::Null)
1813 }
1814 "TRACE_DEBUG" | "TRACE_INFO" | "TRACE_WARN" | "TRACE_ERROR" => {
1815 if args.len() < 2 {
1818 return {
1819 let err = RuntimeError::WrongArity {
1820 expected: 2,
1821 got: args.len(),
1822 };
1823 let err = self.attach_call_stack_if_absent(err);
1824 let _ = self.call_stack.pop();
1825 self.exit_call();
1826 Err(err)
1827 };
1828 }
1829
1830 let level = match name.as_str() {
1832 "TRACE_DEBUG" => crate::runtime::TraceLevel::Debug,
1833 "TRACE_INFO" => crate::runtime::TraceLevel::Info,
1834 "TRACE_WARN" => crate::runtime::TraceLevel::Warn,
1835 "TRACE_ERROR" => crate::runtime::TraceLevel::Error,
1836 _ => unreachable!(),
1837 };
1838
1839 let category = match &args[0] {
1841 Value::String(s) => s.clone(),
1842 _ => {
1843 return {
1844 let err = RuntimeError::CustomError(format!(
1845 "TRACE category must be a string, got {}",
1846 args[0].type_name()
1847 ));
1848 let err = self.attach_call_stack_if_absent(err);
1849 let _ = self.call_stack.pop();
1850 self.exit_call();
1851 Err(err)
1852 };
1853 }
1854 };
1855
1856 let values = args[1..].to_vec();
1858
1859 let entry = crate::runtime::TraceEntry::new(level, category, values);
1861 self.trace_push_entry(entry);
1862
1863 Ok(Value::Null)
1864 }
1865 "MAP" => self.builtin_map(&args),
1866 "FILTER" => self.builtin_filter(&args),
1867 "REDUCE" => self.builtin_reduce(&args),
1868 _ => {
1869 if let Some((func, _arity)) = self.registry.get(name) {
1871 func(&args)
1873 } else {
1874 Err(RuntimeError::NotCallable(format!(
1875 "Built-in function '{}' not found",
1876 name
1877 )))
1878 }
1879 }
1880 };
1881
1882 let _ = self.call_stack.pop();
1883 self.exit_call();
1884 match res {
1885 Ok(v) => Ok(v),
1886 Err(e) => Err(self.attach_call_stack_if_absent(e)),
1887 }
1888 }
1889
1890 _ => {
1891 let err = RuntimeError::NotCallable(func.type_name().to_string());
1892 let err = self.attach_call_stack_if_absent(err);
1893 let _ = self.call_stack.pop();
1894 self.exit_call();
1895 Err(err)
1896 }
1897 }
1898 }
1899
1900 fn builtin_map(&mut self, args: &[Value]) -> EvalResult {
1902 if args.len() != 2 {
1903 return Err(RuntimeError::WrongArity {
1904 expected: 2,
1905 got: args.len(),
1906 });
1907 }
1908
1909 let arr = match &args[0] {
1910 Value::Array(a) => a,
1911 other => {
1912 return Err(RuntimeError::TypeErrorDetailed {
1913 expected: "Array".to_string(),
1914 got: format!("{:?}", other),
1915 });
1916 }
1917 };
1918
1919 let func = &args[1];
1920
1921 let mut result = Vec::new();
1922 for item in arr {
1923 let mapped = self.call_function(None, func, vec![item.clone()])?;
1924 result.push(mapped);
1925 }
1926
1927 Ok(Value::Array(result))
1928 }
1929
1930 fn builtin_filter(&mut self, args: &[Value]) -> EvalResult {
1932 if args.len() != 2 {
1933 return Err(RuntimeError::WrongArity {
1934 expected: 2,
1935 got: args.len(),
1936 });
1937 }
1938
1939 let arr = match &args[0] {
1940 Value::Array(a) => a,
1941 other => {
1942 return Err(RuntimeError::TypeErrorDetailed {
1943 expected: "Array".to_string(),
1944 got: format!("{:?}", other),
1945 });
1946 }
1947 };
1948
1949 let predicate = &args[1];
1950
1951 let mut result = Vec::new();
1952 for item in arr {
1953 let test_result = self.call_function(None, predicate, vec![item.clone()])?;
1954 if test_result.is_truthy() {
1955 result.push(item.clone());
1956 }
1957 }
1958
1959 Ok(Value::Array(result))
1960 }
1961
1962 fn builtin_reduce(&mut self, args: &[Value]) -> EvalResult {
1964 if args.len() != 3 {
1965 return Err(RuntimeError::WrongArity {
1966 expected: 3,
1967 got: args.len(),
1968 });
1969 }
1970
1971 let arr = match &args[0] {
1972 Value::Array(a) => a,
1973 other => {
1974 return Err(RuntimeError::TypeErrorDetailed {
1975 expected: "Array".to_string(),
1976 got: format!("{:?}", other),
1977 });
1978 }
1979 };
1980
1981 let func = match &args[1] {
1982 Value::Function { .. } | Value::BuiltIn { .. } => &args[1],
1983 other => {
1984 return Err(RuntimeError::TypeErrorDetailed {
1985 expected: "Function".to_string(),
1986 got: format!("{:?}", other),
1987 });
1988 }
1989 };
1990
1991 let mut accumulator = args[2].clone();
1992
1993 for (idx, item) in arr.iter().enumerate() {
1994 let arg_count = match func {
1995 Value::Function { params, .. } => params.len(),
1996 Value::BuiltIn { arity, .. } => *arity,
1997 _ => 0,
1998 };
1999
2000 let mut call_args = Vec::new();
2001 call_args.push(accumulator);
2002 call_args.push(item.clone());
2003 if arg_count >= 3 {
2004 call_args.push(Value::Number(idx as f64));
2005 }
2006
2007 if arg_count < 2 {
2008 return Err(RuntimeError::WrongArity {
2009 expected: 2,
2010 got: arg_count,
2011 });
2012 }
2013
2014 accumulator = self.call_function(None, func, call_args)?;
2015 }
2016
2017 Ok(accumulator)
2018 }
2019}
2020
2021impl Evaluator {
2022 fn import_chain(&self) -> Vec<String> {
2023 self.import_base_stack
2024 .iter()
2025 .map(|c| c.module_id.clone())
2026 .collect()
2027 }
2028
2029 fn import_chain_with(&self, leaf: impl Into<String>) -> Vec<String> {
2030 let mut chain = self.import_chain();
2031 chain.push(leaf.into());
2032 chain
2033 }
2034
2035 fn current_import_context(&self) -> Option<&ModuleContext> {
2036 self.import_base_stack.last()
2037 }
2038
2039 fn eval_import(
2040 &mut self,
2041 names: &[String],
2042 specifier: &str,
2043 aliases: &[Option<String>],
2044 namespace: Option<&String>,
2045 ) -> EvalResult {
2046 let from_ctx = self.current_import_context();
2047
2048 let chain_for_resolve = self.import_chain_with(specifier.to_string());
2049
2050 let resolved = self
2051 .module_resolver
2052 .resolve(specifier, from_ctx)
2053 .map_err(|e| {
2054 RuntimeError::ImportError(Box::new(ImportError::from_resolve_error(
2055 specifier,
2056 e,
2057 chain_for_resolve,
2058 )))
2059 })?;
2060
2061 let exports = self.load_module(resolved)?;
2062
2063 if let Some(ns) = namespace {
2064 self.env.borrow_mut().set(ns.clone(), Value::Dict(exports));
2065 return Ok(Value::Null);
2066 }
2067
2068 for (i, name) in names.iter().enumerate() {
2069 let alias = aliases
2070 .get(i)
2071 .and_then(|a| a.clone())
2072 .unwrap_or_else(|| name.clone());
2073 let v = exports.get(name).cloned().ok_or_else(|| {
2074 RuntimeError::ImportError(Box::new(ImportError::not_exported(
2075 specifier,
2076 name,
2077 self.import_chain_with(specifier.to_string()),
2078 )))
2079 })?;
2080 self.env.borrow_mut().set(alias, v);
2081 }
2082
2083 Ok(Value::Null)
2084 }
2085
2086 fn eval_export(&mut self, name: &str) -> EvalResult {
2087 let exports = self.export_stack.last_mut().ok_or_else(|| {
2088 RuntimeError::CustomError("Export error: Export used outside of a module".to_string())
2089 })?;
2090
2091 let val = self.env.borrow().get(name).ok_or_else(|| {
2092 RuntimeError::CustomError(format!("Export error: '{}' is not defined", name))
2093 })?;
2094
2095 exports.insert(name.to_string(), val);
2096 Ok(Value::Null)
2097 }
2098
2099 fn load_module(
2100 &mut self,
2101 resolved: ResolvedModule,
2102 ) -> Result<HashMap<String, Value>, RuntimeError> {
2103 let import_chain = self.import_chain_with(resolved.module_id.clone());
2104
2105 if let Some(cached) = self.module_cache.get(&resolved.module_id) {
2106 return Ok(cached.clone());
2107 }
2108
2109 if self.module_stack.contains(&resolved.module_id) {
2110 let mut chain = self.module_stack.clone();
2111 chain.push(resolved.module_id.clone());
2112 return Err(RuntimeError::ImportError(Box::new(ImportError::circular(
2113 &resolved.module_id,
2114 chain,
2115 import_chain,
2116 ))));
2117 }
2118
2119 self.module_stack.push(resolved.module_id.clone());
2120
2121 let mut parser = crate::parser::Parser::new(&resolved.source);
2123 let program = match parser.parse_program() {
2124 Ok(p) => p,
2125 Err(e) => {
2126 let _ = self.module_stack.pop();
2127 return Err(RuntimeError::ImportError(Box::new(
2128 ImportError::parse_failed(&resolved.module_id, e.to_string(), import_chain),
2129 )));
2130 }
2131 };
2132
2133 let prev_env = Rc::clone(&self.env);
2135 let module_env = Rc::new(RefCell::new(Environment::new()));
2136 Self::register_builtins_into_env(&self.registry, &mut module_env.borrow_mut());
2137 self.env = module_env;
2138
2139 self.import_base_stack.push(ModuleContext {
2141 module_id: resolved.module_id.clone(),
2142 base_dir: resolved.base_dir.clone(),
2143 });
2144
2145 self.export_stack.push(HashMap::new());
2147
2148 let eval_res = self.eval_program(&program);
2149
2150 let exports = self.export_stack.pop().unwrap_or_default();
2152 self.import_base_stack.pop();
2153 self.env = prev_env;
2154
2155 let _ = self.module_stack.pop();
2157
2158 let _ = eval_res.map_err(|e| self.attach_call_stack_if_absent(e))?;
2160
2161 self.module_cache
2162 .insert(resolved.module_id.clone(), exports.clone());
2163 Ok(exports)
2164 }
2165}
2166
2167impl Default for Evaluator {
2168 fn default() -> Self {
2169 Self::new()
2170 }
2171}