diff --git a/src/ast/compiler/analyzer.rs b/src/ast/compiler/analyzer.rs index 9b18a5b..5e65987 100644 --- a/src/ast/compiler/analyzer.rs +++ b/src/ast/compiler/analyzer.rs @@ -6,7 +6,7 @@ use std::collections::{HashMap, HashSet}; use std::rc::Rc; pub struct Analyzer<'a> { - global_purity: &'a HashMap, + root_purity: &'a [Purity], /// Stack of currently visiting lambdas to detect direct recursion. lambda_stack: Vec, /// Map of global index to its Lambda identity if known. @@ -18,10 +18,10 @@ pub struct Analyzer<'a> { impl<'a> Analyzer<'a> { pub fn analyze( node: &TypedNode, - global_purity: &'a HashMap, + root_purity: &'a [Purity], ) -> AnalyzedNode { let mut analyzer = Self { - global_purity, + root_purity, lambda_stack: Vec::new(), globals_to_lambdas: HashMap::new(), recursive_identities: HashSet::new(), @@ -70,7 +70,7 @@ impl<'a> Analyzer<'a> { BoundKind::Get { addr, name } => { let p = match addr { Address::Global(idx) => { - self.global_purity.get(idx).cloned().unwrap_or(Purity::Pure) + self.root_purity.get(idx.0 as usize).cloned().unwrap_or(Purity::Pure) } _ => Purity::Pure, }; @@ -206,8 +206,8 @@ impl<'a> Analyzer<'a> { .. } = &callee.kind { - self.global_purity - .get(idx) + self.root_purity + .get(idx.0 as usize) .cloned() .unwrap_or(Purity::Impure) } else { diff --git a/src/ast/compiler/binder.rs b/src/ast/compiler/binder.rs index 194b5dd..6d7d3ca 100644 --- a/src/ast/compiler/binder.rs +++ b/src/ast/compiler/binder.rs @@ -4,7 +4,6 @@ use crate::ast::compiler::bound_nodes::{ use crate::ast::diagnostics::Diagnostics; use crate::ast::nodes::{Node, Symbol, UntypedKind}; use crate::ast::types::{Identity, StaticType, Purity}; -use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; @@ -123,7 +122,6 @@ pub type BindingResult = ( pub struct Binder { functions: Vec, - globals: Rc>>, capture_map: HashMap>, fixed_scope_idx: i32, } @@ -133,11 +131,9 @@ impl Binder { initial_scopes: Vec, initial_slot_count: u32, fixed_scope_idx: i32, - globals: Rc>>, ) -> Self { let mut binder = Self { functions: Vec::new(), - globals, capture_map: HashMap::new(), fixed_scope_idx, }; @@ -156,11 +152,10 @@ impl Binder { initial_scopes: Vec, initial_slot_count: u32, fixed_scope_idx: i32, - globals: Rc>>, node: &Node, diagnostics: &mut Diagnostics, ) -> Result { - let mut binder = Self::new(initial_scopes, initial_slot_count, fixed_scope_idx, globals); + let mut binder = Self::new(initial_scopes, initial_slot_count, fixed_scope_idx); let bound = binder.bind(node, ExprContext::Expression, diagnostics); let final_captures = binder @@ -580,13 +575,7 @@ impl Binder { } } - // 3. Global Fallback - let globals = self.globals.borrow(); - if let Some((idx, _)) = globals.get(sym) { - return Some(Address::Global(*idx)); - } - - // 4. Global Fallback (search in root level with context removed) + // 3. Global Fallback (search in root level with context removed) if sym.context.is_some() { let fallback_sym = Symbol { name: sym.name.clone(), @@ -600,9 +589,6 @@ impl Binder { return Some(info.addr); } } - if let Some((idx, _)) = globals.get(&fallback_sym) { - return Some(Address::Global(*idx)); - } } diag.push_error( @@ -719,9 +705,8 @@ mod tests { let mut parser = Parser::new(source); let untyped = parser.parse_expression(); - let globals = Rc::new(RefCell::new(HashMap::new())); let mut diagnostics = Diagnostics::new(); - let (bound, captures, _scopes, _slots) = Binder::bind_root(vec![], 0, 0, globals, &untyped, &mut diagnostics).unwrap(); + let (bound, captures, _scopes, _slots) = Binder::bind_root(vec![], 0, 0, &untyped, &mut diagnostics).unwrap(); if let BoundKind::Lambda { body, .. } = &bound.kind { if let BoundKind::Block { exprs } = &body.kind { @@ -749,9 +734,8 @@ mod tests { let mut parser = Parser::new(source); let untyped = parser.parse_expression(); - let globals = Rc::new(RefCell::new(HashMap::new())); let mut diagnostics = Diagnostics::new(); - let (bound, captures, _scopes, _slots) = Binder::bind_root(vec![], 0, 0, globals, &untyped, &mut diagnostics).unwrap(); + let (bound, captures, _scopes, _slots) = Binder::bind_root(vec![], 0, 0, &untyped, &mut diagnostics).unwrap(); if let BoundKind::Lambda { body, .. } = &bound.kind { if let BoundKind::Block { exprs } = &body.kind { @@ -779,9 +763,8 @@ mod tests { let mut parser = Parser::new(source); let untyped = parser.parse_expression(); - let globals = Rc::new(RefCell::new(HashMap::new())); let mut diagnostics = Diagnostics::new(); - let _ = Binder::bind_root(vec![], 0, 0, globals, &untyped, &mut diagnostics); + let _ = Binder::bind_root(vec![], 0, 0, &untyped, &mut diagnostics); assert!(diagnostics.has_errors()); assert!(diagnostics.items.iter().any(|i| i.message.contains("already defined"))); @@ -789,18 +772,16 @@ mod tests { #[test] fn test_repro_global_redefinition() { - let globals = Rc::new(RefCell::new(HashMap::new())); - let source1 = "(def x 1) 1"; let untyped1 = Parser::new(source1).parse_expression(); let mut diagnostics = Diagnostics::new(); - let (_, _, scopes1, slots1) = Binder::bind_root(vec![], 0, -1, globals.clone(), &untyped1, &mut diagnostics).unwrap(); + let (_, _, scopes1, slots1) = Binder::bind_root(vec![], 0, -1, &untyped1, &mut diagnostics).unwrap(); let source2 = "(def x 2) 2"; let untyped2 = 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, globals.clone(), &untyped2, &mut diagnostics2); + let _ = Binder::bind_root(scopes1, slots1, 0, &untyped2, &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 e3a9110..d5c31d3 100644 --- a/src/ast/compiler/macros.rs +++ b/src/ast/compiler/macros.rs @@ -627,7 +627,6 @@ mod tests { use crate::ast::compiler::Binder; use crate::ast::parser::Parser; use crate::ast::types::{Object, Value}; - use std::cell::RefCell; struct SimpleEvaluator; impl MacroEvaluator for SimpleEvaluator { @@ -783,7 +782,7 @@ mod tests { let mut diag = crate::ast::diagnostics::Diagnostics::new(); // fixed_scope_idx = 0 means scope 0 is frozen (Global) - let result = Binder::bind_root(initial_scopes, 1, 0, Rc::new(RefCell::new(HashMap::new())), &expanded, &mut diag); + let result = Binder::bind_root(initial_scopes, 1, 0, &expanded, &mut diag); assert!( result.is_ok(), "Should find global '*' Error: {:?}", @@ -807,7 +806,7 @@ mod tests { let expanded = expander.expand(untyped).unwrap(); let mut diag = crate::ast::diagnostics::Diagnostics::new(); - let result = Binder::bind_root(vec![], 0, 0, Rc::new(RefCell::new(HashMap::new())), &expanded, &mut diag); + let result = Binder::bind_root(vec![], 0, 0, &expanded, &mut diag); assert!(result.is_ok(), "Hygiene failed: {:?}", result.err()); } @@ -827,7 +826,7 @@ mod tests { let expanded = expander.expand(untyped).unwrap(); let mut diag = crate::ast::diagnostics::Diagnostics::new(); - let result = Binder::bind_root(vec![], 0, 0, Rc::new(RefCell::new(HashMap::new())), &expanded, &mut diag); + let result = Binder::bind_root(vec![], 0, 0, &expanded, &mut diag); assert!( result.is_ok(), "Explicit Hygiene with Backticks failed: {:?}", diff --git a/src/ast/compiler/optimizer/engine.rs b/src/ast/compiler/optimizer/engine.rs index 4d0c5fa..cc5056e 100644 --- a/src/ast/compiler/optimizer/engine.rs +++ b/src/ast/compiler/optimizer/engine.rs @@ -1,11 +1,10 @@ use crate::ast::compiler::bound_nodes::{ - Address, AnalyzedNode, BoundKind, GlobalAnalyzedRegistry, GlobalIdx, UpvalueIdx, + Address, AnalyzedNode, BoundKind, GlobalAnalyzedRegistry, UpvalueIdx, }; use crate::ast::nodes::Node; use crate::ast::types::{Purity, Value}; use crate::ast::vm::Closure; use std::cell::RefCell; -use std::collections::HashMap; use std::rc::Rc; use super::folder::Folder; @@ -17,7 +16,7 @@ pub struct Optimizer { pub enabled: bool, max_passes: usize, pub globals: Option>>>, - pub global_purity: Option>>>, + pub root_purity: Option>>>, pub lambda_registry: Option>>, } @@ -27,7 +26,7 @@ impl Optimizer { enabled, max_passes: 5, globals: None, - global_purity: None, + root_purity: None, lambda_registry: None, } } @@ -37,8 +36,8 @@ impl Optimizer { self } - pub fn with_purity(mut self, purity: Rc>>) -> Self { - self.global_purity = Some(purity); + pub fn with_purity(mut self, purity: Rc>>) -> Self { + self.root_purity = Some(purity); self } @@ -79,7 +78,7 @@ impl Optimizer { path: &mut PathTracker, base_sub: Option, ) -> Option> { - let inliner = Inliner::new(&self.globals, &self.global_purity); + let inliner = Inliner::new(&self.globals, &self.root_purity); let mut inner_sub = base_sub.unwrap_or_else(|| sub.new_for_inlining()); if inliner.prepare_beta_reduction(params, arg_nodes, body, &mut inner_sub).is_some() { @@ -105,7 +104,7 @@ impl Optimizer { ) -> Rc { let node = &*node_rc; let folder = Folder::new(&self.globals); - let inliner = Inliner::new(&self.globals, &self.global_purity); + let inliner = Inliner::new(&self.globals, &self.root_purity); let (new_kind, metrics) = match &node.kind { BoundKind::Get { addr, name } => { @@ -215,11 +214,13 @@ impl Optimizer { if let Address::Global(global_index) = addr && value_opt.ty.purity > Purity::Impure - && let Some(purity_rc) = &self.global_purity + && let Some(purity_rc) = &self.root_purity { - purity_rc - .borrow_mut() - .insert(*global_index, value_opt.ty.purity); + let mut pr = purity_rc.borrow_mut(); + let idx = global_index.0 as usize; + if idx < pr.len() { + pr[idx] = value_opt.ty.purity; + } } if Rc::ptr_eq(&value_opt, value) { diff --git a/src/ast/compiler/optimizer/inliner.rs b/src/ast/compiler/optimizer/inliner.rs index 90a5ad4..b2d2d24 100644 --- a/src/ast/compiler/optimizer/inliner.rs +++ b/src/ast/compiler/optimizer/inliner.rs @@ -1,8 +1,8 @@ -use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, GlobalIdx, LocalSlot}; +use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, LocalSlot}; use crate::ast::types::{Purity, Value}; use crate::ast::vm::Closure; use std::cell::RefCell; -use std::collections::{HashMap, HashSet}; +use std::collections::HashSet; use std::rc::Rc; use super::substitution_map::SubstitutionMap; @@ -10,17 +10,17 @@ use super::utils::UsageInfo; pub struct Inliner<'a> { pub globals: &'a Option>>>, - pub global_purity: &'a Option>>>, + pub root_purity: &'a Option>>>, } impl<'a> Inliner<'a> { pub fn new( globals: &'a Option>>>, - global_purity: &'a Option>>>, + root_purity: &'a Option>>>, ) -> Self { Self { globals, - global_purity, + root_purity, } } @@ -48,10 +48,10 @@ impl<'a> Inliner<'a> { } if let Address::Global(idx) = addr { - if let Some(purity_rc) = &self.global_purity { + if let Some(purity_rc) = &self.root_purity { let purity = purity_rc .borrow() - .get(&idx) + .get(idx.0 as usize) .cloned() .unwrap_or(Purity::Impure); return purity >= Purity::Pure; diff --git a/src/ast/compiler/type_checker.rs b/src/ast/compiler/type_checker.rs index 9e0b9f1..806f1f2 100644 --- a/src/ast/compiler/type_checker.rs +++ b/src/ast/compiler/type_checker.rs @@ -1,8 +1,7 @@ -use crate::ast::compiler::bound_nodes::{Address, BoundKind, BoundNode, GlobalIdx, TypedNode}; +use crate::ast::compiler::bound_nodes::{Address, BoundKind, BoundNode, TypedNode}; use crate::ast::diagnostics::Diagnostics; use crate::ast::nodes::Node; use crate::ast::types::StaticType; -use std::collections::HashMap; use std::rc::Rc; /// Manages the types of locals and upvalues during a single type-checking pass. @@ -12,8 +11,8 @@ struct TypeContext<'a> { slots: Vec, /// Types of captured variables (passed from outer scope) upvalue_types: Vec, - /// Access to global types for unified resolution - global_types: &'a std::cell::RefCell>, + /// Access to root types for unified resolution + root_types: &'a std::cell::RefCell>, /// The expected parameters of the current function (for 'again' validation) current_params_ty: Option, } @@ -22,14 +21,14 @@ impl<'a> TypeContext<'a> { fn new( slot_count: u32, upvalue_types: Vec, - global_types: &'a std::cell::RefCell>, + root_types: &'a std::cell::RefCell>, parent: Option<&'a TypeContext<'a>>, ) -> Self { Self { _parent: parent, slots: vec![StaticType::Any; slot_count as usize], upvalue_types, - global_types, + root_types, current_params_ty: None, } } @@ -42,9 +41,9 @@ impl<'a> TypeContext<'a> { .cloned() .unwrap_or(StaticType::Any), Address::Global(idx) => self - .global_types + .root_types .borrow() - .get(&idx) + .get(idx.0 as usize) .cloned() .unwrap_or(StaticType::Any), Address::Upvalue(idx) => self @@ -63,7 +62,10 @@ impl<'a> TypeContext<'a> { } } Address::Global(idx) => { - self.global_types.borrow_mut().insert(idx, ty); + let mut rt = self.root_types.borrow_mut(); + if (idx.0 as usize) < rt.len() { + rt[idx.0 as usize] = ty; + } } _ => {} } @@ -71,12 +73,12 @@ impl<'a> TypeContext<'a> { } pub struct TypeChecker { - global_types: Rc>>, + root_types: Rc>>, } impl TypeChecker { - pub fn new(global_types: Rc>>) -> Self { - Self { global_types } + pub fn new(root_types: Rc>>) -> Self { + Self { root_types } } pub fn check( @@ -99,9 +101,9 @@ impl TypeChecker { } // 2. Create the specialized context - let root_ctx = TypeContext::new(0, vec![], &self.global_types, None); + let root_ctx = TypeContext::new(0, vec![], &self.root_types, None); let mut lambda_ctx = - TypeContext::new(64, upvalue_types, &self.global_types, Some(&root_ctx)); + TypeContext::new(64, upvalue_types, &self.root_types, Some(&root_ctx)); // 3. INJECT specialized argument types into slots let arg_tuple_ty = if arg_types.is_empty() { @@ -141,7 +143,7 @@ impl TypeChecker { } } _ => { - let mut root_ctx = TypeContext::new(0, vec![], &self.global_types, None); + let mut root_ctx = TypeContext::new(0, vec![], &self.root_types, None); self.check_node(node, &mut root_ctx, diag) } } @@ -484,7 +486,7 @@ impl TypeChecker { // 2. Create nested context for lambda body let mut lambda_ctx = - TypeContext::new(64, upvalue_types, ctx.global_types, Some(ctx)); + TypeContext::new(64, upvalue_types, ctx.root_types, Some(ctx)); // 3. Check parameters and body let params_typed = self.check_params( diff --git a/src/ast/environment.rs b/src/ast/environment.rs index 78307a3..be7e3a4 100644 --- a/src/ast/environment.rs +++ b/src/ast/environment.rs @@ -21,7 +21,7 @@ use crate::ast::compiler::optimizer::Optimizer; use crate::ast::compiler::specializer::{FunctionRegistry, MonoCache, Specializer}; use crate::ast::rtl::intrinsics; use crate::ast::types::{ - Identity, NodeIdentity, Object, Purity, SourceLocation, StaticType, Value, + NodeIdentity, Object, Purity, SourceLocation, StaticType, Value, }; use crate::ast::diagnostics::{DiagnosticLevel, Diagnostics}; @@ -71,10 +71,9 @@ impl CompilationResult { } pub struct Environment { - pub global_names: Rc>>, - pub global_types: Rc>>, - pub global_purity: Rc>>, - pub global_values: Rc>>, + pub root_types: Rc>>, + pub root_purity: Rc>>, + pub root_values: Rc>>, pub fixed_scope_idx: i32, pub root_scopes: Rc>>, pub root_slot_count: Rc>, @@ -112,11 +111,11 @@ impl FunctionRegistry for EnvFunctionRegistry { } struct RuntimeMacroEvaluator { - global_names: Rc>>, root_scopes: Rc>>, root_slot_count: Rc>, - global_types: Rc>>, - global_values: Rc>>, + root_types: Rc>>, + root_values: Rc>>, + root_purity: Rc>>, fixed_scope_idx: i32, } @@ -136,9 +135,9 @@ 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, self.global_names.clone(), node, &mut diag)?; + 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 checker = TypeChecker::new(self.root_types.clone()); let typed_ast = checker.check(&bound_ast, &[], &mut diag); if diag.has_errors() { @@ -150,9 +149,9 @@ impl MacroEvaluator for RuntimeMacroEvaluator { .join("\n")); } - let exec_ast = Lowering::lower(Analyzer::analyze(&typed_ast, &HashMap::new())); // Minimal analysis for macro eval + let exec_ast = Lowering::lower(Analyzer::analyze(&typed_ast, &self.root_purity.borrow())); // Minimal analysis for macro eval - let mut vm = VM::new(self.global_values.clone()); + let mut vm = VM::new(self.root_values.clone()); vm.run(&exec_ast) } } @@ -166,10 +165,9 @@ impl Default for Environment { impl Environment { pub fn new() -> Self { let env = Self { - global_names: Rc::new(RefCell::new(HashMap::new())), - global_types: Rc::new(RefCell::new(HashMap::new())), - global_purity: Rc::new(RefCell::new(HashMap::new())), - global_values: Rc::new(RefCell::new(Vec::new())), + root_types: Rc::new(RefCell::new(Vec::new())), + root_purity: Rc::new(RefCell::new(Vec::new())), + root_values: Rc::new(RefCell::new(Vec::new())), fixed_scope_idx: -1, root_scopes: Rc::new(RefCell::new(vec![crate::ast::compiler::binder::CompilerScope::new()])), root_slot_count: Rc::new(RefCell::new(0)), @@ -226,11 +224,11 @@ impl Environment { fn get_expander(&self) -> MacroExpander { 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(), + root_types: self.root_types.clone(), + root_values: self.root_values.clone(), + root_purity: self.root_purity.clone(), fixed_scope_idx: self.fixed_scope_idx, }; MacroExpander::new(self.macro_registry.borrow().clone(), evaluator) @@ -459,7 +457,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, self.global_names.clone(), &expanded_ast, diagnostics) { + 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); @@ -475,7 +473,7 @@ impl Environment { // Pre-allocate global slots to prevent out-of-bounds during specialization/optimization { - let mut values = self.global_values.borrow_mut(); + let mut values = self.root_values.borrow_mut(); let count = *self.root_slot_count.borrow(); if (count as usize) > values.len() { values.resize(count as usize, Value::Void); @@ -484,7 +482,7 @@ impl Environment { LambdaCollector::collect(&bound_ast, &mut self.function_registry.borrow_mut()); - let checker = TypeChecker::new(self.global_types.clone()); + let checker = TypeChecker::new(self.root_types.clone()); let wrapped_ast = if let crate::ast::compiler::bound_nodes::BoundKind::Lambda { .. } = bound_ast.kind { bound_ast } else { @@ -529,19 +527,13 @@ impl Environment { ty: StaticType, func: Rc, ) { - let mut names = self.global_names.borrow_mut(); - let mut types = self.global_types.borrow_mut(); - let mut values = self.global_values.borrow_mut(); - let mut purity = self.global_purity.borrow_mut(); + let mut types = self.root_types.borrow_mut(); + let mut values = self.root_values.borrow_mut(); + let mut purity = self.root_purity.borrow_mut(); - let idx = GlobalIdx(values.len() as u32); let identity = NodeIdentity::new(SourceLocation { line: 0, col: 0 }); - names.insert(Symbol::from(name), (idx, identity.clone())); - types.insert(idx, ty.clone()); - purity.insert(idx, func.purity); - values.push(Value::Function(func.clone())); - // Parallel mode: populate root_scopes[0] + // populate root_scopes[0] let mut root_scopes = self.root_scopes.borrow_mut(); let mut slot_count = self.root_slot_count.borrow_mut(); let slot = crate::ast::compiler::bound_nodes::LocalSlot(*slot_count); @@ -550,11 +542,23 @@ impl Environment { crate::ast::compiler::binder::LocalInfo { addr: Address::Global(GlobalIdx(slot.0)), identity, - _ty: ty, + _ty: ty.clone(), purity: func.purity, }, ); *slot_count += 1; + + // Ensure arrays are large enough + let idx = slot.0 as usize; + if idx >= values.len() { + values.resize(idx + 1, Value::Void); + types.resize(idx + 1, StaticType::Any); + purity.resize(idx + 1, Purity::Impure); + } + + types[idx] = ty; + purity[idx] = func.purity; + values[idx] = Value::Function(func); } pub fn register_native_fn( @@ -575,19 +579,13 @@ impl Environment { } pub fn register_constant(&self, name: &str, ty: StaticType, val: Value) { - let mut names = self.global_names.borrow_mut(); - let mut types = self.global_types.borrow_mut(); - let mut values = self.global_values.borrow_mut(); - let mut purity = self.global_purity.borrow_mut(); + let mut types = self.root_types.borrow_mut(); + let mut values = self.root_values.borrow_mut(); + let mut purity = self.root_purity.borrow_mut(); - let idx = GlobalIdx(values.len() as u32); let identity = NodeIdentity::new(SourceLocation { line: 0, col: 0 }); - names.insert(Symbol::from(name), (idx, identity.clone())); - types.insert(idx, ty.clone()); - purity.insert(idx, Purity::Pure); - values.push(val); - // Parallel mode: populate root_scopes[0] + // populate root_scopes[0] let mut root_scopes = self.root_scopes.borrow_mut(); let mut slot_count = self.root_slot_count.borrow_mut(); let slot = crate::ast::compiler::bound_nodes::LocalSlot(*slot_count); @@ -596,11 +594,22 @@ impl Environment { crate::ast::compiler::binder::LocalInfo { addr: Address::Global(GlobalIdx(slot.0)), identity, - _ty: ty, + _ty: ty.clone(), purity: Purity::Pure, }, ); *slot_count += 1; + + let idx = slot.0 as usize; + if idx >= values.len() { + values.resize(idx + 1, Value::Void); + types.resize(idx + 1, StaticType::Any); + purity.resize(idx + 1, Purity::Impure); + } + + types[idx] = ty; + purity[idx] = Purity::Pure; + values[idx] = val; } @@ -640,7 +649,7 @@ impl Environment { pub fn link(&self, node: TypedNode) -> ExecNode { // 1. Analyze - let analyzed = Analyzer::analyze(&node, &self.global_purity.borrow()); + let analyzed = Analyzer::analyze(&node, &self.root_purity.borrow()); // 2. Collect Analyzed Lambdas LambdaCollector::collect(&analyzed, &mut self.typed_function_registry.borrow_mut()); @@ -650,8 +659,8 @@ impl Environment { // 4. Optimize let optimizer = Optimizer::new(self.optimization) - .with_globals(self.global_values.clone()) - .with_purity(self.global_purity.clone()) + .with_globals(self.root_values.clone()) + .with_purity(self.root_purity.clone()) .with_registry(self.typed_function_registry.clone()); let optimized = optimizer.optimize(specialized); @@ -660,7 +669,7 @@ impl Environment { } pub fn instantiate(&self, node: ExecNode) -> Rc { - let global_values = self.global_values.clone(); + let root_values = self.root_values.clone(); if let BoundKind::Lambda { params, upvalues, @@ -683,7 +692,7 @@ impl Environment { return Rc::new(crate::ast::types::NativeFunction { purity: Purity::Impure, func: Rc::new(move |args| { - let mut vm = VM::new(global_values.clone()); + let mut vm = VM::new(root_values.clone()); match vm.run_with_args(closure_obj.clone(), args) { Ok(v) => v, Err(e) => panic!("Myc Runtime Error: {}", e), @@ -696,7 +705,7 @@ impl Environment { Rc::new(crate::ast::types::NativeFunction { purity: Purity::Impure, func: Rc::new(move |args| { - let mut vm = VM::new(global_values.clone()); + let mut vm = VM::new(root_values.clone()); let res = match vm.run(&exec_node) { Ok(v) => v, Err(e) => panic!("Myc Runtime Error: {}", e), @@ -729,9 +738,9 @@ impl Environment { let typed_reg = self.typed_function_registry.clone(); let untyped_reg = self.function_registry.clone(); let mono_cache = self.monomorph_cache.clone(); - let global_values = self.global_values.clone(); - let global_types = self.global_types.clone(); - let global_purity = self.global_purity.clone(); + let root_values = self.root_values.clone(); + let root_types = self.root_types.clone(); + let root_purity = self.root_purity.clone(); let optimization = self.optimization; let compiler = Rc::new( @@ -739,7 +748,7 @@ impl Environment { arg_types: &[StaticType]| -> Result<(Value, StaticType), String> { let mut diag = Diagnostics::new(); - let checker = TypeChecker::new(global_types.clone()); + let checker = TypeChecker::new(root_types.clone()); let retyped_ast = checker.check(func_template.as_ref(), arg_types, &mut diag); if diag.has_errors() { @@ -751,7 +760,7 @@ impl Environment { .join("\n")); } - let analyzed = Analyzer::analyze(&retyped_ast, &global_purity.borrow()); + let analyzed = Analyzer::analyze(&retyped_ast, &root_purity.borrow()); let sub_registry = Rc::new(EnvFunctionRegistry { registry: untyped_reg.clone(), @@ -770,12 +779,12 @@ impl Environment { let specialized_ast = sub_specializer.specialize(analyzed); let optimizer = Optimizer::new(optimization) - .with_globals(global_values.clone()) - .with_purity(global_purity.clone()); + .with_globals(root_values.clone()) + .with_purity(root_purity.clone()); let optimized_ast = optimizer.optimize(specialized_ast); let exec_ast = Lowering::lower(optimized_ast); - let mut vm = VM::new(global_values.clone()); + let mut vm = VM::new(root_values.clone()); let compiled_val = match vm.run(&exec_ast) { Ok(v) => v, Err(e) => return Err(format!("VM Error during specialization: {}", e)), @@ -824,7 +833,7 @@ impl Environment { let compiled = self.compile(source).into_result()?; let linked = self.link(compiled); - let mut vm = VM::new(self.global_values.clone()); + let mut vm = VM::new(self.root_values.clone()); let mut observer = TracingObserver::new(); // 1. Run the script wrapper (returns a closure representing the script) diff --git a/src/ast/rtl/streams.rs b/src/ast/rtl/streams.rs index 9063abd..4d56ea8 100644 --- a/src/ast/rtl/streams.rs +++ b/src/ast/rtl/streams.rs @@ -413,7 +413,7 @@ pub fn register(env: &Environment) { // (create-ticker condition-closure) -> StreamNode let ticker_generators = env.pipeline_generators.clone(); - let globals = env.global_values.clone(); + let globals = env.root_values.clone(); env.register_native_fn( "create-ticker",