Refactor Binder initialization and root binding

The `Binder` and `FunctionCompiler` initialization has been refactored
to accept initial scopes and slot counts. This allows for more flexible
management of the compiler's state, particularly for the root scope.

The `bind_root` function now returns the final scopes and slot count of
the root function compiler, enabling the `Environment` to update its
state with these new bindings.

The global variable handling has been integrated into the scope
management, removing the direct reliance on a shared `HashMap` for
globals. This promotes a more consistent approach to symbol resolution.
This commit is contained in:
Michael Schimmel
2026-03-12 14:40:13 +01:00
parent 08b5bba2c4
commit a220815bd6
3 changed files with 79 additions and 91 deletions
+19 -7
View File
@@ -112,7 +112,8 @@ impl FunctionRegistry for EnvFunctionRegistry {
}
struct RuntimeMacroEvaluator {
global_names: Rc<RefCell<HashMap<Symbol, (GlobalIdx, Identity)>>>,
root_scopes: Rc<RefCell<Vec<crate::ast::compiler::binder::CompilerScope>>>,
root_slot_count: Rc<RefCell<u32>>,
global_types: Rc<RefCell<HashMap<GlobalIdx, StaticType>>>,
global_values: Rc<RefCell<Vec<Value>>>,
fixed_scope_idx: i32,
@@ -131,7 +132,10 @@ impl MacroEvaluator for RuntimeMacroEvaluator {
}
let mut diag = Diagnostics::new();
let (bound_ast, captures) = Binder::bind_root(self.global_names.clone(), self.fixed_scope_idx, node, &mut diag)?;
let initial_scopes = self.root_scopes.borrow().clone();
let initial_slot_count = *self.root_slot_count.borrow();
let (bound_ast, captures, _, _) = Binder::bind_root(initial_scopes, initial_slot_count, self.fixed_scope_idx, node, &mut diag)?;
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, &[], &mut diag);
@@ -219,7 +223,8 @@ impl Environment {
fn get_expander(&self) -> MacroExpander<RuntimeMacroEvaluator> {
let evaluator = RuntimeMacroEvaluator {
global_names: self.global_names.clone(),
root_scopes: self.root_scopes.clone(),
root_slot_count: self.root_slot_count.clone(),
global_types: self.global_types.clone(),
global_values: self.global_values.clone(),
fixed_scope_idx: self.fixed_scope_idx,
@@ -433,8 +438,11 @@ impl Environment {
}
};
let (bound_ast, captures) =
match Binder::bind_root(self.global_names.clone(), self.fixed_scope_idx, &expanded_ast, diagnostics) {
let initial_scopes = self.root_scopes.borrow().clone();
let initial_slot_count = *self.root_slot_count.borrow();
let (bound_ast, captures, final_scopes, final_slot_count) =
match Binder::bind_root(initial_scopes, initial_slot_count, self.fixed_scope_idx, &expanded_ast, diagnostics) {
Ok(res) => res,
Err(e) => {
diagnostics.push_error(e, None);
@@ -442,6 +450,10 @@ impl Environment {
}
};
// Update environment state with new bindings from this script
*self.root_scopes.borrow_mut() = final_scopes;
*self.root_slot_count.borrow_mut() = final_slot_count;
let bound_ast = crate::ast::compiler::captures::CapturePass::apply(bound_ast, &captures);
// Pre-allocate global slots to prevent out-of-bounds during specialization/optimization
@@ -520,7 +532,7 @@ impl Environment {
root_scopes[0].locals.insert(
Symbol::from(name),
crate::ast::compiler::binder::LocalInfo {
addr: Address::Local(slot),
addr: Address::Global(GlobalIdx(slot.0)),
identity,
_ty: ty,
purity: func.purity,
@@ -566,7 +578,7 @@ impl Environment {
root_scopes[0].locals.insert(
Symbol::from(name),
crate::ast::compiler::binder::LocalInfo {
addr: Address::Local(slot),
addr: Address::Global(GlobalIdx(slot.0)),
identity,
_ty: ty,
purity: Purity::Pure,