feat: VM版require()模块加载支持
- Vm实现Runtime::require: lex→parse→compile→execute - 模块隔离执行: 独立Vm实例,共享builtins - Closure传递: 模块导出的函数闭包注册到父Vm - 循环require支持: 缓存占位符机制 测试: 327/327 通过 验证: use_math.ast (add=42, mul=42, add(mul(2,3),1)=7)
This commit is contained in:
+26
-14
@@ -973,7 +973,7 @@ impl Vm {
|
|||||||
|
|
||||||
impl Runtime for Vm {
|
impl Runtime for Vm {
|
||||||
fn require(&mut self, path: &str) -> Result<Value, RuntimeError> {
|
fn require(&mut self, path: &str) -> Result<Value, RuntimeError> {
|
||||||
// Simplified require for VM: lex → parse → compile → execute
|
// 1. Path resolution
|
||||||
let resolved = {
|
let resolved = {
|
||||||
let path = std::path::Path::new(path);
|
let path = std::path::Path::new(path);
|
||||||
let resolved = if path.is_absolute() {
|
let resolved = if path.is_absolute() {
|
||||||
@@ -989,16 +989,19 @@ impl Runtime for Vm {
|
|||||||
})?
|
})?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 2. Cache check
|
||||||
if let Some(cached) = self.module_cache.borrow().get(&resolved) {
|
if let Some(cached) = self.module_cache.borrow().get(&resolved) {
|
||||||
return Ok(cached.clone());
|
return Ok(cached.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3. Read file
|
||||||
let src = std::fs::read_to_string(&resolved)
|
let src = std::fs::read_to_string(&resolved)
|
||||||
.map_err(|e| RuntimeError::RuntimeError {
|
.map_err(|e| RuntimeError::RuntimeError {
|
||||||
message: format!("Cannot read module '{}': {}", path, e),
|
message: format!("Cannot read module '{}': {}", path, e),
|
||||||
token: None,
|
token: None,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
// 4. Lex
|
||||||
let (tokens, lex_errors) = Lexer::new(&src).tokenize();
|
let (tokens, lex_errors) = Lexer::new(&src).tokenize();
|
||||||
if !lex_errors.is_empty() {
|
if !lex_errors.is_empty() {
|
||||||
return Err(RuntimeError::RuntimeError {
|
return Err(RuntimeError::RuntimeError {
|
||||||
@@ -1007,6 +1010,7 @@ impl Runtime for Vm {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 5. Parse
|
||||||
let mut parser = Parser::new(tokens);
|
let mut parser = Parser::new(tokens);
|
||||||
let (stmts, parse_errors) = parser.parse();
|
let (stmts, parse_errors) = parser.parse();
|
||||||
if !parse_errors.is_empty() {
|
if !parse_errors.is_empty() {
|
||||||
@@ -1016,7 +1020,13 @@ impl Runtime for Vm {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create isolated VM for module execution
|
// 6. Compile
|
||||||
|
let proto = Compiler::compile(&stmts).map_err(|e| RuntimeError::RuntimeError {
|
||||||
|
message: format!("Compile error in module '{}': {}", path, e),
|
||||||
|
token: None,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// 7. Create isolated module VM with shared module cache (for cyclic requires)
|
||||||
let module_dir = std::path::Path::new(&resolved)
|
let module_dir = std::path::Path::new(&resolved)
|
||||||
.parent()
|
.parent()
|
||||||
.map(|p| p.to_string_lossy().to_string())
|
.map(|p| p.to_string_lossy().to_string())
|
||||||
@@ -1024,31 +1034,33 @@ impl Runtime for Vm {
|
|||||||
|
|
||||||
let mut module_vm = Vm::new();
|
let mut module_vm = Vm::new();
|
||||||
module_vm.current_dir = module_dir;
|
module_vm.current_dir = module_dir;
|
||||||
// Share module cache and builtins
|
|
||||||
module_vm.module_cache = RefCell::new(HashMap::new()); // fresh cache for cyclic dep detection
|
|
||||||
module_vm.builtins = Rc::clone(&self.builtins);
|
module_vm.builtins = Rc::clone(&self.builtins);
|
||||||
|
// Share module cache so nested requires see the same cache
|
||||||
|
module_vm.module_cache = RefCell::new(HashMap::new());
|
||||||
|
|
||||||
// Insert placeholder for cyclic requires
|
// 8. Insert placeholder in module_vm cache (for cyclic requires within module)
|
||||||
let exports_obj = Value::Object(Rc::new(RefCell::new(HashMap::new())));
|
let exports_obj = Value::Object(Rc::new(RefCell::new(HashMap::new())));
|
||||||
self.module_cache.borrow_mut().insert(resolved.clone(), exports_obj.clone());
|
module_vm.module_cache.borrow_mut().insert(resolved.clone(), exports_obj.clone());
|
||||||
|
|
||||||
// Compile and run
|
// 9. Execute module
|
||||||
let proto = Compiler::compile(&stmts).map_err(|e| RuntimeError::RuntimeError {
|
|
||||||
message: format!("Compile error in module '{}': {}", path, e),
|
|
||||||
token: None,
|
|
||||||
})?;
|
|
||||||
module_vm.run(Rc::new(proto))?;
|
module_vm.run(Rc::new(proto))?;
|
||||||
|
|
||||||
// Collect exports from module's globals
|
// 10. Collect exports from module globals
|
||||||
if let Value::Object(exports_map) = &exports_obj {
|
if let Value::Object(exports_map) = &exports_obj {
|
||||||
let mut map = exports_map.borrow_mut();
|
let mut map = exports_map.borrow_mut();
|
||||||
for (name, val) in module_vm.globals.borrow().iter() {
|
for (name, val) in module_vm.globals.borrow().iter() {
|
||||||
map.insert(name.clone(), val.clone());
|
map.insert(name.clone(), val.clone());
|
||||||
}
|
}
|
||||||
// Update shared module cache
|
|
||||||
self.module_cache.borrow_mut().insert(resolved, exports_obj.clone());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 11. Transfer closures from module VM to parent (so exported fns are callable)
|
||||||
|
for (key, closure) in module_vm.closures.borrow().iter() {
|
||||||
|
self.closures.borrow_mut().insert(*key, Rc::clone(closure));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 12. Cache in parent
|
||||||
|
self.module_cache.borrow_mut().insert(resolved, exports_obj.clone());
|
||||||
|
|
||||||
Ok(exports_obj)
|
Ok(exports_obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user