Phase 1-3: 基础VM架构 - 新增 Runtime trait: 抽象树遍历解释器和VM的共同接口 - NativeFn 改为接受 &mut dyn Runtime - 重构所有内置函数使用新签名 - vm/opcode.rs: 33个字节码指令 + 编码/解码辅助函数 - vm/compiler.rs: AST→字节码编译器,支持变量解析、跳转回填、作用域 - vm/vm.rs: 栈式VM执行循环,支持全局变量、原生函数调用 - lib.rs: 新增 run_file_vm() + --vm CLI标志 - 修复: 跳转偏移计算、对象字面量编译 工作特性: 算术、变量、while/for循环、条件、数组、对象、字符串 待完成: 用户定义函数调用、闭包/upvalue捕获、完整require支持 Release模式: 1M算术循环 VM 0.44s vs 树遍历 0.89s (2.0x加速)
144 lines
5.0 KiB
Rust
144 lines
5.0 KiB
Rust
//! 模块系统:require() 加载器
|
|
//!
|
|
//! `require("path/to/module.ast")` 加载并执行指定的 Aster 文件,
|
|
//! 返回一个包含模块所有顶层定义的 `Value::Object`。
|
|
//! 模块在自己的作用域中执行,只能访问内置函数,无法访问调用者的变量。
|
|
//! 第二次 require 同一文件会返回缓存的对象。
|
|
|
|
use crate::error::RuntimeError;
|
|
use crate::lexer::Lexer;
|
|
use crate::parser::Parser;
|
|
use super::{Interpreter, Env, Value, Signal, Runtime};
|
|
use std::cell::RefCell;
|
|
use std::collections::HashMap;
|
|
use std::path::Path;
|
|
use std::rc::Rc;
|
|
|
|
impl Runtime for Interpreter {
|
|
fn require(&mut self, path: &str) -> Result<Value, RuntimeError> {
|
|
require_impl(self, path)
|
|
}
|
|
}
|
|
|
|
/// require() 的内置函数实现 — 薄包装,委托给 Runtime::require
|
|
pub fn require_fn(runtime: &mut dyn Runtime, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
|
let path_str = match args.first() {
|
|
Some(Value::String(s)) => s.clone(),
|
|
Some(other) => return Err(runtime_error(format!(
|
|
"require() expects a string argument, got {}", other))),
|
|
None => return Err(runtime_error(
|
|
"require() expects 1 argument (string path)")),
|
|
};
|
|
runtime.require(&path_str)
|
|
}
|
|
|
|
/// require() 的内部实现 (供 Interpreter::require 使用)
|
|
fn require_impl(interp: &mut Interpreter, path_str: &str) -> Result<Value, RuntimeError> {
|
|
// 1. 路径解析
|
|
let resolved = resolve_path(&interp.current_dir, path_str)?;
|
|
|
|
// 2. 缓存查找
|
|
if let Some(cached) = interp.module_cache.borrow().get(&resolved) {
|
|
return Ok(cached.clone());
|
|
}
|
|
|
|
// 3. 读取文件
|
|
let src = std::fs::read_to_string(&resolved)
|
|
.map_err(|e| runtime_error(format!(
|
|
"Module '{}' not found: {}", path_str, e)))?;
|
|
|
|
// 4. 词法分析
|
|
let (tokens, lex_errors) = Lexer::new(&src).tokenize();
|
|
if !lex_errors.is_empty() {
|
|
return Err(runtime_error(format!(
|
|
"Lex error in module '{}': {}", path_str, lex_errors[0])));
|
|
}
|
|
|
|
// 5. 语法分析
|
|
let mut parser = Parser::new(tokens);
|
|
let (stmts, parse_errors) = parser.parse();
|
|
if !parse_errors.is_empty() {
|
|
return Err(runtime_error(format!(
|
|
"Parse error in module '{}': {}", path_str, parse_errors[0])));
|
|
}
|
|
|
|
// 6. 创建隔离的模块 env(父级 = builtins_env,看不到调用者的变量)
|
|
let module_env = Rc::new(RefCell::new(Env::new(Some(Rc::clone(&interp.builtins_env)))));
|
|
|
|
// 7. 在缓存中插入占位符(支持循环 require)
|
|
let exports_map = Rc::new(RefCell::new(HashMap::new()));
|
|
let exports = Value::Object(Rc::clone(&exports_map));
|
|
interp.module_cache.borrow_mut().insert(resolved.clone(), exports.clone());
|
|
|
|
// 8. 保存调用者状态
|
|
let previous_env = Rc::clone(&interp.env);
|
|
let previous_dir = interp.current_dir.clone();
|
|
|
|
// 9. 切换到模块上下文
|
|
interp.env = module_env.clone();
|
|
interp.current_dir = module_dir(&resolved);
|
|
|
|
// 10. 执行模块
|
|
for stmt in &stmts {
|
|
match interp.execute(stmt.clone()) {
|
|
Ok(Signal::Break) | Ok(Signal::Continue) => {
|
|
interp.env = previous_env;
|
|
interp.current_dir = previous_dir;
|
|
interp.module_cache.borrow_mut().remove(&resolved);
|
|
return Err(runtime_error(
|
|
"break/continue outside of loop in module"));
|
|
}
|
|
Err(e) => {
|
|
interp.env = previous_env;
|
|
interp.current_dir = previous_dir;
|
|
interp.module_cache.borrow_mut().remove(&resolved);
|
|
return Err(e);
|
|
}
|
|
Ok(Signal::None) | Ok(Signal::Return(_)) => {}
|
|
}
|
|
}
|
|
|
|
// 11. 恢复调用者状态
|
|
interp.env = previous_env;
|
|
interp.current_dir = previous_dir;
|
|
|
|
// 12. 收集 exports(模块 env 中的所有直接绑定)
|
|
for (name, (val, _mutable)) in module_env.borrow().values.clone() {
|
|
exports_map.borrow_mut().insert(name, val);
|
|
}
|
|
|
|
Ok(exports)
|
|
}
|
|
|
|
// ============================================================================
|
|
// Helpers
|
|
// ============================================================================
|
|
|
|
fn resolve_path(current_dir: &str, path_str: &str) -> Result<String, RuntimeError> {
|
|
let path = Path::new(path_str);
|
|
let resolved = if path.is_absolute() {
|
|
path.to_path_buf()
|
|
} else {
|
|
Path::new(current_dir).join(path)
|
|
};
|
|
std::fs::canonicalize(&resolved)
|
|
.map(|p| p.to_string_lossy().to_string())
|
|
.map_err(|_| runtime_error(format!(
|
|
"Module '{}' not found (resolved to '{}')",
|
|
path_str, resolved.display())))
|
|
}
|
|
|
|
fn module_dir(resolved: &str) -> String {
|
|
Path::new(resolved)
|
|
.parent()
|
|
.map(|p| p.to_string_lossy().to_string())
|
|
.unwrap_or_else(|| ".".to_string())
|
|
}
|
|
|
|
fn runtime_error(msg: impl Into<String>) -> RuntimeError {
|
|
RuntimeError::RuntimeError {
|
|
message: msg.into(),
|
|
token: None,
|
|
}
|
|
}
|