refactor: VM-only architecture — remove tree-walking interpreter
Eliminate dual-engine architecture (Interpreter + Vm) in favor of a single bytecode VM executor. - Extract shared types (Value, FunctionProto, Closure, UpvalueObj, Runtime trait, NativeFn) into new module - Consolidate builtin registration in — single used by VM, eliminates 40-line duplicate - Delete tree-walker: exec.rs, eval.rs, interpreter.rs, env.rs, module.rs - Change Value::Function(Rc<Function>) → Value::Function(Rc<Closure>) eliminating the closures HashMap pointer-key hack - Fix VM semantic gaps found during migration: * Structural equality for Object/Array in is_equal * CompoundAssignGlobal opcode (global compound assigns were broken) * 9 string methods added to VM get_property * ForInInit error on non-iterable values - Switch run_file/run_repl to VM; remove --vm CLI flag - Move 327 tests from interpreter/ to vm/ — all pass Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -7,67 +7,12 @@
|
||||
use crate::ast::*;
|
||||
use crate::ast::expr::{Literal, UnaryOp, BinaryOp, LogicalOp, AssignOp};
|
||||
use crate::error::RuntimeError;
|
||||
use crate::interpreter::Value;
|
||||
use crate::runtime::{Value, FunctionProto};
|
||||
use super::opcode::*;
|
||||
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
|
||||
// ============================================================================
|
||||
// FunctionProto — compiled function blueprint
|
||||
// ============================================================================
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FunctionProto {
|
||||
pub name: Option<String>,
|
||||
pub arity: u8,
|
||||
pub code: Vec<u8>,
|
||||
pub constants: Vec<Value>,
|
||||
/// Nested function protos (for closures and function declarations)
|
||||
pub protos: Vec<Rc<FunctionProto>>,
|
||||
pub upvalue_count: u8,
|
||||
/// Upvalue descriptors for this function (for Closure opcode emission)
|
||||
pub upvalues: Vec<(bool, u8)>, // (is_local, index)
|
||||
pub lines: Vec<(usize, usize)>, // (bytecode_offset, source_line)
|
||||
}
|
||||
|
||||
impl FunctionProto {
|
||||
pub fn new(name: Option<String>) -> Self {
|
||||
Self {
|
||||
name,
|
||||
arity: 0,
|
||||
code: Vec::new(),
|
||||
constants: Vec::new(),
|
||||
protos: Vec::new(),
|
||||
upvalue_count: 0,
|
||||
upvalues: Vec::new(),
|
||||
lines: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_constant(&mut self, val: Value) -> u16 {
|
||||
// Check for existing identical constant
|
||||
for (i, c) in self.constants.iter().enumerate() {
|
||||
if values_eq(c, &val) {
|
||||
return i as u16;
|
||||
}
|
||||
}
|
||||
let idx = self.constants.len();
|
||||
self.constants.push(val);
|
||||
idx as u16
|
||||
}
|
||||
}
|
||||
|
||||
fn values_eq(a: &Value, b: &Value) -> bool {
|
||||
match (a, b) {
|
||||
(Value::Number(x), Value::Number(y)) => (x - y).abs() < f64::EPSILON,
|
||||
(Value::String(x), Value::String(y)) => x == y,
|
||||
(Value::Bool(x), Value::Bool(y)) => x == y,
|
||||
(Value::Nil, Value::Nil) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Compiler
|
||||
// ============================================================================
|
||||
@@ -536,7 +481,7 @@ impl Compiler {
|
||||
self.function.code.push(compound_op as u8);
|
||||
} else {
|
||||
let name_idx = self.add_string_constant(name);
|
||||
emit_u16(&mut self.function.code, OpCode::CompoundAssignProp, name_idx);
|
||||
emit_u16(&mut self.function.code, OpCode::CompoundAssignGlobal, name_idx);
|
||||
self.function.code.push(compound_op as u8);
|
||||
}
|
||||
}
|
||||
@@ -558,16 +503,11 @@ impl Compiler {
|
||||
emit_u16(&mut self.function.code, OpCode::SetProperty, name_idx);
|
||||
} else {
|
||||
// Compound property set: object.name op= value
|
||||
// Strategy: load object, dup, get property as current value,
|
||||
// load rhs, apply op, set property
|
||||
// CompoundAssignProp handler does get_property internally
|
||||
self.compile_expr(object)?;
|
||||
self.emit_op(OpCode::Dup);
|
||||
let name_idx = self.add_string_constant(name);
|
||||
emit_u16(&mut self.function.code, OpCode::GetProperty, name_idx); // current value
|
||||
self.compile_expr(value)?; // rhs
|
||||
let compound_op = assign_op_to_compound(op);
|
||||
self.function.code.push(compound_op as u8);
|
||||
// Now stack: object, current_val, rhs → set property
|
||||
let name_idx = self.add_string_constant(name);
|
||||
emit_u16(&mut self.function.code, OpCode::CompoundAssignProp, name_idx);
|
||||
self.function.code.push(compound_op as u8);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user