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:
+40
-19
@@ -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)?;
|
||||
|
||||
Reference in New Issue
Block a user