Refactor: Remove explicit upvalue analysis pass

The `UpvalueAnalyzer` pass is no longer necessary as the binder now
directly tracks captures. This commit removes the `UpvalueAnalyzer`
struct and associated logic from `src/ast/compiler/upvalues.rs`.

The `Binder::bind_root` function now returns the `captures` map, which
is then processed by a new `CapturePass` in `src/ast/environment.rs`
before type checking. This consolidates capture logic within the binder
and its subsequent processing steps.
This commit is contained in:
Michael Schimmel
2026-02-25 12:15:59 +01:00
parent 82daf03522
commit 0371c21523
5 changed files with 92 additions and 204 deletions
+18 -7
View File
@@ -17,10 +17,12 @@ use crate::ast::compiler::specializer::{FunctionRegistry, MonoCache, Specializer
use crate::ast::compiler::tco::{ExecNode, TCO};
use crate::ast::rtl;
use crate::ast::rtl::intrinsics;
use crate::ast::types::{Object, Purity, StaticType, Value};
use crate::ast::types::{
Identity, NodeIdentity, Object, Purity, SourceLocation, StaticType, Value,
};
pub struct Environment {
pub global_names: Rc<RefCell<HashMap<Symbol, u32>>>,
pub global_names: Rc<RefCell<HashMap<Symbol, (u32, Identity)>>>,
pub global_types: Rc<RefCell<HashMap<u32, StaticType>>>,
pub global_purity: Rc<RefCell<HashMap<u32, Purity>>>,
pub global_values: Rc<RefCell<Vec<Value>>>,
@@ -55,7 +57,7 @@ impl FunctionRegistry for EnvFunctionRegistry {
}
struct RuntimeMacroEvaluator {
global_names: Rc<RefCell<HashMap<Symbol, u32>>>,
global_names: Rc<RefCell<HashMap<Symbol, (u32, Identity)>>>,
global_types: Rc<RefCell<HashMap<u32, StaticType>>>,
global_values: Rc<RefCell<Vec<Value>>>,
}
@@ -72,7 +74,8 @@ impl MacroEvaluator for RuntimeMacroEvaluator {
return Ok(Value::Object(Rc::new(arg_node.clone()) as Rc<dyn Object>));
}
let bound_ast = Binder::bind_root(self.global_names.clone(), node)?;
let (bound_ast, captures) = Binder::bind_root(self.global_names.clone(), node)?;
let bound_ast = crate::ast::compiler::captures::CapturePass::apply(bound_ast, &captures);
let checker = TypeChecker::new(self.global_types.clone());
let typed_ast = checker.check(bound_ast, &[])?;
let exec_ast = TCO::optimize(Analyzer::analyze(&typed_ast, &HashMap::new())); // Minimal analysis for macro eval
@@ -131,7 +134,10 @@ impl Environment {
let mut purity = self.global_purity.borrow_mut();
let idx = values.len() as u32;
names.insert(Symbol::from(name), idx);
let identity = Rc::new(NodeIdentity {
location: SourceLocation { line: 0, col: 0 },
});
names.insert(Symbol::from(name), (idx, identity));
types.insert(idx, ty);
purity.insert(idx, func.purity);
values.push(Value::Function(func));
@@ -161,7 +167,10 @@ impl Environment {
let mut purity = self.global_purity.borrow_mut();
let idx = values.len() as u32;
names.insert(Symbol::from(name), idx);
let identity = Rc::new(NodeIdentity {
location: SourceLocation { line: 0, col: 0 },
});
names.insert(Symbol::from(name), (idx, identity));
types.insert(idx, ty);
purity.insert(idx, Purity::Pure);
values.push(val);
@@ -186,7 +195,9 @@ impl Environment {
}
let expanded_ast = self.get_expander().expand(untyped_ast)?;
let bound_ast = Binder::bind_root(self.global_names.clone(), &expanded_ast)?;
let (bound_ast, captures) = Binder::bind_root(self.global_names.clone(), &expanded_ast)?;
let bound_ast = crate::ast::compiler::captures::CapturePass::apply(bound_ast, &captures);
LambdaCollector::collect(&bound_ast, &mut self.function_registry.borrow_mut());
let checker = TypeChecker::new(self.global_types.clone());