diff --git a/docs/Analysis_Environment.md b/docs/Analysis_Environment.md index 7783581..472cf73 100644 --- a/docs/Analysis_Environment.md +++ b/docs/Analysis_Environment.md @@ -7,7 +7,7 @@ Die `Environment`-Struktur fungiert im Projekt als zentraler "State-Manager" und * **Modulladung & Abhängigkeiten:** `preload_dependencies` und `discover_globals` lesen `#use`-Abhängigkeiten, durchsuchen den Code vorab nach globalen Definitionen (`def`) und Makros und laden die Standardbibliothek (`prelude.myc`). * **Kompilierungs-Pipeline:** Die Methoden `compile`, `compile_syntax`, `compile_pipeline` und `link` steuern den Code durch alle Compiler-Phasen: Macro-Expansion -> Binding -> Type-Checking -> Analysis -> Specialization -> Optimization -> Lowering. * **Makro-Evaluierung:** Die interne Struktur `RuntimeMacroEvaluator` wird genutzt, um AST-Knoten zur Compile-Zeit an eine VM zu übergeben und den Code für Makros auszuführen. -* **Laufzeit-Ausführung & RTL (Runtime Library):** Methoden wie `run_script`, `run_debug` und `instantiate` starten die `VM`. Zudem gibt es Methoden (`register_native`, `allocate_slot`), um native Rust-Funktionen (Intrinsics) im globalen Scope (`fixed_scope_idx = 0`) zu registrieren. +* **Laufzeit-Ausführung & RTL (Runtime Library):** Methoden wie `run_script`, `run_debug` und `instantiate` starten die `VM`. Zudem gibt es Methoden (`register_native`, `allocate_slot`), um native Rust-Funktionen (Intrinsics) im globalen RTL-Scope (Scope 0) zu registrieren. * **Dokumentations-Registry:** Es speichert sowohl RTL-Dokumentation als auch aus dem Source-Code extrahierte Kommentare (`myc_docs`). ## 2. Prüfung auf Boilerplate diff --git a/src/ast/compiler/binder.rs b/src/ast/compiler/binder.rs index ac0f06f..376291a 100644 --- a/src/ast/compiler/binder.rs +++ b/src/ast/compiler/binder.rs @@ -1,5 +1,5 @@ use crate::ast::nodes::{ - Address, AssignBinding, BoundPhase, DeclarationKind, DefBinding, GlobalIdx, + Address, AssignBinding, BoundPhase, DeclarationKind, DefBinding, IdentifierBinding, LambdaBinding, Node, NodeKind, SyntaxKind, SyntaxNode, Symbol, UpvalueIdx, VirtualId, }; @@ -124,19 +124,16 @@ pub type BindingResult = ( pub struct Binder { functions: Vec, capture_map: HashMap>, - fixed_scope_idx: i32, } impl Binder { pub fn new( initial_scopes: Vec, initial_slot_count: u32, - fixed_scope_idx: i32, ) -> Self { let mut binder = Self { functions: Vec::new(), capture_map: HashMap::new(), - fixed_scope_idx, }; binder.functions.push(FunctionCompiler::new( NodeIdentity::new(SourceLocation { @@ -152,11 +149,10 @@ impl Binder { pub fn bind_root( initial_scopes: Vec, initial_slot_count: u32, - fixed_scope_idx: i32, node: &SyntaxNode, diagnostics: &mut Diagnostics, ) -> Result { - let mut binder = Self::new(initial_scopes, initial_slot_count, fixed_scope_idx); + let mut binder = Self::new(initial_scopes, initial_slot_count); let bound = binder.bind(node, ExprContext::Expression, diagnostics); let final_captures = binder @@ -181,22 +177,6 @@ impl Binder { _kind: DeclarationKind, diag: &mut Diagnostics, ) -> Option> { - let current_fn_idx = self.functions.len() - 1; - - if current_fn_idx == 0 { - let current_scope_idx = self.functions[0].scopes.len() as i32 - 1; - if current_scope_idx <= self.fixed_scope_idx { - diag.push_error( - format!( - "Cannot define '{}': Scope {} is frozen/immutable.", - name.name, current_scope_idx - ), - None, - ); - return None; - } - } - let current_fn = self.functions.last_mut().unwrap(); match current_fn.define_variable(name, identity) { Ok(addr) => Some(addr), @@ -562,25 +542,13 @@ impl Binder { // 2. Try enclosing scopes (capture chain) for i in (0..current_fn_idx).rev() { - if let Some((info, scope_idx)) = self.functions[i].resolve_local(sym) { - // If it's in the root script and within a frozen scope, translate to Global - let is_frozen_root = i == 0 && (scope_idx as i32) <= self.fixed_scope_idx; - + if let Some((info, _scope_idx)) = self.functions[i].resolve_local(sym) { if let Address::Global(_) = info.addr { return Some(info.addr); } let mut addr = info.addr; - if is_frozen_root - && let Address::Local(slot) = addr { - addr = Address::Global(GlobalIdx(slot.0)); - } - - if let Address::Global(_) = addr { - return Some(addr); - } - // Record the capture for each lambda level in between for k in (i + 1)..=current_fn_idx { let lambda_id = self.functions[k].identity.clone(); @@ -723,7 +691,7 @@ mod tests { let syntax = parser.parse_expression(); let mut diagnostics = Diagnostics::new(); - let (bound, captures, _scopes, _slots) = Binder::bind_root(vec![], 0, 0, &syntax, &mut diagnostics).unwrap(); + let (bound, captures, _scopes, _slots) = Binder::bind_root(vec![], 0, &syntax, &mut diagnostics).unwrap(); if let NodeKind::Lambda { body, .. } = &bound.kind { if let NodeKind::Block { exprs } = &body.kind { @@ -756,7 +724,7 @@ mod tests { let syntax = parser.parse_expression(); let mut diagnostics = Diagnostics::new(); - let (bound, captures, _scopes, _slots) = Binder::bind_root(vec![], 0, 0, &syntax, &mut diagnostics).unwrap(); + let (bound, captures, _scopes, _slots) = Binder::bind_root(vec![], 0, &syntax, &mut diagnostics).unwrap(); if let NodeKind::Lambda { body, .. } = &bound.kind { if let NodeKind::Block { exprs } = &body.kind { @@ -789,26 +757,10 @@ mod tests { let syntax = parser.parse_expression(); let mut diagnostics = Diagnostics::new(); - let _ = Binder::bind_root(vec![], 0, 0, &syntax, &mut diagnostics); + let _ = Binder::bind_root(vec![], 0, &syntax, &mut diagnostics); assert!(diagnostics.has_errors()); assert!(diagnostics.items.iter().any(|i| i.message.contains("already defined"))); } - #[test] - fn test_repro_global_redefinition() { - let source1 = "(def x 1) 1"; - let syntax1 = Parser::new(source1).parse_expression(); - let mut diagnostics = Diagnostics::new(); - let (_, _, scopes1, slots1) = Binder::bind_root(vec![], 0, -1, &syntax1, &mut diagnostics).unwrap(); - - let source2 = "(def x 2) 2"; - let syntax2 = Parser::new(source2).parse_expression(); - let mut diagnostics2 = Diagnostics::new(); - // Here we simulate frozen scope by passing fixed_scope_idx = 0 - let _ = Binder::bind_root(scopes1, slots1, 0, &syntax2, &mut diagnostics2); - - assert!(diagnostics2.has_errors()); - assert!(diagnostics2.items.iter().any(|i| i.message.contains("frozen/immutable"))); - } } diff --git a/src/ast/compiler/macros.rs b/src/ast/compiler/macros.rs index 13ef96f..038ce8d 100644 --- a/src/ast/compiler/macros.rs +++ b/src/ast/compiler/macros.rs @@ -633,7 +633,7 @@ mod tests { use crate::ast::compiler::binder::{CompilerScope, LocalInfo}; use crate::ast::compiler::Binder; use crate::ast::diagnostics::Diagnostics; - use crate::ast::nodes::{Address, VirtualId}; + use crate::ast::nodes::{Address, GlobalIdx, VirtualId}; use crate::ast::parser::Parser; use crate::ast::types::{NodeIdentity, Purity, SourceLocation, StaticType, Value}; @@ -778,7 +778,7 @@ mod tests { locals.insert( Symbol::from("*"), LocalInfo { - addr: Address::Local(VirtualId(0)), + addr: Address::Global(GlobalIdx(0)), identity: NodeIdentity::new(SourceLocation { line: 0, col: 0, @@ -790,8 +790,8 @@ mod tests { let initial_scopes = vec![CompilerScope { locals }]; let mut diag = Diagnostics::new(); - // fixed_scope_idx = 0 means scope 0 is frozen (Global) - let result = Binder::bind_root(initial_scopes, 1, 0, &expanded, &mut diag); + // Scope 0 simulates a frozen RTL scope with Global addresses + let result = Binder::bind_root(initial_scopes, 1, &expanded, &mut diag); assert!( result.is_ok(), "Should find global '*' Error: {:?}", @@ -815,7 +815,7 @@ mod tests { let expanded = expander.expand(syntax).unwrap(); let mut diag = Diagnostics::new(); - let result = Binder::bind_root(vec![], 0, 0, &expanded, &mut diag); + let result = Binder::bind_root(vec![], 0, &expanded, &mut diag); assert!(result.is_ok(), "Hygiene failed: {:?}", result.err()); } @@ -835,7 +835,7 @@ mod tests { let expanded = expander.expand(syntax).unwrap(); let mut diag = Diagnostics::new(); - let result = Binder::bind_root(vec![], 0, 0, &expanded, &mut diag); + let result = Binder::bind_root(vec![], 0, &expanded, &mut diag); assert!( result.is_ok(), "Explicit Hygiene with Backticks failed: {:?}", @@ -861,7 +861,7 @@ mod tests { let expanded = expander.expand(syntax).unwrap(); let mut diag = Diagnostics::new(); - let result = Binder::bind_root(vec![], 0, 0, &expanded, &mut diag); + let result = Binder::bind_root(vec![], 0, &expanded, &mut diag); assert!( result.is_ok(), "~nonparam should resolve to call-site variable: {:?}", @@ -887,7 +887,7 @@ mod tests { let expanded = expander.expand(syntax).unwrap(); let mut diag = Diagnostics::new(); - let result = Binder::bind_root(vec![], 0, 0, &expanded, &mut diag); + let result = Binder::bind_root(vec![], 0, &expanded, &mut diag); assert!( result.is_ok(), "Hygiene isolation for def should still hold: {:?}", diff --git a/src/ast/environment.rs b/src/ast/environment.rs index dcc73dd..8f92613 100644 --- a/src/ast/environment.rs +++ b/src/ast/environment.rs @@ -67,7 +67,6 @@ pub struct Environment { rtl_values: Rc<[Value]>, /// Mutable user-defined global slots. Indexed as `[0..)` i.e. offset from `rtl.slot_count`. user_values: Rc>>, - pub fixed_scope_idx: i32, pub root_scopes: Rc>>, pub root_slot_count: Rc>, pub function_registry: Rc>, @@ -110,7 +109,6 @@ struct RuntimeMacroEvaluator { root_types: Rc>>, globals: GlobalStore, root_purity: Rc>>, - fixed_scope_idx: i32, compiler_hooks: Rc>>, } @@ -130,7 +128,7 @@ impl MacroEvaluator for RuntimeMacroEvaluator { 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, captures, _, _) = Binder::bind_root(initial_scopes, initial_slot_count, node, &mut diag)?; let bound_ast = CapturePass::apply(bound_ast, &captures); let checker = TypeChecker::new(self.root_types.clone(), Rc::clone(&self.compiler_hooks)); let typed_ast = checker.check(&bound_ast, &[], &mut diag); @@ -154,14 +152,12 @@ impl Default for Environment { impl Environment { pub fn new() -> Self { - // Phase 1: Bootstrap — fixed_scope_idx = -1 allows allocate_slot to - // write freely into scope 0 (the RTL scope). + // Phase 1: Bootstrap — allocate_slot writes freely into scope 0 (the RTL scope). let mut env = Self { root_types: Rc::new(RefCell::new(Vec::new())), root_purity: Rc::new(RefCell::new(Vec::new())), rtl_values: Rc::from([]), // placeholder — filled after freeze user_values: Rc::new(RefCell::new(Vec::new())), // bootstrap scratch during RTL phase - fixed_scope_idx: -1, root_scopes: Rc::new(RefCell::new(vec![CompilerScope::new()])), root_slot_count: Rc::new(RefCell::new(0)), function_registry: Rc::new(RefCell::new(HashMap::new())), @@ -191,11 +187,22 @@ impl Environment { rtl::register(&env); // Phase 2: Freeze scope 0 and snapshot the RTL state. - env.fixed_scope_idx = 0; let rtl_slot_count = *env.root_slot_count.borrow(); // user_values was used as the bootstrap scratch; freeze it into an immutable slice. let rtl_vals: Rc<[Value]> = env.user_values.borrow().clone().into(); let frozen_hooks = Rc::new(std::mem::take(&mut *env.compiler_hooks.borrow_mut())); + + // Rewrite RTL scope addresses: Local(VirtualId) -> Global(GlobalIdx) + // so the Binder never needs to do this translation at resolve time. + { + let mut scopes = env.root_scopes.borrow_mut(); + for info in scopes[0].locals.values_mut() { + if let Address::Local(vid) = info.addr { + info.addr = Address::Global(GlobalIdx(vid.0)); + } + } + } + env.rtl = Rc::new(Rtl { scope: env.root_scopes.borrow()[0].clone(), slot_count: rtl_slot_count, @@ -243,7 +250,6 @@ impl Environment { root_purity: Rc::new(RefCell::new(rtl.purity.clone())), rtl_values: Rc::clone(&rtl.values), // O(1) Rc increment — no clone of RTL values! user_values: Rc::new(RefCell::new(Vec::new())), - fixed_scope_idx: 0, root_scopes: Rc::new(RefCell::new(scopes)), root_slot_count: Rc::new(RefCell::new(rtl.slot_count)), function_registry: Rc::new(RefCell::new(HashMap::new())), @@ -318,7 +324,6 @@ impl Environment { root_types: self.root_types.clone(), globals: self.global_store(), root_purity: self.root_purity.clone(), - fixed_scope_idx: self.fixed_scope_idx, compiler_hooks: Rc::clone(&self.rtl.compiler_hooks), }; MacroExpander::new(self.macro_registry.borrow().clone(), evaluator) @@ -453,7 +458,7 @@ impl Environment { 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) { + match Binder::bind_root(initial_scopes, initial_slot_count, &expanded_ast, diagnostics) { Ok(res) => res, Err(e) => { diagnostics.push_error(e, None); diff --git a/src/ast/rtl/prelude.myc b/src/ast/rtl/prelude.myc index 4178b72..ce7e9cc 100644 --- a/src/ast/rtl/prelude.myc +++ b/src/ast/rtl/prelude.myc @@ -2,7 +2,7 @@ ;; Standard macros and core utilities. (do - (def func1 (print "Hello World")) + (def func1 (fn [] (print "Hello World"))) (macro while [cond body] `((fn [] (if ~cond