Refactor scope handling and immutability

Introduces `fixed_scope_idx` to `Binder` and `Environment` to track
immutable scopes.
This allows enforcing that definitions (`def`) cannot occur in scopes
that are considered fixed or immutable, such as the global scope or the
initial bootstrap scope.
The `FunctionCompiler` is updated to use `fixed_scope_idx` and `is_root`
to determine scope immutability.
This commit is contained in:
Michael Schimmel
2026-03-12 11:22:40 +01:00
parent bb77caf1af
commit be2bef373f
4 changed files with 53 additions and 40 deletions
+9 -2
View File
@@ -75,6 +75,7 @@ pub struct Environment {
pub global_types: Rc<RefCell<HashMap<GlobalIdx, StaticType>>>,
pub global_purity: Rc<RefCell<HashMap<GlobalIdx, Purity>>>,
pub global_values: Rc<RefCell<Vec<Value>>>,
pub fixed_scope_idx: i32,
pub function_registry: Rc<RefCell<GlobalFunctionRegistry>>,
pub typed_function_registry: Rc<RefCell<GlobalAnalyzedRegistry>>,
pub monomorph_cache: Rc<RefCell<MonoCache>>,
@@ -112,6 +113,7 @@ struct RuntimeMacroEvaluator {
global_names: Rc<RefCell<HashMap<Symbol, (GlobalIdx, Identity)>>>,
global_types: Rc<RefCell<HashMap<GlobalIdx, StaticType>>>,
global_values: Rc<RefCell<Vec<Value>>>,
fixed_scope_idx: i32,
}
impl MacroEvaluator for RuntimeMacroEvaluator {
@@ -127,7 +129,7 @@ impl MacroEvaluator for RuntimeMacroEvaluator {
}
let mut diag = Diagnostics::new();
let (bound_ast, captures) = Binder::bind_root(self.global_names.clone(), node, &mut diag)?;
let (bound_ast, captures) = Binder::bind_root(self.global_names.clone(), 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);
@@ -161,6 +163,7 @@ impl Environment {
global_types: Rc::new(RefCell::new(HashMap::new())),
global_purity: Rc::new(RefCell::new(HashMap::new())),
global_values: Rc::new(RefCell::new(Vec::new())),
fixed_scope_idx: -1,
function_registry: Rc::new(RefCell::new(HashMap::new())),
typed_function_registry: Rc::new(RefCell::new(HashMap::new())),
monomorph_cache: Rc::new(RefCell::new(HashMap::new())),
@@ -172,6 +175,9 @@ impl Environment {
loaded_modules: Rc::new(RefCell::new(HashSet::new())),
};
crate::ast::rtl::register(&env);
let mut env = env;
env.fixed_scope_idx = 0;
// Automatically add standard search paths (CWD and CWD/rtl)
if let Ok(cwd) = std::env::current_dir() {
@@ -212,6 +218,7 @@ impl Environment {
global_names: self.global_names.clone(),
global_types: self.global_types.clone(),
global_values: self.global_values.clone(),
fixed_scope_idx: self.fixed_scope_idx,
};
MacroExpander::new(self.macro_registry.borrow().clone(), evaluator)
}
@@ -423,7 +430,7 @@ impl Environment {
};
let (bound_ast, captures) =
match Binder::bind_root(self.global_names.clone(), &expanded_ast, diagnostics) {
match Binder::bind_root(self.global_names.clone(), self.fixed_scope_idx, &expanded_ast, diagnostics) {
Ok(res) => res,
Err(e) => {
diagnostics.push_error(e, None);