Coverage Report

Created: 2025-09-08 21:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/noah/src/ruchy/src/runtime/interpreter.rs
Line
Count
Source
1
//! High-Performance Interpreter with Safe Value Representation
2
//!
3
//! This module implements the two-tier execution strategy from ruchy-interpreter-spec.md:
4
//! - Tier 0: AST interpreter with enum-based values (safe alternative)
5
//! - Tier 1: JIT compilation (future)
6
//!
7
//! Uses safe Rust enum approach instead of tagged pointers to respect `unsafe_code = "forbid"`.
8
9
#![allow(clippy::unused_self)] // Methods will use self in future phases
10
#![allow(clippy::only_used_in_recursion)] // Recursive print_value is intentional
11
#![allow(clippy::uninlined_format_args)] // Some format strings are clearer unexpanded
12
#![allow(clippy::cast_precision_loss)] // Acceptable for arithmetic operations
13
#![allow(clippy::expect_used)] // Used appropriately in tests
14
#![allow(clippy::cast_possible_truncation)] // Controlled truncations for indices
15
16
use crate::frontend::ast::{BinaryOp as AstBinaryOp, Expr, ExprKind, Literal, StringPart, Pattern, MatchArm};
17
use crate::frontend::Param;
18
use smallvec::{smallvec, SmallVec};
19
use std::collections::HashMap;
20
use std::rc::Rc;
21
22
/// Runtime value representation using safe enum approach
23
/// Alternative to tagged pointers that respects project's `unsafe_code = "forbid"`
24
#[derive(Clone, Debug, PartialEq)]
25
pub enum Value {
26
    /// 64-bit signed integer
27
    Integer(i64),
28
    /// 64-bit float
29
    Float(f64),
30
    /// Boolean value
31
    Bool(bool),
32
    /// Nil/null value
33
    Nil,
34
    /// String value (reference-counted for efficiency)
35
    String(Rc<String>),
36
    /// Array of values
37
    Array(Rc<Vec<Value>>),
38
    /// Tuple of values
39
    Tuple(Rc<Vec<Value>>),
40
    /// Function closure
41
    Closure {
42
        params: Vec<String>,
43
        body: Rc<Expr>,
44
        env: Rc<HashMap<String, Value>>, // Captured environment
45
    },
46
}
47
48
impl Value {
49
    /// Create integer value
50
0
    pub fn from_i64(i: i64) -> Self {
51
0
        Value::Integer(i)
52
0
    }
53
54
    /// Create float value
55
0
    pub fn from_f64(f: f64) -> Self {
56
0
        Value::Float(f)
57
0
    }
58
59
    /// Create boolean value
60
0
    pub fn from_bool(b: bool) -> Self {
61
0
        Value::Bool(b)
62
0
    }
63
64
    /// Create nil value
65
0
    pub fn nil() -> Self {
66
0
        Value::Nil
67
0
    }
68
69
    /// Create string value
70
0
    pub fn from_string(s: String) -> Self {
71
0
        Value::String(Rc::new(s))
72
0
    }
73
74
    /// Create array value
75
0
    pub fn from_array(arr: Vec<Value>) -> Self {
76
0
        Value::Array(Rc::new(arr))
77
0
    }
78
79
    /// Check if value is nil
80
0
    pub fn is_nil(&self) -> bool {
81
0
        matches!(self, Value::Nil)
82
0
    }
83
84
    /// Check if value is truthy (everything except false and nil)
85
0
    pub fn is_truthy(&self) -> bool {
86
0
        match self {
87
0
            Value::Bool(b) => *b,
88
0
            Value::Nil => false,
89
0
            _ => true,
90
        }
91
0
    }
92
93
    /// Extract integer value
94
    /// # Errors
95
    /// Returns error if the value is not an integer
96
0
    pub fn as_i64(&self) -> Result<i64, InterpreterError> {
97
0
        match self {
98
0
            Value::Integer(i) => Ok(*i),
99
0
            _ => Err(InterpreterError::TypeError(format!(
100
0
                "Expected integer, got {}",
101
0
                self.type_name()
102
0
            ))),
103
        }
104
0
    }
105
106
    /// Extract float value  
107
    /// # Errors
108
    /// Returns error if the value is not a float
109
0
    pub fn as_f64(&self) -> Result<f64, InterpreterError> {
110
0
        match self {
111
0
            Value::Float(f) => Ok(*f),
112
0
            _ => Err(InterpreterError::TypeError(format!(
113
0
                "Expected float, got {}",
114
0
                self.type_name()
115
0
            ))),
116
        }
117
0
    }
118
119
    /// Extract boolean value
120
    /// # Errors
121
    /// Returns error if the value is not a boolean
122
0
    pub fn as_bool(&self) -> Result<bool, InterpreterError> {
123
0
        match self {
124
0
            Value::Bool(b) => Ok(*b),
125
0
            _ => Err(InterpreterError::TypeError(format!(
126
0
                "Expected boolean, got {}",
127
0
                self.type_name()
128
0
            ))),
129
        }
130
0
    }
131
132
    /// Get type name for debugging
133
0
    pub fn type_name(&self) -> &'static str {
134
0
        match self {
135
0
            Value::Integer(_) => "integer",
136
0
            Value::Float(_) => "float",
137
0
            Value::Bool(_) => "boolean",
138
0
            Value::Nil => "nil",
139
0
            Value::String(_) => "string",
140
0
            Value::Array(_) => "array",
141
0
            Value::Tuple(_) => "tuple",
142
0
            Value::Closure { .. } => "function",
143
        }
144
0
    }
145
}
146
147
// Note: Complex object structures (ObjectHeader, Class, etc.) will be implemented
148
// in Phase 1 of the interpreter spec when we add proper GC and method dispatch.
149
150
/// Runtime interpreter state
151
pub struct Interpreter {
152
    /// Tagged pointer values for fast operation
153
    stack: Vec<Value>,
154
155
    /// Environment stack for lexical scoping
156
    env_stack: Vec<HashMap<std::string::String, Value>>,
157
158
    /// Call frame for function calls
159
    #[allow(dead_code)]
160
    frames: Vec<CallFrame>,
161
162
    /// Execution statistics for tier transition (will be used in Phase 1)
163
    #[allow(dead_code)]
164
    execution_counts: HashMap<usize, u32>, // Function/method ID -> execution count
165
166
    /// Inline caches for field/method access optimization
167
    field_caches: HashMap<String, InlineCache>,
168
169
    /// Type feedback collection for JIT compilation
170
    type_feedback: TypeFeedback,
171
172
    /// Conservative garbage collector
173
    gc: ConservativeGC,
174
}
175
176
/// Call frame for function invocation (will be used in Phase 1)
177
#[derive(Debug)]
178
#[allow(dead_code)]
179
pub struct CallFrame {
180
    /// Function being executed
181
    closure: Value,
182
183
    /// Instruction pointer
184
    ip: *const u8,
185
186
    /// Base of stack frame
187
    base: usize,
188
189
    /// Number of locals in this frame
190
    locals: usize,
191
}
192
193
/// Interpreter execution result
194
pub enum InterpreterResult {
195
    Continue,
196
    Jump(usize),
197
    Return(Value),
198
    Error(InterpreterError),
199
}
200
201
/// Interpreter errors
202
#[derive(Debug, Clone, PartialEq)]
203
pub enum InterpreterError {
204
    TypeError(std::string::String),
205
    RuntimeError(std::string::String),
206
    StackOverflow,
207
    StackUnderflow,
208
    InvalidInstruction,
209
    DivisionByZero,
210
    IndexOutOfBounds,
211
}
212
213
impl std::fmt::Display for Value {
214
0
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
215
0
        match self {
216
0
            Value::Integer(i) => write!(f, "{i}"),
217
0
            Value::Float(fl) => write!(f, "{fl}"),
218
0
            Value::Bool(b) => write!(f, "{b}"),
219
0
            Value::Nil => write!(f, "nil"),
220
0
            Value::String(s) => write!(f, "{s}"),
221
0
            Value::Array(arr) => {
222
0
                write!(f, "[")?;
223
0
                for (i, val) in arr.iter().enumerate() {
224
0
                    if i > 0 {
225
0
                        write!(f, ", ")?;
226
0
                    }
227
0
                    write!(f, "{val}")?;
228
                }
229
0
                write!(f, "]")
230
            }
231
0
            Value::Tuple(elements) => {
232
0
                write!(f, "(")?;
233
0
                for (i, val) in elements.iter().enumerate() {
234
0
                    if i > 0 {
235
0
                        write!(f, ", ")?;
236
0
                    }
237
0
                    write!(f, "{val}")?;
238
                }
239
0
                write!(f, ")")
240
            }
241
0
            Value::Closure { .. } => write!(f, "<function>"),
242
        }
243
0
    }
244
}
245
246
impl std::fmt::Display for InterpreterError {
247
0
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
248
0
        match self {
249
0
            InterpreterError::TypeError(msg) => write!(f, "Type error: {msg}"),
250
0
            InterpreterError::RuntimeError(msg) => write!(f, "Runtime error: {msg}"),
251
0
            InterpreterError::StackOverflow => write!(f, "Stack overflow"),
252
0
            InterpreterError::StackUnderflow => write!(f, "Stack underflow"),
253
0
            InterpreterError::InvalidInstruction => write!(f, "Invalid instruction"),
254
0
            InterpreterError::DivisionByZero => write!(f, "Division by zero"),
255
0
            InterpreterError::IndexOutOfBounds => write!(f, "Index out of bounds"),
256
        }
257
0
    }
