## Coverage Report

#### Created: 2025-09-08 21:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /home/noah/src/ruchy/src/runtime/interpreter.rs

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