Refactor function compiler scope handling

Introduce a `ScopeKind` enum to distinguish between root and local
scopes.
This allows the `FunctionCompiler` to correctly handle global variable
declarations in the root scope and local variables in other scopes.
The `define_variable` method is introduced to encapsulate this logic.
This commit is contained in:
Michael Schimmel
2026-02-25 11:19:08 +01:00
parent d109cb2018
commit 82daf03522
+40 -19
View File
@@ -52,16 +52,49 @@ impl CompilerScope {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ScopeKind {
Root,
Local,
}
struct FunctionCompiler {
scope: CompilerScope,
upvalues: Vec<Address>,
kind: ScopeKind,
}
impl FunctionCompiler {
fn new() -> Self {
fn new(kind: ScopeKind) -> Self {
Self {
scope: CompilerScope::new(),
upvalues: Vec::new(),
kind,
}
}
fn define_variable(
&mut self,
name: &Symbol,
globals: &Rc<RefCell<HashMap<Symbol, u32>>>,
) -> Result<Address, String> {
match self.kind {
ScopeKind::Root => {
let mut globals_map = globals.borrow_mut();
if globals_map.contains_key(name) {
return Err(format!(
"Global variable '{}' is already defined.",
name.name
));
}
let idx = globals_map.len() as u32;
globals_map.insert(name.clone(), idx);
Ok(Address::Global(idx))
}
ScopeKind::Local => {
let slot = self.scope.define(name)?;
Ok(Address::Local(slot))
}
}
}
@@ -97,7 +130,9 @@ impl Binder {
globals,
capture_map: captures,
};
binder.functions.push(FunctionCompiler::new());
binder
.functions
.push(FunctionCompiler::new(ScopeKind::Root));
binder
}
@@ -115,22 +150,8 @@ impl Binder {
name: &Symbol,
_kind: crate::ast::compiler::bound_nodes::DeclarationKind,
) -> Result<Address, String> {
if self.functions.len() == 1 {
let mut globals = self.globals.borrow_mut();
if globals.contains_key(name) {
return Err(format!(
"Global variable '{}' is already defined.",
name.name
));
}
let idx = globals.len() as u32;
globals.insert(name.clone(), idx);
Ok(Address::Global(idx))
} else {
let current_fn = self.functions.last_mut().unwrap();
let slot = current_fn.scope.define(name)?;
Ok(Address::Local(slot))
}
let current_fn = self.functions.last_mut().unwrap();
current_fn.define_variable(name, &self.globals)
}
pub fn bind(&mut self, node: &Node<UntypedKind>) -> Result<BoundNode, String> {
@@ -244,7 +265,7 @@ impl Binder {
UntypedKind::Lambda { params, body } => {
let identity = node.identity.clone();
self.functions.push(FunctionCompiler::new());
self.functions.push(FunctionCompiler::new(ScopeKind::Local));
// 1. Bind the parameter pattern/tuple
let params_bound = self.bind_pattern(params, DeclarationKind::Parameter)?;