258
}
259
260
impl std::error::Error for InterpreterError {}
261
262
/// Inline cache states for polymorphic method dispatch
263
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
264
pub enum CacheState {
265
    /// No cache entry yet
266
    Uninitialized,
267
    /// Single type cached - fastest path
268
    Monomorphic,
269
    /// 2-4 types cached - still fast
270
    Polymorphic,
271
    /// Too many types - fallback to hash lookup
272
    Megamorphic,
273
}
274
275
/// Cache entry for field access optimization
276
#[derive(Clone, Debug)]
277
pub struct CacheEntry {
278
    /// Type identifier for cache validity
279
    type_id: std::any::TypeId,
280
    /// Field name being accessed
281
    field_name: String,
282
    /// Cached result for this type/field combination
283
    cached_result: Value,
284
    /// Hit count for LRU eviction
285
    hit_count: u32,
286
}
287
288
/// Inline cache for method/field dispatch
289
#[derive(Clone, Debug)]
290
pub struct InlineCache {
291
    /// Current cache state
292
    state: CacheState,
293
    /// Cache entries (inline storage for 2 common entries)
294
    entries: SmallVec<[CacheEntry; 2]>,
295
    /// Total hit count
296
    total_hits: u32,
297
    /// Total miss count
298
    total_misses: u32,
299
}
300
301
impl InlineCache {
302
    /// Create new empty inline cache
303
0
    pub fn new() -> Self {
304
0
        Self {
305
0
            state: CacheState::Uninitialized,
306
0
            entries: smallvec![],
307
0
            total_hits: 0,
308
0
            total_misses: 0,
309
0
        }
310
0
    }
311
312
    /// Look up a field access in the cache
313
0
    pub fn lookup(&mut self, obj: &Value, field_name: &str) -> Option<Value> {
314
0
        let type_id = obj.type_id();
315
316
        // Fast path: check cached entries
317
0
        for entry in &mut self.entries {
318
0
            if entry.type_id == type_id && entry.field_name == field_name {
319
0
                entry.hit_count += 1;
320
0
                self.total_hits += 1;
321
0
                return Some(entry.cached_result.clone());
322
0
            }
323
        }
324
325
        // Cache miss
326
0
        self.total_misses += 1;
327
0
        None
328
0
    }
329
330
    /// Add a new cache entry
331
0
    pub fn insert(&mut self, obj: &Value, field_name: String, result: Value) {
332
0
        let type_id = obj.type_id();
333
0
        let entry = CacheEntry {
334
0
            type_id,
335
0
            field_name,
336
0
            cached_result: result,
337
0
            hit_count: 1,
338
0
        };
339
340
        // Update cache state based on entry count
341
0
        match self.entries.len() {
342
0
            0 => {
343
0
                self.state = CacheState::Monomorphic;
344
0
                self.entries.push(entry);
345
0
            }
346
0
            1..=3 => {
347
0
                self.state = CacheState::Polymorphic;
348
0
                self.entries.push(entry);
349
0
            }
350
            _ => {
351
                // Too many entries - transition to megamorphic
352
0
                self.state = CacheState::Megamorphic;
353
                // Evict least used entry
354
0
                if let Some(min_idx) = self
355
0
                    .entries
356
0
                    .iter()
357
0
                    .enumerate()
358
0
                    .min_by_key(|(_, e)| e.hit_count)
359
0
                    .map(|(i, _)| i)
360
0
                {
361
0
                    self.entries[min_idx] = entry;
362
0
                }
363
            }
364
        }
365
0
    }
366
367
    /// Get cache hit rate for profiling
368
0
    pub fn hit_rate(&self) -> f64 {
369
0
        let total = self.total_hits + self.total_misses;
370
0
        if total == 0 {
371
0
            0.0
372
        } else {
373
0
            f64::from(self.total_hits) / f64::from(total)
374
        }
375
0
    }
376
}
377
378
impl Default for InlineCache {
379
0
    fn default() -> Self {
380
0
        Self::new()
381
0
    }
382
}
383
384
/// Type feedback collection for JIT compilation decisions
385
#[derive(Clone, Debug)]
386
pub struct TypeFeedback {
387
    /// Operation site feedback (indexed by AST node or bytecode offset)
388
    operation_sites: HashMap<usize, OperationFeedback>,
389
    /// Variable type patterns (variable name -> type feedback)
390
    variable_types: HashMap<String, VariableTypeFeedback>,
391
    /// Function call sites with argument/return type information
392
    call_sites: HashMap<usize, CallSiteFeedback>,
393
    /// Total feedback collection count
394
    total_samples: u64,
395
}
396
397
/// Feedback for a specific operation site (binary ops, field access, etc.)
398
#[derive(Clone, Debug)]
399
pub struct OperationFeedback {
400
    /// Types observed for left operand
401
    left_types: SmallVec<[std::any::TypeId; 4]>,
402
    /// Types observed for right operand (for binary ops)
403
    right_types: SmallVec<[std::any::TypeId; 4]>,
404
    /// Result types observed
405
    result_types: SmallVec<[std::any::TypeId; 4]>,
406
    /// Hit counts for each type combination
407
    type_counts: HashMap<(std::any::TypeId, std::any::TypeId), u32>,
408
    /// Total operation count
409
    total_count: u32,
410
}
411
412
/// Type feedback for variables across their lifetime
413
#[derive(Clone, Debug)]
414
pub struct VariableTypeFeedback {
415
    /// Types assigned to this variable
416
    assigned_types: SmallVec<[std::any::TypeId; 4]>,
417
    /// Type transitions (`from_type` -> `to_type`)
418
    transitions: HashMap<std::any::TypeId, HashMap<std::any::TypeId, u32>>,
419
    /// Most common type (for specialization)
420
    dominant_type: Option<std::any::TypeId>,
421
    /// Type stability score (0.0 = highly polymorphic, 1.0 = monomorphic)
422
    stability_score: f64,
423
}
424
425
/// Feedback for function call sites
426
#[derive(Clone, Debug)]
427
pub struct CallSiteFeedback {
428
    /// Argument type patterns observed
429
    arg_type_patterns: SmallVec<[Vec<std::any::TypeId>; 4]>,
430
    /// Return types observed
431
    return_types: SmallVec<[std::any::TypeId; 4]>,
432
    /// Call frequency
433
    call_count: u32,
434
    /// Functions called at this site (for polymorphic calls)
435
    called_functions: HashMap<String, u32>,
436
}
437
438
impl TypeFeedback {
439
    /// Create new type feedback collector
440
0
    pub fn new() -> Self {
441
0
        Self {
442
0
            operation_sites: HashMap::new(),
443
0
            variable_types: HashMap::new(),
444
0
            call_sites: HashMap::new(),
445
0
            total_samples: 0,
446
0
        }
447
0
    }
448
449
    /// Record binary operation type feedback
450
0
    pub fn record_binary_op(
451
0
        &mut self,
452
0
        site_id: usize,
453
0
        left: &Value,
454
0
        right: &Value,
455
0
        result: &Value,
456
0
    ) {
457
0
        let left_type = left.type_id();
458
0
        let right_type = right.type_id();
459
0
        let result_type = result.type_id();
460
461
0
        let feedback = self
462
0
            .operation_sites
463
0
            .entry(site_id)
464
0
            .or_insert_with(|| OperationFeedback {
465
0
                left_types: smallvec![],
466
0
                right_types: smallvec![],
467
0
                result_types: smallvec![],
468
0
                type_counts: HashMap::new(),
469
                total_count: 0,
470
0
            });
471
472
        // Record types if not already seen
473
0
        if !feedback.left_types.contains(&left_type) {
474
0
            feedback.left_types.push(left_type);
475
0
        }
476
0
        if !feedback.right_types.contains(&right_type) {
477
0
            feedback.right_types.push(right_type);
478
0
        }
479
0
        if !feedback.result_types.contains(&result_type) {
480
0
            feedback.result_types.push(result_type);
481
0
        }
482
483
        // Update type combination counts
484
0
        let type_pair = (left_type, right_type);
485
0
        *feedback.type_counts.entry(type_pair).or_insert(0) += 1;
486
0
        feedback.total_count += 1;
487
0
        self.total_samples += 1;
488
0
    }
489
490
    /// Record variable assignment type feedback
491
0
    pub fn record_variable_assignment(&mut self, var_name: &str, new_type: std::any::TypeId) {
492
0
        let feedback = self
493
0
            .variable_types
494
0
            .entry(var_name.to_string())
495
0
            .or_insert_with(|| VariableTypeFeedback {
496
0
                assigned_types: smallvec![],
497
0
                transitions: HashMap::new(),
498
0
                dominant_type: None,
499
                stability_score: 1.0,
500
0
            });
501
502
        // Record type transition if there was a previous type
503
0
        if let Some(prev_type) = feedback.dominant_type {
504
0
            if prev_type != new_type {
505
0
                feedback
506
0
                    .transitions
507
0
                    .entry(prev_type)
508
0
                    .or_default()
509
0
                    .entry(new_type)
510
0
                    .and_modify(|count| *count += 1)
511
0
                    .or_insert(1);
512
0
            }
513
0
        }
514
515
        // Add new type if not seen before
516
0
        if !feedback.assigned_types.contains(&new_type) {
517
0
            feedback.assigned_types.push(new_type);
518
0
        }
519
520
        // Update dominant type (most recently assigned for simplicity)
521
0
        feedback.dominant_type = Some(new_type);
522
523
        // Recalculate stability score
524
0
        feedback.stability_score = if feedback.assigned_types.len() == 1 {
525
0
            1.0 // Monomorphic
526
        } else {
527
0
            1.0 / f64::from(u32::try_from(feedback.assigned_types.len()).unwrap_or(u32::MAX))
528
            // Decreases with more types
529
        };
530
0
    }
531
532
    /// Record function call type feedback
533
0
    pub fn record_function_call(
534
0
        &mut self,
535
0
        site_id: usize,
536
0
        func_name: &str,
537
0
        args: &[Value],
538
0
        result: &Value,
539
0
    ) {
540
0
        let arg_types: Vec<std::any::TypeId> = args.iter().map(Value::type_id).collect();
541
0
        let return_type = result.type_id();
542
543
0
        let feedback = self
544
0
            .call_sites
545
0
            .entry(site_id)
546
0
            .or_insert_with(|| CallSiteFeedback {
547
0
                arg_type_patterns: smallvec![],
548
0
                return_types: smallvec![],
549
                call_count: 0,
550
0
                called_functions: HashMap::new(),
551
0
            });
552
553
        // Record argument pattern if not seen before
554
0
        if !feedback
555
0
            .arg_type_patterns
556
0
            .iter()
557
0
            .any(|pattern| pattern == &arg_types)
558
0
        {
559
0
            feedback.arg_type_patterns.push(arg_types);
560
0
        }
561
562
        // Record return type if not seen before
563
0
        if !feedback.return_types.contains(&return_type) {
564
0
            feedback.return_types.push(return_type);
565
0
        }
566
567
        // Update function call counts
568
0
        *feedback
569
0
            .called_functions
570
0
            .entry(func_name.to_string())
571
0
            .or_insert(0) += 1;
572
0
        feedback.call_count += 1;
573
0
    }
574
575
    /// Get type specialization suggestions for optimization
576
    /// # Panics
577
    /// Panics if a variable's dominant type is None when it should exist
578
0
    pub fn get_specialization_candidates(&self) -> Vec<SpecializationCandidate> {
579
0
        let mut candidates = Vec::new();
580
581
        // Find monomorphic operation sites
582
0
        for (&site_id, feedback) in &self.operation_sites {
583
0
            if feedback.left_types.len() == 1
584
0
                && feedback.right_types.len() == 1
585
0
                && feedback.total_count > 10
586
0
            {
587
0
                candidates.push(SpecializationCandidate {
588
0
                    kind: SpecializationKind::BinaryOperation {
589
0
                        site_id,
590
0
                        left_type: feedback.left_types[0],
591
0
                        right_type: feedback.right_types[0],
592
0
                    },
593
0
                    confidence: 1.0,
594
0
                    benefit_score: f64::from(feedback.total_count),
595
0
                });
596
0
            }
597
        }
598
599
        // Find stable variables
600
0
        for (var_name, feedback) in &self.variable_types {
601
0
            if feedback.stability_score > 0.8 && feedback.dominant_type.is_some() {
602
0
                candidates.push(SpecializationCandidate {
603
0
                    kind: SpecializationKind::Variable {
604
0
                        name: var_name.clone(),
605
0
                        #[allow(clippy::expect_used)] // Safe: we just checked is_some() above
606
0
                        specialized_type: feedback.dominant_type.expect("Dominant type should exist for stable variables"),
607
0
                    },
608
0
                    confidence: feedback.stability_score,
609
0
                    benefit_score: feedback.stability_score * 100.0,
610
0
                });
611
0
            }
612
        }
613
614
        // Find monomorphic call sites
615
0
        for (&site_id, feedback) in &self.call_sites {
616
0
            if feedback.arg_type_patterns.len() == 1
617
0
                && feedback.return_types.len() == 1
618
0
                && feedback.call_count > 5
619
0
            {
620
0
                candidates.push(SpecializationCandidate {
621
0
                    kind: SpecializationKind::FunctionCall {
622
0
                        site_id,
623
0
                        arg_types: feedback.arg_type_patterns[0].clone(),
624
0
                        return_type: feedback.return_types[0],
625
0
                    },
626
0
                    confidence: 1.0,
627
0
                    benefit_score: f64::from(feedback.call_count * 10),
628
0
                });
629
0
            }
630
        }
631
632
        // Sort by benefit score (highest first)
633
0
        candidates.sort_by(|a, b| {
634
0
            b.benefit_score
635
0
                .partial_cmp(&a.benefit_score)
636
0
                .unwrap_or(std::cmp::Ordering::Equal)
637
0
        });
638
0
        candidates
639
0
    }
640
641
    /// Get overall type feedback statistics
642
0
    pub fn get_statistics(&self) -> TypeFeedbackStats {
643
0
        let monomorphic_sites = self
644
0
            .operation_sites
645
0
            .values()
646
0
            .filter(|f| f.left_types.len() == 1 && f.right_types.len() == 1)
647
0
            .count();
648
649
0
        let stable_variables = self
650
0
            .variable_types
651
0
            .values()
652
0
            .filter(|f| f.stability_score > 0.8)
653
0
            .count();
654
655
0
        let monomorphic_calls = self
656
0
            .call_sites
657
0
            .values()
658
0
            .filter(|f| f.arg_type_patterns.len() == 1)
659
0
            .count();
660
661
0
        TypeFeedbackStats {
662
0
            total_operation_sites: self.operation_sites.len(),
663
0
            monomorphic_operation_sites: monomorphic_sites,
664
0
            total_variables: self.variable_types.len(),
665
0
            stable_variables,
666
0
            total_call_sites: self.call_sites.len(),
667
0
            monomorphic_call_sites: monomorphic_calls,
668
0
            total_samples: self.total_samples,
669
0
        }
670
0
    }
671
}
672
673
impl Default for TypeFeedback {
674
0
    fn default() -> Self {
675
0
        Self::new()
676
0
    }
677
}
678
679
/// Specialization candidate for JIT compilation
680
#[derive(Clone, Debug)]
681
#[allow(dead_code)] // Will be used by future JIT implementation
682
pub struct SpecializationCandidate {
683
    /// Type of specialization
684
    kind: SpecializationKind,
685
    /// Confidence level (0.0 - 1.0)
686
    confidence: f64,
687
    /// Expected benefit score
688
    benefit_score: f64,
689
}
690
691
#[derive(Clone, Debug)]
692
pub enum SpecializationKind {
693
    BinaryOperation {
694
        site_id: usize,
695
        left_type: std::any::TypeId,
696
        right_type: std::any::TypeId,
697
    },
698
    Variable {
699
        name: String,
700
        specialized_type: std::any::TypeId,
701
    },
702
    FunctionCall {
703
        site_id: usize,
704
        arg_types: Vec<std::any::TypeId>,
705
        return_type: std::any::TypeId,
706
    },
707
}
708
709
/// Type feedback statistics for profiling
710
#[derive(Clone, Debug)]
711
pub struct TypeFeedbackStats {
712
    /// Total operation sites recorded
713
    pub total_operation_sites: usize,
714
    /// Monomorphic operation sites (candidates for specialization)
715
    pub monomorphic_operation_sites: usize,
716
    /// Total variables tracked
717
    pub total_variables: usize,
718
    /// Variables with stable types
719
    pub stable_variables: usize,
720
    /// Total function call sites
721
    pub total_call_sites: usize,
722
    /// Monomorphic call sites
723
    pub monomorphic_call_sites: usize,
724
    /// Total feedback samples collected
725
    pub total_samples: u64,
726
}
727
728
/// Conservative garbage collector for heap-allocated objects
729
/// Currently operates alongside Rc-based memory management
730
#[derive(Debug)]
731
pub struct ConservativeGC {
732
    /// Objects currently tracked by the GC
733
    tracked_objects: Vec<GCObject>,
734
    /// Collection statistics
735
    collections_performed: u64,
736
    /// Total objects collected
737
    objects_collected: u64,
738
    /// Memory pressure threshold (bytes)
739
    collection_threshold: usize,
740
    /// Current allocated bytes estimate
741
    allocated_bytes: usize,
742
    /// Enable/disable automatic collection
743
    auto_collect_enabled: bool,
744
}
745
746
/// A garbage-collected object with metadata
747
#[derive(Debug, Clone)]
748
pub struct GCObject {
749
    /// Object identifier (address-like)
750
    id: usize,
751
    /// Object size in bytes
752
    size: usize,
753
    /// Mark bit for mark-and-sweep
754
    marked: bool,
755
    /// Object generation (for future generational GC)
756
    #[allow(dead_code)] // Will be used in future generational GC implementation
757
    generation: u8,
758
    /// Reference to the actual value
759
    value: Value,
760
}
761
762
impl ConservativeGC {
763
    /// Create new conservative garbage collector
764
0
    pub fn new() -> Self {
765
0
        Self {
766
0
            tracked_objects: Vec::new(),
767
0
            collections_performed: 0,
768
0
            objects_collected: 0,
769
0
            collection_threshold: 1024 * 1024, // 1MB default threshold
770
0
            allocated_bytes: 0,
771
0
            auto_collect_enabled: true,
772
0
        }
773
0
    }
774
775
    /// Add an object to GC tracking
776
0
    pub fn track_object(&mut self, value: Value) -> usize {
777
0
        let id = self.tracked_objects.len();
778
0
        let size = self.estimate_object_size(&value);
779
780
0
        let gc_object = GCObject {
781
0
            id,
782
0
            size,
783
0
            marked: false,
784
0
            generation: 0,
785
0
            value,
786
0
        };
787
788
0
        self.tracked_objects.push(gc_object);
789
0
        self.allocated_bytes += size;
790
791
        // Trigger collection if we've exceeded threshold
792
0
        if self.auto_collect_enabled && self.allocated_bytes > self.collection_threshold {
793
0
            self.collect_garbage();
794
0
        }
795
796
0
        id
797
0
    }
798
799
    /// Perform garbage collection using conservative stack scanning
800
0
    pub fn collect_garbage(&mut self) -> GCStats {
801
0
        let initial_count = self.tracked_objects.len();
802
0
        let initial_bytes = self.allocated_bytes;
803
804
        // Mark phase: mark all reachable objects
805
0
        self.mark_phase();
806
807
        // Sweep phase: collect unmarked objects
808
0
        let collected = self.sweep_phase();
809
810
0
        self.collections_performed += 1;
811
0
        self.objects_collected += collected as u64;
812
813
0
        GCStats {
814
0
            objects_before: initial_count,
815
0
            objects_after: self.tracked_objects.len(),
816
0
            objects_collected: collected,
817
0
            bytes_before: initial_bytes,
818
0
            bytes_after: self.allocated_bytes,
819
0
            collection_time_ns: 0, // Simple implementation doesn't time
820
0
        }
821
0
    }
822
823
    /// Mark phase: mark all reachable objects
824
0
    fn mark_phase(&mut self) {
825
        // Reset all marks
826
0
        for obj in &mut self.tracked_objects {
827
0
            obj.marked = false;
828
0
        }
829
830
        // Mark objects based on Value references
831
        // In a more sophisticated implementation, this would scan the stack
832
        // For now, we conservatively mark all objects referenced by other tracked objects
833
0
        for i in 0..self.tracked_objects.len() {
834
0
            if self.is_root_object(i) {
835
0
                self.mark_object(i);
836
0
            }
837
        }
838
0
    }
839
840
    /// Check if object is a root (conservatively assume all are roots for safety)
841
0
    fn is_root_object(&self, _index: usize) -> bool {
842
        // Conservative implementation: treat all objects as potentially reachable
843
        // In a real implementation, this would scan the stack and globals
844
0
        true
845
0
    }
846
847
    /// Mark an object and all objects it references
848
0
    fn mark_object(&mut self, index: usize) {
849
0
        if index >= self.tracked_objects.len() || self.tracked_objects[index].marked {
850
0
            return;
851
0
        }
852
853
0
        self.tracked_objects[index].marked = true;
854
855
        // Mark objects referenced by this object
856
0
        let value = &self.tracked_objects[index].value.clone();
857
0
        if let Value::Array(arr) = value {
858
            // Mark all array elements that are tracked objects
859
0
            for elem in arr.iter() {
860
0
                if let Some(referenced_id) = self.find_object_id(elem) {
861
0
                    self.mark_object(referenced_id);
862
0
                }
863
            }
864
0
        }
865
        // Note: Closure environments and other value types don't contain tracked object references
866
        // In a real implementation, would mark closure environment
867
0
    }
868
869
    /// Find the GC object ID for a given value
870
0
    fn find_object_id(&self, target: &Value) -> Option<usize> {
871
        // Simple linear search - in production would use hash table
872
0
        for (id, obj) in self.tracked_objects.iter().enumerate() {
873
0
            if std::ptr::eq(&raw const obj.value, target) {
874
0
                return Some(id);
875
0
            }
876
        }
877
0
        None
878
0
    }
879
880
    /// Sweep phase: collect unmarked objects
881
0
    fn sweep_phase(&mut self) -> usize {
882
0
        let initial_len = self.tracked_objects.len();
883
884
        // Keep only marked objects
885
0
        self.tracked_objects.retain(|obj| {
886
0
            if obj.marked {
887
0
                true
888
            } else {
889
0
                self.allocated_bytes = self.allocated_bytes.saturating_sub(obj.size);
890
0
                false
891
            }
892
0
        });
893
894
        // Reassign IDs after compaction
895
0
        for (new_id, obj) in self.tracked_objects.iter_mut().enumerate() {
896
0
            obj.id = new_id;
897
0
        }
898
899
0
        initial_len - self.tracked_objects.len()
900
0
    }
901
902
    /// Estimate memory size of a value
903
0
    fn estimate_object_size(&self, value: &Value) -> usize {
904
0
        match value {
905
0
            Value::Integer(_) | Value::Float(_) => 8,
906
0
            Value::Bool(_) => 1,
907
0
            Value::Nil => 0,
908
0
            Value::String(s) => s.len() + 24, // String overhead + content
909
0
            Value::Array(arr) => {
910
0
                let base_size = 24; // Vec overhead
911
0
                let element_size = arr
912
0
                    .iter()
913
0
                    .map(|v| self.estimate_object_size(v))
914
0
                    .sum::<usize>();
915
0
                base_size + element_size
916
            }
917
0
            Value::Tuple(elements) => {
918
0
                let base_size = 24; // Vec overhead
919
0
                let element_size = elements
920
0
                    .iter()
921
0
                    .map(|v| self.estimate_object_size(v))
922
0
                    .sum::<usize>();
923
0
                base_size + element_size
924
            }
925
0
            Value::Closure { params, .. } => {
926
0
                let base_size = 48; // Closure overhead
927
0
                let params_size = params.iter().map(std::string::String::len).sum::<usize>();
928
0
                base_size + params_size
929
            }
930
        }
931
0
    }
932
933
    /// Get current GC statistics
934
0
    pub fn get_stats(&self) -> GCStats {
935
0
        GCStats {
936
0
            objects_before: self.tracked_objects.len(),
937
0
            objects_after: self.tracked_objects.len(),
938
0
            objects_collected: 0,
939
0
            bytes_before: self.allocated_bytes,
940
0
            bytes_after: self.allocated_bytes,
941
0
            collection_time_ns: 0,
942
0
        }
943
0
    }
944
945
    /// Get detailed GC information
946
0
    pub fn get_info(&self) -> GCInfo {
947
0
        GCInfo {
948
0
            total_objects: self.tracked_objects.len(),
949
0
            allocated_bytes: self.allocated_bytes,
950
0
            collections_performed: self.collections_performed,
951
0
            objects_collected: self.objects_collected,
952
0
            collection_threshold: self.collection_threshold,
953
0
            auto_collect_enabled: self.auto_collect_enabled,
954
0
        }
955
0
    }
956
957
    /// Set collection threshold
958
0
    pub fn set_collection_threshold(&mut self, threshold: usize) {
959
0
        self.collection_threshold = threshold;
960
0
    }
961
962
    /// Enable or disable automatic collection
963
0
    pub fn set_auto_collect(&mut self, enabled: bool) {
964
0
        self.auto_collect_enabled = enabled;
965
0
    }
966
967
    /// Force garbage collection
968
0
    pub fn force_collect(&mut self) -> GCStats {
969
0
        self.collect_garbage()
970
0
    }
971
972
    /// Clear all tracked objects (for testing)
973
0
    pub fn clear(&mut self) {
974
0
        self.tracked_objects.clear();
975
0
        self.allocated_bytes = 0;
976
0
    }
977
}
978
979
impl Default for ConservativeGC {
980
0
    fn default() -> Self {
981
0
        Self::new()
982
0
    }
983
}
984
985
/// Statistics from a garbage collection cycle
986
#[derive(Debug, Clone, PartialEq)]
987
pub struct GCStats {
988
    /// Objects before collection
989
    pub objects_before: usize,
990
    /// Objects after collection  
991
    pub objects_after: usize,
992
    /// Objects collected
993
    pub objects_collected: usize,
994
    /// Bytes before collection
995
    pub bytes_before: usize,
996
    /// Bytes after collection
997
    pub bytes_after: usize,
998
    /// Collection time in nanoseconds
999
    pub collection_time_ns: u64,
1000
}
1001
1002
/// General GC information
1003
#[derive(Debug, Clone)]
1004
pub struct GCInfo {
1005
    /// Total objects currently tracked
1006
    pub total_objects: usize,
1007
    /// Currently allocated bytes
1008
    pub allocated_bytes: usize,
1009
    /// Total collections performed
1010
    pub collections_performed: u64,
1011
    /// Total objects collected ever
1012
    pub objects_collected: u64,
1013
    /// Collection threshold in bytes
1014
    pub collection_threshold: usize,
1015
    /// Whether auto-collection is enabled
1016
    pub auto_collect_enabled: bool,
1017
}
1018
1019
/// Direct-threaded instruction dispatch system for optimal performance
1020
/// Replaces AST walking with linear instruction stream and function pointers
1021
#[derive(Debug)]
1022
pub struct DirectThreadedInterpreter {
1023
    /// Linear instruction stream with embedded operands
1024
    code: Vec<ThreadedInstruction>,
1025
    /// Constant pool separated from instruction stream for I-cache efficiency
1026
    constants: Vec<Value>,
1027
    /// Program counter
1028
    pc: usize,
1029
    /// Runtime state for instruction execution
1030
    state: InterpreterState,
1031
}
1032
1033
/// Single threaded instruction with direct function pointer dispatch
1034
#[repr(C)]
1035
#[derive(Debug, Clone)]
1036
pub struct ThreadedInstruction {
1037
    /// Direct pointer to handler function - eliminates switch overhead
1038
    handler: fn(&mut InterpreterState, u32) -> InstructionResult,
1039
    /// Inline operand (constant index, local slot, jump target, etc.)
1040
    operand: u32,
1041
}
1042
1043
/// Runtime state for direct-threaded execution
1044
#[derive(Debug)]
1045
pub struct InterpreterState {
1046
    /// Value stack for operands
1047
    stack: Vec<Value>,
1048
    /// Environment stack for variable lookups
1049
    env_stack: Vec<HashMap<String, Value>>,
1050
    /// Constants pool reference
1051
    constants: Vec<Value>,
1052
    /// Inline caches for method dispatch
1053
    #[allow(dead_code)] // Will be used in future phases
1054
    caches: Vec<InlineCache>,
1055
}
1056
1057
impl InterpreterState {
1058
    /// Create new interpreter state
1059
0
    pub fn new() -> Self {
1060
0
        Self {
1061
0
            stack: Vec::new(),
1062
0
            env_stack: vec![HashMap::new()], // Start with global environment
1063
0
            constants: Vec::new(),
1064
0
            caches: Vec::new(),
1065
0
        }
1066
0
    }
1067
}
1068
1069
impl Default for InterpreterState {
1070
0
    fn default() -> Self {
1071
0
        Self::new()
1072
0
    }
1073
}
1074
1075
/// Result of executing a single threaded instruction
1076
#[derive(Debug, Clone, PartialEq)]
1077
pub enum InstructionResult {
1078
    /// Continue to next instruction
1079
    Continue,
1080
    /// Jump to target PC
1081
    Jump(usize),
1082
    /// Return value from function/expression
1083
    Return(Value),
1084
    /// Runtime error occurred
1085
    Error(InterpreterError),
1086
}
1087
1088
impl DirectThreadedInterpreter {
1089
    /// Create new direct-threaded interpreter
1090
0
    pub fn new() -> Self {
1091
0
        Self {
1092
0
            code: Vec::new(),
1093
0
            constants: Vec::new(),
1094
0
            pc: 0,
1095
0
            state: InterpreterState {
1096
0
                stack: Vec::with_capacity(256),
1097
0
                env_stack: vec![HashMap::new()],
1098
0
                constants: Vec::new(),
1099
0
                caches: Vec::new(),
1100
0
            },
1101
0
        }
1102
0
    }
1103
1104
    /// Compile AST expression to threaded instruction stream
1105
    ///
1106
    /// # Errors
1107
    ///
1108
    /// Returns an error if the expression contains unsupported constructs
1109
    /// or if instruction compilation fails.
1110
0
    pub fn compile(&mut self, expr: &Expr) -> Result<(), InterpreterError> {
1111
0
        self.code.clear();
1112
0
        self.constants.clear();
1113
0
        self.pc = 0;
1114
1115
        // Compile expression to instruction stream
1116
0
        self.compile_expr(expr)?;
1117
1118
        // Add return instruction if needed
1119
0
        if self.code.is_empty()
1120
0
            || !matches!(self.code.last(), Some(instr) if
1121
0
            std::ptr::eq(instr.handler as *const (), op_return as *const ()))
1122
0
        {
1123
0
            self.emit_instruction(op_return, 0);
1124
0
        }
1125
1126
        // Copy constants to state
1127
0
        self.state.constants = self.constants.clone();
1128
1129
0
        Ok(())
1130
0
    }
1131
1132
    /// Execute compiled instruction stream using direct-threaded dispatch
1133
    ///
1134
    /// # Errors
1135
    ///
1136
    /// Returns an error if execution encounters runtime errors such as
1137
    /// stack overflow, division by zero, or undefined variables.
1138
0
    pub fn execute(&mut self) -> Result<Value, InterpreterError> {
1139
0
        self.pc = 0;
1140
1141
        loop {
1142
            // Bounds check
1143
0
            if self.pc >= self.code.len() {
1144
0
                return Err(InterpreterError::RuntimeError(
1145
0
                    "PC out of bounds".to_string(),
1146
0
                ));
1147
0
            }
1148
1149
            // Direct function pointer call - no switch overhead
1150
0
            let instruction = &self.code[self.pc];
1151
0
            let result = (instruction.handler)(&mut self.state, instruction.operand);
1152
1153
0
            match result {
1154
0
                InstructionResult::Continue => {
1155
0
                    self.pc += 1;
1156
0
                }
1157
0
                InstructionResult::Jump(target) => {
1158
0
                    if target >= self.code.len() {
1159
0
                        return Err(InterpreterError::RuntimeError(
1160
0
                            "Jump target out of bounds".to_string(),
1161
0
                        ));
1162
0
                    }
1163
0
                    self.pc = target;
1164
                }
1165
0
                InstructionResult::Return(value) => {
1166
0
                    return Ok(value);
1167
                }
1168
0
                InstructionResult::Error(error) => {
1169
0
                    return Err(error);
1170
                }
1171
            }
1172
1173
            // Periodic interrupt check for long-running loops
1174
0
            if self.pc.trailing_zeros() >= 10 {
1175
0
                // Could add interrupt checking here in the future
1176
0
            }
1177
        }
1178
0
    }
1179
1180
    /// Compile single expression to instruction stream
1181
0
    fn compile_expr(&mut self, expr: &Expr) -> Result<(), InterpreterError> {
1182
0
        match &expr.kind {
1183
0
            ExprKind::Literal(lit) => self.compile_literal(lit),
1184
0
            ExprKind::Binary { left, op, right } => self.compile_binary_expr(left, op, right),
1185
0
            ExprKind::Identifier(name) => self.compile_identifier(name),
1186
0
            ExprKind::If { condition, then_branch, else_branch } => 
1187
0
                self.compile_if_expr(condition, then_branch, else_branch.as_deref()),
1188
0
            _ => self.compile_fallback_expr(),
1189
        }
1190
0
    }
1191
    
1192
    // Helper methods for DirectThreadedInterpreter compilation (complexity <10 each)
1193
    
1194
0
    fn compile_literal(&mut self, lit: &Literal) -> Result<(), InterpreterError> {
1195
0
        if matches!(lit, Literal::Unit) {
1196
0
            self.emit_instruction(op_load_nil, 0);
1197
0
        } else {
1198
0
            let const_idx = self.add_constant(self.literal_to_value(lit));
1199
0
            self.emit_instruction(op_load_const, const_idx);
1200
0
        }
1201
0
        Ok(())
1202
0
    }
1203
    
1204
0
    fn compile_binary_expr(&mut self, left: &Expr, op: &crate::frontend::ast::BinaryOp, right: &Expr) -> Result<(), InterpreterError> {
1205
0
        self.compile_expr(left)?;
1206
0
        self.compile_expr(right)?;
1207
        
1208
0
        let op_code = self.binary_op_to_opcode(op)?;
1209
0
        self.emit_instruction(op_code, 0);
1210
0
        Ok(())
1211
0
    }
1212
    
1213
0
    fn binary_op_to_opcode(&self, op: &crate::frontend::ast::BinaryOp) -> Result<fn(&mut InterpreterState, u32) -> InstructionResult, InterpreterError> {
1214
0
        match op {
1215
0
            crate::frontend::ast::BinaryOp::Add => Ok(op_add),
1216
0
            crate::frontend::ast::BinaryOp::Subtract => Ok(op_sub),
1217
0
            crate::frontend::ast::BinaryOp::Multiply => Ok(op_mul),
1218
0
            crate::frontend::ast::BinaryOp::Divide => Ok(op_div),
1219
0
            _ => Err(InterpreterError::RuntimeError(format!(
1220
0
                "Unsupported binary operation: {:?}",
1221
0
                op
1222
0
            ))),
1223
        }
1224
0
    }
1225
    
1226
0
    fn compile_identifier(&mut self, name: &str) -> Result<(), InterpreterError> {
1227
0
        let name_idx = self.add_constant(Value::String(Rc::new(name.to_string())));
1228
0
        self.emit_instruction(op_load_var, name_idx);
1229
0
        Ok(())
1230
0
    }
1231
    
1232
0
    fn compile_if_expr(&mut self, condition: &Expr, then_branch: &Expr, else_branch: Option<&Expr>) -> Result<(), InterpreterError> {
1233
0
        self.compile_expr(condition)?;
1234
        
1235
0
        let else_jump_addr = self.code.len();
1236
0
        self.emit_instruction(op_jump_if_false, 0);
1237
        
1238
0
        self.compile_expr(then_branch)?;
1239
        
1240
0
        if let Some(else_expr) = else_branch {
1241
0
            self.compile_if_with_else_branch(else_jump_addr, else_expr)
1242
        } else {
1243
0
            self.compile_if_without_else_branch(else_jump_addr)
1244
        }
1245
0
    }
1246
    
1247
0
    fn compile_if_with_else_branch(&mut self, else_jump_addr: usize, else_expr: &Expr) -> Result<(), InterpreterError> {
1248
0
        let end_jump_addr = self.code.len();
1249
0
        self.emit_instruction(op_jump, 0);
1250
        
1251
0
        self.patch_jump_target(else_jump_addr, self.code.len());
1252
0
        self.compile_expr(else_expr)?;
1253
0
        self.patch_jump_target(end_jump_addr, self.code.len());
1254
        
1255
0
        Ok(())
1256
0
    }
1257
    
1258
0
    fn compile_if_without_else_branch(&mut self, else_jump_addr: usize) -> Result<(), InterpreterError> {
1259
0
        self.patch_jump_target(else_jump_addr, self.code.len());
1260
0
        self.emit_instruction(op_load_nil, 0);
1261
0
        Ok(())
1262
0
    }
1263
    
1264
0
    fn patch_jump_target(&mut self, jump_addr: usize, target: usize) {
1265
0
        if let Some(instr) = self.code.get_mut(jump_addr) {
1266
0
            instr.operand = target as u32;
1267
0
        }
1268
0
    }
1269
    
1270
0
    fn compile_fallback_expr(&mut self) -> Result<(), InterpreterError> {
1271
0
        let value_idx = self.add_constant(Value::String(Rc::new("AST_FALLBACK".to_string())));
1272
0
        self.emit_instruction(op_ast_fallback, value_idx);
1273
0
        Ok(())
1274
0
    }
1275
1276
    /// Add constant to pool and return index
1277
    #[allow(clippy::cast_possible_truncation)] // Index bounds are controlled
1278
0
    fn add_constant(&mut self, value: Value) -> u32 {
1279
0
        let idx = self.constants.len();
1280
0
        self.constants.push(value);
1281
0
        idx as u32
1282
0
    }
1283
1284
    /// Emit instruction to code stream
1285
0
    fn emit_instruction(
1286
0
        &mut self,
1287
0
        handler: fn(&mut InterpreterState, u32) -> InstructionResult,
1288
0
        operand: u32,
1289
0
    ) {
1290
0
        self.code.push(ThreadedInstruction { handler, operand });
1291
0
    }
1292
1293
    /// Convert literal to value
1294
0
    fn literal_to_value(&self, lit: &Literal) -> Value {
1295
0
        match lit {
1296
0
            Literal::Integer(n) => Value::Integer(*n),
1297
0
            Literal::Float(f) => Value::Float(*f),
1298
0
            Literal::Bool(b) => Value::Bool(*b),
1299
0
            Literal::String(s) => Value::String(Rc::new(s.clone())),
1300
0
            Literal::Char(c) => Value::String(Rc::new(c.to_string())), // Convert char to single-character string
1301
0
            Literal::Unit => Value::Nil,                               // Unit maps to Nil
1302
        }
1303
0
    }
1304
1305
    /// Get instruction count
1306
0
    pub fn instruction_count(&self) -> usize {
1307
0
        self.code.len()
1308
0
    }
1309
1310
    /// Get constants count
1311
0
    pub fn constants_count(&self) -> usize {
1312
0
        self.constants.len()
1313
0
    }
1314
1315
    /// Add instruction to code stream (public interface for tests)
1316
0
    pub fn add_instruction(
1317
0
        &mut self,
1318
0
        handler: fn(&mut InterpreterState, u32) -> InstructionResult,
1319
0
        operand: u32,
1320
0
    ) {
1321
0
        self.emit_instruction(handler, operand);
1322
0
    }
1323
1324
    /// Clear all instructions and constants
1325
0
    pub fn clear(&mut self) {
1326
0
        self.code.clear();
1327
0
        self.constants.clear();
1328
0
        self.pc = 0;
1329
0
        self.state = InterpreterState::new();
1330
0
    }
1331
1332
    /// Execute with custom interpreter state (for tests)
1333
    ///
1334
    /// # Errors
1335
    ///
1336
    /// Returns an error if execution encounters runtime errors such as
1337
    /// stack overflow, division by zero, or undefined variables.
1338
0
    pub fn execute_with_state(
1339
0
        &mut self,
1340
0
        state: &mut InterpreterState,
1341
0
    ) -> Result<Value, InterpreterError> {
1342
0
        self.pc = 0;
1343
1344
        loop {
1345
            // Bounds check
1346
0
            if self.pc >= self.code.len() {
1347
0
                return Err(InterpreterError::RuntimeError(
1348
0
                    "PC out of bounds".to_string(),
1349
0
                ));
1350
0
            }
1351
1352
            // Direct function pointer call - no switch overhead
1353
0
            let instruction = &self.code[self.pc];
1354
0
            let result = (instruction.handler)(state, instruction.operand);
1355
1356
0
            match result {
1357
0
                InstructionResult::Continue => {
1358
0
                    self.pc += 1;
1359
0
                }
1360
0
                InstructionResult::Jump(target) => {
1361
0
                    if target >= self.code.len() {
1362
0
                        return Err(InterpreterError::RuntimeError(
1363
0
                            "Jump target out of bounds".to_string(),
1364
0
                        ));
1365
0
                    }
1366
0
                    self.pc = target;
1367
                }
1368
0
                InstructionResult::Return(value) => {
1369
0
                    return Ok(value);
1370
                }
1371
0
                InstructionResult::Error(error) => {
1372
0
                    return Err(error);
1373
                }
1374
            }
1375
1376
            // Periodic interrupt check for long-running loops
1377
0
            if self.pc.trailing_zeros() >= 10 {
1378
0
                // Could add interrupt checking here in the future
1379
0
            }
1380
        }
1381
0
    }
1382
}
1383
1384
impl Default for DirectThreadedInterpreter {
1385
0
    fn default() -> Self {
1386
0
        Self::new()
1387
0
    }
1388
}
1389
1390
// Instruction handler functions - these are called via function pointers
1391
1392
/// Load constant onto stack
1393
0
fn op_load_const(state: &mut InterpreterState, const_idx: u32) -> InstructionResult {
1394
0
    if let Some(value) = state.constants.get(const_idx as usize) {
1395
0
        state.stack.push(value.clone());
1396
0
        InstructionResult::Continue
1397
    } else {
1398
0
        InstructionResult::Error(InterpreterError::RuntimeError(
1399
0
            "Invalid constant index".to_string(),
1400
0
        ))
1401
    }
1402
0
}
1403
1404
/// Load nil onto stack
1405
0
fn op_load_nil(state: &mut InterpreterState, _operand: u32) -> InstructionResult {
1406
0
    state.stack.push(Value::Nil);
1407
0
    InstructionResult::Continue
1408
0
}
1409
1410
/// Load variable onto stack
1411
0
fn op_load_var(state: &mut InterpreterState, name_idx: u32) -> InstructionResult {
1412
0
    if let Some(Value::String(name)) = state.constants.get(name_idx as usize) {
1413
        // Search environments from innermost to outermost
1414
0
        for env in state.env_stack.iter().rev() {
1415
0
            if let Some(value) = env.get(name.as_str()) {
1416
0
                state.stack.push(value.clone());
1417
0
                return InstructionResult::Continue;
1418
0
            }
1419
        }
1420
0
        InstructionResult::Error(InterpreterError::RuntimeError(format!(
1421
0
            "Undefined variable: {name}"
1422
0
        )))
1423
    } else {
1424
0
        InstructionResult::Error(InterpreterError::RuntimeError(
1425
0
            "Invalid variable name index".to_string(),
1426
0
        ))
1427
    }
1428
0
}
1429
1430
/// Binary add operation
1431
0
fn op_add(state: &mut InterpreterState, _operand: u32) -> InstructionResult {
1432
0
    binary_arithmetic_op(state, |a, b| match (a, b) {
1433
0
        (Value::Integer(x), Value::Integer(y)) => Some(Value::Integer(x + y)),
1434
0
        (Value::Float(x), Value::Float(y)) => Some(Value::Float(x + y)),
1435
0
        (Value::Integer(x), Value::Float(y)) => Some(Value::Float(*x as f64 + y)),
1436
0
        (Value::Float(x), Value::Integer(y)) => Some(Value::Float(x + *y as f64)),
1437
0
        _ => None,
1438
0
    })
1439
0
}
1440
1441
/// Binary subtract operation
1442
0
fn op_sub(state: &mut InterpreterState, _operand: u32) -> InstructionResult {
1443
0
    binary_arithmetic_op(state, |a, b| match (a, b) {
1444
0
        (Value::Integer(x), Value::Integer(y)) => Some(Value::Integer(x - y)),
1445
0
        (Value::Float(x), Value::Float(y)) => Some(Value::Float(x - y)),
1446
0
        (Value::Integer(x), Value::Float(y)) => Some(Value::Float(*x as f64 - y)),
1447
0
        (Value::Float(x), Value::Integer(y)) => Some(Value::Float(x - *y as f64)),
1448
0
        _ => None,
1449
0
    })
1450
0
}
1451
1452
/// Binary multiply operation
1453
0
fn op_mul(state: &mut InterpreterState, _operand: u32) -> InstructionResult {
1454
0
    binary_arithmetic_op(state, |a, b| match (a, b) {
1455
0
        (Value::Integer(x), Value::Integer(y)) => Some(Value::Integer(x * y)),
1456
0
        (Value::Float(x), Value::Float(y)) => Some(Value::Float(x * y)),
1457
0
        (Value::Integer(x), Value::Float(y)) => Some(Value::Float(*x as f64 * y)),
1458
0
        (Value::Float(x), Value::Integer(y)) => Some(Value::Float(x * *y as f64)),
1459
0
        _ => None,
1460
0
    })
1461
0
}
1462
1463
/// Binary divide operation
1464
0
fn op_div(state: &mut InterpreterState, _operand: u32) -> InstructionResult {
1465
0
    binary_arithmetic_op(state, |a, b| match (a, b) {
1466
0
        (Value::Integer(x), Value::Integer(y)) => {
1467
0
            if *y == 0 {
1468
0
                return None; // Division by zero
1469
0
            }
1470
0
            Some(Value::Integer(x / y))
1471
        }
1472
0
        (Value::Float(x), Value::Float(y)) => {
1473
0
            if *y == 0.0 {
1474
0
                return None;
1475
0
            }
1476
0
            Some(Value::Float(x / y))
1477
        }
1478
0
        (Value::Integer(x), Value::Float(y)) => {
1479
0
            if *y == 0.0 {
1480
0
                return None;
1481
0
            }
1482
0
            Some(Value::Float(*x as f64 / y))
1483
        }
1484
0
        (Value::Float(x), Value::Integer(y)) => {
1485
0
            if *y == 0 {
1486
0
                return None;
1487
0
            }
1488
0
            Some(Value::Float(x / *y as f64))
1489
        }
1490
0
        _ => None,
1491
0
    })
1492
0
}
1493
1494
/// Helper for binary arithmetic operations
1495
0
fn binary_arithmetic_op<F>(state: &mut InterpreterState, op: F) -> InstructionResult
1496
0
where
1497
0
    F: FnOnce(&Value, &Value) -> Option<Value>,
