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:
+13
-33
@@ -1,6 +1,7 @@
|
||||
pub mod lexer;
|
||||
pub mod ast;
|
||||
pub mod parser;
|
||||
pub mod runtime;
|
||||
pub mod interpreter;
|
||||
pub mod vm;
|
||||
pub mod error;
|
||||
@@ -8,7 +9,6 @@ pub mod analysis;
|
||||
|
||||
use lexer::Lexer;
|
||||
use parser::Parser;
|
||||
use interpreter::Interpreter;
|
||||
use vm::compiler::Compiler;
|
||||
use vm::vm::Vm;
|
||||
use error::RuntimeError;
|
||||
@@ -37,33 +37,6 @@ pub fn run_file(filename: &str, src: String) {
|
||||
std::process::exit(65);
|
||||
}
|
||||
|
||||
let script_dir = std::path::Path::new(filename)
|
||||
.parent()
|
||||
.map(|p| p.to_string_lossy().to_string())
|
||||
.unwrap_or_else(|| ".".to_string());
|
||||
|
||||
let mut interpreter = Interpreter::with_current_dir(script_dir);
|
||||
if let Err(e) = interpreter.interpret(stmts) {
|
||||
eprintln!("Error: {}", e);
|
||||
std::process::exit(70);
|
||||
}
|
||||
}
|
||||
|
||||
/// Run a file using the bytecode VM (for performance comparison).
|
||||
pub fn run_file_vm(filename: &str, src: String) {
|
||||
let (tokens, lex_errors) = Lexer::new(&src).tokenize();
|
||||
if !lex_errors.is_empty() {
|
||||
print_errors(&lex_errors);
|
||||
std::process::exit(65);
|
||||
}
|
||||
|
||||
let mut parser = Parser::new(tokens);
|
||||
let (stmts, parse_errors) = parser.parse();
|
||||
if !parse_errors.is_empty() {
|
||||
print_errors(&parse_errors);
|
||||
std::process::exit(65);
|
||||
}
|
||||
|
||||
let script_dir = std::path::Path::new(filename)
|
||||
.parent()
|
||||
.map(|p| p.to_string_lossy().to_string())
|
||||
@@ -87,9 +60,9 @@ pub fn run_file_vm(filename: &str, src: String) {
|
||||
pub fn run_repl() {
|
||||
println!("Welcome to Aster REPL!");
|
||||
println!("Type ':exit' to quit.");
|
||||
println!("Type ':reset' to reset the interpreter state.");
|
||||
println!("Type ':reset' to reset the VM state.");
|
||||
|
||||
let mut interpreter = Interpreter::new();
|
||||
let mut vm = Vm::new();
|
||||
let mut line = String::new();
|
||||
|
||||
loop {
|
||||
@@ -113,8 +86,8 @@ pub fn run_repl() {
|
||||
break;
|
||||
}
|
||||
":reset" => {
|
||||
interpreter = Interpreter::new();
|
||||
println!("Interpreter reset.");
|
||||
vm = Vm::new();
|
||||
println!("VM reset.");
|
||||
continue;
|
||||
}
|
||||
_ => {}
|
||||
@@ -133,7 +106,14 @@ pub fn run_repl() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Err(e) = interpreter.interpret(stmts) {
|
||||
let proto = match Compiler::compile(&stmts) {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
eprintln!("Compile Error: {}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
if let Err(e) = vm.run(std::rc::Rc::new(proto)) {
|
||||
eprintln!("Error: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user