Coverage Report

Created: 2025-09-05 15: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
163
    pub fn from_i64(i: i64) -> Self {
51
163
        Value::Integer(i)
52
163
    }
53
54
    /// Create float value
55
41
    pub fn from_f64(f: f64) -> Self {
56
41
        Value::Float(f)
57
41
    }
58
59
    /// Create boolean value
60
22
    pub fn from_bool(b: bool) -> Self {
61
22
        Value::Bool(b)
62
22
    }
63
64
    /// Create nil value
65
2
    pub fn nil() -> Self {
66
2
        Value::Nil
67
2
    }
68
69
    /// Create string value
70
4
    pub fn from_string(s: String) -> Self {
71
4
        Value::String(Rc::new(s))
72
4
    }
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
1
    pub fn is_nil(&self) -> bool {
81
1
        
matches!0
(self, Value::Nil)
82
1
    }
83
84
    /// Check if value is truthy (everything except false and nil)
85
17
    pub fn is_truthy(&self) -> bool {
86
17
        match self {
87
12
            Value::Bool(b) => *b,
88
1
            Value::Nil => false,
89
4
            _ => true,
90
        }
91
17
    }
92
93
    /// Extract integer value
94
    /// # Errors
95
    /// Returns error if the value is not an integer
96
1
    pub fn as_i64(&self) -> Result<i64, InterpreterError> {
97
1
        match self {
98
1
            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
1
    }
105
106
    /// Extract float value  
107
    /// # Errors
108
    /// Returns error if the value is not a float
109
1
    pub fn as_f64(&self) -> Result<f64, InterpreterError> {
110
1
        match self {
111
1
            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
1
    }
118
119
    /// Extract boolean value
120
    /// # Errors
121
    /// Returns error if the value is not a boolean
122
1
    pub fn as_bool(&self) -> Result<bool, InterpreterError> {
123
1
        match self {
124
1
            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
1
    }
131
132
    /// Get type name for debugging
133
16
    pub fn type_name(&self) -> &'static str {
134
16
        match self {
135
3
            Value::Integer(_) => "integer",
136
1
            Value::Float(_) => "float",
137
2
            Value::Bool(_) => "boolean",
138
1
            Value::Nil => "nil",
139
4
            Value::String(_) => "string",
140
0
            Value::Array(_) => "array",
141
0
            Value::Tuple(_) => "tuple",
142
5
            Value::Closure { .. } => "function",
143
        }
144
16
    }
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
12
    pub fn new() -> Self {
304
12
        Self {
305
12
            state: CacheState::Uninitialized,
306
12
            entries: smallvec![],
307
12
            total_hits: 0,
308
12
            total_misses: 0,
309
12
        }
310
12
    }
311
312
    /// Look up a field access in the cache
313
4
    pub fn lookup(&mut self, obj: &Value, field_name: &str) -> Option<Value> {
314
4
        let type_id = obj.type_id();
315
316
        // Fast path: check cached entries
317
4
        for entry in &mut self.entries {
318
4
            if entry.type_id == type_id && entry.field_name == field_name {
319
4
                entry.hit_count += 1;
320
4
                self.total_hits += 1;
321
4
                return Some(entry.cached_result.clone());
322
0
            }
323
        }
324
325
        // Cache miss
326
0
        self.total_misses += 1;
327
0
        None
328
4
    }
329
330
    /// Add a new cache entry
331
12
    pub fn insert(&mut self, obj: &Value, field_name: String, result: Value) {
332
12
        let type_id = obj.type_id();
333
12
        let entry = CacheEntry {
334
12
            type_id,
335
12
            field_name,
336
12
            cached_result: result,
337
12
            hit_count: 1,
338
12
        };
339
340
        // Update cache state based on entry count
341
12
        match self.entries.len() {
342
12
            0 => {
343
12
                self.state = CacheState::Monomorphic;
344
12
                self.entries.push(entry);
345
12
            }
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
12
    }
366
367
    /// Get cache hit rate for profiling
368
4
    pub fn hit_rate(&self) -> f64 {
369
4
        let total = self.total_hits + self.total_misses;
370
4
        if total == 0 {
371
2
            0.0
372
        } else {
373
2
            f64::from(self.total_hits) / f64::from(total)
374
        }
375
4
    }
376
}
377
378
impl Default for InlineCache {
379
12
    fn default() -> Self {
380
12
        Self::new()
381
12
    }
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
38
    pub fn new() -> Self {
441
38
        Self {
442
38
            operation_sites: HashMap::new(),
443
38
            variable_types: HashMap::new(),
444
38
            call_sites: HashMap::new(),
445
38
            total_samples: 0,
446
38
        }
447
38
    }
448
449
    /// Record binary operation type feedback
450
71
    pub fn record_binary_op(
451
71
        &mut self,
452
71
        site_id: usize,
453
71
        left: &Value,
454
71
        right: &Value,
455
71
        result: &Value,
456
71
    ) {
457
71
        let left_type = left.type_id();
458
71
        let right_type = right.type_id();
459
71
        let result_type = result.type_id();
460
461
71
        let feedback = self
462
71
            .operation_sites
463
71
            .entry(site_id)
464
71
            .or_insert_with(|| OperationFeedback {
465
13
                left_types: smallvec![],
466
13
                right_types: smallvec![],
467
13
                result_types: smallvec![],
468
13
                type_counts: HashMap::new(),
469
                total_count: 0,
470
13
            });
471
472
        // Record types if not already seen
473
71
        if !feedback.left_types.contains(&left_type) {
474
13
            feedback.left_types.push(left_type);
475
58
        }
476
71
        if !feedback.right_types.contains(&right_type) {
477
13
            feedback.right_types.push(right_type);
478
58
        }
479
71
        if !feedback.result_types.contains(&result_type) {
480
15
            feedback.result_types.push(result_type);
481
56
        }
482
483
        // Update type combination counts
484
71
        let type_pair = (left_type, right_type);
485
71
        *feedback.type_counts.entry(type_pair).or_insert(0) += 1;
486
71
        feedback.total_count += 1;
487
71
        self.total_samples += 1;
488
71
    }
489
490
    /// Record variable assignment type feedback
491
7
    pub fn record_variable_assignment(&mut self, var_name: &str, new_type: std::any::TypeId) {
492
7
        let feedback = self
493
7
            .variable_types
494
7
            .entry(var_name.to_string())
495
7
            .or_insert_with(|| VariableTypeFeedback {
496
6
                assigned_types: smallvec![],
497
6
                transitions: HashMap::new(),
498
6
                dominant_type: None,
499
                stability_score: 1.0,
500
6
            });
501
502
        // Record type transition if there was a previous type
503
7
        if let Some(
prev_type1
) = feedback.dominant_type {
504
1
            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
1
            }
513
6
        }
514
515
        // Add new type if not seen before
516
7
        if !feedback.assigned_types.contains(&new_type) {
517
6
            feedback.assigned_types.push(new_type);
518
6
        
}1
519
520
        // Update dominant type (most recently assigned for simplicity)
521
7
        feedback.dominant_type = Some(new_type);
522
523
        // Recalculate stability score
524
7
        feedback.stability_score = if feedback.assigned_types.len() == 1 {
525
7
            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
7
    }
531
532
    /// Record function call type feedback
533
17
    pub fn record_function_call(
534
17
        &mut self,
535
17
        site_id: usize,
536
17
        func_name: &str,
537
17
        args: &[Value],
538
17
        result: &Value,
539
17
    ) {
540
17
        let arg_types: Vec<std::any::TypeId> = args.iter().map(Value::type_id).collect();
541
17
        let return_type = result.type_id();
542
543
17
        let feedback = self
544
17
            .call_sites
545
17
            .entry(site_id)
546
17
            .or_insert_with(|| CallSiteFeedback {
547
4
                arg_type_patterns: smallvec![],
548
4
                return_types: smallvec![],
549
                call_count: 0,
550
4
                called_functions: HashMap::new(),
551
4
            });
552
553
        // Record argument pattern if not seen before
554
17
        if !feedback
555
17
            .arg_type_patterns
556
17
            .iter()
557
17
            .any(|pattern| 
pattern13
==
&arg_types13
)
558
4
        {
559
4
            feedback.arg_type_patterns.push(arg_types);
560
13
        }
561
562
        // Record return type if not seen before
563
17
        if !feedback.return_types.contains(&return_type) {
564
4
            feedback.return_types.push(return_type);
565
13
        }
566
567
        // Update function call counts
568
17
        *feedback
569
17
            .called_functions
570
17
            .entry(func_name.to_string())
571
17
            .or_insert(0) += 1;
572
17
        feedback.call_count += 1;
573
17
    }
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
4
    pub fn get_specialization_candidates(&self) -> Vec<SpecializationCandidate> {
579
4
        let mut candidates = Vec::new();
580
581
        // Find monomorphic operation sites
582
8
        for (&
site_id4
,
feedback4
) in &self.operation_sites {
583
4
            if feedback.left_types.len() == 1
584
4
                && feedback.right_types.len() == 1
585
4
                && feedback.total_count > 10
586
3
            {
587
3
                candidates.push(SpecializationCandidate {
588
3
                    kind: SpecializationKind::BinaryOperation {
589
3
                        site_id,
590
3
                        left_type: feedback.left_types[0],
591
3
                        right_type: feedback.right_types[0],
592
3
                    },
593
3
                    confidence: 1.0,
594
3
                    benefit_score: f64::from(feedback.total_count),
595
3
                });
596
3
            
}1
597
        }
598
599
        // Find stable variables
600
6
        for (
var_name2
,
feedback2
) in &self.variable_types {
601
2
            if feedback.stability_score > 0.8 && feedback.dominant_type.is_some() {
602
2
                candidates.push(SpecializationCandidate {
603
2
                    kind: SpecializationKind::Variable {
604
2
                        name: var_name.clone(),
605
2
                        #[allow(clippy::expect_used)] // Safe: we just checked is_some() above
606
2
                        specialized_type: feedback.dominant_type.expect("Dominant type should exist for stable variables"),
607
2
                    },
608
2
                    confidence: feedback.stability_score,
609
2
                    benefit_score: feedback.stability_score * 100.0,
610
2
                });
611
2
            
}0
612
        }
613
614
        // Find monomorphic call sites
615
5
        for (&
site_id1
,
feedback1
) in &self.call_sites {
616
1
            if feedback.arg_type_patterns.len() == 1
617
1
                && feedback.return_types.len() == 1
618
1
                && feedback.call_count > 5
619
1
            {
620
1
                candidates.push(SpecializationCandidate {
621
1
                    kind: SpecializationKind::FunctionCall {
622
1
                        site_id,
623
1
                        arg_types: feedback.arg_type_patterns[0].clone(),
624
1
                        return_type: feedback.return_types[0],
625
1
                    },
626
1
                    confidence: 1.0,
627
1
                    benefit_score: f64::from(feedback.call_count * 10),
628
1
                });
629
1
            
}0
630
        }
631
632
        // Sort by benefit score (highest first)
633
4
        candidates.sort_by(|a, b| 
{2
634
2
            b.benefit_score
635
2
                .partial_cmp(&a.benefit_score)
636
2
                .unwrap_or(std::cmp::Ordering::Equal)
637
2
        });
638
4
        candidates
639
4
    }
640
641
    /// Get overall type feedback statistics
642
6
    pub fn get_statistics(&self) -> TypeFeedbackStats {
643
6
        let monomorphic_sites = self
644
6
            .operation_sites
645
6
            .values()
646
6
            .filter(|f| 
f.left_types.len() == 15
&&
f.right_types.len() == 15
)
647
6
            .count();
648
649
6
        let stable_variables = self
650
6
            .variable_types
651
6
            .values()
652
6
            .filter(|f| 
f.stability_score2
> 0.8)
653
6
            .count();
654
655
6
        let monomorphic_calls = self
656
6
            .call_sites
657
6
            .values()
658
6
            .filter(|f| 
f.arg_type_patterns1
.
len1
() == 1)
659
6
            .count();
660
661
6
        TypeFeedbackStats {
662
6
            total_operation_sites: self.operation_sites.len(),
663
6
            monomorphic_operation_sites: monomorphic_sites,
664
6
            total_variables: self.variable_types.len(),
665
6
            stable_variables,
666
6
            total_call_sites: self.call_sites.len(),
667
6
            monomorphic_call_sites: monomorphic_calls,
668
6
            total_samples: self.total_samples,
669
6
        }
670
6
    }
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
38
    pub fn new() -> Self {
765
38
        Self {
766
38
            tracked_objects: Vec::new(),
767
38
            collections_performed: 0,
768
38
            objects_collected: 0,
769
38
            collection_threshold: 1024 * 1024, // 1MB default threshold
770
38
            allocated_bytes: 0,
771
38
            auto_collect_enabled: true,
772
38
        }
773
38
    }
774
775
    /// Add an object to GC tracking
776
24
    pub fn track_object(&mut self, value: Value) -> usize {
777
24
        let id = self.tracked_objects.len();
778
24
        let size = self.estimate_object_size(&value);
779
780
24
        let gc_object = GCObject {
781
24
            id,
782
24
            size,
783
24
            marked: false,
784
24
            generation: 0,
785
24
            value,
786
24
        };
787
788
24
        self.tracked_objects.push(gc_object);
789
24
        self.allocated_bytes += size;
790
791
        // Trigger collection if we've exceeded threshold
792
24
        if self.auto_collect_enabled && 
self.allocated_bytes > self.collection_threshold14
{
793
1
            self.collect_garbage();
794
23
        }
795
796
24
        id
797
24
    }
798
799
    /// Perform garbage collection using conservative stack scanning
800
2
    pub fn collect_garbage(&mut self) -> GCStats {
801
2
        let initial_count = self.tracked_objects.len();
802
2
        let initial_bytes = self.allocated_bytes;
803
804
        // Mark phase: mark all reachable objects
805
2
        self.mark_phase();
806
807
        // Sweep phase: collect unmarked objects
808
2
        let collected = self.sweep_phase();
809
810
2
        self.collections_performed += 1;
811
2
        self.objects_collected += collected as u64;
812
813
2
        GCStats {
814
2
            objects_before: initial_count,
815
2
            objects_after: self.tracked_objects.len(),
816
2
            objects_collected: collected,
817
2
            bytes_before: initial_bytes,
818
2
            bytes_after: self.allocated_bytes,
819
2
            collection_time_ns: 0, // Simple implementation doesn't time
820
2
        }
821
2
    }
822
823
    /// Mark phase: mark all reachable objects
824
2
    fn mark_phase(&mut self) {
825
        // Reset all marks
826
13
        for 
obj11
in &mut self.tracked_objects {
827
11
            obj.marked = false;
828
11
        }
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
11
        for i in 0..
self.tracked_objects2
.
len2
() {
834
11
            if self.is_root_object(i) {
835
11
                self.mark_object(i);
836
11
            
}0
837
        }
838
2
    }
839
840
    /// Check if object is a root (conservatively assume all are roots for safety)
841
11
    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
11
        true
845
11
    }
846
847
    /// Mark an object and all objects it references
848
11
    fn mark_object(&mut self, index: usize) {
849
11
        if index >= self.tracked_objects.len() || self.tracked_objects[index].marked {
850
0
            return;
851
11
        }
852
853
11
        self.tracked_objects[index].marked = true;
854
855
        // Mark objects referenced by this object
856
11
        let value = &self.tracked_objects[index].value.clone();
857
11
        if let Value::Array(
arr0
) = 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
11
        }
865
        // Note: Closure environments and other value types don't contain tracked object references
866
        // In a real implementation, would mark closure environment
867
11
    }
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
2
    fn sweep_phase(&mut self) -> usize {
882
2
        let initial_len = self.tracked_objects.len();
883
884
        // Keep only marked objects
885
11
        
self.tracked_objects2
.
retain2
(|obj| {
886
11
            if obj.marked {
887
11
                true
888
            } else {
889
0
                self.allocated_bytes = self.allocated_bytes.saturating_sub(obj.size);
890
0
                false
891
            }
892
11
        });
893
894
        // Reassign IDs after compaction
895
11
        for (new_id, obj) in 
self.tracked_objects.iter_mut()2
.
enumerate2
() {
896
11
            obj.id = new_id;
897
11
        }
898
899
2
        initial_len - self.tracked_objects.len()
900
2
    }
901
902
    /// Estimate memory size of a value
903
36
    fn estimate_object_size(&self, value: &Value) -> usize {
904
36
        match value {
905
27
            Value::Integer(_) | Value::Float(_) => 8,
906
1
            Value::Bool(_) => 1,
907
1
            Value::Nil => 0,
908
4
            Value::String(s) => s.len() + 24, // String overhead + content
909
3
            Value::Array(arr) => {
910
3
                let base_size = 24; // Vec overhead
911
3
                let element_size = arr
912
3
                    .iter()
913
6
                    .
map3
(|v| self.estimate_object_size(v))
914
3
                    .sum::<usize>();
915
3
                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
36
    }
932
933
    /// Get current GC statistics
934
1
    pub fn get_stats(&self) -> GCStats {
935
1
        GCStats {
936
1
            objects_before: self.tracked_objects.len(),
937
1
            objects_after: self.tracked_objects.len(),
938
1
            objects_collected: 0,
939
1
            bytes_before: self.allocated_bytes,
940
1
            bytes_after: self.allocated_bytes,
941
1
            collection_time_ns: 0,
942
1
        }
943
1
    }
944
945
    /// Get detailed GC information
946
11
    pub fn get_info(&self) -> GCInfo {
947
11
        GCInfo {
948
11
            total_objects: self.tracked_objects.len(),
949
11
            allocated_bytes: self.allocated_bytes,
950
11
            collections_performed: self.collections_performed,
951
11
            objects_collected: self.objects_collected,
952
11
            collection_threshold: self.collection_threshold,
953
11
            auto_collect_enabled: self.auto_collect_enabled,
954
11
        }
955
11
    }
956
957
    /// Set collection threshold
958
2
    pub fn set_collection_threshold(&mut self, threshold: usize) {
959
2
        self.collection_threshold = threshold;
960
2
    }
961
962
    /// Enable or disable automatic collection
963
4
    pub fn set_auto_collect(&mut self, enabled: bool) {
964
4
        self.auto_collect_enabled = enabled;
965
4
    }
966
967
    /// Force garbage collection
968
1
    pub fn force_collect(&mut self) -> GCStats {
969
1
        self.collect_garbage()
970
1
    }
971
972
    /// Clear all tracked objects (for testing)
973
1
    pub fn clear(&mut self) {
974
1
        self.tracked_objects.clear();
975
1
        self.allocated_bytes = 0;
976
1
    }
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
3
    pub fn new() -> Self {
1060
3
        Self {
1061
3
            stack: Vec::new(),
1062
3
            env_stack: vec![HashMap::new()], // Start with global environment
1063
3
            constants: Vec::new(),
1064
3
            caches: Vec::new(),
1065
3
        }
1066
3
    }
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
16
    pub fn new() -> Self {
1091
16
        Self {
1092
16
            code: Vec::new(),
1093
16
            constants: Vec::new(),
1094
16
            pc: 0,
1095
16
            state: InterpreterState {
1096
16
                stack: Vec::with_capacity(256),
1097
16
                env_stack: vec![HashMap::new()],
1098
16
                constants: Vec::new(),
1099
16
                caches: Vec::new(),
1100
16
            },
1101
16
        }
1102
16
    }
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
16
    pub fn compile(&mut self, expr: &Expr) -> Result<(), InterpreterError> {
1111
16
        self.code.clear();
1112
16
        self.constants.clear();
1113
16
        self.pc = 0;
1114
1115
        // Compile expression to instruction stream
1116
16
        self.compile_expr(expr)
?0
;
1117
1118
        // Add return instruction if needed
1119
16
        if self.code.is_empty()
1120
16
            || !
matches!0
(self.code.last(), Some(
instr0
) if
1121
16
            std::ptr::eq(instr.handler as *const (), op_return as *const ()
)0
)
1122
16
        {
1123
16
            self.emit_instruction(op_return, 0);
1124
16
        
}0
1125
1126
        // Copy constants to state
1127
16
        self.state.constants = self.constants.clone();
1128
1129
16
        Ok(())
1130
16
    }
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
8
    pub fn execute(&mut self) -> Result<Value, InterpreterError> {
1139
8
        self.pc = 0;
1140
1141
        loop {
1142
            // Bounds check
1143
26
            if self.pc >= self.code.len() {
1144
0
                return Err(InterpreterError::RuntimeError(
1145
0
                    "PC out of bounds".to_string(),
1146
0
                ));
1147
26
            }
1148
1149
            // Direct function pointer call - no switch overhead
1150
26
            let instruction = &self.code[self.pc];
1151
26
            let result = (instruction.handler)(&mut self.state, instruction.operand);
1152
1153
26
            match result {
1154
18
                InstructionResult::Continue => {
1155
18
                    self.pc += 1;
1156
18
                }
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
6
                InstructionResult::Return(value) => {
1166
6
                    return Ok(value);
1167
                }
1168
2
                InstructionResult::Error(error) => {
1169
2
                    return Err(error);
1170
                }
1171
            }
1172
1173
            // Periodic interrupt check for long-running loops
1174
18
            if self.pc.trailing_zeros() >= 10 {
1175
0
                // Could add interrupt checking here in the future
1176
18
            }
1177
        }
1178
8
    }
1179
1180
    /// Compile single expression to instruction stream
1181
30
    fn compile_expr(&mut self, expr: &Expr) -> Result<(), InterpreterError> {
1182
30
        match &expr.kind {
1183
20
            ExprKind::Literal(lit) => self.compile_literal(lit),
1184
7
            ExprKind::Binary { left, op, right } => self.compile_binary_expr(left, op, right),
1185
3
            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
30
    }
1191
    
1192
    // Helper methods for DirectThreadedInterpreter compilation (complexity <10 each)
1193
    
1194
20
    fn compile_literal(&mut self, lit: &Literal) -> Result<(), InterpreterError> {
1195
20
        if 
matches!19
(lit, Literal::Unit) {
1196
1
            self.emit_instruction(op_load_nil, 0);
1197
19
        } else {
1198
19
            let const_idx = self.add_constant(self.literal_to_value(lit));
1199
19
            self.emit_instruction(op_load_const, const_idx);
1200
19
        }
1201
20
        Ok(())
1202
20
    }
1203
    
1204
7
    fn compile_binary_expr(&mut self, left: &Expr, op: &crate::frontend::ast::BinaryOp, right: &Expr) -> Result<(), InterpreterError> {
1205
7
        self.compile_expr(left)
?0
;
1206
7
        self.compile_expr(right)
?0
;
1207
        
1208
7
        let op_code = self.binary_op_to_opcode(op)
?0
;
1209
7
        self.emit_instruction(op_code, 0);
1210
7
        Ok(())
1211
7
    }
1212
    
1213
7
    fn binary_op_to_opcode(&self, op: &crate::frontend::ast::BinaryOp) -> Result<fn(&mut InterpreterState, u32) -> InstructionResult, InterpreterError> {
1214
7
        match op {
1215
3
            crate::frontend::ast::BinaryOp::Add => Ok(op_add),
1216
1
            crate::frontend::ast::BinaryOp::Subtract => Ok(op_sub),
1217
1
            crate::frontend::ast::BinaryOp::Multiply => Ok(op_mul),
1218
2
            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
7
    }
1225
    
1226
3
    fn compile_identifier(&mut self, name: &str) -> Result<(), InterpreterError> {
1227
3
        let name_idx = self.add_constant(Value::String(Rc::new(name.to_string())));
1228
3
        self.emit_instruction(op_load_var, name_idx);
1229
3
        Ok(())
1230
3
    }
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
27
    fn add_constant(&mut self, value: Value) -> u32 {
1279
27
        let idx = self.constants.len();
1280
27
        self.constants.push(value);
1281
27
        idx as u32
1282
27
    }
1283
1284
    /// Emit instruction to code stream
1285
49
    fn emit_instruction(
1286
49
        &mut self,
1287
49
        handler: fn(&mut InterpreterState, u32) -> InstructionResult,
1288
49
        operand: u32,
1289
49
    ) {
1290
49
        self.code.push(ThreadedInstruction { handler, operand });
1291
49
    }
1292
1293
    /// Convert literal to value
1294
19
    fn literal_to_value(&self, lit: &Literal) -> Value {
1295
19
        match lit {
1296
15
            Literal::Integer(n) => Value::Integer(*n),
1297
2
            Literal::Float(f) => Value::Float(*f),
1298
1
            Literal::Bool(b) => Value::Bool(*b),
1299
1
            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
19
    }
1304
1305
    /// Get instruction count
1306
11
    pub fn instruction_count(&self) -> usize {
1307
11
        self.code.len()
1308
11
    }
1309
1310
    /// Get constants count
1311
10
    pub fn constants_count(&self) -> usize {
1312
10
        self.constants.len()
1313
10
    }
1314
1315
    /// Add instruction to code stream (public interface for tests)
1316
3
    pub fn add_instruction(
1317
3
        &mut self,
1318
3
        handler: fn(&mut InterpreterState, u32) -> InstructionResult,
1319
3
        operand: u32,
1320
3
    ) {
1321
3
        self.emit_instruction(handler, operand);
1322
3
    }
1323
1324
    /// Clear all instructions and constants
1325
1
    pub fn clear(&mut self) {
1326
1
        self.code.clear();
1327
1
        self.constants.clear();
1328
1
        self.pc = 0;
1329
1
        self.state = InterpreterState::new();
1330
1
    }
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
1
    pub fn execute_with_state(
1339
1
        &mut self,
1340
1
        state: &mut InterpreterState,
1341
1
    ) -> Result<Value, InterpreterError> {
1342
1
        self.pc = 0;
1343
1344
        loop {
1345
            // Bounds check
1346
2
            if self.pc >= self.code.len() {
1347
0
                return Err(InterpreterError::RuntimeError(
1348
0
                    "PC out of bounds".to_string(),
1349
0
                ));
1350
2
            }
1351
1352
            // Direct function pointer call - no switch overhead
1353
2
            let instruction = &self.code[self.pc];
1354
2
            let result = (instruction.handler)(state, instruction.operand);
1355
1356
2
            match result {
1357
1
                InstructionResult::Continue => {
1358
1
                    self.pc += 1;
1359
1
                }
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
1
                InstructionResult::Return(value) => {
1369
1
                    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
1
            if self.pc.trailing_zeros() >= 10 {
1378
0
                // Could add interrupt checking here in the future
1379
1
            }
1380
        }
1381
1
    }
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
14
fn op_load_const(state: &mut InterpreterState, const_idx: u32) -> InstructionResult {
1394
14
    if let Some(value) = state.constants.get(const_idx as usize) {
1395
14
        state.stack.push(value.clone());
1396
14
        InstructionResult::Continue
1397
    } else {
1398
0
        InstructionResult::Error(InterpreterError::RuntimeError(
1399
0
            "Invalid constant index".to_string(),
1400
0
        ))
1401
    }
1402
14
}
1403
1404
/// Load nil onto stack
1405
1
fn op_load_nil(state: &mut InterpreterState, _operand: u32) -> InstructionResult {
1406
1
    state.stack.push(Value::Nil);
1407
1
    InstructionResult::Continue
1408
1
}
1409
1410
/// Load variable onto stack
1411
2
fn op_load_var(state: &mut InterpreterState, name_idx: u32) -> InstructionResult {
1412
2
    if let Some(Value::String(name)) = state.constants.get(name_idx as usize) {
1413
        // Search environments from innermost to outermost
1414
2
        for env in state.env_stack.iter().rev() {
1415
2
            if let Some(
value1
) = env.get(name.as_str()) {
1416
1
                state.stack.push(value.clone());
1417
1
                return InstructionResult::Continue;
1418
1
            }
1419
        }
1420
1
        InstructionResult::Error(InterpreterError::RuntimeError(format!(
1421
1
            "Undefined variable: {name}"
1422
1
        )))
1423
    } else {
1424
0
        InstructionResult::Error(InterpreterError::RuntimeError(
1425
0
            "Invalid variable name index".to_string(),
1426
0
        ))
1427
    }
1428
2
}
1429
1430
/// Binary add operation
1431
3
fn op_add(state: &mut InterpreterState, _operand: u32) -> InstructionResult {
1432
3
    binary_arithmetic_op(state, |a, b| match (a, b) {
1433
2
        (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
1
        (Value::Float(x), Value::Integer(y)) => Some(Value::Float(x + *y as f64)),
1437
0
        _ => None,
1438
3
    })
1439
3
}
1440
1441
/// Binary subtract operation
1442
1
fn op_sub(state: &mut InterpreterState, _operand: u32) -> InstructionResult {
1443
1
    binary_arithmetic_op(state, |a, b| match (a, b) {
1444
1
        (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
1
    })
1450
1
}
1451
1452
/// Binary multiply operation
1453
1
fn op_mul(state: &mut InterpreterState, _operand: u32) -> InstructionResult {
1454
1
    binary_arithmetic_op(state, |a, b| match (a, b) {
1455
1
        (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
1
    })
1461
1
}
1462
1463
/// Binary divide operation
1464
2
fn op_div(state: &mut InterpreterState, _operand: u32) -> InstructionResult {
1465
2
    binary_arithmetic_op(state, |a, b| match (a, b) {
1466
2
        (Value::Integer(x), Value::Integer(y)) => {
1467
2
            if *y == 0 {
1468
1
                return None; // Division by zero
1469
1
            }
1470
1
            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
2
    })
1492
2
}
1493
1494
/// Helper for binary arithmetic operations
1495
7
fn binary_arithmetic_op<F>(state: &mut InterpreterState, op: F) -> InstructionResult
1496
7
where
1497
7
    F: FnOnce(&Value, &Value) -> Option<Value>,
1498
{
1499
7
    if state.stack.len() < 2 {
1500
0
        return InstructionResult::Error(InterpreterError::StackUnderflow);
1501
7
    }
1502
1503
7
    let right = state.stack.pop().expect("Test should not fail");
1504
7
    let left = state.stack.pop().expect("Test should not fail");
1505
1506
7
    match op(&left, &right) {
1507
6
        Some(result) => {
1508
6
            state.stack.push(result);
1509
6
            InstructionResult::Continue
1510
        }
1511
1
        None => InstructionResult::Error(InterpreterError::TypeError(
1512
1
            "Invalid operand types".to_string(),
1513
1
        )),
1514
    }
1515
7
}
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
7
fn op_return(state: &mut InterpreterState, _operand: u32) -> InstructionResult {
1655
7
    if let Some(value) = state.stack.pop() {
1656
7
        InstructionResult::Return(value)
1657
    } else {
1658
0
        InstructionResult::Return(Value::Nil)
1659
    }
1660
7
}
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
289
    pub fn type_id(&self) -> std::any::TypeId {
1674
289
        match self {
1675
211
            Value::Integer(_) => std::any::TypeId::of::<i64>(),
1676
36
            Value::Float(_) => std::any::TypeId::of::<f64>(),
1677
9
            Value::Bool(_) => std::any::TypeId::of::<bool>(),
1678
0
            Value::Nil => std::any::TypeId::of::<()>(),
1679
19
            Value::String(_) => std::any::TypeId::of::<String>(),
1680
11
            Value::Array(_) => std::any::TypeId::of::<Vec<Value>>(),
1681
0
            Value::Tuple(_) => std::any::TypeId::of::<(Value,)>(),
1682
3
            Value::Closure { .. } => std::any::TypeId::of::<fn()>(),
1683
        }
1684
289
    }
1685
}
1686
1687
impl Interpreter {
1688
    /// Create new interpreter instance
1689
37
    pub fn new() -> Self {
1690
37
        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
37
        global_env.insert("format".to_string(), Value::String(Rc::new("__builtin_format__".to_string())));
1695
37
        global_env.insert("HashMap".to_string(), Value::String(Rc::new("__builtin_hashmap__".to_string())));
1696
        
1697
37
        Self {
1698
37
            stack: Vec::with_capacity(1024), // Pre-allocate stack
1699
37
            env_stack: vec![global_env], // Start with global environment containing builtins
1700
37
            frames: Vec::new(),
1701
37
            execution_counts: HashMap::new(),
1702
37
            field_caches: HashMap::new(),
1703
37
            type_feedback: TypeFeedback::new(),
1704
37
            gc: ConservativeGC::new(),
1705
37
        }
1706
37
    }
1707
1708
    /// Evaluate an AST expression directly
1709
    /// # Errors
1710
    /// Returns error if evaluation fails (type errors, runtime errors, etc.)
1711
297
    pub fn eval_expr(&mut self, expr: &Expr) -> Result<Value, InterpreterError> {
1712
297
        self.eval_expr_kind(&expr.kind)
1713
297
    }
1714
1715
    /// Evaluate an expression kind directly (main AST walker)
1716
    /// # Errors
1717
    /// Returns error if evaluation fails
1718
297
    fn eval_expr_kind(&mut self, expr_kind: &ExprKind) -> Result<Value, InterpreterError> {
1719
0
        match expr_kind {
1720
            // Basic expressions
1721
133
            ExprKind::Literal(lit) => Ok(self.eval_literal(lit)),
1722
53
            ExprKind::Identifier(name) => self.lookup_variable(name),
1723
            
1724
            // Operations and calls
1725
74
            ExprKind::Binary { left, op, right } => self.eval_binary_expr(left, *op, right),
1726
3
            ExprKind::Unary { op, operand } => self.eval_unary_expr(*op, operand),
1727
17
            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
3
            ExprKind::Function { name, params, body, .. } => self.eval_function(name, params, body),
1732
4
            ExprKind::Lambda { params, body } => self.eval_lambda(params, body),
1733
            
1734
            // Control flow expressions
1735
10
            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
297
    }
1753
    
1754
    // Helper methods for expression type categorization and evaluation (complexity <10 each)
1755
    
1756
10
    fn is_control_flow_expr(expr_kind: &ExprKind) -> bool {
1757
10
        
matches!0
(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
10
    }
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
10
    fn eval_control_flow_expr(&mut self, expr_kind: &ExprKind) -> Result<Value, InterpreterError> {
1786
10
        match expr_kind {
1787
6
            ExprKind::If { condition, then_branch, else_branch } => 
1788
6
                self.eval_if_expr(condition, then_branch, else_branch.as_deref()),
1789
4
            ExprKind::Let { name, value, body, .. } => 
1790
4
                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
10
    }
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
133
    fn eval_literal(&self, lit: &Literal) -> Value {
1838
133
        match lit {
1839
98
            Literal::Integer(i) => Value::from_i64(*i),
1840
24
            Literal::Float(f) => Value::from_f64(*f),
1841
2
            Literal::String(s) => Value::from_string(s.clone()),
1842
9
            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
133
    }
1847
1848
    /// Look up a variable in the environment (searches from innermost to outermost)
1849
54
    fn lookup_variable(&self, name: &str) -> Result<Value, InterpreterError> {
1850
64
        for env in 
self.env_stack.iter()54
.
rev54
() {
1851
64
            if let Some(
value54
) = env.get(name) {
1852
54
                return Ok(value.clone());
1853
10
            }
1854
        }
1855
0
        Err(InterpreterError::RuntimeError(format!(
1856
0
            "Undefined variable: {name}"
1857
0
        )))
1858
54
    }
1859
1860
    /// Get the current (innermost) environment
1861
    #[allow(clippy::expect_used)] // Environment stack invariant ensures this never panics
1862
7
    fn current_env(&self) -> &HashMap<String, Value> {
1863
7
        self.env_stack
1864
7
            .last()
1865
7
            .expect("Environment stack should never be empty")
1866
7
    }
1867
1868
    /// Set a variable in the current environment
1869
    #[allow(clippy::expect_used)] // Environment stack invariant ensures this never panics
1870
7
    fn env_set(&mut self, name: String, value: Value) {
1871
        // Record type feedback for optimization
1872
7
        self.record_variable_assignment_feedback(&name, &value);
1873
        
1874
7
        let env = self
1875
7
            .env_stack
1876
7
            .last_mut()
1877
7
            .expect("Environment stack should never be empty");
1878
7
        env.insert(name, value);
1879
7
    }
1880
1881
    /// Push a new environment onto the stack
1882
17
    fn env_push(&mut self, env: HashMap<String, Value>) {
1883
17
        self.env_stack.push(env);
1884
17
    }
1885
1886
    /// Pop the current environment from the stack
1887
17
    fn env_pop(&mut self) -> Option<HashMap<String, Value>> {
1888
17
        if self.env_stack.len() > 1 {
1889
            // Keep at least the global environment
1890
17
            self.env_stack.pop()
1891
        } else {
1892
0
            None
1893
        }
1894
17
    }
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
17
    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
17
            Value::Closure { params, body, env } => {
1941
                // Check argument count
1942
17
                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
17
                }
1949
1950
                // Create new environment with captured environment as base
1951
17
                let mut new_env = env.as_ref().clone();
1952
1953
                // Bind parameters to arguments
1954
17
                for (param, arg) in params.iter().zip(args) {
1955
17
                    new_env.insert(param.clone(), arg.clone());
1956
17
                }
1957
1958
                // Push new environment
1959
17
                self.env_push(new_env);
1960
1961
                // Evaluate function body
1962
17
                let result = self.eval_expr(&body);
1963
1964
                // Pop environment
1965
17
                self.env_pop();
1966
1967
17
                result
1968
            }
1969
0
            _ => Err(InterpreterError::TypeError(format!(
1970
0
                "Cannot call non-function value: {}",
1971
0
                func.type_name()
1972
0
            ))),
1973
        }
1974
17
    }
1975
1976
    /// Evaluate a binary operation from AST
1977
71
    fn eval_binary_op(
1978
71
        &self,
1979
71
        op: AstBinaryOp,
1980
71
        left: &Value,
1981
71
        right: &Value,
1982
71
    ) -> Result<Value, InterpreterError> {
1983
71
        match op {
1984
            AstBinaryOp::Add | AstBinaryOp::Subtract | AstBinaryOp::Multiply | 
1985
            AstBinaryOp::Divide | AstBinaryOp::Modulo | AstBinaryOp::Power => {
1986
64
                self.eval_arithmetic_op(op, left, right)
1987
            }
1988
            AstBinaryOp::Equal | AstBinaryOp::NotEqual | AstBinaryOp::Less | 
1989
            AstBinaryOp::Greater | AstBinaryOp::LessEqual | AstBinaryOp::GreaterEqual => {
1990
7
                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
71
    }
2000
    
2001
    /// Handle arithmetic operations (Add, Subtract, Multiply, Divide, Modulo, Power)
2002
64
    fn eval_arithmetic_op(
2003
64
        &self,
2004
64
        op: AstBinaryOp,
2005
64
        left: &Value,
2006
64
        right: &Value,
2007
64
    ) -> Result<Value, InterpreterError> {
2008
64
        match op {
2009
55
            AstBinaryOp::Add => self.add_values(left, right),
2010
4
            AstBinaryOp::Subtract => self.sub_values(left, right),
2011
5
            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
64
    }
2018
    
2019
    /// Handle comparison operations (Equal, `NotEqual`, Less, Greater, `LessEqual`, `GreaterEqual`)
2020
7
    fn eval_comparison_op(
2021
7
        &self,
2022
7
        op: AstBinaryOp,
2023
7
        left: &Value,
2024
7
        right: &Value,
2025
7
    ) -> Result<Value, InterpreterError> {
2026
7
        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
1
            AstBinaryOp::Less => Ok(Value::from_bool(self.less_than_values(left, right)
?0
)),
2030
1
            AstBinaryOp::Greater => Ok(Value::from_bool(self.greater_than_values(left, right)
?0
)),
2031
            AstBinaryOp::LessEqual => {
2032
5
                let less = self.less_than_values(left, right)
?0
;
2033
5
                let equal = self.equal_values(left, right);
2034
5
                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
7
    }
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
3
    fn eval_unary_op(
2075
3
        &self,
2076
3
        op: crate::frontend::ast::UnaryOp,
2077
3
        operand: &Value,
2078
3
    ) -> Result<Value, InterpreterError> {
2079
        use crate::frontend::ast::UnaryOp;
2080
3
        match op {
2081
2
            UnaryOp::Negate => match operand {
2082
2
                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
1
            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
3
    }
2095
2096
    /// Evaluate binary expression
2097
74
    fn eval_binary_expr(
2098
74
        &mut self,
2099
74
        left: &Expr,
2100
74
        op: crate::frontend::ast::BinaryOp,
2101
74
        right: &Expr,
2102
74
    ) -> Result<Value, InterpreterError> {
2103
        // Handle short-circuit operators
2104
74
        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
2
                let left_val = self.eval_expr(left)
?0
;
2115
2
                if left_val.is_truthy() {
2116
2
                    self.eval_expr(right)
2117
                } else {
2118
0
                    Ok(left_val)
2119
                }
2120
            }
2121
            crate::frontend::ast::BinaryOp::Or => {
2122
1
                let left_val = self.eval_expr(left)
?0
;
2123
1
                if left_val.is_truthy() {
2124
0
                    Ok(left_val)
2125
                } else {
2126
1
                    self.eval_expr(right)
2127
                }
2128
            }
2129
            _ => {
2130
71
                let left_val = self.eval_expr(left)
?0
;
2131
71
                let right_val = self.eval_expr(right)
?0
;
2132
71
                let result = self.eval_binary_op(op, &left_val, &right_val)
?0
;
2133
                
2134
                // Record type feedback for optimization
2135
71
                let site_id = left.span.start; // Use span start as site ID
2136
71
                self.record_binary_op_feedback(site_id, &left_val, &right_val, &result);
2137
                
2138
71
                Ok(result)
2139
            }
2140
        }
2141
74
    }
2142
2143
    /// Evaluate unary expression
2144
3
    fn eval_unary_expr(
2145
3
        &mut self,
2146
3
        op: crate::frontend::ast::UnaryOp,
2147
3
        operand: &Expr,
2148
3
    ) -> Result<Value, InterpreterError> {
2149
3
        let operand_val = self.eval_expr(operand)
?0
;
2150
3
        self.eval_unary_op(op, &operand_val)
2151
3
    }
2152
2153
    /// Evaluate if expression
2154
6
    fn eval_if_expr(
2155
6
        &mut self,
2156
6
        condition: &Expr,
2157
6
        then_branch: &Expr,
2158
6
        else_branch: Option<&Expr>,
2159
6
    ) -> Result<Value, InterpreterError> {
2160
6
        let condition_val = self.eval_expr(condition)
?0
;
2161
6
        if condition_val.is_truthy() {
2162
2
            self.eval_expr(then_branch)
2163
4
        } else if let Some(else_expr) = else_branch {
2164
4
            self.eval_expr(else_expr)
2165
        } else {
2166
0
            Ok(Value::nil())
2167
        }
2168
6
    }
2169
2170
    /// Evaluate let expression
2171
4
    fn eval_let_expr(
2172
4
        &mut self,
2173
4
        name: &str,
2174
4
        value: &Expr,
2175
4
        body: &Expr,
2176
4
    ) -> Result<Value, InterpreterError> {
2177
4
        let val = self.eval_expr(value)
?0
;
2178
4
        self.env_set(name.to_string(), val);
2179
4
        self.eval_expr(body)
2180
4
    }
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
5
    pub fn eval_string(&mut self, input: &str) -> Result<Value, Box<dyn std::error::Error>> {
2249
        use crate::frontend::parser::Parser;
2250
2251
5
        let mut parser = Parser::new(input);
2252
5
        let expr = parser.parse_expr()
?0
;
2253
2254
5
        Ok(self.eval_expr(&expr)
?0
)
2255
5
    }
2256
2257
    /// Push value onto stack
2258
    /// # Errors
2259
    /// Returns error if stack overflow occurs
2260
13
    pub fn push(&mut self, value: Value) -> Result<(), InterpreterError> {
2261
13
        if self.stack.len() >= 10_000 {
2262
            // Stack limit from spec
2263
0
            return Err(InterpreterError::StackOverflow);
2264
13
        }
2265
13
        self.stack.push(value);
2266
13
        Ok(())
2267
13
    }
2268
2269
    /// Pop value from stack
2270
    /// # Errors
2271
    /// Returns error if stack underflow occurs
2272
13
    pub fn pop(&mut self) -> Result<Value, InterpreterError> {
2273
13
        self.stack.pop().ok_or(InterpreterError::StackUnderflow)
2274
13
    }
2275
2276
    /// Peek at top of stack without popping
2277
    /// # Errors
2278
    /// Returns error if stack underflow occurs
2279
2
    pub fn peek(&self, depth: usize) -> Result<Value, InterpreterError> {
2280
2
        let index = self
2281
2
            .stack
2282
2
            .len()
2283
2
            .checked_sub(depth + 1)
2284
2
            .ok_or(InterpreterError::StackUnderflow)
?0
;
2285
2
        Ok(self.stack[index].clone())
2286
2
    }
2287
2288
    /// Binary arithmetic operation with type checking
2289
    /// # Errors
2290
    /// Returns error if stack underflow, type mismatch, or arithmetic error occurs
2291
4
    pub fn binary_op(&mut self, op: BinaryOp) -> Result<(), InterpreterError> {
2292
4
        let right = self.pop()
?0
;
2293
4
        let left = self.pop()
?0
;
2294
2295
4
        let 
result3
= match op {
2296
2
            BinaryOp::Add => self.add_values(&left, &right)
?0
,
2297
0
            BinaryOp::Sub => self.sub_values(&left, &right)?,
2298
0
            BinaryOp::Mul => self.mul_values(&left, &right)?,
2299
1
            BinaryOp::Div => self.div_values(&left, &right)?,
2300
0
            BinaryOp::Eq => Value::from_bool(self.equal_values(&left, &right)),
2301
1
            BinaryOp::Lt => Value::from_bool(self.less_than_values(&left, &right)
?0
),
2302
0
            BinaryOp::Gt => Value::from_bool(self.greater_than_values(&left, &right)?),
2303
        };
2304
2305
3
        self.push(result)
?0
;
2306
3
        Ok(())
2307
4
    }
2308
2309
    /// Add two values with type coercion
2310
57
    fn add_values(&self, left: &Value, right: &Value) -> Result<Value, InterpreterError> {
2311
57
        match (left, right) {
2312
44
            (Value::Integer(a), Value::Integer(b)) => Ok(Value::from_i64(a + b)),
2313
12
            (Value::Float(a), Value::Float(b)) => Ok(Value::from_f64(a + b)),
2314
1
            (Value::Integer(a), Value::Float(b)) =>
2315
            {
2316
                #[allow(clippy::cast_precision_loss)]
2317
1
                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
57
    }
2334
2335
    /// Subtract two values
2336
4
    fn sub_values(&self, left: &Value, right: &Value) -> Result<Value, InterpreterError> {
2337
4
        match (left, right) {
2338
4
            (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
4
    }
2357
2358
    /// Multiply two values
2359
5
    fn mul_values(&self, left: &Value, right: &Value) -> Result<Value, InterpreterError> {
2360
5
        match (left, right) {
2361
5
            (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
5
    }
2380
2381
    /// Divide two values
2382
1
    fn div_values(&self, left: &Value, right: &Value) -> Result<Value, InterpreterError> {
2383
1
        match (left, right) {
2384
1
            (Value::Integer(a), Value::Integer(b)) => {
2385
1
                if *b == 0 {
2386
1
                    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
1
    }
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
5
    fn equal_values(&self, left: &Value, right: &Value) -> bool {
2497
5
        left == right // PartialEq is derived for Value
2498
5
    }
2499
2500
    /// Check if left < right
2501
7
    fn less_than_values(&self, left: &Value, right: &Value) -> Result<bool, InterpreterError> {
2502
7
        match (left, right) {
2503
7
            (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
7
    }
2522
2523
    /// Check if left > right
2524
1
    fn greater_than_values(&self, left: &Value, right: &Value) -> Result<bool, InterpreterError> {
2525
1
        match (left, right) {
2526
1
            (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
1
    }
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
18
    pub fn get_field_cached(
2666
18
        &mut self,
2667
18
        obj: &Value,
2668
18
        field_name: &str,
2669
18
    ) -> Result<Value, InterpreterError> {
2670
        // Create cache key combining object type and field name
2671
18
        let cache_key = format!("{:?}::{}", obj.type_id(), field_name);
2672
2673
        // Check inline cache first
2674
18
        if let Some(
cache4
) = self.field_caches.get_mut(&cache_key) {
2675
4
            if let Some(cached_result) = cache.lookup(obj, field_name) {
2676
4
                return Ok(cached_result);
2677
0
            }
2678
14
        }
2679
2680
        // Cache miss - compute result and update cache
2681
14
        let 
result12
= self.compute_field_access(obj, field_name)
?2
;
2682
2683
        // Update or create cache entry
2684
12
        let cache = self.field_caches.entry(cache_key).or_default();
2685
12
        cache.insert(obj, field_name.to_string(), result.clone());
2686
2687
12
        Ok(result)
2688
18
    }
2689
2690
    /// Compute field access result (detailed path)
2691
14
    fn compute_field_access(
2692
14
        &self,
2693
14
        obj: &Value,
2694
14
        field_name: &str,
2695
14
    ) -> Result<Value, InterpreterError> {
2696
14
        match (obj, field_name) {
2697
            // String methods
2698
6
            (Value::String(
s3
), "len") =>
Ok(Value::Integer(3
s.len()3
.try_into().unwrap_or(i64::MAX))),
2699
3
            (Value::String(
s1
), "to_upper") =>
Ok(Value::String(1
Rc::new1
(s.to_uppercase()))),
2700
2
            (Value::String(
s0
), "to_lower") =>
Ok(Value::String(0
Rc::new0
(s.to_lowercase()))),
2701
2
            (Value::String(
s1
), "trim") =>
Ok(Value::String(1
Rc::new1
(s.trim().to_string()))),
2702
2703
            // Array methods
2704
5
            (Value::Array(
arr2
), "len") => {
2705
2
                Ok(Value::Integer(arr.len().try_into().unwrap_or(i64::MAX)))
2706
            }
2707
3
            (Value::Array(
arr2
), "first") => arr
2708
2
                .first()
2709
2
                .cloned()
2710
2
                .ok_or_else(|| InterpreterError::RuntimeError(
"Array is empty"1
.
to_string1
())),
2711
1
            (Value::Array(arr), "last") => arr
2712
1
                .last()
2713
1
                .cloned()
2714
1
                .ok_or_else(|| InterpreterError::RuntimeError(
"Array is empty"0
.
to_string0
())),
2715
0
            (Value::Array(arr), "is_empty") => {
2716
0
                Ok(Value::from_bool(arr.is_empty()))
2717
            }
2718
2719
            // Type information
2720
4
            (
obj3
, "type") =>
Ok(Value::String(3
Rc::new3
(obj.type_name().to_string()))),
2721
2722
1
            _ => Err(InterpreterError::RuntimeError(format!(
2723
1
                "Field '{}' not found on type '{}'",
2724
1
                field_name,
2725
1
                obj.type_name()
2726
1
            ))),
2727
        }
2728
14
    }
2729
2730
    /// Get inline cache statistics for profiling
2731
5
    pub fn get_cache_stats(&self) -> HashMap<String, f64> {
2732
5
        let mut stats = HashMap::new();
2733
9
        for (
key4
,
cache4
) in &self.field_caches {
2734
4
            stats.insert(key.clone(), cache.hit_rate());
2735
4
        }
2736
5
        stats
2737
5
    }
2738
2739
    /// Clear all inline caches (for testing)
2740
1
    pub fn clear_caches(&mut self) {
2741
1
        self.field_caches.clear();
2742
1
    }
2743
2744
    /// Record type feedback for binary operations
2745
    #[allow(dead_code)] // Used by tests and type feedback system
2746
71
    fn record_binary_op_feedback(
2747
71
        &mut self,
2748
71
        site_id: usize,
2749
71
        left: &Value,
2750
71
        right: &Value,
2751
71
        result: &Value,
2752
71
    ) {
2753
71
        self.type_feedback
2754
71
            .record_binary_op(site_id, left, right, result);
2755
71
    }
2756
2757
    /// Record type feedback for variable assignments
2758
    #[allow(dead_code)] // Used by tests and type feedback system
2759
7
    fn record_variable_assignment_feedback(&mut self, var_name: &str, value: &Value) {
2760
7
        let type_id = value.type_id();
2761
7
        self.type_feedback
2762
7
            .record_variable_assignment(var_name, type_id);
2763
7
    }
2764
2765
    /// Record type feedback for function calls
2766
17
    fn record_function_call_feedback(
2767
17
        &mut self,
2768
17
        site_id: usize,
2769
17
        func_name: &str,
2770
17
        args: &[Value],
2771
17
        result: &Value,
2772
17
    ) {
2773
17
        self.type_feedback
2774
17
            .record_function_call(site_id, func_name, args, result);
2775
17
    }
2776
2777
    /// Get type feedback statistics
2778
6
    pub fn get_type_feedback_stats(&self) -> TypeFeedbackStats {
2779
6
        self.type_feedback.get_statistics()
2780
6
    }
2781
2782
    /// Get specialization candidates for JIT compilation
2783
4
    pub fn get_specialization_candidates(&self) -> Vec<SpecializationCandidate> {
2784
4
        self.type_feedback.get_specialization_candidates()
2785
4
    }
2786
2787
    /// Clear type feedback data (for testing)
2788
1
    pub fn clear_type_feedback(&mut self) {
2789
1
        self.type_feedback = TypeFeedback::new();
2790
1
    }
2791
2792
    /// Track a value in the garbage collector
2793
22
    pub fn gc_track(&mut self, value: Value) -> usize {
2794
22
        self.gc.track_object(value)
2795
22
    }
2796
2797
    /// Force garbage collection
2798
1
    pub fn gc_collect(&mut self) -> GCStats {
2799
1
        self.gc.force_collect()
2800
1
    }
2801
2802
    /// Get garbage collection statistics
2803
1
    pub fn gc_stats(&self) -> GCStats {
2804
1
        self.gc.get_stats()
2805
1
    }
2806
2807
    /// Get detailed garbage collection information
2808
11
    pub fn gc_info(&self) -> GCInfo {
2809
11
        self.gc.get_info()
2810
11
    }
2811
2812
    /// Set garbage collection threshold
2813
2
    pub fn gc_set_threshold(&mut self, threshold: usize) {
2814
2
        self.gc.set_collection_threshold(threshold);
2815
2
    }
2816
2817
    /// Enable or disable automatic garbage collection
2818
4
    pub fn gc_set_auto_collect(&mut self, enabled: bool) {
2819
4
        self.gc.set_auto_collect(enabled);
2820
4
    }
2821
2822
    /// Clear all GC-tracked objects (for testing)
2823
1
    pub fn gc_clear(&mut self) {
2824
1
        self.gc.clear();
2825
1
    }
2826
2827
    /// Allocate a new array and track it in GC
2828
1
    pub fn gc_alloc_array(&mut self, elements: Vec<Value>) -> Value {
2829
1
        let array_value = Value::Array(Rc::new(elements));
2830
1
        self.gc.track_object(array_value.clone());
2831
1
        array_value
2832
1
    }
2833
2834
    /// Allocate a new string and track it in GC
2835
1
    pub fn gc_alloc_string(&mut self, content: String) -> Value {
2836
1
        let string_value = Value::String(Rc::new(content));
2837
1
        self.gc.track_object(string_value.clone());
2838
1
        string_value
2839
1
    }
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
3
    fn eval_function(&mut self, name: &str, params: &[Param], body: &Expr) -> Result<Value, InterpreterError> {
3254
3
        let param_names: Vec<String> = params
3255
3
            .iter()
3256
3
            .map(crate::frontend::ast::Param::name)
3257
3
            .collect();
3258
3259
3
        let closure = Value::Closure {
3260
3
            params: param_names,
3261
3
            body: Rc::new(body.clone()),
3262
3
            env: Rc::new(self.current_env().clone()),
3263
3
        };
3264
3265
        // Bind function name in environment for recursion
3266
3
        self.env_set(name.to_string(), closure.clone());
3267
3
        Ok(closure)
3268
3
    }
3269
    
3270
    /// Evaluate lambda expression
3271
4
    fn eval_lambda(&mut self, params: &[Param], body: &Expr) -> Result<Value, InterpreterError> {
3272
4
        let param_names: Vec<String> = params
3273
4
            .iter()
3274
4
            .map(crate::frontend::ast::Param::name)
3275
4
            .collect();
3276
3277
4
        let closure = Value::Closure {
3278
4
            params: param_names,
3279
4
            body: Rc::new(body.clone()),
3280
4
            env: Rc::new(self.current_env().clone()),
3281
4
        };
3282
3283
4
        Ok(closure)
3284
4
    }
3285
    
3286
    /// Evaluate function call
3287
17
    fn eval_function_call(&mut self, func: &Expr, args: &[Expr]) -> Result<Value, InterpreterError> {
3288
17
        let func_val = self.eval_expr(func)
?0
;
3289
17
        let arg_vals: Result<Vec<Value>, InterpreterError> =
3290
17
            args.iter().map(|arg| self.eval_expr(arg)).collect();
3291
17
        let arg_vals = arg_vals
?0
;
3292
3293
17
        let result = self.call_function(func_val, &arg_vals)
?0
;
3294
3295
        // Collect type feedback for function call
3296
17
        let site_id = func.span.start; // Use func span start as site ID
3297
17
        let func_name = match &func.kind {
3298
15
            ExprKind::Identifier(name) => name.clone(),
3299
2
            _ => "anonymous".to_string(),
3300
        };
3301
17
        self.record_function_call_feedback(site_id, &func_name, &arg_vals, &result);
3302
17
        Ok(result)
3303
17
    }
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
1
    fn test_value_creation() {
3335
1
        let int_val = Value::from_i64(42);
3336
1
        assert_eq!(int_val.as_i64().expect("Should be integer"), 42);
3337
1
        assert_eq!(int_val.type_name(), "integer");
3338
3339
1
        let bool_val = Value::from_bool(true);
3340
1
        assert_eq!(bool_val.as_bool().expect("Should be boolean"), true);
3341
1
        assert_eq!(bool_val.type_name(), "boolean");
3342
3343
1
        let nil_val = Value::nil();
3344
1
        assert!(nil_val.is_nil());
3345
1
        assert_eq!(nil_val.type_name(), "nil");
3346
3347
1
        let float_val = Value::from_f64(3.14);
3348
1
        let f_value = float_val.as_f64().expect("Should be float");
3349
1
        assert!((f_value - 3.14).abs() < f64::EPSILON);
3350
1
        assert_eq!(float_val.type_name(), "float");
3351
3352
1
        let string_val = Value::from_string("hello".to_string());
3353
1
        assert_eq!(string_val.type_name(), "string");
3354
1
    }
3355
3356
    #[test]
3357
1
    fn test_arithmetic() {
3358
1
        let mut interp = Interpreter::new();
3359
3360
        // Test 2 + 3 = 5
3361
1
        assert!(interp.push(Value::from_i64(2)).is_ok());
3362
1
        assert!(interp.push(Value::from_i64(3)).is_ok());
3363
1
        assert!(interp.binary_op(BinaryOp::Add).is_ok());
3364
3365
1
        let result = interp.pop().expect("Stack should not be empty");
3366
1
        assert_eq!(result, Value::Integer(5));
3367
1
    }
3368
3369
    #[test]
3370
1
    fn test_mixed_arithmetic() {
3371
1
        let mut interp = Interpreter::new();
3372
3373
        // Test 2 + 3.5 = 5.5 (int + float -> float)
3374
1
        assert!(interp.push(Value::from_i64(2)).is_ok());
3375
1
        assert!(interp.push(Value::from_f64(3.5)).is_ok());
3376
1
        assert!(interp.binary_op(BinaryOp::Add).is_ok());
3377
3378
1
        let result = interp.pop().expect("Stack should not be empty");
3379
1
        match result {
3380
1
            Value::Float(f) => assert!((f - 5.5).abs() < f64::EPSILON),
3381
0
            _ => unreachable!("Expected float, got {result:?}"),
3382
        }
3383
1
    }
3384
3385
    #[test]
3386
1
    fn test_division_by_zero() {
3387
1
        let mut interp = Interpreter::new();
3388
3389
1
        assert!(interp.push(Value::from_i64(10)).is_ok());
3390
1
        assert!(interp.push(Value::from_i64(0)).is_ok());
3391
3392
1
        let result = interp.binary_op(BinaryOp::Div);
3393
1
        assert!(
matches!0
(result, Err(InterpreterError::DivisionByZero)));
3394
1
    }
3395
3396
    #[test]
3397
1
    fn test_comparison() {
3398
1
        let mut interp = Interpreter::new();
3399
3400
        // Test 5 < 10
3401
1
        assert!(interp.push(Value::from_i64(5)).is_ok());
3402
1
        assert!(interp.push(Value::from_i64(10)).is_ok());
3403
1
        assert!(interp.binary_op(BinaryOp::Lt).is_ok());
3404
3405
1
        let result = interp.pop().expect("Stack should not be empty");
3406
1
        assert_eq!(result, Value::Bool(true));
3407
1
    }
3408
3409
    #[test]
3410
1
    fn test_stack_operations() {
3411
1
        let mut interp = Interpreter::new();
3412
3413
1
        let val1 = Value::from_i64(42);
3414
1
        let val2 = Value::from_bool(true);
3415
3416
1
        assert!(interp.push(val1.clone()).is_ok());
3417
1
        assert!(interp.push(val2.clone()).is_ok());
3418
3419
1
        assert_eq!(interp.peek(0).expect("Should peek at top"), val2);
3420
1
        assert_eq!(interp.peek(1).expect("Should peek at second"), val1);
3421
3422
1
        assert_eq!(interp.pop().expect("Should pop top"), val2);
3423
1
        assert_eq!(interp.pop().expect("Should pop second"), val1);
3424
1
    }
3425
3426
    #[test]
3427
1
    fn test_truthiness() {
3428
1
        assert!(Value::from_i64(42).is_truthy());
3429
1
        assert!(Value::from_bool(true).is_truthy());
3430
1
        assert!(!Value::from_bool(false).is_truthy());
3431
1
        assert!(!Value::nil().is_truthy());
3432
1
        assert!(Value::from_f64(std::f64::consts::PI).is_truthy());
3433
1
        assert!(Value::from_f64(0.0).is_truthy()); // 0.0 is truthy in Ruchy
3434
1
        assert!(Value::from_string("hello".to_string()).is_truthy());
3435
1
    }
3436
3437
    // AST Walker tests
3438
3439
    #[test]
3440
1
    fn test_eval_literal() {
3441
1
        let mut interp = Interpreter::new();
3442
3443
        // Test integer literal
3444
1
        let int_expr = Expr::new(ExprKind::Literal(Literal::Integer(42)), Span::new(0, 2));
3445
1
        let result = interp
3446
1
            .eval_expr(&int_expr)
3447
1
            .expect("Should evaluate integer");
3448
1
        assert_eq!(result, Value::Integer(42));
3449
3450
        // Test string literal
3451
1
        let str_expr = Expr::new(
3452
1
            ExprKind::Literal(Literal::String("hello".to_string())),
3453
1
            Span::new(0, 7),
3454
        );
3455
1
        let result = interp.eval_expr(&str_expr).expect("Should evaluate string");
3456
1
        assert_eq!(result.type_name(), "string");
3457
3458
        // Test boolean literal
3459
1
        let bool_expr = Expr::new(ExprKind::Literal(Literal::Bool(true)), Span::new(0, 4));
3460
1
        let result = interp
3461
1
            .eval_expr(&bool_expr)
3462
1
            .expect("Should evaluate boolean");
3463
1
        assert_eq!(result, Value::Bool(true));
3464
1
    }
3465
3466
    #[test]
3467
1
    fn test_eval_binary_arithmetic() {
3468
1
        let mut interp = Interpreter::new();
3469
3470
        // Test 5 + 3 = 8
3471
1
        let left = Box::new(Expr::new(
3472
1
            ExprKind::Literal(Literal::Integer(5)),
3473
1
            Span::new(0, 1),
3474
        ));
3475
1
        let right = Box::new(Expr::new(
3476
1
            ExprKind::Literal(Literal::Integer(3)),
3477
1
            Span::new(4, 5),
3478
        ));
3479
1
        let add_expr = Expr::new(
3480
1
            ExprKind::Binary {
3481
1
                left,
3482
1
                op: AstBinaryOp::Add,
3483
1
                right,
3484
1
            },
3485
1
            Span::new(0, 5),
3486
        );
3487
3488
1
        let result = interp
3489
1
            .eval_expr(&add_expr)
3490
1
            .expect("Should evaluate addition");
3491
1
        assert_eq!(result, Value::Integer(8));
3492
1
    }
3493
3494
    #[test]
3495
1
    fn test_eval_binary_comparison() {
3496
1
        let mut interp = Interpreter::new();
3497
3498
        // Test 5 < 10 = true
3499
1
        let left = Box::new(Expr::new(
3500
1
            ExprKind::Literal(Literal::Integer(5)),
3501
1
            Span::new(0, 1),
3502
        ));
3503
1
        let right = Box::new(Expr::new(
3504
1
            ExprKind::Literal(Literal::Integer(10)),
3505
1
            Span::new(4, 6),
3506
        ));
3507
1
        let cmp_expr = Expr::new(
3508
1
            ExprKind::Binary {
3509
1
                left,
3510
1
                op: AstBinaryOp::Less,
3511
1
                right,
3512
1
            },
3513
1
            Span::new(0, 6),
3514
        );
3515
3516
1
        let result = interp
3517
1
            .eval_expr(&cmp_expr)
3518
1
            .expect("Should evaluate comparison");
3519
1
        assert_eq!(result, Value::Bool(true));
3520
1
    }
3521
3522
    #[test]
3523
1
    fn test_eval_unary_operations() {
3524
1
        let mut interp = Interpreter::new();
3525
3526
        // Test -42 = -42
3527
1
        let operand = Box::new(Expr::new(
3528
1
            ExprKind::Literal(Literal::Integer(42)),
3529
1
            Span::new(1, 3),
3530
        ));
3531
1
        let neg_expr = Expr::new(
3532
1
            ExprKind::Unary {
3533
1
                op: crate::frontend::ast::UnaryOp::Negate,
3534
1
                operand,
3535
1
            },
3536
1
            Span::new(0, 3),
3537
        );
3538
3539
1
        let result = interp
3540
1
            .eval_expr(&neg_expr)
3541
1
            .expect("Should evaluate negation");
3542
1
        assert_eq!(result, Value::Integer(-42));
3543
3544
        // Test !true = false
3545
1
        let operand = Box::new(Expr::new(
3546
1
            ExprKind::Literal(Literal::Bool(true)),
3547
1
            Span::new(1, 5),
3548
        ));
3549
1
        let not_expr = Expr::new(
3550
1
            ExprKind::Unary {
3551
1
                op: crate::frontend::ast::UnaryOp::Not,
3552
1
                operand,
3553
1
            },
3554
1
            Span::new(0, 5),
3555
        );
3556
3557
1
        let result = interp
3558
1
            .eval_expr(&not_expr)
3559
1
            .expect("Should evaluate logical not");
3560
1
        assert_eq!(result, Value::Bool(false));
3561
1
    }
3562
3563
    #[test]
3564
1
    fn test_eval_if_expression() {
3565
1
        let mut interp = Interpreter::new();
3566
3567
        // Test if true then 1 else 2 = 1
3568
1
        let condition = Box::new(Expr::new(
3569
1
            ExprKind::Literal(Literal::Bool(true)),
3570
1
            Span::new(3, 7),
3571
        ));
3572
1
        let then_branch = Box::new(Expr::new(
3573
1
            ExprKind::Literal(Literal::Integer(1)),
3574
1
            Span::new(13, 14),
3575
        ));
3576
1
        let else_branch = Some(Box::new(Expr::new(
3577
1
            ExprKind::Literal(Literal::Integer(2)),
3578
1
            Span::new(20, 21),
3579
1
        )));
3580
3581
1
        let if_expr = Expr::new(
3582
1
            ExprKind::If {
3583
1
                condition,
3584
1
                then_branch,
3585
1
                else_branch,
3586
1
            },
3587
1
            Span::new(0, 21),
3588
        );
3589
3590
1
        let result = interp
3591
1
            .eval_expr(&if_expr)
3592
1
            .expect("Should evaluate if expression");
3593
1
        assert_eq!(result, Value::Integer(1));
3594
1
    }
3595
3596
    #[test]
3597
1
    fn test_eval_let_expression() {
3598
1
        let mut interp = Interpreter::new();
3599
3600
        // Test let x = 5 in x + 2 = 7
3601
1
        let value = Box::new(Expr::new(
3602
1
            ExprKind::Literal(Literal::Integer(5)),
3603
1
            Span::new(8, 9),
3604
        ));
3605
3606
1
        let left = Box::new(Expr::new(
3607
1
            ExprKind::Identifier("x".to_string()),
3608
1
            Span::new(13, 14),
3609
        ));
3610
1
        let right = Box::new(Expr::new(
3611
1
            ExprKind::Literal(Literal::Integer(2)),
3612
1
            Span::new(17, 18),
3613
        ));
3614
1
        let body = Box::new(Expr::new(
3615
1
            ExprKind::Binary {
3616
1
                left,
3617
1
                op: AstBinaryOp::Add,
3618
1
                right,
3619
1
            },
3620
1
            Span::new(13, 18),
3621
        ));
3622
3623
1
        let let_expr = Expr::new(
3624
1
            ExprKind::Let {
3625
1
                name: "x".to_string(),
3626
1
                type_annotation: None,
3627
1
                value,
3628
1
                body,
3629
1
                is_mutable: false,
3630
1
            },
3631
1
            Span::new(0, 18),
3632
        );
3633
3634
1
        let result = interp
3635
1
            .eval_expr(&let_expr)
3636
1
            .expect("Should evaluate let expression");
3637
1
        assert_eq!(result, Value::Integer(7));
3638
1
    }
3639
3640
    #[test]
3641
1
    fn test_eval_logical_operators() {
3642
1
        let mut interp = Interpreter::new();
3643
3644
        // Test true && false = false (short-circuit)
3645
1
        let left = Box::new(Expr::new(
3646
1
            ExprKind::Literal(Literal::Bool(true)),
3647
1
            Span::new(0, 4),
3648
        ));
3649
1
        let right = Box::new(Expr::new(
3650
1
            ExprKind::Literal(Literal::Bool(false)),
3651
1
            Span::new(8, 13),
3652
        ));
3653
1
        let and_expr = Expr::new(
3654
1
            ExprKind::Binary {
3655
1
                left,
3656
1
                op: AstBinaryOp::And,
3657
1
                right,
3658
1
            },
3659
1
            Span::new(0, 13),
3660
        );
3661
3662
1
        let result = interp
3663
1
            .eval_expr(&and_expr)
3664
1
            .expect("Should evaluate logical AND");
3665
1
        assert_eq!(result, Value::Bool(false));
3666
3667
        // Test false || true = true (short-circuit)
3668
1
        let left = Box::new(Expr::new(
3669
1
            ExprKind::Literal(Literal::Bool(false)),
3670
1
            Span::new(0, 5),
3671
        ));
3672
1
        let right = Box::new(Expr::new(
3673
1
            ExprKind::Literal(Literal::Bool(true)),
3674
1
            Span::new(9, 13),
3675
        ));
3676
1
        let or_expr = Expr::new(
3677
1
            ExprKind::Binary {
3678
1
                left,
3679
1
                op: AstBinaryOp::Or,
3680
1
                right,
3681
1
            },
3682
1
            Span::new(0, 13),
3683
        );
3684
3685
1
        let result = interp
3686
1
            .eval_expr(&or_expr)
3687
1
            .expect("Should evaluate logical OR");
3688
1
        assert_eq!(result, Value::Bool(true));
3689
1
    }
3690
3691
    #[test]
3692
1
    fn test_parser_integration() {
3693
1
        let mut interp = Interpreter::new();
3694
3695
        // Test simple arithmetic: 2 + 3 * 4 = 14
3696
1
        let result = interp
3697
1
            .eval_string("2 + 3 * 4")
3698
1
            .expect("Should parse and evaluate");
3699
1
        assert_eq!(result, Value::Integer(14));
3700
3701
        // Test comparison: 5 > 3 = true
3702
1
        let result = interp
3703
1
            .eval_string("5 > 3")
3704
1
            .expect("Should parse and evaluate");
3705
1
        assert_eq!(result, Value::Bool(true));
3706
3707
        // Test boolean literals: true && false = false
3708
1
        let result = interp
3709
1
            .eval_string("true && false")
3710
1
            .expect("Should parse and evaluate");
3711
1
        assert_eq!(result, Value::Bool(false));
3712
3713
        // Test unary operations: -42 = -42
3714
1
        let result = interp
3715
1
            .eval_string("-42")
3716
1
            .expect("Should parse and evaluate");
3717
1
        assert_eq!(result, Value::Integer(-42));
3718
3719
        // Test string literals
3720
1
        let result = interp
3721
1
            .eval_string(r#""hello""#)
3722
1
            .expect("Should parse and evaluate");
3723
1
        assert_eq!(result.type_name(), "string");
3724
1
    }
3725
3726
    #[test]
3727
1
    fn test_eval_lambda() {
3728
        use crate::frontend::ast::{Pattern, Type, TypeKind};
3729
1
        let mut interp = Interpreter::new();
3730
3731
        // Test lambda: |x| x + 1
3732
1
        let param = Param {
3733
1
            pattern: Pattern::Identifier("x".to_string()),
3734
1
            ty: Type {
3735
1
                kind: TypeKind::Named("i32".to_string()),
3736
1
                span: Span::new(0, 3),
3737
1
            },
3738
1
            span: Span::new(0, 1),
3739
1
            is_mutable: false,
3740
1
            default_value: None,
3741
1
        };
3742
3743
1
        let left = Box::new(Expr::new(
3744
1
            ExprKind::Identifier("x".to_string()),
3745
1
            Span::new(0, 1),
3746
        ));
3747
1
        let right = Box::new(Expr::new(
3748
1
            ExprKind::Literal(Literal::Integer(1)),
3749
1
            Span::new(4, 5),
3750
        ));
3751
1
        let body = Box::new(Expr::new(
3752
1
            ExprKind::Binary {
3753
1
                left,
3754
1
                op: AstBinaryOp::Add,
3755
1
                right,
3756
1
            },
3757
1
            Span::new(0, 5),
3758
        ));
3759
3760
1
        let lambda_expr = Expr::new(
3761
1
            ExprKind::Lambda {
3762
1
                params: vec![param],
3763
1
                body,
3764
1
            },
3765
1
            Span::new(0, 10),
3766
        );
3767
3768
1
        let result = interp
3769
1
            .eval_expr(&lambda_expr)
3770
1
            .expect("Should evaluate lambda");
3771
1
        assert_eq!(result.type_name(), "function");
3772
1
    }
3773
3774
    #[test]
3775
1
    fn test_eval_function_call() {
3776
        use crate::frontend::ast::{Pattern, Type, TypeKind};
3777
1
        let mut interp = Interpreter::new();
3778
3779
        // Create lambda: |x| x + 1
3780
1
        let param = Param {
3781
1
            pattern: Pattern::Identifier("x".to_string()),
3782
1
            ty: Type {
3783
1
                kind: TypeKind::Named("i32".to_string()),
3784
1
                span: Span::new(0, 3),
3785
1
            },
3786
1
            span: Span::new(0, 1),
3787
1
            is_mutable: false,
3788
1
            default_value: None,
3789
1
        };
3790
3791
1
        let left = Box::new(Expr::new(
3792
1
            ExprKind::Identifier("x".to_string()),
3793
1
            Span::new(0, 1),
3794
        ));
3795
1
        let right = Box::new(Expr::new(
3796
1
            ExprKind::Literal(Literal::Integer(1)),
3797
1
            Span::new(4, 5),
3798
        ));
3799
1
        let body = Box::new(Expr::new(
3800
1
            ExprKind::Binary {
3801
1
                left,
3802
1
                op: AstBinaryOp::Add,
3803
1
                right,
3804
1
            },
3805
1
            Span::new(0, 5),
3806
        ));
3807
3808
1
        let lambda_expr = Expr::new(
3809
1
            ExprKind::Lambda {
3810
1
                params: vec![param],
3811
1
                body,
3812
1
            },
3813
1
            Span::new(0, 10),
3814
        );
3815
3816
        // Call lambda with argument 5: (|x| x + 1)(5) = 6
3817
1
        let call_expr = Expr::new(
3818
1
            ExprKind::Call {
3819
1
                func: Box::new(lambda_expr),
3820
1
                args: vec![Expr::new(
3821
1
                    ExprKind::Literal(Literal::Integer(5)),
3822
1
                    Span::new(0, 1),
3823
1
                )],
3824
1
            },
3825
1
            Span::new(0, 15),
3826
        );
3827
3828
1
        let result = interp
3829
1
            .eval_expr(&call_expr)
3830
1
            .expect("Should evaluate function call");
3831
1
        assert_eq!(result, Value::Integer(6));
3832
1
    }
3833
3834
    #[test]
3835
1
    fn test_eval_function_definition() {
3836
        use crate::frontend::ast::{Pattern, Type, TypeKind};
3837
1
        let mut interp = Interpreter::new();
3838
3839
        // Create function: fn add_one(x) = x + 1
3840
1
        let param = Param {
3841
1
            pattern: Pattern::Identifier("x".to_string()),
3842
1
            ty: Type {
3843
1
                kind: TypeKind::Named("i32".to_string()),
3844
1
                span: Span::new(0, 3),
3845
1
            },
3846
1
            span: Span::new(0, 1),
3847
1
            is_mutable: false,
3848
1
            default_value: None,
3849
1
        };
3850
3851
1
        let left = Box::new(Expr::new(
3852
1
            ExprKind::Identifier("x".to_string()),
3853
1
            Span::new(0, 1),
3854
        ));
3855
1
        let right = Box::new(Expr::new(
3856
1
            ExprKind::Literal(Literal::Integer(1)),
3857
1
            Span::new(4, 5),
3858
        ));
3859
1
        let body = Box::new(Expr::new(
3860
1
            ExprKind::Binary {
3861
1
                left,
3862
1
                op: AstBinaryOp::Add,
3863
1
                right,
3864
1
            },
3865
1
            Span::new(0, 5),
3866
        ));
3867
3868
1
        let func_expr = Expr::new(
3869
1
            ExprKind::Function {
3870
1
                name: "add_one".to_string(),
3871
1
                type_params: vec![],
3872
1
                params: vec![param],
3873
1
                return_type: None,
3874
1
                body,
3875
1
                is_async: false,
3876
1
                is_pub: false,
3877
1
            },
3878
1
            Span::new(0, 20),
3879
        );
3880
3881
1
        let result = interp
3882
1
            .eval_expr(&func_expr)
3883
1
            .expect("Should evaluate function");
3884
1
        assert_eq!(result.type_name(), "function");
3885
3886
        // Verify function is bound in environment
3887
1
        let bound_func = interp
3888
1
            .lookup_variable("add_one")
3889
1
            .expect("Function should be bound");
3890
1
        assert_eq!(bound_func.type_name(), "function");
3891
1
    }
3892
3893
    #[test]
3894
1
    fn test_eval_recursive_function() {
3895
        use crate::frontend::ast::{Pattern, Type, TypeKind};
3896
1
        let mut interp = Interpreter::new();
3897
3898
        // Create recursive factorial function
3899
1
        let param = Param {
3900
1
            pattern: Pattern::Identifier("n".to_string()),
3901
1
            ty: Type {
3902
1
                kind: TypeKind::Named("i32".to_string()),
3903
1
                span: Span::new(0, 3),
3904
1
            },
3905
1
            span: Span::new(0, 1),
3906
1
            is_mutable: false,
3907
1
            default_value: None,
3908
1
        };
3909
3910
        // if n <= 1 then 1 else n * factorial(n - 1)
3911
1
        let n_id = Expr::new(ExprKind::Identifier("n".to_string()), Span::new(0, 1));
3912
1
        let one = Expr::new(ExprKind::Literal(Literal::Integer(1)), Span::new(0, 1));
3913
3914
1
        let condition = Box::new(Expr::new(
3915
1
            ExprKind::Binary {
3916
1
                left: Box::new(n_id.clone()),
3917
1
                op: AstBinaryOp::LessEqual,
3918
1
                right: Box::new(one.clone()),
3919
1
            },
3920
1
            Span::new(0, 6),
3921
        ));
3922
3923
1
        let then_branch = Box::new(one.clone());
3924
3925
        // n * factorial(n - 1)
3926
1
        let n_minus_1 = Expr::new(
3927
1
            ExprKind::Binary {
3928
1
                left: Box::new(n_id.clone()),
3929
1
                op: AstBinaryOp::Subtract,
3930
1
                right: Box::new(one),
3931
1
            },
3932
1
            Span::new(0, 5),
3933
        );
3934
3935
1
        let recursive_call = Expr::new(
3936
1
            ExprKind::Call {
3937
1
                func: Box::new(Expr::new(
3938
1
                    ExprKind::Identifier("factorial".to_string()),
3939
1
                    Span::new(0, 9),
3940
1
                )),
3941
1
                args: vec![n_minus_1],
3942
1
            },
3943
1
            Span::new(0, 15),
3944
        );
3945
3946
1
        let else_branch = Some(Box::new(Expr::new(
3947
1
            ExprKind::Binary {
3948
1
                left: Box::new(n_id),
3949
1
                op: AstBinaryOp::Multiply,
3950
1
                right: Box::new(recursive_call),
3951
1
            },
3952
1
            Span::new(0, 20),
3953
1
        )));
3954
3955
1
        let body = Box::new(Expr::new(
3956
1
            ExprKind::If {
3957
1
                condition,
3958
1
                then_branch,
3959
1
                else_branch,
3960
1
            },
3961
1
            Span::new(0, 25),
3962
        ));
3963
3964
1
        let factorial_expr = Expr::new(
3965
1
            ExprKind::Function {
3966
1
                name: "factorial".to_string(),
3967
1
                type_params: vec![],
3968
1
                params: vec![param],
3969
1
                return_type: None,
3970
1
                body,
3971
1
                is_async: false,
3972
1
                is_pub: false,
3973
1
            },
3974
1
            Span::new(0, 30),
3975
        );
3976
3977
        // Define factorial function
3978
1
        let result = interp
3979
1
            .eval_expr(&factorial_expr)
3980
1
            .expect("Should evaluate factorial function");
3981
1
        assert_eq!(result.type_name(), "function");
3982
3983
        // Test factorial(5) = 120
3984
1
        let call_expr = Expr::new(
3985
1
            ExprKind::Call {
3986
1
                func: Box::new(Expr::new(
3987
1
                    ExprKind::Identifier("factorial".to_string()),
3988
1
                    Span::new(0, 9),
3989
1
                )),
3990
1
                args: vec![Expr::new(
3991
1
                    ExprKind::Literal(Literal::Integer(5)),
3992
1
                    Span::new(0, 1),
3993
1
                )],
3994
1
            },
3995
1
            Span::new(0, 15),
3996
        );
3997
3998
1
        let result = interp
3999
1
            .eval_expr(&call_expr)
4000
1
            .expect("Should evaluate factorial(5)");
4001
1
        assert_eq!(result, Value::Integer(120));
4002
1
    }
4003
4004
    #[test]
4005
1
    fn test_function_closure() {
4006
        use crate::frontend::ast::{Pattern, Type, TypeKind};
4007
1
        let mut interp = Interpreter::new();
4008
4009
        // Test closure: let x = 10 in |y| x + y
4010
1
        let x_val = Box::new(Expr::new(
4011
1
            ExprKind::Literal(Literal::Integer(10)),
4012
1
            Span::new(8, 10),
4013
        ));
4014
4015
1
        let param = Param {
4016
1
            pattern: Pattern::Identifier("y".to_string()),
4017
1
            ty: Type {
4018
1
                kind: TypeKind::Named("i32".to_string()),
4019
1
                span: Span::new(0, 3),
4020
1
            },
4021
1
            span: Span::new(0, 1),
4022
1
            is_mutable: false,
4023
1
            default_value: None,
4024
1
        };
4025
4026
1
        let left = Box::new(Expr::new(
4027
1
            ExprKind::Identifier("x".to_string()),
4028
1
            Span::new(0, 1),
4029
        ));
4030
1
        let right = Box::new(Expr::new(
4031
1
            ExprKind::Identifier("y".to_string()),
4032
1
            Span::new(4, 5),
4033
        ));
4034
1
        let lambda_body = Box::new(Expr::new(
4035
1
            ExprKind::Binary {
4036
1
                left,
4037
1
                op: AstBinaryOp::Add,
4038
1
                right,
4039
1
            },
4040
1
            Span::new(0, 5),
4041
        ));
4042
4043
1
        let lambda = Expr::new(
4044
1
            ExprKind::Lambda {
4045
1
                params: vec![param],
4046
1
                body: lambda_body,
4047
1
            },
4048
1
            Span::new(14, 24),
4049
        );
4050
4051
1
        let let_body = Box::new(lambda);
4052
4053
1
        let let_expr = Expr::new(
4054
1
            ExprKind::Let {
4055
1
                name: "x".to_string(),
4056
1
                type_annotation: None,
4057
1
                value: x_val,
4058
1
                body: let_body,
4059
1
                is_mutable: false,
4060
1
            },
4061
1
            Span::new(0, 24),
4062
        );
4063
4064
1
        let closure = interp
4065
1
            .eval_expr(&let_expr)
4066
1
            .expect("Should evaluate closure");
4067
1
        assert_eq!(closure.type_name(), "function");
4068
4069
        // Call closure with argument 5: (|y| x + y)(5) = 15 (x = 10)
4070
1
        let call_expr = Expr::new(
4071
1
            ExprKind::Call {
4072
1
                func: Box::new(let_expr), // Re-create the closure
4073
1
                args: vec![Expr::new(
4074
1
                    ExprKind::Literal(Literal::Integer(5)),
4075
1
                    Span::new(0, 1),
4076
1
                )],
4077
1
            },
4078
1
            Span::new(0, 30),
4079
        );
4080
4081
        // Note: This test demonstrates lexical scoping where the closure captures 'x'
4082
1
        let result = interp
4083
1
            .eval_expr(&call_expr)
4084
1
            .expect("Should evaluate closure call");
4085
1
        assert_eq!(result, Value::Integer(15));
4086
1
    }
4087
4088
    #[test]
4089
1
    fn test_inline_cache_string_methods() {
4090
1
        let mut interp = Interpreter::new();
4091
1
        let test_string = Value::String(Rc::new("Hello World".to_string()));
4092
4093
        // Test string.len() with caching
4094
1
        let result1 = interp
4095
1
            .get_field_cached(&test_string, "len")
4096
1
            .expect("Should get string length");
4097
1
        assert_eq!(result1, Value::Integer(11));
4098
4099
1
        let result2 = interp
4100
1
            .get_field_cached(&test_string, "len")
4101
1
            .expect("Should get cached result");
4102
1
        assert_eq!(result2, Value::Integer(11));
4103
4104
        // Verify cache hit occurred
4105
1
        let stats = interp.get_cache_stats();
4106
1
        let cache_key = format!("{:?}::len", test_string.type_id());
4107
1
        assert!(stats.get(&cache_key).unwrap_or(&0.0) > &0.0);
4108
4109
        // Test other string methods
4110
1
        let upper_result = interp
4111
1
            .get_field_cached(&test_string, "to_upper")
4112
1
            .expect("Should get uppercase");
4113
1
        assert_eq!(
4114
            upper_result,
4115
1
            Value::String(Rc::new("HELLO WORLD".to_string()))
4116
        );
4117
4118
1
        let trim_result = interp
4119
1
            .get_field_cached(&Value::String(Rc::new("  test  ".to_string())), "trim")
4120
1
            .expect("Should trim string");
4121
1
        assert_eq!(trim_result, Value::String(Rc::new("test".to_string())));
4122
1
    }
4123
4124
    #[test]
4125
1
    fn test_inline_cache_array_methods() {
4126
1
        let mut interp = Interpreter::new();
4127
1
        let test_array = Value::Array(Rc::new(vec![
4128
1
            Value::Integer(1),
4129
1
            Value::Integer(2),
4130
1
            Value::Integer(3),
4131
1
        ]));
4132
4133
        // Test array.len() with caching
4134
1
        let result1 = interp
4135
1
            .get_field_cached(&test_array, "len")
4136
1
            .expect("Should get array length");
4137
1
        assert_eq!(result1, Value::Integer(3));
4138
4139
1
        let result2 = interp
4140
1
            .get_field_cached(&test_array, "len")
4141
1
            .expect("Should get cached result");
4142
1
        assert_eq!(result2, Value::Integer(3));
4143
4144
        // Test first and last
4145
1
        let first_result = interp
4146
1
            .get_field_cached(&test_array, "first")
4147
1
            .expect("Should get first element");
4148
1
        assert_eq!(first_result, Value::Integer(1));
4149
4150
1
        let last_result = interp
4151
1
            .get_field_cached(&test_array, "last")
4152
1
            .expect("Should get last element");
4153
1
        assert_eq!(last_result, Value::Integer(3));
4154
4155
        // Test empty array (use fresh interpreter to avoid cache pollution)
4156
1
        let mut fresh_interp = Interpreter::new();
4157
1
        let empty_array = Value::Array(Rc::new(vec![]));
4158
1
        let first_err = fresh_interp.get_field_cached(&empty_array, "first");
4159
1
        assert!(first_err.is_err());
4160
1
    }
4161
4162
    #[test]
4163
1
    fn test_inline_cache_polymorphic() {
4164
1
        let mut interp = Interpreter::new();
4165
4166
        // Test polymorphic caching with different types calling same method
4167
1
        let string_val = Value::String(Rc::new("test".to_string()));
4168
1
        let array_val = Value::Array(Rc::new(vec![Value::Integer(1), Value::Integer(2)]));
4169
4170
        // Both call len() method
4171
1
        let string_len = interp
4172
1
            .get_field_cached(&string_val, "len")
4173
1
            .expect("Should get string length");
4174
1
        assert_eq!(string_len, Value::Integer(4));
4175
4176
1
        let array_len = interp
4177
1
            .get_field_cached(&array_val, "len")
4178
1
            .expect("Should get array length");
4179
1
        assert_eq!(array_len, Value::Integer(2));
4180
4181
        // Both should have separate cache entries
4182
1
        let stats = interp.get_cache_stats();
4183
1
        assert_eq!(stats.len(), 2); // Two different cache keys
4184
1
    }
4185
4186
    #[test]
4187
1
    fn test_inline_cache_type_method() {
4188
1
        let mut interp = Interpreter::new();
4189
4190
        // Test the universal 'type' method
4191
1
        let int_val = Value::Integer(42);
4192
1
        let string_val = Value::String(Rc::new("test".to_string()));
4193
1
        let bool_val = Value::Bool(true);
4194
4195
1
        let int_type = interp
4196
1
            .get_field_cached(&int_val, "type")
4197
1
            .expect("Should get int type");
4198
1
        assert_eq!(int_type, Value::String(Rc::new("integer".to_string())));
4199
4200
1
        let string_type = interp
4201
1
            .get_field_cached(&string_val, "type")
4202
1
            .expect("Should get string type");
4203
1
        assert_eq!(string_type, Value::String(Rc::new("string".to_string())));
4204
4205
1
        let bool_type = interp
4206
1
            .get_field_cached(&bool_val, "type")
4207
1
            .expect("Should get bool type");
4208
1
        assert_eq!(bool_type, Value::String(Rc::new("boolean".to_string())));
4209
1
    }
4210
4211
    #[test]
4212
1
    fn test_inline_cache_miss_handling() {
4213
1
        let mut interp = Interpreter::new();
4214
1
        let test_val = Value::Integer(42);
4215
4216
        // Test accessing non-existent field
4217
1
        let result = interp.get_field_cached(&test_val, "non_existent");
4218
1
        assert!(result.is_err());
4219
4220
        // Test that error doesn't get cached (cache should be empty)
4221
1
        let stats = interp.get_cache_stats();
4222
1
        assert!(stats.is_empty());
4223
1
    }
4224
4225
    #[test]
4226
1
    fn test_cache_state_transitions() {
4227
1
        let mut interp = Interpreter::new();
4228
4229
        // Create multiple values of same type for same field
4230
1
        let vals = [
4231
1
            Value::String(Rc::new("test1".to_string())),
4232
1
            Value::String(Rc::new("test2".to_string())),
4233
1
            Value::String(Rc::new("test3".to_string())),
4234
1
        ];
4235
4236
        // Access same field multiple times to test cache evolution
4237
4
        for 
val3
in &vals {
4238
3
            let _ = interp
4239
3
                .get_field_cached(val, "len")
4240
3
                .expect("Should get length");
4241
3
        }
4242
4243
        // Verify caching occurred
4244
1
        let stats = interp.get_cache_stats();
4245
1
        assert!(!stats.is_empty());
4246
4247
        // Clear caches and verify
4248
1
        interp.clear_caches();
4249
1
        let stats_after = interp.get_cache_stats();
4250
1
        assert!(stats_after.is_empty());
4251
1
    }
4252
4253
    #[test]
4254
1
    fn test_type_feedback_binary_operations() {
4255
        use crate::frontend::ast::Span;
4256
1
        let mut interp = Interpreter::new();
4257
4258
        // Create binary operation: 42 + 10
4259
1
        let left = Expr::new(ExprKind::Literal(Literal::Integer(42)), Span::new(0, 2));
4260
1
        let right = Expr::new(ExprKind::Literal(Literal::Integer(10)), Span::new(5, 7));
4261
1
        let binary_expr = Expr::new(
4262
1
            ExprKind::Binary {
4263
1
                left: Box::new(left),
4264
1
                op: AstBinaryOp::Add,
4265
1
                right: Box::new(right),
4266
1
            },
4267
1
            Span::new(0, 7),
4268
        );
4269
4270
        // Evaluate the expression multiple times to collect feedback
4271
16
        for _ in 0..15 {
4272
15
            let result = interp
4273
15
                .eval_expr(&binary_expr)
4274
15
                .expect("Should evaluate binary operation");
4275
15
            assert_eq!(result, Value::Integer(52));
4276
        }
4277
4278
        // Check type feedback statistics
4279
1
        let stats = interp.get_type_feedback_stats();
4280
1
        assert_eq!(stats.total_operation_sites, 1);
4281
1
        assert_eq!(stats.monomorphic_operation_sites, 1);
4282
1
        assert_eq!(stats.total_samples, 15);
4283
4284
        // Check specialization candidates
4285
1
        let candidates = interp.get_specialization_candidates();
4286
1
        assert!(!candidates.is_empty());
4287
1
        assert!((candidates[0].confidence - 1.0).abs() < f64::EPSILON); // Monomorphic operation
4288
1
    }
4289
4290
    #[test]
4291
1
    fn test_type_feedback_variable_assignments() {
4292
        use crate::frontend::ast::Span;
4293
1
        let mut interp = Interpreter::new();
4294
4295
        // Create let binding: let x = 42 in x
4296
1
        let value_expr = Box::new(Expr::new(
4297
1
            ExprKind::Literal(Literal::Integer(42)),
4298
1
            Span::new(8, 10),
4299
        ));
4300
1
        let body_expr = Box::new(Expr::new(
4301
1
            ExprKind::Identifier("x".to_string()),
4302
1
            Span::new(14, 15),
4303
        ));
4304
4305
1
        let let_expr = Expr::new(
4306
1
            ExprKind::Let {
4307
1
                name: "x".to_string(),
4308
1
                type_annotation: None,
4309
1
                value: value_expr,
4310
1
                body: body_expr,
4311
1
                is_mutable: false,
4312
1
            },
4313
1
            Span::new(0, 15),
4314
        );
4315
4316
        // Evaluate the expression
4317
1
        let result = interp
4318
1
            .eval_expr(&let_expr)
4319
1
            .expect("Should evaluate let expression");
4320
1
        assert_eq!(result, Value::Integer(42));
4321
4322
        // Check type feedback statistics
4323
1
        let stats = interp.get_type_feedback_stats();
4324
1
        assert_eq!(stats.total_variables, 1);
4325
1
        assert_eq!(stats.stable_variables, 1);
4326
4327
        // Check specialization candidates for stable variable
4328
1
        let candidates = interp.get_specialization_candidates();
4329
1
        let variable_candidates: Vec<_> = candidates
4330
1
            .iter()
4331
1
            .filter(|c| matches!(c.kind, SpecializationKind::Variable { .. }))
4332
1
            .collect();
4333
1
        assert!(!variable_candidates.is_empty());
4334
1
    }
4335
4336
    #[test]
4337
1
    fn test_type_feedback_function_calls() {
4338
        use crate::frontend::ast::{Param, Pattern, Span, Type, TypeKind};
4339
1
        let mut interp = Interpreter::new();
4340
4341
        // Create function: fn double(x) = x + x
4342
1
        let param = Param {
4343
1
            pattern: Pattern::Identifier("x".to_string()),
4344
1
            ty: Type {
4345
1
                kind: TypeKind::Named("i32".to_string()),
4346
1
                span: Span::new(0, 3),
4347
1
            },
4348
1
            span: Span::new(0, 1),
4349
1
            is_mutable: false,
4350
1
            default_value: None,
4351
1
        };
4352
4353
1
        let left_body = Box::new(Expr::new(
4354
1
            ExprKind::Identifier("x".to_string()),
4355
1
            Span::new(0, 1),
4356
        ));
4357
1
        let right_body = Box::new(Expr::new(
4358
1
            ExprKind::Identifier("x".to_string()),
4359
1
            Span::new(4, 5),
4360
        ));
4361
1
        let func_body = Box::new(Expr::new(
4362
1
            ExprKind::Binary {
4363
1
                left: left_body,
4364
1
                op: AstBinaryOp::Add,
4365
1
                right: right_body,
4366
1
            },
4367
1
            Span::new(0, 5),
4368
        ));
4369
4370
1
        let func_expr = Expr::new(
4371
1
            ExprKind::Function {
4372
1
                name: "double".to_string(),
4373
1
                type_params: vec![],
4374
1
                params: vec![param],
4375
1
                body: func_body,
4376
1
                return_type: None,
4377
1
                is_async: false,
4378
1
                is_pub: false,
4379
1
            },
4380
1
            Span::new(0, 20),
4381
        );
4382
4383
        // Define the function
4384
1
        let _func = interp
4385
1
            .eval_expr(&func_expr)
4386
1
            .expect("Should define function");
4387
4388
        // Create function call: double(21)
4389
1
        let func_ref = Box::new(Expr::new(
4390
1
            ExprKind::Identifier("double".to_string()),
4391
1
            Span::new(0, 6),
4392
        ));
4393
1
        let arg = Expr::new(ExprKind::Literal(Literal::Integer(21)), Span::new(7, 9));
4394
1
        let call_expr = Expr::new(
4395
1
            ExprKind::Call {
4396
1
                func: func_ref,
4397
1
                args: vec![arg],
4398
1
            },
4399
1
            Span::new(0, 10),
4400
        );
4401
4402
        // Call the function multiple times
4403
11
        for _ in 0..10 {
4404
10
            let result = interp.eval_expr(&call_expr).expect("Should call function");
4405
10
            assert_eq!(result, Value::Integer(42));
4406
        }
4407
4408
        // Check type feedback statistics
4409
1
        let stats = interp.get_type_feedback_stats();
4410
1
        assert!(stats.total_call_sites > 0);
4411
1
        assert!(stats.monomorphic_call_sites > 0);
4412
4413
        // Check specialization candidates for function calls
4414
1
        let candidates = interp.get_specialization_candidates();
4415
1
        let call_candidates: Vec<_> = candidates
4416
1
            .iter()
4417
2
            .
filter1
(|c| matches!(c.kind, SpecializationKind::FunctionCall { .. }))
4418
1
            .collect();
4419
1
        assert!(!call_candidates.is_empty());
4420
1
    }
4421
4422
    #[test]
4423
1
    fn test_type_feedback_polymorphic_detection() {
4424
        use crate::frontend::ast::Span;
4425
1
        let mut interp = Interpreter::new();
4426
4427
        // Create integer addition
4428
1
        let int_expr = Expr::new(
4429
1
            ExprKind::Binary {
4430
1
                left: Box::new(Expr::new(
4431
1
                    ExprKind::Literal(Literal::Integer(1)),
4432
1
                    Span::new(0, 1),
4433
1
                )),
4434
1
                op: AstBinaryOp::Add,
4435
1
                right: Box::new(Expr::new(
4436
1
                    ExprKind::Literal(Literal::Integer(2)),
4437
1
                    Span::new(4, 5),
4438
1
                )),
4439
1
            },
4440
1
            Span::new(0, 5),
4441
        );
4442
4443
        // Create float addition (different site)
4444
1
        let float_expr = Expr::new(
4445
1
            ExprKind::Binary {
4446
1
                left: Box::new(Expr::new(
4447
1
                    ExprKind::Literal(Literal::Float(1.5)),
4448
1
                    Span::new(10, 13),
4449
1
                )),
4450
1
                op: AstBinaryOp::Add,
4451
1
                right: Box::new(Expr::new(
4452
1
                    ExprKind::Literal(Literal::Float(2.5)),
4453
1
                    Span::new(16, 19),
4454
1
                )),
4455
1
            },
4456
1
            Span::new(10, 19),
4457
        );
4458
4459
        // Evaluate both expressions multiple times
4460
13
        for _ in 0..12 {
4461
12
            let _ = interp
4462
12
                .eval_expr(&int_expr)
4463
12
                .expect("Should evaluate int addition");
4464
12
            let _ = interp
4465
12
                .eval_expr(&float_expr)
4466
12
                .expect("Should evaluate float addition");
4467
12
        }
4468
4469
        // Check that we have multiple operation sites
4470
1
        let stats = interp.get_type_feedback_stats();
4471
1
        assert_eq!(stats.total_operation_sites, 2);
4472
1
        assert_eq!(stats.monomorphic_operation_sites, 2); // Both should be monomorphic
4473
1
        assert_eq!(stats.total_samples, 24); // 12 * 2 operations
4474
4475
        // Both should be candidates for specialization
4476
1
        let candidates = interp.get_specialization_candidates();
4477
1
        let op_candidates: Vec<_> = candidates
4478
1
            .iter()
4479
2
            .
filter1
(|c| matches!(c.kind, SpecializationKind::BinaryOperation { .. }))
4480
1
            .collect();
4481
1
        assert_eq!(op_candidates.len(), 2);
4482
1
    }
4483
4484
    #[test]
4485
1
    fn test_type_feedback_clear() {
4486
        use crate::frontend::ast::Span;
4487
1
        let mut interp = Interpreter::new();
4488
4489
        // Create and evaluate a simple expression
4490
1
        let expr = Expr::new(
4491
1
            ExprKind::Binary {
4492
1
                left: Box::new(Expr::new(
4493
1
                    ExprKind::Literal(Literal::Integer(1)),
4494
1
                    Span::new(0, 1),
4495
1
                )),
4496
1
                op: AstBinaryOp::Add,
4497
1
                right: Box::new(Expr::new(
4498
1
                    ExprKind::Literal(Literal::Integer(1)),
4499
1
                    Span::new(4, 5),
4500
1
                )),
4501
1
            },
4502
1
            Span::new(0, 5),
4503
        );
4504
4505
1
        let _ = interp.eval_expr(&expr).expect("Should evaluate");
4506
4507
        // Verify feedback was collected
4508
1
        let stats_before = interp.get_type_feedback_stats();
4509
1
        assert!(stats_before.total_samples > 0);
4510
4511
        // Clear feedback and verify
4512
1
        interp.clear_type_feedback();
4513
1
        let stats_after = interp.get_type_feedback_stats();
4514
1
        assert_eq!(stats_after.total_samples, 0);
4515
1
        assert_eq!(stats_after.total_operation_sites, 0);
4516
1
    }
4517
4518
    #[test]
4519
1
    fn test_gc_basic_tracking() {
4520
1
        let mut interp = Interpreter::new();
4521
4522
        // Create some values to track
4523
1
        let values = vec![
4524
1
            Value::Integer(42),
4525
1
            Value::String(Rc::new("hello".to_string())),
4526
1
            Value::Array(Rc::new(vec![Value::Integer(1), Value::Integer(2)])),
4527
        ];
4528
4529
        // Track them in GC
4530
4
        for 
value3
in values {
4531
3
            interp.gc_track(value);
4532
3
        }
4533
4534
        // Check GC info
4535
1
        let info = interp.gc_info();
4536
1
        assert_eq!(info.total_objects, 3);
4537
1
        assert!(info.allocated_bytes > 0);
4538
1
        assert_eq!(info.collections_performed, 0);
4539
1
    }
4540
4541
    #[test]
4542
1
    fn test_gc_collection() {
4543
1
        let mut interp = Interpreter::new();
4544
4545
        // Disable auto-collection for manual testing
4546
1
        interp.gc_set_auto_collect(false);
4547
4548
        // Track several objects
4549
11
        for 
i10
in 0..10 {
4550
10
            let value = Value::Integer(i);
4551
10
            interp.gc_track(value);
4552
10
        }
4553
4554
1
        let info_before = interp.gc_info();
4555
1
        assert_eq!(info_before.total_objects, 10);
4556
4557
        // Force garbage collection
4558
1
        let stats = interp.gc_collect();
4559
4560
        // Since we treat all objects as roots conservatively, none should be collected
4561
1
        assert_eq!(stats.objects_collected, 0);
4562
1
        assert_eq!(stats.objects_after, 10);
4563
4564
1
        let info_after = interp.gc_info();
4565
1
        assert_eq!(info_after.collections_performed, 1);
4566
1
    }
4567
4568
    #[test]
4569
1
    fn test_gc_auto_collection() {
4570
1
        let mut interp = Interpreter::new();
4571
4572
        // Set a very low threshold to trigger auto-collection
4573
1
        interp.gc_set_threshold(100);
4574
1
        interp.gc_set_auto_collect(true);
4575
4576
        // Track a large object to trigger collection
4577
1
        let large_string = "x".repeat(200);
4578
1
        let value = Value::String(Rc::new(large_string));
4579
1
        interp.gc_track(value);
4580
4581
        // Auto-collection should have been triggered
4582
1
        let info = interp.gc_info();
4583
1
        assert!(info.collections_performed > 0);
4584
1
    }
4585
4586
    #[test]
4587
1
    fn test_gc_allocation_helpers() {
4588
1
        let mut interp = Interpreter::new();
4589
4590
        // Test GC allocation helpers
4591
1
        let array = interp.gc_alloc_array(vec![Value::Integer(1), Value::Integer(2)]);
4592
1
        let string = interp.gc_alloc_string("test".to_string());
4593
4594
        // Both should be tracked
4595
1
        let info = interp.gc_info();
4596
1
        assert_eq!(info.total_objects, 2);
4597
4598
        // Verify the values are correct
4599
1
        match array {
4600
1
            Value::Array(arr) => {
4601
1
                assert_eq!(arr.len(), 2);
4602
1
                assert_eq!(arr[0], Value::Integer(1));
4603
1
                assert_eq!(arr[1], Value::Integer(2));
4604
            }
4605
0
            _ => panic!("Expected array"),
4606
        }
4607
4608
1
        match string {
4609
1
            Value::String(s) => {
4610
1
                assert_eq!(s.as_ref(), "test");
4611
            }
4612
0
            _ => panic!("Expected string"),
4613
        }
4614
1
    }
4615
4616
    #[test]
4617
1
    fn test_gc_size_estimation() {
4618
1
        let gc = ConservativeGC::new();
4619
4620
        // Test size estimation for different value types
4621
1
        let int_size = gc.estimate_object_size(&Value::Integer(42));
4622
1
        let float_size = gc.estimate_object_size(&Value::Float(3.14));
4623
1
        let bool_size = gc.estimate_object_size(&Value::Bool(true));
4624
1
        let nil_size = gc.estimate_object_size(&Value::Nil);
4625
4626
1
        assert_eq!(int_size, 8);
4627
1
        assert_eq!(float_size, 8);
4628
1
        assert_eq!(bool_size, 1);
4629
1
        assert_eq!(nil_size, 0);
4630
4631
        // Test string size estimation
4632
1
        let string_val = Value::String(Rc::new("hello".to_string()));
4633
1
        let string_size = gc.estimate_object_size(&string_val);
4634
1
        assert_eq!(string_size, 5 + 24); // content + overhead
4635
4636
        // Test array size estimation
4637
1
        let array_val = Value::Array(Rc::new(vec![Value::Integer(1), Value::Integer(2)]));
4638
1
        let array_size = gc.estimate_object_size(&array_val);
4639
1
        assert_eq!(array_size, 24 + 8 + 8); // overhead + 2 integers
4640
1
    }
4641
4642
    #[test]
4643
1
    fn test_gc_threshold_management() {
4644
1
        let mut interp = Interpreter::new();
4645
4646
        // Test threshold setting
4647
1
        interp.gc_set_threshold(2048);
4648
1
        let info = interp.gc_info();
4649
1
        assert_eq!(info.collection_threshold, 2048);
4650
4651
        // Test auto-collect setting
4652
1
        interp.gc_set_auto_collect(false);
4653
1
        let info = interp.gc_info();
4654
1
        assert!(!info.auto_collect_enabled);
4655
4656
1
        interp.gc_set_auto_collect(true);
4657
1
        let info = interp.gc_info();
4658
1
        assert!(info.auto_collect_enabled);
4659
1
    }
4660
4661
    #[test]
4662
1
    fn test_gc_clear() {
4663
1
        let mut interp = Interpreter::new();
4664
4665
        // Track some objects
4666
6
        for 
i5
in 0..5 {
4667
5
            interp.gc_track(Value::Integer(i));
4668
5
        }
4669
4670
1
        let info_before = interp.gc_info();
4671
1
        assert_eq!(info_before.total_objects, 5);
4672
1
        assert!(info_before.allocated_bytes > 0);
4673
4674
        // Clear GC
4675
1
        interp.gc_clear();
4676
4677
1
        let info_after = interp.gc_info();
4678
1
        assert_eq!(info_after.total_objects, 0);
4679
1
        assert_eq!(info_after.allocated_bytes, 0);
4680
1
    }
4681
4682
    #[test]
4683
1
    fn test_gc_stats_consistency() {
4684
1
        let mut interp = Interpreter::new();
4685
4686
        // Track objects and get initial stats
4687
4
        for 
i3
in 0..3 {
4688
3
            interp.gc_track(Value::Integer(i));
4689
3
        }
4690
4691
1
        let stats = interp.gc_stats();
4692
1
        let info = interp.gc_info();
4693
4694
        // Stats and info should be consistent
4695
1
        assert_eq!(stats.objects_before, info.total_objects);
4696
1
        assert_eq!(stats.objects_after, info.total_objects);
4697
1
        assert_eq!(stats.bytes_before, info.allocated_bytes);
4698
1
        assert_eq!(stats.bytes_after, info.allocated_bytes);
4699
1
        assert_eq!(stats.objects_collected, 0);
4700
1
    }
4701
4702
    // Direct-threaded interpreter tests
4703
4704
    #[test]
4705
1
    fn test_direct_threaded_creation() {
4706
1
        let interp = DirectThreadedInterpreter::new();
4707
1
        assert_eq!(interp.instruction_count(), 0);
4708
1
        assert_eq!(interp.constants_count(), 0);
4709
1
    }
4710
4711
    #[test]
4712
1
    fn test_direct_threaded_constants() {
4713
1
        let mut interp = DirectThreadedInterpreter::new();
4714
4715
1
        let int_idx = interp.add_constant(Value::Integer(42));
4716
1
        let float_idx = interp.add_constant(Value::Float(3.14));
4717
1
        let string_idx = interp.add_constant(Value::String(Rc::new("hello".to_string())));
4718
4719
1
        assert_eq!(int_idx, 0);
4720
1
        assert_eq!(float_idx, 1);
4721
1
        assert_eq!(string_idx, 2);
4722
1
        assert_eq!(interp.constants_count(), 3);
4723
1
    }
4724
4725
    #[test]
4726
1
    fn test_direct_threaded_instruction_stream() {
4727
1
        let mut interp = DirectThreadedInterpreter::new();
4728
4729
        // Add some constants
4730
1
        let const_idx = interp.add_constant(Value::Integer(42));
4731
4732
        // Add instructions
4733
1
        interp.add_instruction(op_load_const, const_idx);
4734
1
        interp.add_instruction(op_load_nil, 0);
4735
4736
1
        assert_eq!(interp.instruction_count(), 2);
4737
1
    }
4738
4739
    #[test]
4740
1
    fn test_direct_threaded_literal_compilation() {
4741
        use crate::frontend::ast::{Expr, ExprKind};
4742
4743
1
        let mut interp = DirectThreadedInterpreter::new();
4744
4745
        // Compile integer literal
4746
1
        let int_ast = Expr::new(
4747
1
            ExprKind::Literal(Literal::Integer(42)),
4748
1
            crate::frontend::ast::Span::new(0, 0),
4749
        );
4750
1
        let result = interp.compile(&int_ast);
4751
1
        assert!(result.is_ok());
4752
4753
1
        assert_eq!(interp.constants_count(), 1);
4754
1
        assert_eq!(interp.instruction_count(), 2); // load_const + return
4755
4756
        // Compile float literal
4757
1
        let float_ast = Expr::new(
4758
1
            ExprKind::Literal(Literal::Float(3.14)),
4759
1
            crate::frontend::ast::Span::new(0, 0),
4760
        );
4761
1
        let result = interp.compile(&float_ast);
4762
1
        assert!(result.is_ok());
4763
4764
1
        assert_eq!(interp.constants_count(), 1); // resets on each compile
4765
1
        assert_eq!(interp.instruction_count(), 2); // load_const + return
4766
4767
        // Compile string literal
4768
1
        let string_ast = Expr::new(
4769
1
            ExprKind::Literal(Literal::String("hello".to_string())),
4770
1
            crate::frontend::ast::Span::new(0, 0),
4771
        );
4772
1
        let result = interp.compile(&string_ast);
4773
1
        assert!(result.is_ok());
4774
4775
1
        assert_eq!(interp.constants_count(), 1); // resets on each compile
4776
1
        assert_eq!(interp.instruction_count(), 2); // load_const + return
4777
4778
        // Compile boolean literal
4779
1
        let bool_ast = Expr::new(
4780
1
            ExprKind::Literal(Literal::Bool(true)),
4781
1
            crate::frontend::ast::Span::new(0, 0),
4782
        );
4783
1
        let result = interp.compile(&bool_ast);
4784
1
        assert!(result.is_ok());
4785
4786
1
        assert_eq!(interp.constants_count(), 1); // resets on each compile
4787
1
        assert_eq!(interp.instruction_count(), 2); // load_const + return
4788
4789
        // Compile nil literal
4790
1
        let nil_ast = Expr::new(
4791
1
            ExprKind::Literal(Literal::Unit),
4792
1
            crate::frontend::ast::Span::new(0, 0),
4793
        );
4794
1
        let result = interp.compile(&nil_ast);
4795
1
        assert!(result.is_ok());
4796
4797
1
        assert_eq!(interp.instruction_count(), 2); // load_nil + return
4798
                                                   // Nil doesn't add to constants, uses special instruction
4799
1
    }
4800
4801
    #[test]
4802
1
    fn test_direct_threaded_binary_op_compilation() {
4803
        use crate::frontend::ast::{BinaryOp, Expr, ExprKind};
4804
4805
1
        let mut interp = DirectThreadedInterpreter::new();
4806
4807
        // Compile: 2 + 3
4808
1
        let add_ast = Expr::new(
4809
1
            ExprKind::Binary {
4810
1
                op: BinaryOp::Add,
4811
1
                left: Box::new(Expr::new(
4812
1
                    ExprKind::Literal(Literal::Integer(2)),
4813
1
                    crate::frontend::ast::Span::new(0, 0),
4814
1
                )),
4815
1
                right: Box::new(Expr::new(
4816
1
                    ExprKind::Literal(Literal::Integer(3)),
4817
1
                    crate::frontend::ast::Span::new(0, 0),
4818
1
                )),
4819
1
            },
4820
1
            crate::frontend::ast::Span::new(0, 0),
4821
        );
4822
4823
1
        let result = interp.compile(&add_ast);
4824
1
        assert!(result.is_ok());
4825
4826
        // Should have: load_const(2), load_const(3), add, return
4827
1
        assert_eq!(interp.instruction_count(), 4);
4828
1
        assert_eq!(interp.constants_count(), 2);
4829
1
    }
4830
4831
    #[test]
4832
1
    fn test_direct_threaded_identifier_compilation() {
4833
        use crate::frontend::ast::{Expr, ExprKind};
4834
4835
1
        let mut interp = DirectThreadedInterpreter::new();
4836
4837
1
        let ident_ast = Expr::new(
4838
1
            ExprKind::Identifier("x".to_string()),
4839
1
            crate::frontend::ast::Span::new(0, 0),
4840
        );
4841
1
        let result = interp.compile(&ident_ast);
4842
1
        assert!(result.is_ok());
4843
4844
        // Should add variable name to constants and generate load_var instruction
4845
1
        assert_eq!(interp.constants_count(), 1);
4846
1
        assert_eq!(interp.instruction_count(), 2); // load_var + return
4847
1
    }
4848
4849
    #[test]
4850
1
    fn test_direct_threaded_execution_simple() {
4851
        use crate::frontend::ast::{Expr, ExprKind};
4852
4853
1
        let mut interp = DirectThreadedInterpreter::new();
4854
4855
        // Compile and execute: 42
4856
1
        let ast = Expr::new(
4857
1
            ExprKind::Literal(Literal::Integer(42)),
4858
1
            crate::frontend::ast::Span::new(0, 0),
4859
        );
4860
1
        interp.compile(&ast).expect("Test should not fail");
4861
4862
1
        let result = interp.execute();
4863
1
        assert!(result.is_ok());
4864
1
        assert_eq!(result.expect("Test should not fail"), Value::Integer(42));
4865
1
    }
4866
4867
    #[test]
4868
1
    fn test_direct_threaded_execution_arithmetic() {
4869
        use crate::frontend::ast::{BinaryOp, Expr, ExprKind};
4870
4871
1
        let mut interp = DirectThreadedInterpreter::new();
4872
4873
        // Compile and execute: 2 + 3
4874
1
        let ast = Expr::new(
4875
1
            ExprKind::Binary {
4876
1
                op: BinaryOp::Add,
4877
1
                left: Box::new(Expr::new(
4878
1
                    ExprKind::Literal(Literal::Integer(2)),
4879
1
                    crate::frontend::ast::Span::new(0, 0),
4880
1
                )),
4881
1
                right: Box::new(Expr::new(
4882
1
                    ExprKind::Literal(Literal::Integer(3)),
4883
1
                    crate::frontend::ast::Span::new(0, 0),
4884
1
                )),
4885
1
            },
4886
1
            crate::frontend::ast::Span::new(0, 0),
4887
        );
4888
4889
1
        interp.compile(&ast).expect("Test should not fail");
4890
1
        let result = interp.execute();
4891
1
        assert!(result.is_ok());
4892
1
        assert_eq!(result.expect("Test should not fail"), Value::Integer(5));
4893
1
    }
4894
4895
    #[test]
4896
1
    fn test_direct_threaded_execution_subtraction() {
4897
        use crate::frontend::ast::{BinaryOp, Expr, ExprKind};
4898
4899
1
        let mut interp = DirectThreadedInterpreter::new();
4900
4901
        // Compile and execute: 10 - 4
4902
1
        let ast = Expr::new(
4903
1
            ExprKind::Binary {
4904
1
                op: BinaryOp::Subtract,
4905
1
                left: Box::new(Expr::new(
4906
1
                    ExprKind::Literal(Literal::Integer(10)),
4907
1
                    crate::frontend::ast::Span::new(0, 0),
4908
1
                )),
4909
1
                right: Box::new(Expr::new(
4910
1
                    ExprKind::Literal(Literal::Integer(4)),
4911
1
                    crate::frontend::ast::Span::new(0, 0),
4912
1
                )),
4913
1
            },
4914
1
            crate::frontend::ast::Span::new(0, 0),
4915
        );
4916
4917
1
        interp.compile(&ast).expect("Test should not fail");
4918
1
        let result = interp.execute();
4919
1
        assert!(result.is_ok());
4920
1
        assert_eq!(result.expect("Test should not fail"), Value::Integer(6));
4921
1
    }
4922
4923
    #[test]
4924
1
    fn test_direct_threaded_execution_multiplication() {
4925
        use crate::frontend::ast::{BinaryOp, Expr, ExprKind};
4926
4927
1
        let mut interp = DirectThreadedInterpreter::new();
4928
4929
        // Compile and execute: 6 * 7
4930
1
        let ast = Expr::new(
4931
1
            ExprKind::Binary {
4932
1
                op: BinaryOp::Multiply,
4933
1
                left: Box::new(Expr::new(
4934
1
                    ExprKind::Literal(Literal::Integer(6)),
4935
1
                    crate::frontend::ast::Span::new(0, 0),
4936
1
                )),
4937
1
                right: Box::new(Expr::new(
4938
1
                    ExprKind::Literal(Literal::Integer(7)),
4939
1
                    crate::frontend::ast::Span::new(0, 0),
4940
1
                )),
4941
1
            },
4942
1
            crate::frontend::ast::Span::new(0, 0),
4943
        );
4944
4945
1
        interp.compile(&ast).expect("Test should not fail");
4946
1
        let result = interp.execute();
4947
1
        assert!(result.is_ok());
4948
1
        assert_eq!(result.expect("Test should not fail"), Value::Integer(42));
4949
1
    }
4950
4951
    #[test]
4952
1
    fn test_direct_threaded_execution_division() {
4953
        use crate::frontend::ast::{BinaryOp, Expr, ExprKind};
4954
4955
1
        let mut interp = DirectThreadedInterpreter::new();
4956
4957
        // Compile and execute: 20 / 4
4958
1
        let ast = Expr::new(
4959
1
            ExprKind::Binary {
4960
1
                op: BinaryOp::Divide,
4961
1
                left: Box::new(Expr::new(
4962
1
                    ExprKind::Literal(Literal::Integer(20)),
4963
1
                    crate::frontend::ast::Span::new(0, 0),
4964
1
                )),
4965
1
                right: Box::new(Expr::new(
4966
1
                    ExprKind::Literal(Literal::Integer(4)),
4967
1
                    crate::frontend::ast::Span::new(0, 0),
4968
1
                )),
4969
1
            },
4970
1
            crate::frontend::ast::Span::new(0, 0),
4971
        );
4972
4973
1
        interp.compile(&ast).expect("Test should not fail");
4974
1
        let result = interp.execute();
4975
1
        assert!(result.is_ok());
4976
1
        assert_eq!(result.expect("Test should not fail"), Value::Integer(5));
4977
1
    }
4978
4979
    #[test]
4980
1
    fn test_direct_threaded_execution_mixed_types() {
4981
        use crate::frontend::ast::{BinaryOp, Expr, ExprKind};
4982
4983
1
        let mut interp = DirectThreadedInterpreter::new();
4984
4985
        // Compile and execute: 2.5 + 3 (float + int)
4986
1
        let ast = Expr::new(
4987
1
            ExprKind::Binary {
4988
1
                op: BinaryOp::Add,
4989
1
                left: Box::new(Expr::new(
4990
1
                    ExprKind::Literal(Literal::Float(2.5)),
4991
1
                    crate::frontend::ast::Span::new(0, 0),
4992
1
                )),
4993
1
                right: Box::new(Expr::new(
4994
1
                    ExprKind::Literal(Literal::Integer(3)),
4995
1
                    crate::frontend::ast::Span::new(0, 0),
4996
1
                )),
4997
1
            },
4998
1
            crate::frontend::ast::Span::new(0, 0),
4999
        );
5000
5001
1
        interp.compile(&ast).expect("Test should not fail");
5002
1
        let result = interp.execute();
5003
1
        assert!(result.is_ok());
5004
1
        assert_eq!(result.expect("Test should not fail"), Value::Float(5.5));
5005
1
    }
5006
5007
    #[test]
5008
1
    fn test_direct_threaded_execution_division_by_zero() {
5009
        use crate::frontend::ast::{BinaryOp, Expr, ExprKind};
5010
5011
1
        let mut interp = DirectThreadedInterpreter::new();
5012
5013
        // Compile and execute: 5 / 0
5014
1
        let ast = Expr::new(
5015
1
            ExprKind::Binary {
5016
1
                op: BinaryOp::Divide,
5017
1
                left: Box::new(Expr::new(
5018
1
                    ExprKind::Literal(Literal::Integer(5)),
5019
1
                    crate::frontend::ast::Span::new(0, 0),
5020
1
                )),
5021
1
                right: Box::new(Expr::new(
5022
1
                    ExprKind::Literal(Literal::Integer(0)),
5023
1
                    crate::frontend::ast::Span::new(0, 0),
5024
1
                )),
5025
1
            },
5026
1
            crate::frontend::ast::Span::new(0, 0),
5027
        );
5028
5029
1
        interp.compile(&ast).expect("Test should not fail");
5030
1
        let result = interp.execute();
5031
1
        assert!(result.is_err());
5032
1
    }
5033
5034
    #[test]
5035
1
    fn test_direct_threaded_execution_variable_lookup() {
5036
        use crate::frontend::ast::{Expr, ExprKind};
5037
        use std::collections::HashMap;
5038
5039
1
        let mut interp = DirectThreadedInterpreter::new();
5040
5041
        // Set up environment with variable
5042
1
        let mut env = HashMap::new();
5043
1
        env.insert("x".to_string(), Value::Integer(42));
5044
5045
        // Compile and execute: x
5046
1
        let ast = Expr::new(
5047
1
            ExprKind::Identifier("x".to_string()),
5048
1
            crate::frontend::ast::Span::new(0, 0),
5049
        );
5050
1
        interp.compile(&ast).expect("Test should not fail");
5051
5052
1
        let mut state = InterpreterState::new();
5053
1
        state.env_stack.push(env);
5054
1
        state.constants = interp.constants.clone();
5055
5056
        // Execute with variable in environment
5057
1
        let result = interp.execute_with_state(&mut state);
5058
1
        assert!(result.is_ok());
5059
1
        assert_eq!(result.expect("Test should not fail"), Value::Integer(42));
5060
1
    }
5061
5062
    #[test]
5063
1
    fn test_direct_threaded_execution_undefined_variable() {
5064
        use crate::frontend::ast::{Expr, ExprKind};
5065
5066
1
        let mut interp = DirectThreadedInterpreter::new();
5067
5068
        // Compile and execute: undefined_var
5069
1
        let ast = Expr::new(
5070
1
            ExprKind::Identifier("undefined_var".to_string()),
5071
1
            crate::frontend::ast::Span::new(0, 0),
5072
        );
5073
1
        interp.compile(&ast).expect("Test should not fail");
5074
5075
1
        let result = interp.execute();
5076
1
        assert!(result.is_err());
5077
1
        match result.expect_err("Test should fail") {
5078
1
            InterpreterError::RuntimeError(msg) => {
5079
1
                assert!(msg.contains("Undefined variable"));
5080
            }
5081
0
            _ => panic!("Expected RuntimeError"),
5082
        }
5083
1
    }
5084
5085
    #[test]
5086
1
    fn test_direct_threaded_instruction_handlers() {
5087
1
        let mut state = InterpreterState::new();
5088
5089
        // Test op_load_const
5090
1
        state.constants.push(Value::Integer(42));
5091
1
        let result = op_load_const(&mut state, 0);
5092
1
        assert_eq!(result, InstructionResult::Continue);
5093
1
        assert_eq!(state.stack.len(), 1);
5094
1
        assert_eq!(state.stack[0], Value::Integer(42));
5095
5096
        // Test op_load_nil
5097
1
        let result = op_load_nil(&mut state, 0);
5098
1
        assert_eq!(result, InstructionResult::Continue);
5099
1
        assert_eq!(state.stack.len(), 2);
5100
1
        assert_eq!(state.stack[1], Value::Nil);
5101
5102
        // Test arithmetic operations
5103
1
        state.stack.clear();
5104
1
        state.stack.push(Value::Integer(5));
5105
1
        state.stack.push(Value::Integer(3));
5106
5107
1
        let result = op_add(&mut state, 0);
5108
1
        assert_eq!(result, InstructionResult::Continue);
5109
1
        assert_eq!(state.stack.len(), 1);
5110
1
        assert_eq!(state.stack[0], Value::Integer(8));
5111
1
    }
5112
5113
    #[test]
5114
1
    fn test_direct_threaded_clear() {
5115
1
        let mut interp = DirectThreadedInterpreter::new();
5116
5117
        // Add some instructions and constants
5118
1
        interp.add_constant(Value::Integer(42));
5119
1
        interp.add_instruction(op_load_const, 0);
5120
5121
1
        assert!(interp.instruction_count() > 0);
5122
1
        assert!(interp.constants_count() > 0);
5123
5124
        // Clear should reset everything
5125
1
        interp.clear();
5126
5127
1
        assert_eq!(interp.instruction_count(), 0);
5128
1
        assert_eq!(interp.constants_count(), 0);
5129
1
    }
5130
}