1498
{
1499
0
    if state.stack.len() < 2 {
1500
0
        return InstructionResult::Error(InterpreterError::StackUnderflow);
1501
0
    }
1502
1503
0
    let right = state.stack.pop().expect("Test should not fail");
1504
0
    let left = state.stack.pop().expect("Test should not fail");
1505
1506
0
    match op(&left, &right) {
1507
0
        Some(result) => {
1508
0
            state.stack.push(result);
1509
0
            InstructionResult::Continue
1510
        }
1511
0
        None => InstructionResult::Error(InterpreterError::TypeError(
1512
0
            "Invalid operand types".to_string(),
1513
0
        )),
1514
    }
1515
0
}
1516
1517
/// Binary equality operation
1518
#[allow(dead_code)] // Will be used in future phases
1519
0
fn op_eq(state: &mut InterpreterState, _operand: u32) -> InstructionResult {
1520
0
    binary_comparison_op(state, |a, b| Some(Value::Bool(a == b)))
1521
0
}
1522
1523
/// Binary not-equal operation
1524
#[allow(dead_code)] // Will be used in future phases
1525
0
fn op_ne(state: &mut InterpreterState, _operand: u32) -> InstructionResult {
1526
0
    binary_comparison_op(state, |a, b| Some(Value::Bool(a != b)))
1527
0
}
1528
1529
/// Binary less-than operation
1530
#[allow(dead_code)] // Will be used in future phases
1531
0
fn op_lt(state: &mut InterpreterState, _operand: u32) -> InstructionResult {
1532
0
    binary_comparison_op(state, |a, b| match (a, b) {
1533
0
        (Value::Integer(x), Value::Integer(y)) => Some(Value::Bool(x < y)),
1534
0
        (Value::Float(x), Value::Float(y)) => Some(Value::Bool(x < y)),
1535
0
        (Value::Integer(x), Value::Float(y)) => Some(Value::Bool((*x as f64) < *y)),
1536
0
        (Value::Float(x), Value::Integer(y)) => Some(Value::Bool(*x < (*y as f64))),
1537
0
        _ => None,
1538
0
    })
1539
0
}
1540
1541
/// Binary less-equal operation
1542
#[allow(dead_code)] // Will be used in future phases
1543
0
fn op_le(state: &mut InterpreterState, _operand: u32) -> InstructionResult {
1544
0
    binary_comparison_op(state, |a, b| match (a, b) {
1545
0
        (Value::Integer(x), Value::Integer(y)) => Some(Value::Bool(x <= y)),
1546
0
        (Value::Float(x), Value::Float(y)) => Some(Value::Bool(x <= y)),
1547
0
        (Value::Integer(x), Value::Float(y)) => Some(Value::Bool((*x as f64) <= *y)),
1548
0
        (Value::Float(x), Value::Integer(y)) => Some(Value::Bool(*x <= (*y as f64))),
1549
0
        _ => None,
1550
0
    })
1551
0
}
1552
1553
/// Binary greater-than operation
1554
#[allow(dead_code)] // Will be used in future phases
1555
0
fn op_gt(state: &mut InterpreterState, _operand: u32) -> InstructionResult {
1556
0
    binary_comparison_op(state, |a, b| match (a, b) {
1557
0
        (Value::Integer(x), Value::Integer(y)) => Some(Value::Bool(x > y)),
1558
0
        (Value::Float(x), Value::Float(y)) => Some(Value::Bool(x > y)),
1559
0
        (Value::Integer(x), Value::Float(y)) => Some(Value::Bool((*x as f64) > *y)),
1560
0
        (Value::Float(x), Value::Integer(y)) => Some(Value::Bool(*x > (*y as f64))),
1561
0
        _ => None,
1562
0
    })
1563
0
}
1564
1565
/// Binary greater-equal operation
1566
#[allow(dead_code)] // Will be used in future phases
1567
0
fn op_ge(state: &mut InterpreterState, _operand: u32) -> InstructionResult {
1568
0
    binary_comparison_op(state, |a, b| match (a, b) {
1569
0
        (Value::Integer(x), Value::Integer(y)) => Some(Value::Bool(x >= y)),
1570
0
        (Value::Float(x), Value::Float(y)) => Some(Value::Bool(x >= y)),
1571
0
        (Value::Integer(x), Value::Float(y)) => Some(Value::Bool((*x as f64) >= *y)),
1572
0
        (Value::Float(x), Value::Integer(y)) => Some(Value::Bool(*x >= (*y as f64))),
1573
0
        _ => None,
1574
0
    })
1575
0
}
1576
1577
/// Helper for binary comparison operations
1578
#[allow(dead_code)] // Will be used in future phases
1579
0
fn binary_comparison_op<F>(state: &mut InterpreterState, op: F) -> InstructionResult
1580
0
where
1581
0
    F: FnOnce(&Value, &Value) -> Option<Value>,
1582
{
1583
0
    if state.stack.len() < 2 {
1584
0
        return InstructionResult::Error(InterpreterError::StackUnderflow);
1585
0
    }
1586
1587
0
    let right = state.stack.pop().expect("Test should not fail");
1588
0
    let left = state.stack.pop().expect("Test should not fail");
1589
1590
0
    match op(&left, &right) {
1591
0
        Some(result) => {
1592
0
            state.stack.push(result);
1593
0
            InstructionResult::Continue
1594
        }
1595
0
        None => InstructionResult::Error(InterpreterError::TypeError(
1596
0
            "Invalid operand types for comparison".to_string(),
1597
0
        )),
1598
    }
1599
0
}
1600
1601
/// Binary logical AND operation
1602
#[allow(dead_code)] // Will be used in future phases
1603
0
fn op_and(state: &mut InterpreterState, _operand: u32) -> InstructionResult {
1604
0
    if state.stack.len() < 2 {
1605
0
        return InstructionResult::Error(InterpreterError::StackUnderflow);
1606
0
    }
1607
1608
0
    let right = state.stack.pop().expect("Test should not fail");
1609
0
    let left = state.stack.pop().expect("Test should not fail");
1610
1611
    // Short-circuit evaluation: if left is false, return left; otherwise return right
1612
0
    let result = if left.is_truthy() { right } else { left };
1613
0
    state.stack.push(result);
1614
0
    InstructionResult::Continue
1615
0
}
1616
1617
/// Binary logical OR operation
1618
#[allow(dead_code)] // Will be used in future phases
1619
0
fn op_or(state: &mut InterpreterState, _operand: u32) -> InstructionResult {
1620
0
    if state.stack.len() < 2 {
1621
0
        return InstructionResult::Error(InterpreterError::StackUnderflow);
1622
0
    }
1623
1624
0
    let right = state.stack.pop().expect("Test should not fail");
1625
0
    let left = state.stack.pop().expect("Test should not fail");
1626
1627
    // Short-circuit evaluation: if left is true, return left; otherwise return right
1628
0
    let result = if left.is_truthy() { left } else { right };
1629
0
    state.stack.push(result);
1630
0
    InstructionResult::Continue
1631
0
}
1632
1633
/// Jump if top of stack is false
1634
0
fn op_jump_if_false(state: &mut InterpreterState, target: u32) -> InstructionResult {
1635
0
    if state.stack.is_empty() {
1636
0
        return InstructionResult::Error(InterpreterError::StackUnderflow);
1637
0
    }
1638
1639
0
    let condition = state.stack.pop().expect("Test should not fail");
1640
0
    if condition.is_truthy() {
1641
0
        InstructionResult::Continue
1642
    } else {
1643
0
        InstructionResult::Jump(target as usize)
1644
    }
1645
0
}
1646
1647
/// Unconditional jump
1648
0
fn op_jump(state: &mut InterpreterState, target: u32) -> InstructionResult {
1649
0
    let _ = state; // Unused but required for signature consistency
1650
0
    InstructionResult::Jump(target as usize)
1651
0
}
1652
1653
/// Return top of stack
1654
0
fn op_return(state: &mut InterpreterState, _operand: u32) -> InstructionResult {
1655
0
    if let Some(value) = state.stack.pop() {
1656
0
        InstructionResult::Return(value)
1657
    } else {
1658
0
        InstructionResult::Return(Value::Nil)
1659
    }
1660
0
}
1661
1662
/// Fallback to AST evaluation for unsupported expressions
1663
0
fn op_ast_fallback(_state: &mut InterpreterState, _operand: u32) -> InstructionResult {
1664
    // In a real implementation, this would call back to the AST evaluator
1665
    // For now, just return an error
1666
0
    InstructionResult::Error(InterpreterError::RuntimeError(
1667
0
        "AST fallback not implemented".to_string(),
1668
0
    ))
1669
0
}
1670
1671
impl Value {
1672
    /// Get type identifier for inline caching
1673
0
    pub fn type_id(&self) -> std::any::TypeId {
1674
0
        match self {
1675
0
            Value::Integer(_) => std::any::TypeId::of::<i64>(),
1676
0
            Value::Float(_) => std::any::TypeId::of::<f64>(),
1677
0
            Value::Bool(_) => std::any::TypeId::of::<bool>(),
1678
0
            Value::Nil => std::any::TypeId::of::<()>(),
1679
0
            Value::String(_) => std::any::TypeId::of::<String>(),
1680
0
            Value::Array(_) => std::any::TypeId::of::<Vec<Value>>(),
1681
0
            Value::Tuple(_) => std::any::TypeId::of::<(Value,)>(),
1682
0
            Value::Closure { .. } => std::any::TypeId::of::<fn()>(),
1683
        }
1684
0
    }
1685
}
1686
1687
impl Interpreter {
1688
    /// Create new interpreter instance
1689
0
    pub fn new() -> Self {
1690
0
        let mut global_env = HashMap::new();
1691
        
1692
        // Add builtin functions to global environment
1693
        // These are special markers that will be handled in eval_function_call
1694
0
        global_env.insert("format".to_string(), Value::String(Rc::new("__builtin_format__".to_string())));
1695
0
        global_env.insert("HashMap".to_string(), Value::String(Rc::new("__builtin_hashmap__".to_string())));
1696
        
1697
0
        Self {
1698
0
            stack: Vec::with_capacity(1024), // Pre-allocate stack
1699
0
            env_stack: vec![global_env], // Start with global environment containing builtins
1700
0
            frames: Vec::new(),
1701
0
            execution_counts: HashMap::new(),
1702
0
            field_caches: HashMap::new(),
1703
0
            type_feedback: TypeFeedback::new(),
1704
0
            gc: ConservativeGC::new(),
1705
0
        }
1706
0
    }
1707
1708
    /// Evaluate an AST expression directly
1709
    /// # Errors
1710
    /// Returns error if evaluation fails (type errors, runtime errors, etc.)
1711
0
    pub fn eval_expr(&mut self, expr: &Expr) -> Result<Value, InterpreterError> {
1712
0
        self.eval_expr_kind(&expr.kind)
1713
0
    }
1714
1715
    /// Evaluate an expression kind directly (main AST walker)
1716
    /// # Errors
1717
    /// Returns error if evaluation fails
1718
0
    fn eval_expr_kind(&mut self, expr_kind: &ExprKind) -> Result<Value, InterpreterError> {
1719
0
        match expr_kind {
1720
            // Basic expressions
1721
0
            ExprKind::Literal(lit) => Ok(self.eval_literal(lit)),
1722
0
            ExprKind::Identifier(name) => self.lookup_variable(name),
1723
            
1724
            // Operations and calls
1725
0
            ExprKind::Binary { left, op, right } => self.eval_binary_expr(left, *op, right),
1726
0
            ExprKind::Unary { op, operand } => self.eval_unary_expr(*op, operand),
1727
0
            ExprKind::Call { func, args } => self.eval_function_call(func, args),
1728
0
            ExprKind::MethodCall { receiver, method, args } => self.eval_method_call(receiver, method, args),
1729
            
1730
            // Functions and lambdas
1731
0
            ExprKind::Function { name, params, body, .. } => self.eval_function(name, params, body),
1732
0
            ExprKind::Lambda { params, body } => self.eval_lambda(params, body),
1733
            
1734
            // Control flow expressions
1735
0
            kind if Self::is_control_flow_expr(kind) => self.eval_control_flow_expr(kind),
1736
            
1737
            // Data structure expressions
1738
0
            kind if Self::is_data_structure_expr(kind) => self.eval_data_structure_expr(kind),
1739
            
1740
            // Assignment expressions
1741
0
            kind if Self::is_assignment_expr(kind) => self.eval_assignment_expr(kind),
1742
            
1743
            // Other expressions
1744
0
            ExprKind::StringInterpolation { parts } => self.eval_string_interpolation(parts),
1745
0
            ExprKind::QualifiedName { module, name } => self.eval_qualified_name(module, name),
1746
            
1747
            // Unimplemented expressions
1748
0
            _ => Err(InterpreterError::RuntimeError(format!(
1749
0
                "Expression type not yet implemented: {expr_kind:?}"
1750
0
            ))),
1751
        }
1752
0
    }
1753
    
1754
    // Helper methods for expression type categorization and evaluation (complexity <10 each)
1755
    
1756
0
    fn is_control_flow_expr(expr_kind: &ExprKind) -> bool {
1757
0
        matches!(expr_kind, 
1758
            ExprKind::If { .. } | 
1759
            ExprKind::Let { .. } | 
1760
            ExprKind::For { .. } | 
1761
            ExprKind::While { .. } | 
1762
            ExprKind::Match { .. } | 
1763
            ExprKind::Break { .. } | 
1764
            ExprKind::Continue { .. } | 
1765
            ExprKind::Return { .. }
1766
        )
1767
0
    }
1768
    
1769
0
    fn is_data_structure_expr(expr_kind: &ExprKind) -> bool {
1770
0
        matches!(expr_kind,
1771
            ExprKind::List(_) |
1772
            ExprKind::Block(_) |
1773
            ExprKind::Tuple(_) |
1774
            ExprKind::Range { .. }
1775
        )
1776
0
    }
1777
    
1778
0
    fn is_assignment_expr(expr_kind: &ExprKind) -> bool {
1779
0
        matches!(expr_kind,
1780
            ExprKind::Assign { .. } |
1781
            ExprKind::CompoundAssign { .. }
1782
        )
1783
0
    }
1784
    
1785
0
    fn eval_control_flow_expr(&mut self, expr_kind: &ExprKind) -> Result<Value, InterpreterError> {
1786
0
        match expr_kind {
1787
0
            ExprKind::If { condition, then_branch, else_branch } => 
1788
0
                self.eval_if_expr(condition, then_branch, else_branch.as_deref()),
1789
0
            ExprKind::Let { name, value, body, .. } => 
1790
0
                self.eval_let_expr(name, value, body),
1791
0
            ExprKind::For { var, pattern, iter, body } => 
1792
0
                self.eval_for_loop(var, pattern.as_ref(), iter, body),
1793
0
            ExprKind::While { condition, body } => 
1794
0
                self.eval_while_loop(condition, body),
1795
0
            ExprKind::Match { expr, arms } => 
1796
0
                self.eval_match(expr, arms),
1797
            ExprKind::Break { label: _ } => 
1798
0
                Err(InterpreterError::RuntimeError("break".to_string())),
1799
            ExprKind::Continue { label: _ } => 
1800
0
                Err(InterpreterError::RuntimeError("continue".to_string())),
1801
0
            ExprKind::Return { value } => 
1802
0
                self.eval_return_expr(value.as_deref()),
1803
0
            _ => unreachable!("Non-control-flow expression passed to eval_control_flow_expr"),
1804
        }
1805
0
    }
1806
    
1807
0
    fn eval_data_structure_expr(&mut self, expr_kind: &ExprKind) -> Result<Value, InterpreterError> {
1808
0
        match expr_kind {
1809
0
            ExprKind::List(elements) => self.eval_list_expr(elements),
1810
0
            ExprKind::Block(statements) => self.eval_block_expr(statements),
1811
0
            ExprKind::Tuple(elements) => self.eval_tuple_expr(elements),
1812
0
            ExprKind::Range { start, end, inclusive } => self.eval_range_expr(start, end, *inclusive),
1813
0
            _ => unreachable!("Non-data-structure expression passed to eval_data_structure_expr"),
1814
        }
1815
0
    }
1816
    
1817
0
    fn eval_assignment_expr(&mut self, expr_kind: &ExprKind) -> Result<Value, InterpreterError> {
1818
0
        match expr_kind {
1819
0
            ExprKind::Assign { target, value } => self.eval_assign(target, value),
1820
0
            ExprKind::CompoundAssign { target, op, value } => self.eval_compound_assign(target, *op, value),
1821
0
            _ => unreachable!("Non-assignment expression passed to eval_assignment_expr"),
1822
        }
1823
0
    }
1824
    
1825
0
    fn eval_qualified_name(&self, module: &str, name: &str) -> Result<Value, InterpreterError> {
1826
0
        if module == "HashMap" && name == "new" {
1827
0
            Ok(Value::String(Rc::new("__builtin_hashmap__".to_string())))
1828
        } else {
1829
0
            Err(InterpreterError::RuntimeError(format!(
1830
0
                "Unknown qualified name: {}::{}",
1831
0
                module, name
1832
0
            )))
1833
        }
1834
0
    }
1835
1836
    /// Evaluate a literal value
1837
0
    fn eval_literal(&self, lit: &Literal) -> Value {
1838
0
        match lit {
1839
0
            Literal::Integer(i) => Value::from_i64(*i),
1840
0
            Literal::Float(f) => Value::from_f64(*f),
1841
0
            Literal::String(s) => Value::from_string(s.clone()),
1842
0
            Literal::Bool(b) => Value::from_bool(*b),
1843
0
            Literal::Char(c) => Value::from_string(c.to_string()),
1844
0
            Literal::Unit => Value::nil(),
1845
        }
1846
0
    }
1847
1848
    /// Look up a variable in the environment (searches from innermost to outermost)
1849
0
    fn lookup_variable(&self, name: &str) -> Result<Value, InterpreterError> {
1850
0
        for env in self.env_stack.iter().rev() {
1851
0
            if let Some(value) = env.get(name) {
1852
0
                return Ok(value.clone());
1853
0
            }
1854
        }
1855
0
        Err(InterpreterError::RuntimeError(format!(
1856
0
            "Undefined variable: {name}"
1857
0
        )))
1858
0
    }
1859
1860
    /// Get the current (innermost) environment
1861
    #[allow(clippy::expect_used)] // Environment stack invariant ensures this never panics
1862
0
    fn current_env(&self) -> &HashMap<String, Value> {
1863
0
        self.env_stack
1864
0
            .last()
1865
0
            .expect("Environment stack should never be empty")
1866
0
    }
1867
1868
    /// Set a variable in the current environment
1869
    #[allow(clippy::expect_used)] // Environment stack invariant ensures this never panics
1870
0
    fn env_set(&mut self, name: String, value: Value) {
1871
        // Record type feedback for optimization
1872
0
        self.record_variable_assignment_feedback(&name, &value);
1873
        
1874
0
        let env = self
1875
0
            .env_stack
1876
0
            .last_mut()
1877
0
            .expect("Environment stack should never be empty");
1878
0
        env.insert(name, value);
1879
0
    }
1880
1881
    /// Push a new environment onto the stack
1882
0
    fn env_push(&mut self, env: HashMap<String, Value>) {
1883
0
        self.env_stack.push(env);
1884
0
    }
1885
1886
    /// Pop the current environment from the stack
1887
0
    fn env_pop(&mut self) -> Option<HashMap<String, Value>> {
1888
0
        if self.env_stack.len() > 1 {
1889
            // Keep at least the global environment
1890
0
            self.env_stack.pop()
1891
        } else {
1892
0
            None
1893
        }
1894
0
    }
1895
1896
    /// Helper method to call a Value function with arguments (for array methods)
1897
0
    fn eval_function_call_value(&mut self, func: &Value, args: &[Value]) -> Result<Value, InterpreterError> {
1898
0
        self.call_function(func.clone(), args)
1899
0
    }
1900
    
1901
    /// Call a function with given arguments
1902
0
    fn call_function(&mut self, func: Value, args: &[Value]) -> Result<Value, InterpreterError> {
1903
0
        match func {
1904
0
            Value::String(s) if s.starts_with("__builtin_") => {
1905
                // Handle builtin functions
1906
0
                match s.as_str() {
1907
0
                    "__builtin_format__" => {
1908
0
                        if args.is_empty() {
1909
0
                            return Err(InterpreterError::RuntimeError("format requires at least one argument".to_string()));
1910
0
                        }
1911
                        
1912
                        // First argument is the format string
1913
0
                        if let Value::String(format_str) = &args[0] {
1914
0
                            let mut result = format_str.to_string();
1915
0
                            let mut arg_index = 1;
1916
                            
1917
                            // Simple format string replacement - find {} and replace with arguments
1918
0
                            while let Some(pos) = result.find("{}") {
1919
0
                                if arg_index < args.len() {
1920
0
                                    let replacement = args[arg_index].to_string();
1921
0
                                    result.replace_range(pos..pos+2, &replacement);
1922
0
                                    arg_index += 1;
1923
0
                                } else {
1924
0
                                    break;
1925
                                }
1926
                            }
1927
                            
1928
0
                            Ok(Value::from_string(result))
1929
                        } else {
1930
0
                            Err(InterpreterError::RuntimeError("format expects string as first argument".to_string()))
1931
                        }
1932
                    }
1933
0
                    "__builtin_hashmap__" => {
1934
                        // For now, we don't have a proper HashMap type, so return empty string representation
1935
0
                        Ok(Value::from_string("{}".to_string()))
1936
                    }
1937
0
                    _ => Err(InterpreterError::RuntimeError(format!("Unknown builtin function: {}", s))),
1938
                }
1939
            }
1940
0
            Value::Closure { params, body, env } => {
1941
                // Check argument count
1942
0
                if args.len() != params.len() {
1943
0
                    return Err(InterpreterError::RuntimeError(format!(
1944
0
                        "Function expects {} arguments, got {}",
1945
0
                        params.len(),
1946
0
                        args.len()
1947
0
                    )));
1948
0
                }
1949
1950
                // Create new environment with captured environment as base
1951
0
                let mut new_env = env.as_ref().clone();
1952
1953
                // Bind parameters to arguments
1954
0
                for (param, arg) in params.iter().zip(args) {
1955
0
                    new_env.insert(param.clone(), arg.clone());
1956
0
                }
1957
1958
                // Push new environment
1959
0
                self.env_push(new_env);
1960
1961
                // Evaluate function body
1962
0
                let result = self.eval_expr(&body);
1963
1964
                // Pop environment
1965
0
                self.env_pop();
1966
1967
0
                result
1968
            }
1969
0
            _ => Err(InterpreterError::TypeError(format!(
1970
0
                "Cannot call non-function value: {}",
1971
0
                func.type_name()
1972
0
            ))),
1973
        }
1974
0
    }
1975
1976
    /// Evaluate a binary operation from AST
1977
0
    fn eval_binary_op(
1978
0
        &self,
1979
0
        op: AstBinaryOp,
1980
0
        left: &Value,
1981
0
        right: &Value,
1982
0
    ) -> Result<Value, InterpreterError> {
1983
0
        match op {
1984
            AstBinaryOp::Add | AstBinaryOp::Subtract | AstBinaryOp::Multiply | 
1985
            AstBinaryOp::Divide | AstBinaryOp::Modulo | AstBinaryOp::Power => {
1986
0
                self.eval_arithmetic_op(op, left, right)
1987
            }
1988
            AstBinaryOp::Equal | AstBinaryOp::NotEqual | AstBinaryOp::Less | 
1989
            AstBinaryOp::Greater | AstBinaryOp::LessEqual | AstBinaryOp::GreaterEqual => {
1990
0
                self.eval_comparison_op(op, left, right)
1991
            }
1992
            AstBinaryOp::And | AstBinaryOp::Or => {
1993
0
                self.eval_logical_op(op, left, right)
1994
            }
1995
0
            _ => Err(InterpreterError::RuntimeError(format!(
1996
0
                "Binary operator not yet implemented: {op:?}"
1997
0
            ))),
1998
        }
1999
0
    }
2000
    
2001
    /// Handle arithmetic operations (Add, Subtract, Multiply, Divide, Modulo, Power)
2002
0
    fn eval_arithmetic_op(
2003
0
        &self,
2004
0
        op: AstBinaryOp,
2005
0
        left: &Value,
2006
0
        right: &Value,
2007
0
    ) -> Result<Value, InterpreterError> {
2008
0
        match op {
2009
0
            AstBinaryOp::Add => self.add_values(left, right),
2010
0
            AstBinaryOp::Subtract => self.sub_values(left, right),
2011
0
            AstBinaryOp::Multiply => self.mul_values(left, right),
2012
0
            AstBinaryOp::Divide => self.div_values(left, right),
2013
0
            AstBinaryOp::Modulo => self.modulo_values(left, right),
2014
0
            AstBinaryOp::Power => self.power_values(left, right),
2015
0
            _ => unreachable!("Non-arithmetic operation passed to eval_arithmetic_op"),
2016
        }
2017
0
    }
2018
    
2019
    /// Handle comparison operations (Equal, `NotEqual`, Less, Greater, `LessEqual`, `GreaterEqual`)
2020
0
    fn eval_comparison_op(
2021
0
        &self,
2022
0
        op: AstBinaryOp,
2023
0
        left: &Value,
2024
0
        right: &Value,
2025
0
    ) -> Result<Value, InterpreterError> {
2026
0
        match op {
2027
0
            AstBinaryOp::Equal => Ok(Value::from_bool(self.equal_values(left, right))),
2028
0
            AstBinaryOp::NotEqual => Ok(Value::from_bool(!self.equal_values(left, right))),
2029
0
            AstBinaryOp::Less => Ok(Value::from_bool(self.less_than_values(left, right)?)),
2030
0
            AstBinaryOp::Greater => Ok(Value::from_bool(self.greater_than_values(left, right)?)),
2031
            AstBinaryOp::LessEqual => {
2032
0
                let less = self.less_than_values(left, right)?;
2033
0
                let equal = self.equal_values(left, right);
2034
0
                Ok(Value::from_bool(less || equal))
2035
            }
2036
            AstBinaryOp::GreaterEqual => {
2037
0
                let greater = self.greater_than_values(left, right)?;
2038
0
                let equal = self.equal_values(left, right);
2039
0
                Ok(Value::from_bool(greater || equal))
2040
            }
2041
0
            _ => unreachable!("Non-comparison operation passed to eval_comparison_op"),
2042
        }
2043
0
    }
2044
    
2045
    /// Handle logical operations (And, Or)
2046
0
    fn eval_logical_op(
2047
0
        &self,
2048
0
        op: AstBinaryOp,
2049
0
        left: &Value,
2050
0
        right: &Value,
2051
0
    ) -> Result<Value, InterpreterError> {
2052
0
        match op {
2053
            AstBinaryOp::And => {
2054
                // Short-circuit evaluation for logical AND
2055
0
                if left.is_truthy() {
2056
0
                    Ok(right.clone())
2057
                } else {
2058
0
                    Ok(left.clone())
2059
                }
2060
            }
2061
            AstBinaryOp::Or => {
2062
                // Short-circuit evaluation for logical OR
2063
0
                if left.is_truthy() {
2064
0
                    Ok(left.clone())
2065
                } else {
2066
0
                    Ok(right.clone())
2067
                }
2068
            }
2069
0
            _ => unreachable!("Non-logical operation passed to eval_logical_op"),
2070
        }
2071
0
    }
2072
2073
    /// Evaluate a unary operation
2074
0
    fn eval_unary_op(
2075
0
        &self,
2076
0
        op: crate::frontend::ast::UnaryOp,
2077
0
        operand: &Value,
2078
0
    ) -> Result<Value, InterpreterError> {
2079
        use crate::frontend::ast::UnaryOp;
2080
0
        match op {
2081
0
            UnaryOp::Negate => match operand {
2082
0
                Value::Integer(i) => Ok(Value::from_i64(-i)),
2083
0
                Value::Float(f) => Ok(Value::from_f64(-f)),
2084
0
                _ => Err(InterpreterError::TypeError(format!(
2085
0
                    "Cannot negate {}",
2086
0
                    operand.type_name()
2087
0
                ))),
2088
            },
2089
0
            UnaryOp::Not => Ok(Value::from_bool(!operand.is_truthy())),
2090
0
            _ => Err(InterpreterError::RuntimeError(format!(
2091
0
                "Unary operator not yet implemented: {op:?}"
2092
0
            ))),
2093
        }
2094
0
    }
2095
2096
    /// Evaluate binary expression
2097
0
    fn eval_binary_expr(
2098
0
        &mut self,
2099
0
        left: &Expr,
2100
0
        op: crate::frontend::ast::BinaryOp,
2101
0
        right: &Expr,
2102
0
    ) -> Result<Value, InterpreterError> {
2103
        // Handle short-circuit operators
2104
0
        match op {
2105
            crate::frontend::ast::BinaryOp::NullCoalesce => {
2106
0
                let left_val = self.eval_expr(left)?;
2107
0
                if matches!(left_val, Value::Nil) {
2108
0
                    self.eval_expr(right)
2109
                } else {
2110
0
                    Ok(left_val)
2111
                }
2112
            }
2113
            crate::frontend::ast::BinaryOp::And => {
2114
0
                let left_val = self.eval_expr(left)?;
2115
0
                if left_val.is_truthy() {
2116
0
                    self.eval_expr(right)
2117
                } else {
2118
0
                    Ok(left_val)
2119
                }
2120
            }
2121
            crate::frontend::ast::BinaryOp::Or => {
2122
0
                let left_val = self.eval_expr(left)?;
2123
0
                if left_val.is_truthy() {
2124
0
                    Ok(left_val)
2125
                } else {
2126
0
                    self.eval_expr(right)
2127
                }
2128
            }
2129
            _ => {
2130
0
                let left_val = self.eval_expr(left)?;
2131
0
                let right_val = self.eval_expr(right)?;
2132
0
                let result = self.eval_binary_op(op, &left_val, &right_val)?;
2133
                
2134
                // Record type feedback for optimization
2135
0
                let site_id = left.span.start; // Use span start as site ID
2136
0
                self.record_binary_op_feedback(site_id, &left_val, &right_val, &result);
2137
                
2138
0
                Ok(result)
2139
            }
2140
        }
2141
0
    }
2142
2143
    /// Evaluate unary expression
2144
0
    fn eval_unary_expr(
2145
0
        &mut self,
2146
0
        op: crate::frontend::ast::UnaryOp,
2147
0
        operand: &Expr,
2148
0
    ) -> Result<Value, InterpreterError> {
2149
0
        let operand_val = self.eval_expr(operand)?;
2150
0
        self.eval_unary_op(op, &operand_val)
2151
0
    }
2152
2153
    /// Evaluate if expression
2154
0
    fn eval_if_expr(
2155
0
        &mut self,
2156
0
        condition: &Expr,
2157
0
        then_branch: &Expr,
2158
0
        else_branch: Option<&Expr>,
2159
0
    ) -> Result<Value, InterpreterError> {
2160
0
        let condition_val = self.eval_expr(condition)?;
2161
0
        if condition_val.is_truthy() {
2162
0
            self.eval_expr(then_branch)
2163
0
        } else if let Some(else_expr) = else_branch {
2164
0
            self.eval_expr(else_expr)
2165
        } else {
2166
0
            Ok(Value::nil())
2167
        }
2168
0
    }
2169
2170
    /// Evaluate let expression
2171
0
    fn eval_let_expr(
2172
0
        &mut self,
2173
0
        name: &str,
2174
0
        value: &Expr,
2175
0
        body: &Expr,
2176
0
    ) -> Result<Value, InterpreterError> {
2177
0
        let val = self.eval_expr(value)?;
2178
0
        self.env_set(name.to_string(), val);
2179
0
        self.eval_expr(body)
2180
0
    }
2181
2182
    /// Evaluate return expression
2183
0
    fn eval_return_expr(&mut self, value: Option<&Expr>) -> Result<Value, InterpreterError> {
2184
0
        if let Some(expr) = value {
2185
0
            let val = self.eval_expr(expr)?;
2186
0
            Err(InterpreterError::RuntimeError(format!("return {val:?}")))
2187
        } else {
2188
0
            Err(InterpreterError::RuntimeError("return".to_string()))
2189
        }
2190
0
    }
2191
2192
    /// Evaluate list expression
2193
0
    fn eval_list_expr(&mut self, elements: &[Expr]) -> Result<Value, InterpreterError> {
2194
0
        let mut values = Vec::new();
2195
0
        for elem in elements {
2196
0
            values.push(self.eval_expr(elem)?);
2197
        }
2198
0
        Ok(Value::from_array(values))
2199
0
    }
2200
2201
    /// Evaluate block expression
2202
0
    fn eval_block_expr(&mut self, statements: &[Expr]) -> Result<Value, InterpreterError> {
2203
0
        let mut result = Value::nil();
2204
0
        for stmt in statements {
2205
0
            result = self.eval_expr(stmt)?;
2206
        }
2207
0
        Ok(result)
2208
0
    }
2209
2210
    /// Evaluate tuple expression
2211
0
    fn eval_tuple_expr(&mut self, elements: &[Expr]) -> Result<Value, InterpreterError> {
2212
0
        let mut values = Vec::new();
2213
0
        for elem in elements {
2214
0
            values.push(self.eval_expr(elem)?);
2215
        }
2216
0
        Ok(Value::Tuple(Rc::new(values)))
2217
0
    }
2218
2219
    /// Evaluate range expression
2220
0
    fn eval_range_expr(
2221
0
        &mut self,
2222
0
        start: &Expr,
2223
0
        end: &Expr,
2224
0
        inclusive: bool,
2225
0
    ) -> Result<Value, InterpreterError> {
2226
0
        let start_val = self.eval_expr(start)?;
2227
0
        let end_val = self.eval_expr(end)?;
2228
        
2229
0
        match (start_val, end_val) {
2230
0
            (Value::Integer(start_i), Value::Integer(end_i)) => {
2231
0
                let range: Vec<Value> = if inclusive {
2232
0
                    (start_i..=end_i).map(Value::from_i64).collect()
2233
                } else {
2234
0
                    (start_i..end_i).map(Value::from_i64).collect()
2235
                };
2236
0
                Ok(Value::from_array(range))
2237
            }
2238
0
            _ => Err(InterpreterError::TypeError(
2239
0
                "Range bounds must be integers".to_string(),
2240
0
            )),
2241
        }
2242
0
    }
2243
2244
    /// Helper function for testing - evaluate a string expression via parser
2245
    /// # Errors
2246
    /// Returns error if parsing or evaluation fails
2247
    #[cfg(test)]
2248
    pub fn eval_string(&mut self, input: &str) -> Result<Value, Box<dyn std::error::Error>> {
2249
        use crate::frontend::parser::Parser;
2250
2251
        let mut parser = Parser::new(input);
2252
        let expr = parser.parse_expr()?;
2253
2254
        Ok(self.eval_expr(&expr)?)
2255
    }
2256
2257
    /// Push value onto stack
2258
    /// # Errors
2259
    /// Returns error if stack overflow occurs
2260
0
    pub fn push(&mut self, value: Value) -> Result<(), InterpreterError> {
2261
0
        if self.stack.len() >= 10_000 {
2262
            // Stack limit from spec
2263
0
            return Err(InterpreterError::StackOverflow);
2264
0
        }
2265
0
        self.stack.push(value);
2266
0
        Ok(())
2267
0
    }
2268
2269
    /// Pop value from stack
2270
    /// # Errors
2271
    /// Returns error if stack underflow occurs
2272
0
    pub fn pop(&mut self) -> Result<Value, InterpreterError> {
2273
0
        self.stack.pop().ok_or(InterpreterError::StackUnderflow)
2274
0
    }
2275
2276
    /// Peek at top of stack without popping
2277
    /// # Errors
2278
    /// Returns error if stack underflow occurs
2279
0
    pub fn peek(&self, depth: usize) -> Result<Value, InterpreterError> {
2280
0
        let index = self
2281
0
            .stack
2282
0
            .len()
2283
0
            .checked_sub(depth + 1)
2284
0
            .ok_or(InterpreterError::StackUnderflow)?;
2285
0
        Ok(self.stack[index].clone())
2286
0
    }
2287
2288
    /// Binary arithmetic operation with type checking
2289
    /// # Errors
2290
    /// Returns error if stack underflow, type mismatch, or arithmetic error occurs
2291
0
    pub fn binary_op(&mut self, op: BinaryOp) -> Result<(), InterpreterError> {
2292
0
        let right = self.pop()?;
2293
0
        let left = self.pop()?;
2294
2295
0
        let result = match op {
2296
0
            BinaryOp::Add => self.add_values(&left, &right)?,
2297
0
            BinaryOp::Sub => self.sub_values(&left, &right)?,
2298
0
            BinaryOp::Mul => self.mul_values(&left, &right)?,
2299
0
            BinaryOp::Div => self.div_values(&left, &right)?,
2300
0
            BinaryOp::Eq => Value::from_bool(self.equal_values(&left, &right)),
2301
0
            BinaryOp::Lt => Value::from_bool(self.less_than_values(&left, &right)?),
2302
0
            BinaryOp::Gt => Value::from_bool(self.greater_than_values(&left, &right)?),
2303
        };
2304
2305
0
        self.push(result)?;
2306
0
        Ok(())
2307
0
    }
2308
2309
    /// Add two values with type coercion
2310
0
    fn add_values(&self, left: &Value, right: &Value) -> Result<Value, InterpreterError> {
2311
0
        match (left, right) {
2312
0
            (Value::Integer(a), Value::Integer(b)) => Ok(Value::from_i64(a + b)),
2313
0
            (Value::Float(a), Value::Float(b)) => Ok(Value::from_f64(a + b)),
2314
0
            (Value::Integer(a), Value::Float(b)) =>
2315
            {
2316
                #[allow(clippy::cast_precision_loss)]
2317
0
                Ok(Value::from_f64(*a as f64 + b))
2318
            }
2319
0
            (Value::Float(a), Value::Integer(b)) =>
2320
            {
2321
                #[allow(clippy::cast_precision_loss)]
2322
0
                Ok(Value::from_f64(a + *b as f64))
2323
            }
2324
0
            (Value::String(a), Value::String(b)) => {
2325
0
                Ok(Value::from_string(format!("{}{}", a.as_ref(), b.as_ref())))
2326
            }
2327
0
            _ => Err(InterpreterError::TypeError(format!(
2328
0
                "Cannot add {} and {}",
2329
0
                left.type_name(),
2330
0
                right.type_name()
2331
0
            ))),
2332
        }
2333
0
    }
2334
2335
    /// Subtract two values
2336
0
    fn sub_values(&self, left: &Value, right: &Value) -> Result<Value, InterpreterError> {
2337
0
        match (left, right) {
2338
0
            (Value::Integer(a), Value::Integer(b)) => Ok(Value::from_i64(a - b)),
2339
0
            (Value::Float(a), Value::Float(b)) => Ok(Value::from_f64(a - b)),
2340
0
            (Value::Integer(a), Value::Float(b)) =>
2341
            {
2342
                #[allow(clippy::cast_precision_loss)]
2343
0
                Ok(Value::from_f64(*a as f64 - b))
2344
            }
2345
0
            (Value::Float(a), Value::Integer(b)) =>
2346
            {
2347
                #[allow(clippy::cast_precision_loss)]
2348
0
                Ok(Value::from_f64(a - *b as f64))
2349
            }
2350
0
            _ => Err(InterpreterError::TypeError(format!(
2351
0
                "Cannot subtract {} from {}",
2352
0
                right.type_name(),
2353
0
                left.type_name()
2354
0
            ))),
2355
        }
2356
0
    }
2357
2358
    /// Multiply two values
2359
0
    fn mul_values(&self, left: &Value, right: &Value) -> Result<Value, InterpreterError> {
2360
0
        match (left, right) {
2361
0
            (Value::Integer(a), Value::Integer(b)) => Ok(Value::from_i64(a * b)),
2362
0
            (Value::Float(a), Value::Float(b)) => Ok(Value::from_f64(a * b)),
2363
0
            (Value::Integer(a), Value::Float(b)) =>
2364
            {
2365
                #[allow(clippy::cast_precision_loss)]
2366
0
                Ok(Value::from_f64(*a as f64 * b))
2367
            }
2368
0
            (Value::Float(a), Value::Integer(b)) =>
2369
            {
2370
                #[allow(clippy::cast_precision_loss)]
2371
0
                Ok(Value::from_f64(a * *b as f64))
2372
            }
2373
0
            _ => Err(InterpreterError::TypeError(format!(
2374
0
                "Cannot multiply {} and {}",
2375
0
                left.type_name(),
2376
0
                right.type_name()
2377
0
            ))),
2378
        }
2379
0
    }
2380
2381
    /// Divide two values
2382
0
    fn div_values(&self, left: &Value, right: &Value) -> Result<Value, InterpreterError> {
2383
0
        match (left, right) {
2384
0
            (Value::Integer(a), Value::Integer(b)) => {
2385
0
                if *b == 0 {
2386
0
                    return Err(InterpreterError::DivisionByZero);
2387
0
                }
2388
0
                Ok(Value::from_i64(a / b))
2389
            }
2390
0
            (Value::Float(a), Value::Float(b)) => {
2391
0
                if *b == 0.0 {
2392
0
                    return Err(InterpreterError::DivisionByZero);
2393
0
                }
2394
0
                Ok(Value::from_f64(a / b))
2395
            }
2396
0
            (Value::Integer(a), Value::Float(b)) => {
2397
0
                if *b == 0.0 {
2398
0
                    return Err(InterpreterError::DivisionByZero);
2399
0
                }
2400
                #[allow(clippy::cast_precision_loss)]
2401
0
                Ok(Value::from_f64(*a as f64 / b))
2402
            }
2403
0
            (Value::Float(a), Value::Integer(b)) => {
2404
                #[allow(clippy::cast_precision_loss)]
2405
0
                let divisor = *b as f64;
2406
0
                if divisor == 0.0 {
2407
0
                    return Err(InterpreterError::DivisionByZero);
2408
0
                }
2409
0
                Ok(Value::from_f64(a / divisor))
2410
            }
2411
0
            _ => Err(InterpreterError::TypeError(format!(
2412
0
                "Cannot divide {} by {}",
2413
0
                left.type_name(),
2414
0
                right.type_name()
2415
0
            ))),
2416
        }
2417
0
    }
2418
2419
    /// Modulo operation between two values
2420
0
    fn modulo_values(&self, left: &Value, right: &Value) -> Result<Value, InterpreterError> {
2421
0
        match (left, right) {
2422
0
            (Value::Integer(a), Value::Integer(b)) => {
2423
0
                if *b == 0 {
2424
0
                    return Err(InterpreterError::DivisionByZero);
2425
0
                }
2426
0
                Ok(Value::from_i64(a % b))
2427
            }
2428
0
            (Value::Float(a), Value::Float(b)) => {
2429
0
                if *b == 0.0 {
2430
0
                    return Err(InterpreterError::DivisionByZero);
2431
0
                }
2432
0
                Ok(Value::from_f64(a % b))
2433
            }
2434
0
            (Value::Integer(a), Value::Float(b)) => {
2435
0
                if *b == 0.0 {
2436
0
                    return Err(InterpreterError::DivisionByZero);
2437
0
                }
2438
                #[allow(clippy::cast_precision_loss)]
2439
0
                Ok(Value::from_f64((*a as f64) % b))
2440
            }
2441
0
            (Value::Float(a), Value::Integer(b)) => {
2442
                #[allow(clippy::cast_precision_loss)]
2443
0
                let divisor = *b as f64;
2444
0
                if divisor == 0.0 {
2445
0
                    return Err(InterpreterError::DivisionByZero);
2446
0
                }
2447
0
                Ok(Value::from_f64(a % divisor))
2448
            }
2449
0
            _ => Err(InterpreterError::TypeError(format!(
2450
0
                "Cannot compute modulo of {} and {}",
2451
0
                left.type_name(),
2452
0
                right.type_name()
2453
0
            ))),
2454
        }
2455
0
    }
2456
2457
    /// Power operation between two values
2458
0
    fn power_values(&self, left: &Value, right: &Value) -> Result<Value, InterpreterError> {
2459
0
        match (left, right) {
2460
0
            (Value::Integer(a), Value::Integer(b)) => {
2461
0
                if *b < 0 {
2462
                    // For negative exponents, convert to float
2463
                    #[allow(clippy::cast_precision_loss)]
2464
0
                    let result = (*a as f64).powf(*b as f64);
2465
0
                    Ok(Value::from_f64(result))
2466
                } else {
2467
                    #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
2468
0
                    if let Some(result) = a.checked_pow(*b as u32) { Ok(Value::from_i64(result)) } else {
2469
                        // Overflow - convert to float
2470
                        #[allow(clippy::cast_precision_loss)]
2471
0
                        let result = (*a as f64).powf(*b as f64);
2472
0
                        Ok(Value::from_f64(result))
2473
                    }
2474
                }
2475
            }
2476
0
            (Value::Float(a), Value::Float(b)) => {
2477
0
                Ok(Value::from_f64(a.powf(*b)))
2478
            }
2479
0
            (Value::Integer(a), Value::Float(b)) => {
2480
                #[allow(clippy::cast_precision_loss)]
2481
0
                Ok(Value::from_f64((*a as f64).powf(*b)))
2482
            }
2483
0
            (Value::Float(a), Value::Integer(b)) => {
2484
                #[allow(clippy::cast_precision_loss)]
2485
0
                Ok(Value::from_f64(a.powf(*b as f64)))
2486
            }
2487
0
            _ => Err(InterpreterError::TypeError(format!(
2488
0
                "Cannot raise {} to the power of {}",
2489
0
                left.type_name(),
2490
0
                right.type_name()
2491
0
            ))),
2492
        }
2493
0
    }
2494
2495
    /// Check equality of two values
2496
0
    fn equal_values(&self, left: &Value, right: &Value) -> bool {
2497
0
        left == right // PartialEq is derived for Value
2498
0
    }
2499
2500
    /// Check if left < right
2501
0
    fn less_than_values(&self, left: &Value, right: &Value) -> Result<bool, InterpreterError> {
2502
0
        match (left, right) {
2503
0
            (Value::Integer(a), Value::Integer(b)) => Ok(a < b),
2504
0
            (Value::Float(a), Value::Float(b)) => Ok(a < b),
2505
0
            (Value::Integer(a), Value::Float(b)) =>
2506
            {
2507
                #[allow(clippy::cast_precision_loss)]
2508
0
                Ok((*a as f64) < *b)
2509
            }
2510
0
            (Value::Float(a), Value::Integer(b)) =>
2511
            {
2512
                #[allow(clippy::cast_precision_loss)]
2513
0
                Ok(*a < (*b as f64))
2514
            }
2515
0
            _ => Err(InterpreterError::TypeError(format!(
2516
0
                "Cannot compare {} and {}",
2517
0
                left.type_name(),
2518
0
                right.type_name()
2519
0
            ))),
2520
        }
2521
0
    }
2522
2523
    /// Check if left > right
2524
0
    fn greater_than_values(&self, left: &Value, right: &Value) -> Result<bool, InterpreterError> {
2525
0
        match (left, right) {
2526
0
            (Value::Integer(a), Value::Integer(b)) => Ok(a > b),
2527
0
            (Value::Float(a), Value::Float(b)) => Ok(a > b),
2528
0
            (Value::Integer(a), Value::Float(b)) =>
2529
            {
2530
                #[allow(clippy::cast_precision_loss)]
2531
0
                Ok((*a as f64) > *b)
2532
            }
2533
0
            (Value::Float(a), Value::Integer(b)) =>
2534
            {
2535
                #[allow(clippy::cast_precision_loss)]
2536
0
                Ok(*a > (*b as f64))
2537
            }
2538
0
            _ => Err(InterpreterError::TypeError(format!(
2539
0
                "Cannot compare {} and {}",
2540
0
                left.type_name(),
2541
0
                right.type_name()
2542
0
            ))),
2543
        }
2544
0
    }
2545
2546
    /// Print value for debugging
2547
0
    pub fn print_value(&self, value: &Value) -> std::string::String {
2548
0
        match value {
2549
0
            Value::Integer(i) => i.to_string(),
2550
0
            Value::Float(f) => f.to_string(),
2551
0
            Value::Bool(b) => b.to_string(),
2552
0
            Value::Nil => "nil".to_string(),
2553
0
            Value::String(s) => s.as_ref().clone(),
2554
0
            Value::Array(arr) => {
2555
0
                let elements: Vec<String> = arr.iter().map(|v| self.print_value(v)).collect();
2556
0
                format!("[{}]", elements.join(", "))
2557
            }
2558
0
            Value::Tuple(elements) => {
2559
0
                let element_strs: Vec<String> = elements.iter().map(|v| self.print_value(v)).collect();
2560
0
                format!("({})", element_strs.join(", "))
2561
            }
2562
0
            Value::Closure { params, .. } => {
2563
0
                format!("function/{}", params.len())
2564
            }
2565
        }
2566
0
    }
2567
2568
    /// Set a variable in the current environment
2569
0
    fn set_variable(&mut self, name: String, value: Value) {
2570
0
        self.env_set(name, value);
2571
0
    }
2572
    
2573
    /// Apply a binary operation to two values
2574
0
    fn apply_binary_op(&self, left: &Value, op: AstBinaryOp, right: &Value) -> Result<Value, InterpreterError> {
2575
        // Delegate to existing binary operation evaluation
2576
0
        self.eval_binary_op(op, left, right)
2577
0
    }
2578
    
2579
    /// Check if a pattern matches a value
2580
    /// # Errors
2581
    /// Returns error if pattern matching fails
2582
0
    fn pattern_matches(&self, pattern: &Pattern, value: &Value) -> Result<bool, InterpreterError> {
2583
0
        match pattern {
2584
0
            Pattern::Wildcard => Ok(true),
2585
0
            Pattern::Literal(lit) => self.match_literal_pattern(lit, value),
2586
0
            Pattern::Identifier(_name) => Ok(true), // Always matches, binding handled separately
2587
0
            Pattern::Tuple(patterns) => self.match_tuple_pattern(patterns, value),
2588
0
            Pattern::List(patterns) => self.match_list_pattern(patterns, value),
2589
0
            Pattern::Or(patterns) => self.match_or_pattern(patterns, value),
2590
0
            Pattern::Range { start, end, inclusive } => self.match_range_pattern(start, end, *inclusive, value),
2591
0
            _ => Ok(false), // Other patterns not yet implemented
2592
        }
2593
0
    }
2594
    
2595
    // Helper methods for pattern matching (complexity <10 each)
2596
    
2597
0
    fn match_literal_pattern(&self, lit: &Literal, value: &Value) -> Result<bool, InterpreterError> {
2598
0
        let lit_value = self.eval_literal(lit);
2599
0
        Ok(lit_value == *value)
2600
0
    }
2601
    
2602
0
    fn match_tuple_pattern(&self, patterns: &[Pattern], value: &Value) -> Result<bool, InterpreterError> {
2603
0
        if let Value::Tuple(elements) = value {
2604
0
            self.match_sequence_patterns(patterns, elements)
2605
        } else {
2606
0
            Ok(false)
2607
        }
2608
0
    }
2609
    
2610
0
    fn match_list_pattern(&self, patterns: &[Pattern], value: &Value) -> Result<bool, InterpreterError> {
2611
0
        if let Value::Array(elements) = value {
2612
0
            self.match_sequence_patterns(patterns, elements)
2613
        } else {
2614
0
            Ok(false)
2615
        }
2616
0
    }
2617
    
2618
0
    fn match_sequence_patterns(&self, patterns: &[Pattern], elements: &[Value]) -> Result<bool, InterpreterError> {
2619
0
        if patterns.len() != elements.len() {
2620
0
            return Ok(false);
2621
0
        }
2622
0
        for (pat, val) in patterns.iter().zip(elements.iter()) {
2623
0
            if !self.pattern_matches(pat, val)? {
2624
0
                return Ok(false);
2625
0
            }
2626
        }
2627
0
        Ok(true)
2628
0
    }
2629
    
2630
0
    fn match_or_pattern(&self, patterns: &[Pattern], value: &Value) -> Result<bool, InterpreterError> {
2631
0
        for pat in patterns {
2632
0
            if self.pattern_matches(pat, value)? {
2633
0
                return Ok(true);
2634
0
            }
2635
        }
2636
0
        Ok(false)
2637
0
    }
2638
    
2639
0
    fn match_range_pattern(&self, start: &Pattern, end: &Pattern, inclusive: bool, value: &Value) -> Result<bool, InterpreterError> {
2640
0
        if let Value::Integer(i) = value {
2641
0
            let start_val = self.extract_integer_from_pattern(start)?;
2642
0
            let end_val = self.extract_integer_from_pattern(end)?;
2643
            
2644
0
            if inclusive {
2645
0
                Ok(*i >= start_val && *i <= end_val)
2646
            } else {
2647
0
                Ok(*i >= start_val && *i < end_val)
2648
            }
2649
        } else {
2650
0
            Ok(false)
2651
        }
2652
0
    }
2653
    
2654
0
    fn extract_integer_from_pattern(&self, pattern: &Pattern) -> Result<i64, InterpreterError> {
2655
0
        if let Pattern::Literal(Literal::Integer(val)) = pattern {
2656
0
            Ok(*val)
2657
        } else {
2658
0
            Err(InterpreterError::RuntimeError("Range pattern requires integer literals".to_string()))
2659
        }
2660
0
    }
2661
    
2662
    /// Access field with inline caching optimization
2663
    /// # Errors
2664
    /// Returns error if field access fails
2665
0
    pub fn get_field_cached(
2666
0
        &mut self,
2667
0
        obj: &Value,
2668
0
        field_name: &str,
2669
0
    ) -> Result<Value, InterpreterError> {
2670
        // Create cache key combining object type and field name
2671
0
        let cache_key = format!("{:?}::{}", obj.type_id(), field_name);
2672
2673
        // Check inline cache first
2674
0
        if let Some(cache) = self.field_caches.get_mut(&cache_key) {
2675
0
            if let Some(cached_result) = cache.lookup(obj, field_name) {
2676
0
                return Ok(cached_result);
2677
0
            }
2678
0
        }
2679
2680
        // Cache miss - compute result and update cache
2681
0
        let result = self.compute_field_access(obj, field_name)?;
2682
2683
        // Update or create cache entry
2684
0
        let cache = self.field_caches.entry(cache_key).or_default();
2685
0
        cache.insert(obj, field_name.to_string(), result.clone());
2686
2687
0
        Ok(result)
2688
0
    }
2689
2690
    /// Compute field access result (detailed path)
2691
0
    fn compute_field_access(
2692
0
        &self,
2693
0
        obj: &Value,
2694
0
        field_name: &str,
2695
0
    ) -> Result<Value, InterpreterError> {
2696
0
        match (obj, field_name) {
2697
            // String methods
2698
0
            (Value::String(s), "len") => Ok(Value::Integer(s.len().try_into().unwrap_or(i64::MAX))),
2699
0
            (Value::String(s), "to_upper") => Ok(Value::String(Rc::new(s.to_uppercase()))),
2700
0
            (Value::String(s), "to_lower") => Ok(Value::String(Rc::new(s.to_lowercase()))),
2701
0
            (Value::String(s), "trim") => Ok(Value::String(Rc::new(s.trim().to_string()))),
2702
2703
            // Array methods
2704
0
            (Value::Array(arr), "len") => {
2705
0
                Ok(Value::Integer(arr.len().try_into().unwrap_or(i64::MAX)))
2706
            }
2707
0
            (Value::Array(arr), "first") => arr
2708
0
                .first()
2709
0
                .cloned()
2710
0
                .ok_or_else(|| InterpreterError::RuntimeError("Array is empty".to_string())),
2711
0
            (Value::Array(arr), "last") => arr
2712
0
                .last()
2713
0
                .cloned()
2714
0
                .ok_or_else(|| InterpreterError::RuntimeError("Array is empty".to_string())),
2715
0
            (Value::Array(arr), "is_empty") => {
2716
0
                Ok(Value::from_bool(arr.is_empty()))
2717
            }
2718
2719
            // Type information
2720
0
            (obj, "type") => Ok(Value::String(Rc::new(obj.type_name().to_string()))),
2721
2722
0
            _ => Err(InterpreterError::RuntimeError(format!(
2723
0
                "Field '{}' not found on type '{}'",
2724
0
                field_name,
2725
0
                obj.type_name()
2726
0
            ))),
2727
        }
2728
0
    }
2729
2730
    /// Get inline cache statistics for profiling
2731
0
    pub fn get_cache_stats(&self) -> HashMap<String, f64> {
2732
0
        let mut stats = HashMap::new();
2733
0
        for (key, cache) in &self.field_caches {
2734
0
            stats.insert(key.clone(), cache.hit_rate());
2735
0
        }
2736
0
        stats
2737
0
    }
2738
2739
    /// Clear all inline caches (for testing)
2740
0
    pub fn clear_caches(&mut self) {
2741
0
        self.field_caches.clear();
2742
0
    }
2743
2744
    /// Record type feedback for binary operations
2745
    #[allow(dead_code)] // Used by tests and type feedback system
2746
0
    fn record_binary_op_feedback(
2747
0
        &mut self,
2748
0
        site_id: usize,
2749
0
        left: &Value,
2750
0
        right: &Value,
2751
0
        result: &Value,
2752
0
    ) {
2753
0
        self.type_feedback
2754
0
            .record_binary_op(site_id, left, right, result);
2755
0
    }
2756
2757
    /// Record type feedback for variable assignments
2758
    #[allow(dead_code)] // Used by tests and type feedback system
2759
0
    fn record_variable_assignment_feedback(&mut self, var_name: &str, value: &Value) {
2760
0
        let type_id = value.type_id();
2761
0
        self.type_feedback
2762
0
            .record_variable_assignment(var_name, type_id);
2763
0
    }
2764
2765
    /// Record type feedback for function calls
2766
0
    fn record_function_call_feedback(
2767
0
        &mut self,
2768
0
        site_id: usize,
2769
0
        func_name: &str,
2770
0
        args: &[Value],
2771
0
        result: &Value,
2772
0
    ) {
2773
0
        self.type_feedback
2774
0
            .record_function_call(site_id, func_name, args, result);
2775
0
    }
2776
2777
    /// Get type feedback statistics
2778
0
    pub fn get_type_feedback_stats(&self) -> TypeFeedbackStats {
2779
0
        self.type_feedback.get_statistics()
2780
0
    }
2781
2782
    /// Get specialization candidates for JIT compilation
2783
0
    pub fn get_specialization_candidates(&self) -> Vec<SpecializationCandidate> {
2784
0
        self.type_feedback.get_specialization_candidates()
2785
0
    }
2786
2787
    /// Clear type feedback data (for testing)
2788
0
    pub fn clear_type_feedback(&mut self) {
2789
0
        self.type_feedback = TypeFeedback::new();
2790
0
    }
2791
2792
    /// Track a value in the garbage collector
2793
0
    pub fn gc_track(&mut self, value: Value) -> usize {
2794
0
        self.gc.track_object(value)
2795
0
    }
2796
2797
    /// Force garbage collection
2798
0
    pub fn gc_collect(&mut self) -> GCStats {
2799
0
        self.gc.force_collect()
2800
0
    }
2801
2802
    /// Get garbage collection statistics
2803
0
    pub fn gc_stats(&self) -> GCStats {
2804
0
        self.gc.get_stats()
2805
0
    }
2806
2807
    /// Get detailed garbage collection information
2808
0
    pub fn gc_info(&self) -> GCInfo {
2809
0
        self.gc.get_info()
2810
0
    }
2811
2812
    /// Set garbage collection threshold
2813
0
    pub fn gc_set_threshold(&mut self, threshold: usize) {
2814
0
        self.gc.set_collection_threshold(threshold);
2815
0
    }
2816
2817
    /// Enable or disable automatic garbage collection
2818
0
    pub fn gc_set_auto_collect(&mut self, enabled: bool) {
2819
0
        self.gc.set_auto_collect(enabled);
2820
0
    }
2821
2822
    /// Clear all GC-tracked objects (for testing)
2823
0
    pub fn gc_clear(&mut self) {
2824
0
        self.gc.clear();
2825
0
    }
2826
2827
    /// Allocate a new array and track it in GC
2828
0
    pub fn gc_alloc_array(&mut self, elements: Vec<Value>) -> Value {
2829
0
        let array_value = Value::Array(Rc::new(elements));
2830
0
        self.gc.track_object(array_value.clone());
2831
0
        array_value
2832
0
    }
2833
2834
    /// Allocate a new string and track it in GC
2835
0
    pub fn gc_alloc_string(&mut self, content: String) -> Value {
2836
0
        let string_value = Value::String(Rc::new(content));
2837
0
        self.gc.track_object(string_value.clone());
2838
0
        string_value
2839
0
    }
2840
2841
    /// Allocate a new closure and track it in GC
2842
0
    pub fn gc_alloc_closure(
2843
0
        &mut self,
2844
0
        params: Vec<String>,
2845
0
        body: Rc<Expr>,
2846
0
        env: Rc<HashMap<String, Value>>,
2847
0
    ) -> Value {
2848
0
        let closure_value = Value::Closure { params, body, env };
2849
0
        self.gc.track_object(closure_value.clone());
2850
0
        closure_value
2851
0
    }
2852
    
2853
    /// Evaluate a for loop
2854
0
    fn eval_for_loop(&mut self, var: &str, pattern: Option<&Pattern>, iter: &Expr, body: &Expr) -> Result<Value, InterpreterError> {
2855
0
        let iter_value = self.eval_expr(iter)?;
2856
        
2857
0
        match iter_value {
2858
0
            Value::Array(arr) => {
2859
0
                let mut last_value = Value::nil();
2860
0
                for item in arr.iter() {
2861
                    // Handle pattern matching if present
2862
0
                    if let Some(_pat) = pattern {
2863
0
                        // Pattern matching for destructuring would go here
2864
0
                        // For now, just bind to var
2865
0
                        self.set_variable(var.to_string(), item.clone());
2866
0
                    } else {
2867
0
                        // Simple variable binding
2868
0
                        self.set_variable(var.to_string(), item.clone());
2869
0
                    }
2870
                    
2871
                    // Execute body
2872
0
                    match self.eval_expr(body) {
2873
0
                        Ok(value) => last_value = value,
2874
0
                        Err(InterpreterError::RuntimeError(msg)) if msg == "break" => break,
2875
0
                        Err(InterpreterError::RuntimeError(msg)) if msg == "continue" => {},
2876
0
                        Err(e) => return Err(e),
2877
                    }
2878
                }
2879
0
                Ok(last_value)
2880
            }
2881
0
            _ => Err(InterpreterError::TypeError(
2882
0
                "For loop requires an iterable (array)".to_string()
2883
0
            )),
2884
        }
2885
0
    }
2886
    
2887
    /// Evaluate a while loop
2888
0
    fn eval_while_loop(&mut self, condition: &Expr, body: &Expr) -> Result<Value, InterpreterError> {
2889
0
        let mut last_value = Value::nil();
2890
        loop {
2891
0
            let cond_value = self.eval_expr(condition)?;
2892
0
            if !cond_value.is_truthy() {
2893
0
                break;
2894
0
            }
2895
            
2896
0
            match self.eval_expr(body) {
2897
0
                Ok(val) => last_value = val,
2898
0
                Err(InterpreterError::RuntimeError(msg)) if msg == "break" => break,
2899
0
                Err(InterpreterError::RuntimeError(msg)) if msg == "continue" => {},
2900
0
                Err(e) => return Err(e),
2901
            }
2902
        }
2903
0
        Ok(last_value)
2904
0
    }
2905
    
2906
    /// Evaluate a match expression
2907
0
    fn eval_match(&mut self, expr: &Expr, arms: &[MatchArm]) -> Result<Value, InterpreterError> {
2908
0
        let value = self.eval_expr(expr)?;
2909
        
2910
0
        for arm in arms {
2911
0
            if self.pattern_matches(&arm.pattern, &value)? {
2912
                // Pattern bindings are handled by pattern_matches method
2913
                // when it returns true, any variables are already bound
2914
0
                return self.eval_expr(&arm.body);
2915
0
            }
2916
        }
2917
        
2918
0
        Err(InterpreterError::RuntimeError(
2919
0
            "No match arm matched the value".to_string()
2920
0
        ))
2921
0
    }
2922
    
2923
    /// Evaluate an assignment
2924
0
    fn eval_assign(&mut self, target: &Expr, value: &Expr) -> Result<Value, InterpreterError> {
2925
0
        let val = self.eval_expr(value)?;
2926
        
2927
        // Handle different assignment targets
2928
0
        match &target.kind {
2929
0
            ExprKind::Identifier(name) => {
2930
0
                self.set_variable(name.clone(), val.clone());
2931
0
                Ok(val)
2932
            }
2933
0
            _ => Err(InterpreterError::RuntimeError(
2934
0
                "Invalid assignment target".to_string()
2935
0
            )),
2936
        }
2937
0
    }
2938
    
2939
    /// Evaluate a compound assignment
2940
0
    fn eval_compound_assign(&mut self, target: &Expr, op: AstBinaryOp, value: &Expr) -> Result<Value, InterpreterError> {
2941
        // Get current value
2942
0
        let current = match &target.kind {
2943
0
            ExprKind::Identifier(name) => self.lookup_variable(name)?,
2944
0
            _ => return Err(InterpreterError::RuntimeError(
2945
0
                "Invalid compound assignment target".to_string()
2946
0
            )),
2947
        };
2948
        
2949
        // Compute new value
2950
0
        let rhs = self.eval_expr(value)?;
2951
0
        let new_val = self.apply_binary_op(&current, op, &rhs)?;
2952
        
2953
        // Assign back
2954
0
        if let ExprKind::Identifier(name) = &target.kind {
2955
0
            self.set_variable(name.clone(), new_val.clone());
2956
0
        }
2957
        
2958
0
        Ok(new_val)
2959
0
    }
2960
    
2961
    /// Evaluate string methods
2962
    #[allow(clippy::rc_buffer)]
2963
0
    fn eval_string_method(&mut self, s: &Rc<String>, method: &str, args: &[Value]) -> Result<Value, InterpreterError> {
2964
0
        match method {
2965
0
            "len" if args.is_empty() => Ok(Value::Integer(s.len() as i64)),
2966
0
            "to_upper" if args.is_empty() => Ok(Value::from_string(s.to_uppercase())),
2967
0
            "to_lower" if args.is_empty() => Ok(Value::from_string(s.to_lowercase())),
2968
0
            "trim" if args.is_empty() => Ok(Value::from_string(s.trim().to_string())),
2969
0
            "to_string" if args.is_empty() => Ok(Value::from_string(s.to_string())),
2970
0
            "contains" if args.len() == 1 => {
2971
0
                if let Value::String(needle) = &args[0] {
2972
0
                    Ok(Value::Bool(s.contains(needle.as_str())))
2973
                } else {
2974
0
                    Err(InterpreterError::RuntimeError("contains expects string argument".to_string()))
2975
                }
2976
            }
2977
0
            "starts_with" if args.len() == 1 => {
2978
0
                if let Value::String(prefix) = &args[0] {
2979
0
                    Ok(Value::Bool(s.starts_with(prefix.as_str())))
2980
                } else {
2981
0
                    Err(InterpreterError::RuntimeError("starts_with expects string argument".to_string()))
2982
                }
2983
            }
2984
0
            "ends_with" if args.len() == 1 => {
2985
0
                if let Value::String(suffix) = &args[0] {
2986
0
                    Ok(Value::Bool(s.ends_with(suffix.as_str())))
2987
                } else {
2988
0
                    Err(InterpreterError::RuntimeError("ends_with expects string argument".to_string()))
2989
                }
2990
            }
2991
0
            "replace" if args.len() == 2 => {
2992
0
                if let (Value::String(from), Value::String(to)) = (&args[0], &args[1]) {
2993
0
                    Ok(Value::from_string(s.replace(from.as_str(), to.as_str())))
2994
                } else {
2995
0
                    Err(InterpreterError::RuntimeError("replace expects two string arguments".to_string()))
2996
                }
2997
            }
2998
0
            "split" if args.len() == 1 => {
2999
0
                if let Value::String(separator) = &args[0] {
3000
0
                    let parts: Vec<Value> = s.split(separator.as_str())
3001
0
                        .map(|part| Value::from_string(part.to_string()))
3002
0
                        .collect();
3003
0
                    Ok(Value::Array(Rc::new(parts)))
3004
                } else {
3005
0
                    Err(InterpreterError::RuntimeError("split expects string argument".to_string()))
3006
                }
3007
            }
3008
0
            _ => Err(InterpreterError::RuntimeError(format!("Unknown string method: {}", method))),
3009
        }
3010
0
    }
3011
3012
    /// Evaluate array methods
3013
    #[allow(clippy::rc_buffer)]
3014
0
    fn eval_array_method(&mut self, arr: &Rc<Vec<Value>>, method: &str, args: &[Value]) -> Result<Value, InterpreterError> {
3015
0
        match method {
3016
0
            "len" if args.is_empty() => Ok(Value::Integer(arr.len() as i64)),
3017
0
            "push" if args.len() == 1 => {
3018
0
                let mut new_arr = (**arr).clone();
3019
0
                new_arr.push(args[0].clone());
3020
0
                Ok(Value::Array(Rc::new(new_arr)))
3021
            }
3022
0
            "pop" if args.is_empty() => {
3023
0
                let mut new_arr = (**arr).clone();
3024
0
                new_arr.pop().unwrap_or(Value::nil());
3025
0
                Ok(Value::Array(Rc::new(new_arr)))
3026
            }
3027
0
            "get" if args.len() == 1 => {
3028
0
                if let Value::Integer(idx) = &args[0] {
3029
0
                    if *idx < 0 {
3030
0
                        return Ok(Value::Nil);
3031
0
                    }
3032
                    #[allow(clippy::cast_sign_loss)]
3033
0
                    let index = *idx as usize;
3034
0
                    if index < arr.len() {
3035
0
                        Ok(arr[index].clone())
3036
                    } else {
3037
0
                        Ok(Value::Nil)
3038
                    }
3039
                } else {
3040
0
                    Err(InterpreterError::RuntimeError("get expects integer index".to_string()))
3041
                }
3042
            }
3043
0
            "first" if args.is_empty() => Ok(arr.first().cloned().unwrap_or(Value::Nil)),
3044
0
            "last" if args.is_empty() => Ok(arr.last().cloned().unwrap_or(Value::Nil)),
3045
0
            "map" | "filter" | "reduce" | "any" | "all" | "find" => 
3046
0
                self.eval_array_higher_order_method(arr, method, args),
3047
0
            _ => Err(InterpreterError::RuntimeError(format!("Unknown array method: {}", method))),
3048
        }
3049
0
    }
3050
    
3051
    /// Evaluate higher-order array methods
3052
    #[allow(clippy::rc_buffer)]
3053
0
    fn eval_array_higher_order_method(&mut self, arr: &Rc<Vec<Value>>, method: &str, args: &[Value]) -> Result<Value, InterpreterError> {
3054
0
        match method {
3055
0
            "map" => self.eval_array_map_method(arr, args),
3056
0
            "filter" => self.eval_array_filter_method(arr, args),
3057
0
            "reduce" => self.eval_array_reduce_method(arr, args),
3058
0
            "any" => self.eval_array_any_method(arr, args),
3059
0
            "all" => self.eval_array_all_method(arr, args),
3060
0
            "find" => self.eval_array_find_method(arr, args),
3061
0
            _ => Err(InterpreterError::RuntimeError(format!("Unknown array method: {}", method))),
3062
        }
3063
0
    }
3064
    
3065
    // Helper methods for array higher-order functions (complexity <10 each)
3066
    
3067
    #[allow(clippy::rc_buffer)]
3068
0
    fn eval_array_map_method(&mut self, arr: &Rc<Vec<Value>>, args: &[Value]) -> Result<Value, InterpreterError> {
3069
0
        self.validate_single_closure_argument(args, "map")?;
3070
0
        let mut result = Vec::new();
3071
0
        for item in arr.iter() {
3072
0
            let func_result = self.eval_function_call_value(&args[0], std::slice::from_ref(item))?;
3073
0
            result.push(func_result);
3074
        }
3075
0
        Ok(Value::Array(Rc::new(result)))
3076
0
    }
3077
    
3078
    #[allow(clippy::rc_buffer)]
3079
0
    fn eval_array_filter_method(&mut self, arr: &Rc<Vec<Value>>, args: &[Value]) -> Result<Value, InterpreterError> {
3080
0
        self.validate_single_closure_argument(args, "filter")?;
3081
0
        let mut result = Vec::new();
3082
0
        for item in arr.iter() {
3083
0
            let func_result = self.eval_function_call_value(&args[0], std::slice::from_ref(item))?;
3084
0
            if func_result.is_truthy() {
3085
0
                result.push(item.clone());
3086
0
            }
3087
        }
3088
0
        Ok(Value::Array(Rc::new(result)))
3089
0
    }
3090
    
3091
    #[allow(clippy::rc_buffer)]
3092
0
    fn eval_array_reduce_method(&mut self, arr: &Rc<Vec<Value>>, args: &[Value]) -> Result<Value, InterpreterError> {
3093
0
        if args.len() != 2 {
3094
0
            return Err(InterpreterError::RuntimeError("reduce expects 2 arguments".to_string()));
3095
0
        }
3096
0
        if !matches!(&args[0], Value::Closure { .. }) {
3097
0
            return Err(InterpreterError::RuntimeError("reduce expects a function and initial value".to_string()));
3098
0
        }
3099
        
3100
0
        let mut accumulator = args[1].clone();
3101
0
        for item in arr.iter() {
3102
0
            accumulator = self.eval_function_call_value(&args[0], &[accumulator, item.clone()])?;
3103
        }
3104
0
        Ok(accumulator)
3105
0
    }
3106
    
3107
    #[allow(clippy::rc_buffer)]
3108
0
    fn eval_array_any_method(&mut self, arr: &Rc<Vec<Value>>, args: &[Value]) -> Result<Value, InterpreterError> {
3109
0
        self.validate_single_closure_argument(args, "any")?;
3110
0
        for item in arr.iter() {
3111
0
            let func_result = self.eval_function_call_value(&args[0], std::slice::from_ref(item))?;
3112
0
            if func_result.is_truthy() {
3113
0
                return Ok(Value::Bool(true));
3114
0
            }
3115
        }
3116
0
        Ok(Value::Bool(false))
3117
0
    }
3118
    
3119
    #[allow(clippy::rc_buffer)]
3120
0
    fn eval_array_all_method(&mut self, arr: &Rc<Vec<Value>>, args: &[Value]) -> Result<Value, InterpreterError> {
3121
0
        self.validate_single_closure_argument(args, "all")?;
3122
0
        for item in arr.iter() {
3123
0
            let func_result = self.eval_function_call_value(&args[0], std::slice::from_ref(item))?;
3124
0
            if !func_result.is_truthy() {
3125
0
                return Ok(Value::Bool(false));
3126
0
            }
3127
        }
3128
0
        Ok(Value::Bool(true))
3129
0
    }
3130
    
3131
    #[allow(clippy::rc_buffer)]
3132
0
    fn eval_array_find_method(&mut self, arr: &Rc<Vec<Value>>, args: &[Value]) -> Result<Value, InterpreterError> {
3133
0
        self.validate_single_closure_argument(args, "find")?;
3134
0
        for item in arr.iter() {
3135
0
            let func_result = self.eval_function_call_value(&args[0], std::slice::from_ref(item))?;
3136
0
            if func_result.is_truthy() {
3137
0
                return Ok(item.clone());
3138
0
            }
3139
        }
3140
0
        Ok(Value::Nil)
3141
0
    }
3142
    
3143
0
    fn validate_single_closure_argument(&self, args: &[Value], method_name: &str) -> Result<(), InterpreterError> {
3144
0
        if args.len() != 1 {
3145
0
            return Err(InterpreterError::RuntimeError(format!("{} expects 1 argument", method_name)));
3146
0
        }
3147
0
        if !matches!(&args[0], Value::Closure { .. }) {
3148
0
            return Err(InterpreterError::RuntimeError(format!("{} expects a function argument", method_name)));
3149
0
        }
3150
0
        Ok(())
3151
0
    }
3152
3153
    /// Evaluate a method call
3154
0
    fn eval_method_call(&mut self, receiver: &Expr, method: &str, args: &[Expr]) -> Result<Value, InterpreterError> {
3155
0
        let receiver_value = self.eval_expr(receiver)?;
3156
0
        let arg_values: Result<Vec<_>, _> = args.iter().map(|arg| self.eval_expr(arg)).collect();
3157
0
        let arg_values = arg_values?;
3158
        
3159
0
        self.dispatch_method_call(&receiver_value, method, &arg_values, args.is_empty())
3160
0
    }
3161
    
3162
    // Helper methods for method dispatch (complexity <10 each)
3163
    
3164
0
    fn dispatch_method_call(&mut self, receiver: &Value, method: &str, arg_values: &[Value], args_empty: bool) -> Result<Value, InterpreterError> {
3165
0
        match receiver {
3166
0
            Value::String(s) => self.eval_string_method(s, method, arg_values),
3167
0
            Value::Array(arr) => self.eval_array_method(arr, method, arg_values),
3168
0
            Value::Float(f) => self.eval_float_method(*f, method, args_empty),
3169
0
            Value::Integer(n) => self.eval_integer_method(*n, method, args_empty),
3170
0
            _ => self.eval_generic_method(receiver, method, args_empty),
3171
        }
3172
0
    }
3173
    
3174
0
    fn eval_float_method(&self, f: f64, method: &str, args_empty: bool) -> Result<Value, InterpreterError> {
3175
0
        if !args_empty {
3176
0
            return Err(InterpreterError::RuntimeError(format!("Float method '{}' takes no arguments", method)));
3177
0
        }
3178
        
3179
0
        match method {
3180
0
            "sqrt" => Ok(Value::Float(f.sqrt())),
3181
0
            "abs" => Ok(Value::Float(f.abs())),
3182
0
            "round" => Ok(Value::Float(f.round())),
3183
0
            "floor" => Ok(Value::Float(f.floor())),
3184
0
            "ceil" => Ok(Value::Float(f.ceil())),
3185
0
            "to_string" => Ok(Value::from_string(f.to_string())),
3186
0
            _ => Err(InterpreterError::RuntimeError(format!("Unknown float method: {}", method))),
3187
        }
3188
0
    }
3189
    
3190
0
    fn eval_integer_method(&self, n: i64, method: &str, args_empty: bool) -> Result<Value, InterpreterError> {
3191
0
        if !args_empty {
3192
0
            return Err(InterpreterError::RuntimeError(format!("Integer method '{}' takes no arguments", method)));
3193
0
        }
3194
        
3195
0
        match method {
3196
0
            "abs" => Ok(Value::Integer(n.abs())),
3197
0
            "to_string" => Ok(Value::from_string(n.to_string())),
3198
0
            _ => Err(InterpreterError::RuntimeError(format!("Unknown integer method: {}", method))),
3199
        }
3200
0
    }
3201
    
3202
0
    fn eval_generic_method(&self, receiver: &Value, method: &str, args_empty: bool) -> Result<Value, InterpreterError> {
3203
0
        if method == "to_string" && args_empty {
3204
0
            Ok(Value::from_string(receiver.to_string()))
3205
        } else {
3206
0
            Err(InterpreterError::RuntimeError(format!(
3207
0
                "Method '{}' not found for type {}",
3208
0
                method,
3209
0
                receiver.type_name()
3210
0
            )))
3211
        }
3212
0
    }
3213
    
3214
    
3215
    /// Evaluate string interpolation
3216
0
    fn eval_string_interpolation(&mut self, parts: &[StringPart]) -> Result<Value, InterpreterError> {
3217
0
        let mut result = String::new();
3218
0
        for part in parts {
3219
0
            match part {
3220
0
                StringPart::Text(text) => result.push_str(text),
3221
0
                StringPart::Expr(expr) => {
3222
0
                    let value = self.eval_expr(expr)?;
3223
0
                    result.push_str(&value.to_string());
3224
                }
3225
0
                StringPart::ExprWithFormat { expr, format_spec } => {
3226
0
                    let value = self.eval_expr(expr)?;
3227
                    // Apply format specifier for interpreter
3228
0
                    let formatted = Self::format_value_with_spec(&value, format_spec);
3229
0
                    result.push_str(&formatted);
3230
                }
3231
            }
3232
        }
3233
0
        Ok(Value::from_string(result))
3234
0
    }
3235
3236
    /// Format a value with a format specifier like :.2 for floats
3237
0
    fn format_value_with_spec(value: &Value, spec: &str) -> String {
3238
        // Parse format specifier (e.g., ":.2" -> precision 2)
3239
0
        if let Some(stripped) = spec.strip_prefix(":.") {
3240
0
            if let Ok(precision) = stripped.parse::<usize>() {
3241
0
                match value {
3242
0
                    Value::Float(f) => return format!("{:.precision$}", f, precision = precision),
3243
0
                    Value::Integer(i) => return format!("{:.precision$}", *i as f64, precision = precision),
3244
0
                    _ => {}
3245
                }
3246
0
            }
3247
0
        }
3248
        // Default formatting if spec doesn't match or isn't supported
3249
0
        value.to_string()
3250
0
    }
3251
    
3252
    /// Evaluate function definition
3253
0
    fn eval_function(&mut self, name: &str, params: &[Param], body: &Expr) -> Result<Value, InterpreterError> {
3254
0
        let param_names: Vec<String> = params
3255
0
            .iter()
3256
0
            .map(crate::frontend::ast::Param::name)
3257
0
            .collect();
3258
3259
0
        let closure = Value::Closure {
3260
0
            params: param_names,
3261
0
            body: Rc::new(body.clone()),
3262
0
            env: Rc::new(self.current_env().clone()),
3263
0
        };
3264
3265
        // Bind function name in environment for recursion
3266
0
        self.env_set(name.to_string(), closure.clone());
3267
0
        Ok(closure)
3268
0
    }
3269
    
3270
    /// Evaluate lambda expression
3271
0
    fn eval_lambda(&mut self, params: &[Param], body: &Expr) -> Result<Value, InterpreterError> {
3272
0
        let param_names: Vec<String> = params
3273
0
            .iter()
3274
0
            .map(crate::frontend::ast::Param::name)
3275
0
            .collect();
3276
3277
0
        let closure = Value::Closure {
3278
0
            params: param_names,
3279
0
            body: Rc::new(body.clone()),
3280
0
            env: Rc::new(self.current_env().clone()),
3281
0
        };
3282
3283
0
        Ok(closure)
3284
0
    }
3285
    
3286
    /// Evaluate function call
3287
0
    fn eval_function_call(&mut self, func: &Expr, args: &[Expr]) -> Result<Value, InterpreterError> {
3288
0
        let func_val = self.eval_expr(func)?;
3289
0
        let arg_vals: Result<Vec<Value>, InterpreterError> =
3290
0
            args.iter().map(|arg| self.eval_expr(arg)).collect();
3291
0
        let arg_vals = arg_vals?;
3292
3293
0
        let result = self.call_function(func_val, &arg_vals)?;
3294
3295
        // Collect type feedback for function call
3296
0
        let site_id = func.span.start; // Use func span start as site ID
3297
0
        let func_name = match &func.kind {
3298
0
            ExprKind::Identifier(name) => name.clone(),
3299
0
            _ => "anonymous".to_string(),
3300
        };
3301
0
        self.record_function_call_feedback(site_id, &func_name, &arg_vals, &result);
3302
0
        Ok(result)
3303
0
    }
3304
}
3305
3306
impl Default for Interpreter {
3307
0
    fn default() -> Self {
3308
0
        Self::new()
3309
0
    }
3310
}
3311
3312
/// Binary operations
3313
#[derive(Debug, Clone, Copy)]
3314
pub enum BinaryOp {
3315
    Add,
3316
    Sub,
3317
    Mul,
3318
    Div,
3319
    Eq,
3320
    Lt,
3321
    Gt,
3322
}
3323
3324
#[cfg(test)]
3325
#[allow(clippy::expect_used)] // Tests can use expect for clarity
3326
#[allow(clippy::bool_assert_comparison)] // Clear test assertions
3327
#[allow(clippy::approx_constant)] // Test constants are acceptable
3328
#[allow(clippy::panic)] // Tests can panic on assertion failures
3329
mod tests {
3330
    use super::*;
3331
    use crate::frontend::ast::Span;
3332
3333
    #[test]
3334
    fn test_value_creation() {
3335
        let int_val = Value::from_i64(42);
3336
        assert_eq!(int_val.as_i64().expect("Should be integer"), 42);
3337
        assert_eq!(int_val.type_name(), "integer");
3338
3339
        let bool_val = Value::from_bool(true);
3340
        assert_eq!(bool_val.as_bool().expect("Should be boolean"), true);
3341
        assert_eq!(bool_val.type_name(), "boolean");
3342
3343
        let nil_val = Value::nil();
3344
        assert!(nil_val.is_nil());
3345
        assert_eq!(nil_val.type_name(), "nil");
3346
3347
        let float_val = Value::from_f64(3.14);
3348
        let f_value = float_val.as_f64().expect("Should be float");
3349
        assert!((f_value - 3.14).abs() < f64::EPSILON);
3350
        assert_eq!(float_val.type_name(), "float");
3351
3352
        let string_val = Value::from_string("hello".to_string());
3353
        assert_eq!(string_val.type_name(), "string");
3354
    }
3355
3356
    #[test]
3357
    fn test_arithmetic() {
3358
        let mut interp = Interpreter::new();
3359
3360
        // Test 2 + 3 = 5
3361
        assert!(interp.push(Value::from_i64(2)).is_ok());
3362
        assert!(interp.push(Value::from_i64(3)).is_ok());
3363
        assert!(interp.binary_op(BinaryOp::Add).is_ok());
3364
3365
        let result = interp.pop().expect("Stack should not be empty");
3366
        assert_eq!(result, Value::Integer(5));
3367
    }
3368
3369
    #[test]
3370
    fn test_mixed_arithmetic() {
3371
        let mut interp = Interpreter::new();
3372
3373
        // Test 2 + 3.5 = 5.5 (int + float -> float)
3374
        assert!(interp.push(Value::from_i64(2)).is_ok());
3375
        assert!(interp.push(Value::from_f64(3.5)).is_ok());
3376
        assert!(interp.binary_op(BinaryOp::Add).is_ok());
3377
3378
        let result = interp.pop().expect("Stack should not be empty");
3379
        match result {
3380
            Value::Float(f) => assert!((f - 5.5).abs() < f64::EPSILON),
3381
            _ => unreachable!("Expected float, got {result:?}"),
3382
        }
3383
    }
3384
3385
    #[test]
3386
    fn test_division_by_zero() {
3387
        let mut interp = Interpreter::new();
3388
3389
        assert!(interp.push(Value::from_i64(10)).is_ok());
3390
        assert!(interp.push(Value::from_i64(0)).is_ok());
3391
3392
        let result = interp.binary_op(BinaryOp::Div);
3393
        assert!(matches!(result, Err(InterpreterError::DivisionByZero)));
3394
    }
3395
3396
    #[test]
3397
    fn test_comparison() {
3398
        let mut interp = Interpreter::new();
3399
3400
        // Test 5 < 10
3401
        assert!(interp.push(Value::from_i64(5)).is_ok());
3402
        assert!(interp.push(Value::from_i64(10)).is_ok());
3403
        assert!(interp.binary_op(BinaryOp::Lt).is_ok());
3404
3405
        let result = interp.pop().expect("Stack should not be empty");
3406
        assert_eq!(result, Value::Bool(true));
3407
    }
3408
3409
    #[test]
3410
    fn test_stack_operations() {
3411
        let mut interp = Interpreter::new();
3412
3413
        let val1 = Value::from_i64(42);
3414
        let val2 = Value::from_bool(true);
3415
3416
        assert!(interp.push(val1.clone()).is_ok());
3417
        assert!(interp.push(val2.clone()).is_ok());
3418
3419
        assert_eq!(interp.peek(0).expect("Should peek at top"), val2);
3420
        assert_eq!(interp.peek(1).expect("Should peek at second"), val1);
3421
3422
        assert_eq!(interp.pop().expect("Should pop top"), val2);
3423
        assert_eq!(interp.pop().expect("Should pop second"), val1);
3424
    }
3425
3426
    #[test]
3427
    fn test_truthiness() {
3428
        assert!(Value::from_i64(42).is_truthy());
3429
        assert!(Value::from_bool(true).is_truthy());
3430
        assert!(!Value::from_bool(false).is_truthy());
3431
        assert!(!Value::nil().is_truthy());
3432
        assert!(Value::from_f64(std::f64::consts::PI).is_truthy());
3433
        assert!(Value::from_f64(0.0).is_truthy()); // 0.0 is truthy in Ruchy
3434
        assert!(Value::from_string("hello".to_string()).is_truthy());
3435
    }
3436
3437
    // AST Walker tests
3438
3439
    #[test]
3440
    fn test_eval_literal() {
3441
        let mut interp = Interpreter::new();
3442
3443
        // Test integer literal
3444
        let int_expr = Expr::new(ExprKind::Literal(Literal::Integer(42)), Span::new(0, 2));
3445
        let result = interp
3446
            .eval_expr(&int_expr)
3447
            .expect("Should evaluate integer");
3448
        assert_eq!(result, Value::Integer(42));
3449
3450
        // Test string literal
3451
        let str_expr = Expr::new(
3452
            ExprKind::Literal(Literal::String("hello".to_string())),
3453
            Span::new(0, 7),
3454
        );
3455
        let result = interp.eval_expr(&str_expr).expect("Should evaluate string");
3456
        assert_eq!(result.type_name(), "string");
3457
3458
        // Test boolean literal
3459
        let bool_expr = Expr::new(ExprKind::Literal(Literal::Bool(true)), Span::new(0, 4));
3460
        let result = interp
3461
            .eval_expr(&bool_expr)
3462
            .expect("Should evaluate boolean");
3463
        assert_eq!(result, Value::Bool(true));
3464
    }
3465
3466
    #[test]
3467
    fn test_eval_binary_arithmetic() {
3468
        let mut interp = Interpreter::new();
3469
3470
        // Test 5 + 3 = 8
3471
        let left = Box::new(Expr::new(
3472
            ExprKind::Literal(Literal::Integer(5)),
3473
            Span::new(0, 1),
3474
        ));
3475
        let right = Box::new(Expr::new(
3476
            ExprKind::Literal(Literal::Integer(3)),
3477
            Span::new(4, 5),
3478
        ));
3479
        let add_expr = Expr::new(
3480
            ExprKind::Binary {
3481
                left,
3482
                op: AstBinaryOp::Add,
3483
                right,
3484
            },
3485
            Span::new(0, 5),
3486
        );
3487
3488
        let result = interp
3489
            .eval_expr(&add_expr)
3490
            .expect("Should evaluate addition");
3491
        assert_eq!(result, Value::Integer(8));
3492
    }
3493
3494
    #[test]
3495
    fn test_eval_binary_comparison() {
3496
        let mut interp = Interpreter::new();
3497
3498
        // Test 5 < 10 = true
3499
        let left = Box::new(Expr::new(
3500
            ExprKind::Literal(Literal::Integer(5)),
3501
            Span::new(0, 1),
3502
        ));
3503
        let right = Box::new(Expr::new(
3504
            ExprKind::Literal(Literal::Integer(10)),
3505
            Span::new(4, 6),
3506
        ));
3507
        let cmp_expr = Expr::new(
3508
            ExprKind::Binary {
3509
                left,
3510
                op: AstBinaryOp::Less,
3511
                right,
3512
            },
3513
            Span::new(0, 6),
3514
        );
3515
3516
        let result = interp
3517
            .eval_expr(&cmp_expr)
3518
            .expect("Should evaluate comparison");
3519
        assert_eq!(result, Value::Bool(true));
3520
    }
3521
3522
    #[test]
3523
    fn test_eval_unary_operations() {
3524
        let mut interp = Interpreter::new();
3525
3526
        // Test -42 = -42
3527
        let operand = Box::new(Expr::new(
3528
            ExprKind::Literal(Literal::Integer(42)),
3529
            Span::new(1, 3),
3530
        ));
3531
        let neg_expr = Expr::new(
3532
            ExprKind::Unary {
3533
                op: crate::frontend::ast::UnaryOp::Negate,
3534
                operand,
3535
            },
3536
            Span::new(0, 3),
3537
        );
3538
3539
        let result = interp
3540
            .eval_expr(&neg_expr)
3541
            .expect("Should evaluate negation");
3542
        assert_eq!(result, Value::Integer(-42));
3543
3544
        // Test !true = false
3545
        let operand = Box::new(Expr::new(
3546
            ExprKind::Literal(Literal::Bool(true)),
3547
            Span::new(1, 5),
3548
        ));
3549
        let not_expr = Expr::new(
3550
            ExprKind::Unary {
3551
                op: crate::frontend::ast::UnaryOp::Not,
3552
                operand,
3553
            },
3554
            Span::new(0, 5),
3555
        );
3556
3557
        let result = interp
3558
            .eval_expr(&not_expr)
3559
            .expect("Should evaluate logical not");
3560
        assert_eq!(result, Value::Bool(false));
3561
    }
3562
3563
    #[test]
3564
    fn test_eval_if_expression() {
3565
        let mut interp = Interpreter::new();
3566
3567
        // Test if true then 1 else 2 = 1
3568
        let condition = Box::new(Expr::new(
3569
            ExprKind::Literal(Literal::Bool(true)),
3570
            Span::new(3, 7),
3571
        ));
3572
        let then_branch = Box::new(Expr::new(
3573
            ExprKind::Literal(Literal::Integer(1)),
3574
            Span::new(13, 14),
3575
        ));
3576
        let else_branch = Some(Box::new(Expr::new(
3577
            ExprKind::Literal(Literal::Integer(2)),
3578
            Span::new(20, 21),
3579
        )));
3580
3581
        let if_expr = Expr::new(
3582
            ExprKind::If {
3583
                condition,
3584
                then_branch,
3585
                else_branch,
3586
            },
3587
            Span::new(0, 21),
3588
        );
3589
3590
        let result = interp
3591
            .eval_expr(&if_expr)
3592
            .expect("Should evaluate if expression");
3593
        assert_eq!(result, Value::Integer(1));
3594
    }
3595
3596
    #[test]
3597
    fn test_eval_let_expression() {
3598
        let mut interp = Interpreter::new();
3599
3600
        // Test let x = 5 in x + 2 = 7
3601
        let value = Box::new(Expr::new(
3602
            ExprKind::Literal(Literal::Integer(5)),
3603
            Span::new(8, 9),
3604
        ));
3605
3606
        let left = Box::new(Expr::new(
3607
            ExprKind::Identifier("x".to_string()),
3608
            Span::new(13, 14),
3609
        ));
3610
        let right = Box::new(Expr::new(
3611
            ExprKind::Literal(Literal::Integer(2)),
3612
            Span::new(17, 18),
3613
        ));
3614
        let body = Box::new(Expr::new(
3615
            ExprKind::Binary {
3616
                left,
3617
                op: AstBinaryOp::Add,
3618
                right,
3619
            },
3620
            Span::new(13, 18),
3621
        ));
3622
3623
        let let_expr = Expr::new(
3624
            ExprKind::Let {
3625
                name: "x".to_string(),
3626
                type_annotation: None,
3627
                value,
3628
                body,
3629
                is_mutable: false,
3630
            },
3631
            Span::new(0, 18),
3632
        );
3633
3634
        let result = interp
3635
            .eval_expr(&let_expr)
3636
            .expect("Should evaluate let expression");
3637
        assert_eq!(result, Value::Integer(7));
3638
    }
3639
3640
    #[test]
3641
    fn test_eval_logical_operators() {
3642
        let mut interp = Interpreter::new();
3643
3644
        // Test true && false = false (short-circuit)
3645
        let left = Box::new(Expr::new(
3646
            ExprKind::Literal(Literal::Bool(true)),
3647
            Span::new(0, 4),
3648
        ));
3649
        let right = Box::new(Expr::new(
3650
            ExprKind::Literal(Literal::Bool(false)),
3651
            Span::new(8, 13),
3652
        ));
3653
        let and_expr = Expr::new(
3654
            ExprKind::Binary {
3655
                left,
3656
                op: AstBinaryOp::And,
3657
                right,
3658
            },
3659
            Span::new(0, 13),
3660
        );
3661
3662
        let result = interp
3663
            .eval_expr(&and_expr)
3664
            .expect("Should evaluate logical AND");
3665
        assert_eq!(result, Value::Bool(false));
3666
3667
        // Test false || true = true (short-circuit)
3668
        let left = Box::new(Expr::new(
3669
            ExprKind::Literal(Literal::Bool(false)),
3670
            Span::new(0, 5),
3671
        ));
3672
        let right = Box::new(Expr::new(
3673
            ExprKind::Literal(Literal::Bool(true)),
3674
            Span::new(9, 13),
3675
        ));
3676
        let or_expr = Expr::new(
3677
            ExprKind::Binary {
3678
                left,
3679
                op: AstBinaryOp::Or,
3680
                right,
3681
            },
3682
            Span::new(0, 13),
3683
        );
3684
3685
        let result = interp
3686
            .eval_expr(&or_expr)
3687
            .expect("Should evaluate logical OR");
3688
        assert_eq!(result, Value::Bool(true));
3689
    }
3690
3691
    #[test]
3692
    fn test_parser_integration() {
3693
        let mut interp = Interpreter::new();
3694
3695
        // Test simple arithmetic: 2 + 3 * 4 = 14
3696
        let result = interp
3697
            .eval_string("2 + 3 * 4")
3698
            .expect("Should parse and evaluate");
3699
        assert_eq!(result, Value::Integer(14));
3700
3701
        // Test comparison: 5 > 3 = true
3702
        let result = interp
3703
            .eval_string("5 > 3")
3704
            .expect("Should parse and evaluate");
3705
        assert_eq!(result, Value::Bool(true));
3706
3707
        // Test boolean literals: true && false = false
3708
        let result = interp
3709
            .eval_string("true && false")
3710
            .expect("Should parse and evaluate");
3711
        assert_eq!(result, Value::Bool(false));
3712
3713
        // Test unary operations: -42 = -42
3714
        let result = interp
3715
            .eval_string("-42")
3716
            .expect("Should parse and evaluate");
3717
        assert_eq!(result, Value::Integer(-42));
3718
3719
        // Test string literals
3720
        let result = interp
3721
            .eval_string(r#""hello""#)
3722
            .expect("Should parse and evaluate");
3723
        assert_eq!(result.type_name(), "string");
3724
    }
3725
3726
    #[test]
3727
    fn test_eval_lambda() {
3728
        use crate::frontend::ast::{Pattern, Type, TypeKind};
3729
        let mut interp = Interpreter::new();
3730
3731
        // Test lambda: |x| x + 1
3732
        let param = Param {
3733
            pattern: Pattern::Identifier("x".to_string()),
3734
            ty: Type {
3735
                kind: TypeKind::Named("i32".to_string()),
3736
                span: Span::new(0, 3),
3737
            },
3738
            span: Span::new(0, 1),
3739
            is_mutable: false,
3740
            default_value: None,
3741
        };
3742
3743
        let left = Box::new(Expr::new(
3744
            ExprKind::Identifier("x".to_string()),
3745
            Span::new(0, 1),
3746
        ));
3747
        let right = Box::new(Expr::new(
3748
            ExprKind::Literal(Literal::Integer(1)),
3749
            Span::new(4, 5),
3750
        ));
3751
        let body = Box::new(Expr::new(
3752
            ExprKind::Binary {
3753
                left,
3754
                op: AstBinaryOp::Add,
3755
                right,
3756
            },
3757
            Span::new(0, 5),
3758
        ));
3759
3760
        let lambda_expr = Expr::new(
3761
            ExprKind::Lambda {
3762
                params: vec![param],
3763
                body,
3764
            },
3765
            Span::new(0, 10),
3766
        );
3767
3768
        let result = interp
3769
            .eval_expr(&lambda_expr)
3770
            .expect("Should evaluate lambda");
3771
        assert_eq!(result.type_name(), "function");
3772
    }
3773
3774
    #[test]
3775
    fn test_eval_function_call() {
3776
        use crate::frontend::ast::{Pattern, Type, TypeKind};
3777
        let mut interp = Interpreter::new();
3778
3779
        // Create lambda: |x| x + 1
3780
        let param = Param {
3781
            pattern: Pattern::Identifier("x".to_string()),
3782
            ty: Type {
3783
                kind: TypeKind::Named("i32".to_string()),
3784
                span: Span::new(0, 3),
3785
            },
3786
            span: Span::new(0, 1),
3787
            is_mutable: false,
3788
            default_value: None,
3789
        };
3790
3791
        let left = Box::new(Expr::new(
3792
            ExprKind::Identifier("x".to_string()),
3793
            Span::new(0, 1),
3794
        ));
3795
        let right = Box::new(Expr::new(
3796
            ExprKind::Literal(Literal::Integer(1)),
3797
            Span::new(4, 5),
3798
        ));
3799
        let body = Box::new(Expr::new(
3800
            ExprKind::Binary {
3801
                left,
3802
                op: AstBinaryOp::Add,
3803
                right,
3804
            },
3805
            Span::new(0, 5),
3806
        ));
3807
3808
        let lambda_expr = Expr::new(
3809
            ExprKind::Lambda {
3810
                params: vec![param],
3811
                body,
3812
            },
3813
            Span::new(0, 10),
3814
        );
3815
3816
        // Call lambda with argument 5: (|x| x + 1)(5) = 6
3817
        let call_expr = Expr::new(
3818
            ExprKind::Call {
3819
                func: Box::new(lambda_expr),
3820
                args: vec![Expr::new(
3821
                    ExprKind::Literal(Literal::Integer(5)),
3822
                    Span::new(0, 1),
3823
                )],
3824
            },
3825
            Span::new(0, 15),
3826
        );
3827
3828
        let result = interp
3829
            .eval_expr(&call_expr)
3830
            .expect("Should evaluate function call");
3831
        assert_eq!(result, Value::Integer(6));
3832
    }
3833
3834
    #[test]
3835
    fn test_eval_function_definition() {
3836
        use crate::frontend::ast::{Pattern, Type, TypeKind};
3837
        let mut interp = Interpreter::new();
3838
3839
        // Create function: fn add_one(x) = x + 1
3840
        let param = Param {
3841
            pattern: Pattern::Identifier("x".to_string()),
3842
            ty: Type {
3843
                kind: TypeKind::Named("i32".to_string()),
3844
                span: Span::new(0, 3),
3845
            },
3846
            span: Span::new(0, 1),
3847
            is_mutable: false,
3848
            default_value: None,
3849
        };
3850
3851
        let left = Box::new(Expr::new(
3852
            ExprKind::Identifier("x".to_string()),
3853
            Span::new(0, 1),
3854
        ));
3855
        let right = Box::new(Expr::new(
3856
            ExprKind::Literal(Literal::Integer(1)),
3857
            Span::new(4, 5),
3858
        ));
3859
        let body = Box::new(Expr::new(
3860
            ExprKind::Binary {
3861
                left,
3862
                op: AstBinaryOp::Add,
3863
                right,
3864
            },
3865
            Span::new(0, 5),
3866
        ));
3867
3868
        let func_expr = Expr::new(
3869
            ExprKind::Function {
3870
                name: "add_one".to_string(),
3871
                type_params: vec![],
3872
                params: vec![param],
3873
                return_type: None,
3874
                body,
3875
                is_async: false,
3876
                is_pub: false,
3877
            },
3878
            Span::new(0, 20),
3879
        );
3880
3881
        let result = interp
3882
            .eval_expr(&func_expr)
3883
            .expect("Should evaluate function");
3884
        assert_eq!(result.type_name(), "function");
3885
3886
        // Verify function is bound in environment
3887
        let bound_func = interp
3888
            .lookup_variable("add_one")
3889
            .expect("Function should be bound");
3890
        assert_eq!(bound_func.type_name(), "function");
3891
    }
3892
3893
    #[test]
3894
    fn test_eval_recursive_function() {
3895
        use crate::frontend::ast::{Pattern, Type, TypeKind};
3896
        let mut interp = Interpreter::new();
3897
3898
        // Create recursive factorial function
3899
        let param = Param {
3900
            pattern: Pattern::Identifier("n".to_string()),
3901
            ty: Type {
3902
                kind: TypeKind::Named("i32".to_string()),
3903
                span: Span::new(0, 3),
3904
            },
3905
            span: Span::new(0, 1),
3906
            is_mutable: false,
3907
            default_value: None,
3908
        };
3909
3910
        // if n <= 1 then 1 else n * factorial(n - 1)
3911
        let n_id = Expr::new(ExprKind::Identifier("n".to_string()), Span::new(0, 1));
3912
        let one = Expr::new(ExprKind::Literal(Literal::Integer(1)), Span::new(0, 1));
3913
3914
        let condition = Box::new(Expr::new(
3915
            ExprKind::Binary {
3916
                left: Box::new(n_id.clone()),
3917
                op: AstBinaryOp::LessEqual,
3918
                right: Box::new(one.clone()),
3919
            },
3920
            Span::new(0, 6),
3921
        ));
3922
3923
        let then_branch = Box::new(one.clone());
3924
3925
        // n * factorial(n - 1)
3926
        let n_minus_1 = Expr::new(
3927
            ExprKind::Binary {
3928
                left: Box::new(n_id.clone()),
3929
                op: AstBinaryOp::Subtract,
3930
                right: Box::new(one),
3931
            },
3932
            Span::new(0, 5),
3933
        );
3934
3935
        let recursive_call = Expr::new(
3936
            ExprKind::Call {
3937
                func: Box::new(Expr::new(
3938
                    ExprKind::Identifier("factorial".to_string()),
3939
                    Span::new(0, 9),
3940
                )),
3941
                args: vec![n_minus_1],
3942
            },
3943
            Span::new(0, 15),
3944
        );
3945
3946
        let else_branch = Some(Box::new(Expr::new(
3947
            ExprKind::Binary {
3948
                left: Box::new(n_id),
3949
                op: AstBinaryOp::Multiply,
3950
                right: Box::new(recursive_call),
3951
            },
3952
            Span::new(0, 20),
3953
        )));
3954
3955
        let body = Box::new(Expr::new(
3956
            ExprKind::If {
3957
                condition,
3958
                then_branch,
3959
                else_branch,
3960
            },
3961
            Span::new(0, 25),
3962
        ));
3963
3964
        let factorial_expr = Expr::new(
3965
            ExprKind::Function {
3966
                name: "factorial".to_string(),
3967
                type_params: vec![],
3968
                params: vec![param],
3969
                return_type: None,
3970
                body,
3971
                is_async: false,
3972
                is_pub: false,
3973
            },
3974
            Span::new(0, 30),
3975
        );
3976
3977
        // Define factorial function
3978
        let result = interp
3979
            .eval_expr(&factorial_expr)
3980
            .expect("Should evaluate factorial function");
3981
        assert_eq!(result.type_name(), "function");
3982
3983
        // Test factorial(5) = 120
3984
        let call_expr = Expr::new(
3985
            ExprKind::Call {
3986
                func: Box::new(Expr::new(
3987
                    ExprKind::Identifier("factorial".to_string()),
3988
                    Span::new(0, 9),
3989
                )),
3990
                args: vec![Expr::new(
3991
                    ExprKind::Literal(Literal::Integer(5)),
3992
                    Span::new(0, 1),
3993
                )],
3994
            },
3995
            Span::new(0, 15),
3996
        );
3997
3998
        let result = interp
3999
            .eval_expr(&call_expr)
4000
            .expect("Should evaluate factorial(5)");
4001
        assert_eq!(result, Value::Integer(120));
4002
    }
4003
4004
    #[test]
4005
    fn test_function_closure() {
4006
        use crate::frontend::ast::{Pattern, Type, TypeKind};
4007
        let mut interp = Interpreter::new();
4008
4009
        // Test closure: let x = 10 in |y| x + y
4010
        let x_val = Box::new(Expr::new(
4011
            ExprKind::Literal(Literal::Integer(10)),
4012
            Span::new(8, 10),
4013
        ));
4014
4015
        let param = Param {
4016
            pattern: Pattern::Identifier("y".to_string()),
4017
            ty: Type {
4018
                kind: TypeKind::Named("i32".to_string()),
4019
                span: Span::new(0, 3),
4020
            },
4021
            span: Span::new(0, 1),
4022
            is_mutable: false,
4023
            default_value: None,
4024
        };
4025
4026
        let left = Box::new(Expr::new(
4027
            ExprKind::Identifier("x".to_string()),
4028
            Span::new(0, 1),
4029
        ));
4030
        let right = Box::new(Expr::new(
4031
            ExprKind::Identifier("y".to_string()),
4032
            Span::new(4, 5),
4033
        ));
4034
        let lambda_body = Box::new(Expr::new(
4035
            ExprKind::Binary {
4036
                left,
4037
                op: AstBinaryOp::Add,
4038
                right,
4039
            },
4040
            Span::new(0, 5),
4041
        ));
4042
4043
        let lambda = Expr::new(
4044
            ExprKind::Lambda {
4045
                params: vec![param],
4046
                body: lambda_body,
4047
            },
4048
            Span::new(14, 24),
4049
        );
4050
4051
        let let_body = Box::new(lambda);
4052
4053
        let let_expr = Expr::new(
4054
            ExprKind::Let {
4055
                name: "x".to_string(),
4056
                type_annotation: None,
4057
                value: x_val,
4058
                body: let_body,
4059
                is_mutable: false,
4060
            },
4061
            Span::new(0, 24),
4062
        );
4063
4064
        let closure = interp
4065
            .eval_expr(&let_expr)
4066
            .expect("Should evaluate closure");
4067
        assert_eq!(closure.type_name(), "function");
4068
4069
        // Call closure with argument 5: (|y| x + y)(5) = 15 (x = 10)
4070
        let call_expr = Expr::new(
4071
            ExprKind::Call {
4072
                func: Box::new(let_expr), // Re-create the closure
4073
                args: vec![Expr::new(
4074
                    ExprKind::Literal(Literal::Integer(5)),
4075
                    Span::new(0, 1),
4076
                )],
4077
            },
4078
            Span::new(0, 30),
4079
        );
4080
4081
        // Note: This test demonstrates lexical scoping where the closure captures 'x'
4082
        let result = interp
4083
            .eval_expr(&call_expr)
4084
            .expect("Should evaluate closure call");
4085
        assert_eq!(result, Value::Integer(15));
4086
    }
4087
4088
    #[test]
4089
    fn test_inline_cache_string_methods() {
4090
        let mut interp = Interpreter::new();
4091
        let test_string = Value::String(Rc::new("Hello World".to_string()));
4092
4093
        // Test string.len() with caching
4094
        let result1 = interp
4095
            .get_field_cached(&test_string, "len")
4096
            .expect("Should get string length");
4097
        assert_eq!(result1, Value::Integer(11));
4098
4099
        let result2 = interp
4100
            .get_field_cached(&test_string, "len")
4101
            .expect("Should get cached result");
4102
        assert_eq!(result2, Value::Integer(11));
4103
4104
        // Verify cache hit occurred
4105
        let stats = interp.get_cache_stats();
4106
        let cache_key = format!("{:?}::len", test_string.type_id());
4107
        assert!(stats.get(&cache_key).unwrap_or(&0.0) > &0.0);
4108
4109
        // Test other string methods
4110
        let upper_result = interp
4111
            .get_field_cached(&test_string, "to_upper")
4112
            .expect("Should get uppercase");
4113
        assert_eq!(
4114
            upper_result,
4115
            Value::String(Rc::new("HELLO WORLD".to_string()))
4116
        );
4117
4118
        let trim_result = interp
4119
            .get_field_cached(&Value::String(Rc::new("  test  ".to_string())), "trim")
4120
            .expect("Should trim string");
4121
        assert_eq!(trim_result, Value::String(Rc::new("test".to_string())));
4122
    }
4123
4124
    #[test]
4125
    fn test_inline_cache_array_methods() {
4126
        let mut interp = Interpreter::new();
4127
        let test_array = Value::Array(Rc::new(vec![
4128
            Value::Integer(1),
4129
            Value::Integer(2),
4130
            Value::Integer(3),
4131
        ]));
4132
4133
        // Test array.len() with caching
4134
        let result1 = interp
4135
            .get_field_cached(&test_array, "len")
4136
            .expect("Should get array length");
4137
        assert_eq!(result1, Value::Integer(3));
4138
4139
        let result2 = interp
4140
            .get_field_cached(&test_array, "len")
4141
            .expect("Should get cached result");
4142
        assert_eq!(result2, Value::Integer(3));
4143
4144
        // Test first and last
4145
        let first_result = interp
4146
            .get_field_cached(&test_array, "first")
4147
            .expect("Should get first element");
4148
        assert_eq!(first_result, Value::Integer(1));
4149
4150
        let last_result = interp
4151
            .get_field_cached(&test_array, "last")
4152
            .expect("Should get last element");
4153
        assert_eq!(last_result, Value::Integer(3));
4154
4155
        // Test empty array (use fresh interpreter to avoid cache pollution)
4156
        let mut fresh_interp = Interpreter::new();
4157
        let empty_array = Value::Array(Rc::new(vec![]));
4158
        let first_err = fresh_interp.get_field_cached(&empty_array, "first");
4159
        assert!(first_err.is_err());
4160
    }
4161
4162
    #[test]
4163
    fn test_inline_cache_polymorphic() {
4164
        let mut interp = Interpreter::new();
4165
4166
        // Test polymorphic caching with different types calling same method
4167
        let string_val = Value::String(Rc::new("test".to_string()));
4168
        let array_val = Value::Array(Rc::new(vec![Value::Integer(1), Value::Integer(2)]));
4169
4170
        // Both call len() method
4171
        let string_len = interp
4172
            .get_field_cached(&string_val, "len")
4173
            .expect("Should get string length");
4174
        assert_eq!(string_len, Value::Integer(4));
4175
4176
        let array_len = interp
4177
            .get_field_cached(&array_val, "len")
4178
            .expect("Should get array length");
4179
        assert_eq!(array_len, Value::Integer(2));
4180
4181
        // Both should have separate cache entries
4182
        let stats = interp.get_cache_stats();
4183
        assert_eq!(stats.len(), 2); // Two different cache keys
4184
    }
4185
4186
    #[test]
4187
    fn test_inline_cache_type_method() {
4188
        let mut interp = Interpreter::new();
4189
4190
        // Test the universal 'type' method
4191
        let int_val = Value::Integer(42);
4192
        let string_val = Value::String(Rc::new("test".to_string()));
4193
        let bool_val = Value::Bool(true);
4194
4195
        let int_type = interp
4196
            .get_field_cached(&int_val, "type")
4197
            .expect("Should get int type");
4198
        assert_eq!(int_type, Value::String(Rc::new("integer".to_string())));
4199
4200
        let string_type = interp
4201
            .get_field_cached(&string_val, "type")
4202
            .expect("Should get string type");
4203
        assert_eq!(string_type, Value::String(Rc::new("string".to_string())));
4204
4205
        let bool_type = interp
4206
            .get_field_cached(&bool_val, "type")
4207
            .expect("Should get bool type");
4208
        assert_eq!(bool_type, Value::String(Rc::new("boolean".to_string())));
4209
    }
4210
4211
    #[test]
4212
    fn test_inline_cache_miss_handling() {
4213
        let mut interp = Interpreter::new();
4214
        let test_val = Value::Integer(42);
4215
4216
        // Test accessing non-existent field
4217
        let result = interp.get_field_cached(&test_val, "non_existent");
4218
        assert!(result.is_err());
4219
4220
        // Test that error doesn't get cached (cache should be empty)
4221
        let stats = interp.get_cache_stats();
4222
        assert!(stats.is_empty());
4223
    }
4224
4225
    #[test]
4226
    fn test_cache_state_transitions() {
4227
        let mut interp = Interpreter::new();
4228
4229
        // Create multiple values of same type for same field
4230
        let vals = [
4231
            Value::String(Rc::new("test1".to_string())),
4232
            Value::String(Rc::new("test2".to_string())),
4233
            Value::String(Rc::new("test3".to_string())),
4234
        ];
4235
4236
        // Access same field multiple times to test cache evolution
4237
        for val in &vals {
4238
            let _ = interp
4239
                .get_field_cached(val, "len")
4240
                .expect("Should get length");
4241
        }
4242
4243
        // Verify caching occurred
4244
        let stats = interp.get_cache_stats();
4245
        assert!(!stats.is_empty());
4246
4247
        // Clear caches and verify
4248
        interp.clear_caches();
4249
        let stats_after = interp.get_cache_stats();
4250
        assert!(stats_after.is_empty());
4251
    }
4252
4253
    #[test]
4254
    fn test_type_feedback_binary_operations() {
4255
        use crate::frontend::ast::Span;
4256
        let mut interp = Interpreter::new();
4257
4258
        // Create binary operation: 42 + 10
4259
        let left = Expr::new(ExprKind::Literal(Literal::Integer(42)), Span::new(0, 2));
4260
        let right = Expr::new(ExprKind::Literal(Literal::Integer(10)), Span::new(5, 7));
4261
        let binary_expr = Expr::new(
4262
            ExprKind::Binary {
4263
                left: Box::new(left),
4264
                op: AstBinaryOp::Add,
4265
                right: Box::new(right),
4266
            },
4267
            Span::new(0, 7),
4268
        );
4269
4270
        // Evaluate the expression multiple times to collect feedback
4271
        for _ in 0..15 {
4272
            let result = interp
4273
                .eval_expr(&binary_expr)
4274
                .expect("Should evaluate binary operation");
4275
            assert_eq!(result, Value::Integer(52));
4276
        }
4277
4278
        // Check type feedback statistics
4279
        let stats = interp.get_type_feedback_stats();
4280
        assert_eq!(stats.total_operation_sites, 1);
4281
        assert_eq!(stats.monomorphic_operation_sites, 1);
4282
        assert_eq!(stats.total_samples, 15);
4283
4284
        // Check specialization candidates
4285
        let candidates = interp.get_specialization_candidates();
4286
        assert!(!candidates.is_empty());
4287
        assert!((candidates[0].confidence - 1.0).abs() < f64::EPSILON); // Monomorphic operation
4288
    }
4289
4290
    #[test]
4291
    fn test_type_feedback_variable_assignments() {
4292
        use crate::frontend::ast::Span;
4293
        let mut interp = Interpreter::new();
4294
4295
        // Create let binding: let x = 42 in x
4296
        let value_expr = Box::new(Expr::new(
4297
            ExprKind::Literal(Literal::Integer(42)),
4298
            Span::new(8, 10),
4299
        ));
4300
        let body_expr = Box::new(Expr::new(
4301
            ExprKind::Identifier("x".to_string()),
4302
            Span::new(14, 15),
4303
        ));
4304
4305
        let let_expr = Expr::new(
4306
            ExprKind::Let {
4307
                name: "x".to_string(),
4308
                type_annotation: None,
4309
                value: value_expr,
4310
                body: body_expr,
4311
                is_mutable: false,
4312
            },
4313
            Span::new(0, 15),
4314
        );
4315
4316
        // Evaluate the expression
4317
        let result = interp
4318
            .eval_expr(&let_expr)
4319
            .expect("Should evaluate let expression");
4320
        assert_eq!(result, Value::Integer(42));
4321
4322
        // Check type feedback statistics
4323
        let stats = interp.get_type_feedback_stats();
4324
        assert_eq!(stats.total_variables, 1);
4325
        assert_eq!(stats.stable_variables, 1);
4326
4327
        // Check specialization candidates for stable variable
4328
        let candidates = interp.get_specialization_candidates();
4329
        let variable_candidates: Vec<_> = candidates
4330
            .iter()
4331
            .filter(|c| matches!(c.kind, SpecializationKind::Variable { .. }))
4332
            .collect();
4333
        assert!(!variable_candidates.is_empty());
4334
    }
4335
4336
    #[test]
4337
    fn test_type_feedback_function_calls() {
4338
        use crate::frontend::ast::{Param, Pattern, Span, Type, TypeKind};
4339
        let mut interp = Interpreter::new();
4340
4341
        // Create function: fn double(x) = x + x
4342
        let param = Param {
4343
            pattern: Pattern::Identifier("x".to_string()),
4344
            ty: Type {
4345
                kind: TypeKind::Named("i32".to_string()),
4346
                span: Span::new(0, 3),
4347
            },
4348
            span: Span::new(0, 1),
4349
            is_mutable: false,
4350
            default_value: None,
4351
        };
4352
4353
        let left_body = Box::new(Expr::new(
4354
            ExprKind::Identifier("x".to_string()),
4355
            Span::new(0, 1),
4356
        ));
4357
        let right_body = Box::new(Expr::new(
4358
            ExprKind::Identifier("x".to_string()),
4359
            Span::new(4, 5),
4360
        ));
4361
        let func_body = Box::new(Expr::new(
4362
            ExprKind::Binary {
4363
                left: left_body,
4364
                op: AstBinaryOp::Add,
4365
                right: right_body,
4366
            },
4367
            Span::new(0, 5),
4368
        ));
4369
4370
        let func_expr = Expr::new(
4371
            ExprKind::Function {
4372
                name: "double".to_string(),
4373
                type_params: vec![],
4374
                params: vec![param],
4375
                body: func_body,
4376
                return_type: None,
4377
                is_async: false,
4378
                is_pub: false,
4379
            },
4380
            Span::new(0, 20),
4381
        );
4382
4383
        // Define the function
4384
        let _func = interp
4385
            .eval_expr(&func_expr)
4386
            .expect("Should define function");
4387
4388
        // Create function call: double(21)
4389
        let func_ref = Box::new(Expr::new(
4390
            ExprKind::Identifier("double".to_string()),
4391
            Span::new(0, 6),
4392
        ));
4393
        let arg = Expr::new(ExprKind::Literal(Literal::Integer(21)), Span::new(7, 9));
4394
        let call_expr = Expr::new(
4395
            ExprKind::Call {
4396
                func: func_ref,
4397
                args: vec![arg],
4398
            },
4399
            Span::new(0, 10),
4400
        );
4401
4402
        // Call the function multiple times
4403
        for _ in 0..10 {
4404
            let result = interp.eval_expr(&call_expr).expect("Should call function");
4405
            assert_eq!(result, Value::Integer(42));
4406
        }
4407
4408
        // Check type feedback statistics
4409
        let stats = interp.get_type_feedback_stats();
4410
        assert!(stats.total_call_sites > 0);
4411
        assert!(stats.monomorphic_call_sites > 0);
4412
4413
        // Check specialization candidates for function calls
4414
        let candidates = interp.get_specialization_candidates();
4415
        let call_candidates: Vec<_> = candidates
4416
            .iter()
4417
            .filter(|c| matches!(c.kind, SpecializationKind::FunctionCall { .. }))
4418
            .collect();
4419
        assert!(!call_candidates.is_empty());
4420
    }
4421
4422
    #[test]
4423
    fn test_type_feedback_polymorphic_detection() {
4424
        use crate::frontend::ast::Span;
4425
        let mut interp = Interpreter::new();
4426
4427
        // Create integer addition
4428
        let int_expr = Expr::new(
4429
            ExprKind::Binary {
4430
                left: Box::new(Expr::new(
4431
                    ExprKind::Literal(Literal::Integer(1)),
4432
                    Span::new(0, 1),
4433
                )),
4434
                op: AstBinaryOp::Add,
4435
                right: Box::new(Expr::new(
4436
                    ExprKind::Literal(Literal::Integer(2)),
4437
                    Span::new(4, 5),
4438
                )),
4439
            },
4440
            Span::new(0, 5),
4441
        );
4442
4443
        // Create float addition (different site)
4444
        let float_expr = Expr::new(
4445
            ExprKind::Binary {
4446
                left: Box::new(Expr::new(
4447
                    ExprKind::Literal(Literal::Float(1.5)),
4448
                    Span::new(10, 13),
4449
                )),
4450
                op: AstBinaryOp::Add,
4451
                right: Box::new(Expr::new(
4452
                    ExprKind::Literal(Literal::Float(2.5)),
4453
                    Span::new(16, 19),
4454
                )),
4455
            },
4456
            Span::new(10, 19),
4457
        );
4458
4459
        // Evaluate both expressions multiple times
4460
        for _ in 0..12 {
4461
            let _ = interp
4462
                .eval_expr(&int_expr)
4463
                .expect("Should evaluate int addition");
4464
            let _ = interp
4465
                .eval_expr(&float_expr)
4466
                .expect("Should evaluate float addition");
4467
        }
4468
4469
        // Check that we have multiple operation sites
4470
        let stats = interp.get_type_feedback_stats();
4471
        assert_eq!(stats.total_operation_sites, 2);
4472
        assert_eq!(stats.monomorphic_operation_sites, 2); // Both should be monomorphic
4473
        assert_eq!(stats.total_samples, 24); // 12 * 2 operations
4474
4475
        // Both should be candidates for specialization
4476
        let candidates = interp.get_specialization_candidates();
4477
        let op_candidates: Vec<_> = candidates
4478
            .iter()
4479
            .filter(|c| matches!(c.kind, SpecializationKind::BinaryOperation { .. }))
4480
            .collect();
4481
        assert_eq!(op_candidates.len(), 2);
4482
    }
4483
4484
    #[test]
4485
    fn test_type_feedback_clear() {
4486
        use crate::frontend::ast::Span;
4487
        let mut interp = Interpreter::new();
4488
4489
        // Create and evaluate a simple expression
4490
        let expr = Expr::new(
4491
            ExprKind::Binary {
4492
                left: Box::new(Expr::new(
4493
                    ExprKind::Literal(Literal::Integer(1)),
4494
                    Span::new(0, 1),
4495
                )),
4496
                op: AstBinaryOp::Add,
4497
                right: Box::new(Expr::new(
4498
                    ExprKind::Literal(Literal::Integer(1)),
4499
                    Span::new(4, 5),
4500
                )),
4501
            },
4502
            Span::new(0, 5),
4503
        );
4504
4505
        let _ = interp.eval_expr(&expr).expect("Should evaluate");
4506
4507
        // Verify feedback was collected
4508
        let stats_before = interp.get_type_feedback_stats();
4509
        assert!(stats_before.total_samples > 0);
4510
4511
        // Clear feedback and verify
4512
        interp.clear_type_feedback();
4513
        let stats_after = interp.get_type_feedback_stats();
4514
        assert_eq!(stats_after.total_samples, 0);
4515
        assert_eq!(stats_after.total_operation_sites, 0);
4516
    }
4517
4518
    #[test]
4519
    fn test_gc_basic_tracking() {
4520
        let mut interp = Interpreter::new();
4521
4522
        // Create some values to track
4523
        let values = vec![
4524
            Value::Integer(42),
4525
            Value::String(Rc::new("hello".to_string())),
4526
            Value::Array(Rc::new(vec![Value::Integer(1), Value::Integer(2)])),
4527
        ];
4528
4529
        // Track them in GC
4530
        for value in values {
4531
            interp.gc_track(value);
4532
        }
4533
4534
        // Check GC info
4535
        let info = interp.gc_info();
4536
        assert_eq!(info.total_objects, 3);
4537
        assert!(info.allocated_bytes > 0);
4538
        assert_eq!(info.collections_performed, 0);
4539
    }
4540
4541
    #[test]
4542
    fn test_gc_collection() {
4543
        let mut interp = Interpreter::new();
4544
4545
        // Disable auto-collection for manual testing
4546
        interp.gc_set_auto_collect(false);
4547
4548
        // Track several objects
4549
        for i in 0..10 {
4550
            let value = Value::Integer(i);
4551
            interp.gc_track(value);
4552
        }
4553
4554
        let info_before = interp.gc_info();
4555
        assert_eq!(info_before.total_objects, 10);
4556
4557
        // Force garbage collection
4558
        let stats = interp.gc_collect();
4559
4560
        // Since we treat all objects as roots conservatively, none should be collected
4561
        assert_eq!(stats.objects_collected, 0);
4562
        assert_eq!(stats.objects_after, 10);
4563
4564
        let info_after = interp.gc_info();
4565
        assert_eq!(info_after.collections_performed, 1);
4566
    }
4567
4568
    #[test]
4569
    fn test_gc_auto_collection() {
4570
        let mut interp = Interpreter::new();
4571
4572
        // Set a very low threshold to trigger auto-collection
4573
        interp.gc_set_threshold(100);
4574
        interp.gc_set_auto_collect(true);
4575
4576
        // Track a large object to trigger collection
4577
        let large_string = "x".repeat(200);
4578
        let value = Value::String(Rc::new(large_string));
4579
        interp.gc_track(value);
4580
4581
        // Auto-collection should have been triggered
4582
        let info = interp.gc_info();
4583
        assert!(info.collections_performed > 0);
4584
    }
4585
4586
    #[test]
4587
    fn test_gc_allocation_helpers() {
4588
        let mut interp = Interpreter::new();
4589
4590
        // Test GC allocation helpers
4591
        let array = interp.gc_alloc_array(vec![Value::Integer(1), Value::Integer(2)]);
4592
        let string = interp.gc_alloc_string("test".to_string());
4593
4594
        // Both should be tracked
4595
        let info = interp.gc_info();
4596
        assert_eq!(info.total_objects, 2);
4597
4598
        // Verify the values are correct
4599
        match array {
4600
            Value::Array(arr) => {
4601
                assert_eq!(arr.len(), 2);
4602
                assert_eq!(arr[0], Value::Integer(1));
4603
                assert_eq!(arr[1], Value::Integer(2));
4604
            }
4605
            _ => panic!("Expected array"),
4606
        }
4607
4608
        match string {
4609
            Value::String(s) => {
4610
                assert_eq!(s.as_ref(), "test");
4611
            }
4612
            _ => panic!("Expected string"),
4613
        }
4614
    }
4615
4616
    #[test]
4617
    fn test_gc_size_estimation() {
4618
        let gc = ConservativeGC::new();
4619
4620
        // Test size estimation for different value types
4621
        let int_size = gc.estimate_object_size(&Value::Integer(42));
4622
        let float_size = gc.estimate_object_size(&Value::Float(3.14));
4623
        let bool_size = gc.estimate_object_size(&Value::Bool(true));
4624
        let nil_size = gc.estimate_object_size(&Value::Nil);
4625
4626
        assert_eq!(int_size, 8);
4627
        assert_eq!(float_size, 8);
4628
        assert_eq!(bool_size, 1);
4629
        assert_eq!(nil_size, 0);
4630
4631
        // Test string size estimation
4632
        let string_val = Value::String(Rc::new("hello".to_string()));
4633
        let string_size = gc.estimate_object_size(&string_val);
4634
        assert_eq!(string_size, 5 + 24); // content + overhead
4635
4636
        // Test array size estimation
4637
        let array_val = Value::Array(Rc::new(vec![Value::Integer(1), Value::Integer(2)]));
4638
        let array_size = gc.estimate_object_size(&array_val);
4639
        assert_eq!(array_size, 24 + 8 + 8); // overhead + 2 integers
4640
    }
4641
4642
    #[test]
4643
    fn test_gc_threshold_management() {
4644
        let mut interp = Interpreter::new();
4645
4646
        // Test threshold setting
4647
        interp.gc_set_threshold(2048);
4648
        let info = interp.gc_info();
4649
        assert_eq!(info.collection_threshold, 2048);
4650
4651
        // Test auto-collect setting
4652
        interp.gc_set_auto_collect(false);
4653
        let info = interp.gc_info();
4654
        assert!(!info.auto_collect_enabled);
4655
4656
        interp.gc_set_auto_collect(true);
4657
        let info = interp.gc_info();
4658
        assert!(info.auto_collect_enabled);
4659
    }
4660
4661
    #[test]
4662
    fn test_gc_clear() {
4663
        let mut interp = Interpreter::new();
4664
4665
        // Track some objects
4666
        for i in 0..5 {
4667
            interp.gc_track(Value::Integer(i));
4668
        }
4669
4670
        let info_before = interp.gc_info();
4671
        assert_eq!(info_before.total_objects, 5);
4672
        assert!(info_before.allocated_bytes > 0);
4673
4674
        // Clear GC
4675
        interp.gc_clear();
4676
4677
        let info_after = interp.gc_info();
4678
        assert_eq!(info_after.total_objects, 0);
4679
        assert_eq!(info_after.allocated_bytes, 0);
4680
    }
4681
4682
    #[test]
4683
    fn test_gc_stats_consistency() {
4684
        let mut interp = Interpreter::new();
4685
4686
        // Track objects and get initial stats
4687
        for i in 0..3 {
4688
            interp.gc_track(Value::Integer(i));
4689
        }
4690
4691
        let stats = interp.gc_stats();
4692
        let info = interp.gc_info();
4693
4694
        // Stats and info should be consistent
4695
        assert_eq!(stats.objects_before, info.total_objects);
4696
        assert_eq!(stats.objects_after, info.total_objects);
4697
        assert_eq!(stats.bytes_before, info.allocated_bytes);
4698
        assert_eq!(stats.bytes_after, info.allocated_bytes);
4699
        assert_eq!(stats.objects_collected, 0);
4700
    }
4701
4702
    // Direct-threaded interpreter tests
4703
4704
    #[test]
4705
    fn test_direct_threaded_creation() {
4706
        let interp = DirectThreadedInterpreter::new();
4707
        assert_eq!(interp.instruction_count(), 0);
4708
        assert_eq!(interp.constants_count(), 0);
4709
    }
4710
4711
    #[test]
4712
    fn test_direct_threaded_constants() {
4713
        let mut interp = DirectThreadedInterpreter::new();
4714
4715
        let int_idx = interp.add_constant(Value::Integer(42));
4716
        let float_idx = interp.add_constant(Value::Float(3.14));
4717
        let string_idx = interp.add_constant(Value::String(Rc::new("hello".to_string())));
4718
4719
        assert_eq!(int_idx, 0);
4720
        assert_eq!(float_idx, 1);
4721
        assert_eq!(string_idx, 2);
4722
        assert_eq!(interp.constants_count(), 3);
4723
    }
4724
4725
    #[test]
4726
    fn test_direct_threaded_instruction_stream() {
4727
        let mut interp = DirectThreadedInterpreter::new();
4728
4729
        // Add some constants
4730
        let const_idx = interp.add_constant(Value::Integer(42));
4731
4732
        // Add instructions
4733
        interp.add_instruction(op_load_const, const_idx);
4734
        interp.add_instruction(op_load_nil, 0);
4735
4736
        assert_eq!(interp.instruction_count(), 2);
4737
    }
4738
4739
    #[test]
4740
    fn test_direct_threaded_literal_compilation() {
4741
        use crate::frontend::ast::{Expr, ExprKind};
4742
4743
        let mut interp = DirectThreadedInterpreter::new();
4744
4745
        // Compile integer literal
4746
        let int_ast = Expr::new(
4747
            ExprKind::Literal(Literal::Integer(42)),
4748
            crate::frontend::ast::Span::new(0, 0),
4749
        );
4750
        let result = interp.compile(&int_ast);
4751
        assert!(result.is_ok());
4752
4753
        assert_eq!(interp.constants_count(), 1);
4754
        assert_eq!(interp.instruction_count(), 2); // load_const + return
4755
4756
        // Compile float literal
4757
        let float_ast = Expr::new(
4758
            ExprKind::Literal(Literal::Float(3.14)),
4759
            crate::frontend::ast::Span::new(0, 0),
4760
        );
4761
        let result = interp.compile(&float_ast);
4762
        assert!(result.is_ok());
4763
4764
        assert_eq!(interp.constants_count(), 1); // resets on each compile
4765
        assert_eq!(interp.instruction_count(), 2); // load_const + return
4766
4767
        // Compile string literal
4768
        let string_ast = Expr::new(
4769
            ExprKind::Literal(Literal::String("hello".to_string())),
4770
            crate::frontend::ast::Span::new(0, 0),
4771
        );
4772
        let result = interp.compile(&string_ast);
4773
        assert!(result.is_ok());
4774
4775
        assert_eq!(interp.constants_count(), 1); // resets on each compile
4776
        assert_eq!(interp.instruction_count(), 2); // load_const + return
4777
4778
        // Compile boolean literal
4779
        let bool_ast = Expr::new(
4780
            ExprKind::Literal(Literal::Bool(true)),
4781
            crate::frontend::ast::Span::new(0, 0),
4782
        );
4783
        let result = interp.compile(&bool_ast);
4784
        assert!(result.is_ok());
4785
4786
        assert_eq!(interp.constants_count(), 1); // resets on each compile
4787
        assert_eq!(interp.instruction_count(), 2); // load_const + return
4788
4789
        // Compile nil literal
4790
        let nil_ast = Expr::new(
4791
            ExprKind::Literal(Literal::Unit),
4792
            crate::frontend::ast::Span::new(0, 0),
4793
        );
4794
        let result = interp.compile(&nil_ast);
4795
        assert!(result.is_ok());
4796
4797
        assert_eq!(interp.instruction_count(), 2); // load_nil + return
4798
                                                   // Nil doesn't add to constants, uses special instruction
4799
    }
4800
4801
    #[test]
4802
    fn test_direct_threaded_binary_op_compilation() {
4803
        use crate::frontend::ast::{BinaryOp, Expr, ExprKind};
4804
4805
        let mut interp = DirectThreadedInterpreter::new();
4806
4807
        // Compile: 2 + 3
4808
        let add_ast = Expr::new(
4809
            ExprKind::Binary {
4810
                op: BinaryOp::Add,
4811
                left: Box::new(Expr::new(
4812
                    ExprKind::Literal(Literal::Integer(2)),
4813
                    crate::frontend::ast::Span::new(0, 0),
4814
                )),
4815
                right: Box::new(Expr::new(
4816
                    ExprKind::Literal(Literal::Integer(3)),
4817
                    crate::frontend::ast::Span::new(0, 0),
4818
                )),
4819
            },
4820
            crate::frontend::ast::Span::new(0, 0),
4821
        );
4822
4823
        let result = interp.compile(&add_ast);
4824
        assert!(result.is_ok());
4825
4826
        // Should have: load_const(2), load_const(3), add, return
4827
        assert_eq!(interp.instruction_count(), 4);
4828
        assert_eq!(interp.constants_count(), 2);
4829
    }
4830
4831
    #[test]
4832
    fn test_direct_threaded_identifier_compilation() {
4833
        use crate::frontend::ast::{Expr, ExprKind};
4834
4835
        let mut interp = DirectThreadedInterpreter::new();
4836
4837
        let ident_ast = Expr::new(
4838
            ExprKind::Identifier("x".to_string()),
4839
            crate::frontend::ast::Span::new(0, 0),
4840
        );
4841
        let result = interp.compile(&ident_ast);
4842
        assert!(result.is_ok());
4843
4844
        // Should add variable name to constants and generate load_var instruction
4845
        assert_eq!(interp.constants_count(), 1);
4846
        assert_eq!(interp.instruction_count(), 2); // load_var + return
4847
    }
4848
4849
    #[test]
4850
    fn test_direct_threaded_execution_simple() {
4851
        use crate::frontend::ast::{Expr, ExprKind};
4852
4853
        let mut interp = DirectThreadedInterpreter::new();
4854
4855
        // Compile and execute: 42
4856
        let ast = Expr::new(
4857
            ExprKind::Literal(Literal::Integer(42)),
4858
            crate::frontend::ast::Span::new(0, 0),
4859
        );
4860
        interp.compile(&ast).expect("Test should not fail");
4861
4862
        let result = interp.execute();
4863
        assert!(result.is_ok());
4864
        assert_eq!(result.expect("Test should not fail"), Value::Integer(42));
4865
    }
4866
4867
    #[test]
4868
    fn test_direct_threaded_execution_arithmetic() {
4869
        use crate::frontend::ast::{BinaryOp, Expr, ExprKind};
4870
4871
        let mut interp = DirectThreadedInterpreter::new();
4872
4873
        // Compile and execute: 2 + 3
4874
        let ast = Expr::new(
4875
            ExprKind::Binary {
4876
                op: BinaryOp::Add,
4877
                left: Box::new(Expr::new(
4878
                    ExprKind::Literal(Literal::Integer(2)),
4879
                    crate::frontend::ast::Span::new(0, 0),
4880
                )),
4881
                right: Box::new(Expr::new(
4882
                    ExprKind::Literal(Literal::Integer(3)),
4883
                    crate::frontend::ast::Span::new(0, 0),
4884
                )),
4885
            },
4886
            crate::frontend::ast::Span::new(0, 0),
4887
        );
4888
4889
        interp.compile(&ast).expect("Test should not fail");
4890
        let result = interp.execute();
4891
        assert!(result.is_ok());
4892
        assert_eq!(result.expect("Test should not fail"), Value::Integer(5));
4893
    }
4894
4895
    #[test]
4896
    fn test_direct_threaded_execution_subtraction() {
4897
        use crate::frontend::ast::{BinaryOp, Expr, ExprKind};
4898
4899
        let mut interp = DirectThreadedInterpreter::new();
4900
4901
        // Compile and execute: 10 - 4
4902
        let ast = Expr::new(
4903
            ExprKind::Binary {
4904
                op: BinaryOp::Subtract,
4905
                left: Box::new(Expr::new(
4906
                    ExprKind::Literal(Literal::Integer(10)),
4907
                    crate::frontend::ast::Span::new(0, 0),
4908
                )),
4909
                right: Box::new(Expr::new(
4910
                    ExprKind::Literal(Literal::Integer(4)),
4911
                    crate::frontend::ast::Span::new(0, 0),
4912
                )),
4913
            },
4914
            crate::frontend::ast::Span::new(0, 0),
4915
        );
4916
4917
        interp.compile(&ast).expect("Test should not fail");
4918
        let result = interp.execute();
4919
        assert!(result.is_ok());
4920
        assert_eq!(result.expect("Test should not fail"), Value::Integer(6));
4921
    }
4922
4923
    #[test]
4924
    fn test_direct_threaded_execution_multiplication() {
4925
        use crate::frontend::ast::{BinaryOp, Expr, ExprKind};
4926
4927
        let mut interp = DirectThreadedInterpreter::new();
4928
4929
        // Compile and execute: 6 * 7
4930
        let ast = Expr::new(
4931
            ExprKind::Binary {
4932
                op: BinaryOp::Multiply,
4933
                left: Box::new(Expr::new(
4934
                    ExprKind::Literal(Literal::Integer(6)),
4935
                    crate::frontend::ast::Span::new(0, 0),
4936
                )),
4937
                right: Box::new(Expr::new(
4938
                    ExprKind::Literal(Literal::Integer(7)),
4939
                    crate::frontend::ast::Span::new(0, 0),
4940
                )),
4941
            },
4942
            crate::frontend::ast::Span::new(0, 0),
4943
        );
4944
4945
        interp.compile(&ast).expect("Test should not fail");
4946
        let result = interp.execute();
4947
        assert!(result.is_ok());
4948
        assert_eq!(result.expect("Test should not fail"), Value::Integer(42));
4949
    }
4950
4951
    #[test]
4952
    fn test_direct_threaded_execution_division() {
4953
        use crate::frontend::ast::{BinaryOp, Expr, ExprKind};
4954
4955
        let mut interp = DirectThreadedInterpreter::new();
4956
4957
        // Compile and execute: 20 / 4
4958
        let ast = Expr::new(
4959
            ExprKind::Binary {
4960
                op: BinaryOp::Divide,
4961
                left: Box::new(Expr::new(
4962
                    ExprKind::Literal(Literal::Integer(20)),
4963
                    crate::frontend::ast::Span::new(0, 0),
4964
                )),
4965
                right: Box::new(Expr::new(
4966
                    ExprKind::Literal(Literal::Integer(4)),
4967
                    crate::frontend::ast::Span::new(0, 0),
4968
                )),
4969
            },
4970
            crate::frontend::ast::Span::new(0, 0),
4971
        );
4972
4973
        interp.compile(&ast).expect("Test should not fail");
4974
        let result = interp.execute();
4975
        assert!(result.is_ok());
4976
        assert_eq!(result.expect("Test should not fail"), Value::Integer(5));
4977
    }
4978
4979
    #[test]
4980
    fn test_direct_threaded_execution_mixed_types() {
4981
        use crate::frontend::ast::{BinaryOp, Expr, ExprKind};
4982
4983
        let mut interp = DirectThreadedInterpreter::new();
4984
4985
        // Compile and execute: 2.5 + 3 (float + int)
4986
        let ast = Expr::new(
4987
            ExprKind::Binary {
4988
                op: BinaryOp::Add,
4989
                left: Box::new(Expr::new(
4990
                    ExprKind::Literal(Literal::Float(2.5)),
4991
                    crate::frontend::ast::Span::new(0, 0),
4992
                )),
4993
                right: Box::new(Expr::new(
4994
                    ExprKind::Literal(Literal::Integer(3)),
4995
                    crate::frontend::ast::Span::new(0, 0),
4996
                )),
4997
            },
4998
            crate::frontend::ast::Span::new(0, 0),
4999
        );
5000
5001
        interp.compile(&ast).expect("Test should not fail");
5002
        let result = interp.execute();
5003
        assert!(result.is_ok());
5004
        assert_eq!(result.expect("Test should not fail"), Value::Float(5.5));
5005
    }
5006
5007
    #[test]
5008
    fn test_direct_threaded_execution_division_by_zero() {
5009
        use crate::frontend::ast::{BinaryOp, Expr, ExprKind};
5010
5011
        let mut interp = DirectThreadedInterpreter::new();
5012
5013
        // Compile and execute: 5 / 0
5014
        let ast = Expr::new(
5015
            ExprKind::Binary {
5016
                op: BinaryOp::Divide,
5017
                left: Box::new(Expr::new(
5018
                    ExprKind::Literal(Literal::Integer(5)),
5019
                    crate::frontend::ast::Span::new(0, 0),
5020
                )),
5021
                right: Box::new(Expr::new(
5022
                    ExprKind::Literal(Literal::Integer(0)),
5023
                    crate::frontend::ast::Span::new(0, 0),
5024
                )),
5025
            },
5026
            crate::frontend::ast::Span::new(0, 0),
5027
        );
5028
5029
        interp.compile(&ast).expect("Test should not fail");
5030
        let result = interp.execute();
5031
        assert!(result.is_err());
5032
    }
5033
5034
    #[test]
5035
    fn test_direct_threaded_execution_variable_lookup() {
5036
        use crate::frontend::ast::{Expr, ExprKind};
5037
        use std::collections::HashMap;
5038
5039
        let mut interp = DirectThreadedInterpreter::new();
5040
5041
        // Set up environment with variable
5042
        let mut env = HashMap::new();
5043
        env.insert("x".to_string(), Value::Integer(42));
5044
5045
        // Compile and execute: x
5046
        let ast = Expr::new(
5047
            ExprKind::Identifier("x".to_string()),
5048
            crate::frontend::ast::Span::new(0, 0),
5049
        );
5050
        interp.compile(&ast).expect("Test should not fail");
5051
5052
        let mut state = InterpreterState::new();
5053
        state.env_stack.push(env);
5054
        state.constants = interp.constants.clone();
5055
5056
        // Execute with variable in environment
5057
        let result = interp.execute_with_state(&mut state);
5058
        assert!(result.is_ok());
5059
        assert_eq!(result.expect("Test should not fail"), Value::Integer(42));
5060
    }
5061
5062
    #[test]
5063
    fn test_direct_threaded_execution_undefined_variable() {
5064
        use crate::frontend::ast::{Expr, ExprKind};
5065
5066
        let mut interp = DirectThreadedInterpreter::new();
5067
5068
        // Compile and execute: undefined_var
5069
        let ast = Expr::new(
5070
            ExprKind::Identifier("undefined_var".to_string()),
5071
            crate::frontend::ast::Span::new(0, 0),
5072
        );
5073
        interp.compile(&ast).expect("Test should not fail");
5074
5075
        let result = interp.execute();
5076
        assert!(result.is_err());
5077
        match result.expect_err("Test should fail") {
5078
            InterpreterError::RuntimeError(msg) => {
5079
                assert!(msg.contains("Undefined variable"));
5080
            }
5081
            _ => panic!("Expected RuntimeError"),
5082
        }
5083
    }
5084
5085
    #[test]
5086
    fn test_direct_threaded_instruction_handlers() {
5087
        let mut state = InterpreterState::new();
5088
5089
        // Test op_load_const
5090
        state.constants.push(Value::Integer(42));
5091
        let result = op_load_const(&mut state, 0);
5092
        assert_eq!(result, InstructionResult::Continue);
5093
        assert_eq!(state.stack.len(), 1);
5094
        assert_eq!(state.stack[0], Value::Integer(42));
5095
5096
        // Test op_load_nil
5097
        let result = op_load_nil(&mut state, 0);
5098
        assert_eq!(result, InstructionResult::Continue);
5099
        assert_eq!(state.stack.len(), 2);
5100
        assert_eq!(state.stack[1], Value::Nil);
5101
5102
        // Test arithmetic operations
5103
        state.stack.clear();
5104
        state.stack.push(Value::Integer(5));
5105
        state.stack.push(Value::Integer(3));
5106
5107
        let result = op_add(&mut state, 0);
5108
        assert_eq!(result, InstructionResult::Continue);
5109
        assert_eq!(state.stack.len(), 1);
5110
        assert_eq!(state.stack[0], Value::Integer(8));
5111
    }
5112
5113
    #[test]
5114
    fn test_direct_threaded_clear() {
5115
        let mut interp = DirectThreadedInterpreter::new();
5116
5117
        // Add some instructions and constants
5118
        interp.add_constant(Value::Integer(42));
5119
        interp.add_instruction(op_load_const, 0);
5120
5121
        assert!(interp.instruction_count() > 0);
5122
        assert!(interp.constants_count() > 0);
5123
5124
        // Clear should reset everything
5125
        interp.clear();
5126
5127
        assert_eq!(interp.instruction_count(), 0);
5128
        assert_eq!(interp.constants_count(), 0);
5129
    }
5130
}