From c256a8a992a1c21d43912d45f2b709ee58f481d1 Mon Sep 17 00:00:00 2001 From: Michael Schimmel Date: Wed, 25 Feb 2026 10:45:36 +0100 Subject: [PATCH] Refactor: Use generic `Define` bound kind This commit consolidates `DefLocal` and `DefGlobal` into a single `Define` bound kind. This simplifies the AST and makes it more consistent. It also introduces `DeclarationKind` to differentiate between variable and parameter definitions. --- examples/tuple-struct.myc | 2 + src/ast/compiler/analyzer.rs | 42 ++---- src/ast/compiler/binder.rs | 160 +++++++++++----------- src/ast/compiler/bound_nodes.rs | 66 ++++----- src/ast/compiler/dumper.rs | 34 ++--- src/ast/compiler/lambda_collector.rs | 16 +-- src/ast/compiler/optimizer.rs | 192 +++++++++++---------------- src/ast/compiler/specializer.rs | 29 ++-- src/ast/compiler/tco.rs | 23 +--- src/ast/compiler/type_checker.rs | 111 ++++++++-------- src/ast/vm.rs | 69 ++-------- 11 files changed, 280 insertions(+), 464 deletions(-) diff --git a/examples/tuple-struct.myc b/examples/tuple-struct.myc index 567811c..29bb835 100644 --- a/examples/tuple-struct.myc +++ b/examples/tuple-struct.myc @@ -1,3 +1,5 @@ +;; Benchmark: 962ns +;; Benchmark-Repeat: 2089 (do (def pipe (fn [conf] (do diff --git a/src/ast/compiler/analyzer.rs b/src/ast/compiler/analyzer.rs index 0027cd0..ddcce82 100644 --- a/src/ast/compiler/analyzer.rs +++ b/src/ast/compiler/analyzer.rs @@ -31,8 +31,8 @@ impl<'a> Analyzer<'a> { fn collect_globals(&mut self, node: &TypedNode) { match &node.kind { - BoundKind::DefGlobal { - global_index, + BoundKind::Define { + addr: Address::Global(global_index), value, .. } => { @@ -61,13 +61,6 @@ impl<'a> Analyzer<'a> { let (new_kind, purity) = match &node.kind { BoundKind::Constant(v) => (BoundKind::Constant(v.clone()), Purity::Pure), BoundKind::Nop => (BoundKind::Nop, Purity::Pure), - BoundKind::Parameter { name, slot } => ( - BoundKind::Parameter { - name: name.clone(), - slot: *slot, - }, - Purity::Pure, - ), BoundKind::Get { addr, name } => { let p = match addr { @@ -96,18 +89,20 @@ impl<'a> Analyzer<'a> { ) } - BoundKind::DefLocal { + BoundKind::Define { name, - slot, + addr, + kind, value, captured_by, } => { let val_m = self.visit(Rc::new((**value).clone())); let p = val_m.ty.purity; ( - BoundKind::DefLocal { + BoundKind::Define { name: name.clone(), - slot: *slot, + addr: *addr, + kind: *kind, value: Box::new(val_m), captured_by: captured_by.clone(), }, @@ -115,23 +110,6 @@ impl<'a> Analyzer<'a> { ) } - BoundKind::DefGlobal { - name, - global_index, - value, - } => { - let val_m = self.visit(Rc::new((**value).clone())); - let p = val_m.ty.purity; - ( - BoundKind::DefGlobal { - name: name.clone(), - global_index: *global_index, - value: Box::new(val_m), - }, - p, - ) - } - BoundKind::If { cond, then_br, @@ -327,9 +305,7 @@ impl NodeExt for BoundKind { f(e); } } - BoundKind::DefLocal { value, .. } - | BoundKind::DefGlobal { value, .. } - | BoundKind::Set { value, .. } => { + BoundKind::Define { value, .. } | BoundKind::Set { value, .. } => { f(value); } BoundKind::Lambda { params, body, .. } => { diff --git a/src/ast/compiler/binder.rs b/src/ast/compiler/binder.rs index 36c8466..9e4dc37 100644 --- a/src/ast/compiler/binder.rs +++ b/src/ast/compiler/binder.rs @@ -1,4 +1,4 @@ -use crate::ast::compiler::bound_nodes::{Address, BoundKind, BoundNode}; +use crate::ast::compiler::bound_nodes::{Address, BoundKind, BoundNode, DeclarationKind}; use crate::ast::nodes::{Node, Symbol, UntypedKind}; use crate::ast::types::{Identity, StaticType}; use std::cell::RefCell; @@ -110,6 +110,26 @@ impl Binder { binder.bind(node) } + fn declare_variable( + &mut self, + name: &Symbol, + _kind: crate::ast::compiler::bound_nodes::DeclarationKind, + ) -> Result { + 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)) + } + } + pub fn bind(&mut self, node: &Node) -> Result { match &node.kind { UntypedKind::Nop => Ok(self.make_node(node.identity.clone(), BoundKind::Nop)), @@ -157,55 +177,33 @@ impl Binder { UntypedKind::Def { target, value } => { // Special case: Single identifier (to support recursion) if let UntypedKind::Parameter(ref name) = target.kind { - let slot_or_idx = 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); - idx - } else { - let current_fn = self.functions.last_mut().unwrap(); - current_fn.scope.define(name)? - }; - + let addr = self.declare_variable( + name, + crate::ast::compiler::bound_nodes::DeclarationKind::Variable, + )?; let val_node = self.bind(value)?; + let captured_by = self + .capture_map + .get(&target.identity) + .cloned() + .unwrap_or_default(); - if self.functions.len() == 1 { - Ok(self.make_node( - node.identity.clone(), - BoundKind::DefGlobal { - name: name.clone(), - global_index: slot_or_idx, - value: Box::new(val_node), - }, - )) - } else { - let captured_by = self - .capture_map - .get(&target.identity) - .cloned() - .unwrap_or_default(); - Ok(self.make_node( - node.identity.clone(), - BoundKind::DefLocal { - name: name.clone(), - slot: slot_or_idx, - value: Box::new(val_node), - captured_by, - }, - )) - } + Ok(self.make_node( + node.identity.clone(), + BoundKind::Define { + name: name.clone(), + addr, + kind: crate::ast::compiler::bound_nodes::DeclarationKind::Variable, + value: Box::new(val_node), + captured_by, + }, + )) } else { // Complex Destructuring Pattern // NOTE: Destructuring definitions are NOT recursive by default // (the variables are only available AFTER the definition) let val_node = self.bind(value)?; - let target_node = self.bind_pattern(target)?; + let target_node = self.bind_pattern(target, DeclarationKind::Variable)?; Ok(self.make_node( node.identity.clone(), @@ -246,7 +244,7 @@ impl Binder { self.functions.push(FunctionCompiler::new()); // 1. Bind the parameter pattern/tuple - let params_bound = self.bind_pattern(params)?; + let params_bound = self.bind_pattern(params, DeclarationKind::Parameter)?; // 2. Bind the body let body_bound = self.bind(body)?; @@ -256,7 +254,10 @@ impl Binder { // 3. Static optimization: count total parameters needed in flat argument list fn count_params(node: &BoundNode) -> Option { match &node.kind { - BoundKind::Parameter { .. } => Some(1), + BoundKind::Define { + kind: DeclarationKind::Parameter, + .. + } => Some(1), BoundKind::Tuple { elements } => { let mut total = 0; for e in elements { @@ -411,46 +412,35 @@ impl Binder { Err(format!("Undefined variable '{}'", sym.name)) } - fn bind_pattern(&mut self, node: &Node) -> Result { + fn bind_pattern( + &mut self, + node: &Node, + kind: DeclarationKind, + ) -> Result { match &node.kind { UntypedKind::Parameter(sym) => { - if self.functions.len() == 1 { - // Global Definition in pattern - let mut globals = self.globals.borrow_mut(); - if globals.contains_key(sym) { - return Err(format!( - "Global variable '{}' is already defined.", - sym.name - )); - } - let idx = globals.len() as u32; - globals.insert(sym.clone(), idx); - // For Global Destructuring, we return a DefGlobal with Nop value as it's a pattern part - Ok(self.make_node( - node.identity.clone(), - BoundKind::DefGlobal { - name: sym.clone(), - global_index: idx, - value: Box::new(self.make_node(node.identity.clone(), BoundKind::Nop)), - }, - )) - } else { - // Local Parameter/Definition in pattern - let current_fn = self.functions.last_mut().unwrap(); - let slot = current_fn.scope.define(sym)?; - Ok(self.make_node( - node.identity.clone(), - BoundKind::Parameter { - name: sym.clone(), - slot, - }, - )) - } + let addr = self.declare_variable(sym, kind)?; + let captured_by = self + .capture_map + .get(&node.identity) + .cloned() + .unwrap_or_default(); + + Ok(self.make_node( + node.identity.clone(), + BoundKind::Define { + name: sym.clone(), + addr, + kind, + value: Box::new(self.make_node(node.identity.clone(), BoundKind::Nop)), + captured_by, + }, + )) } UntypedKind::Tuple { elements } => { let mut bound_elems = Vec::new(); for e in elements { - bound_elems.push(self.bind_pattern(e)?); + bound_elems.push(self.bind_pattern(e, kind)?); } Ok(self.make_node( node.identity.clone(), @@ -518,18 +508,19 @@ mod tests { let globals = Rc::new(RefCell::new(HashMap::new())); let bound = Binder::bind_root(globals, &untyped).unwrap(); - // Structure: Lambda -> Block -> [ DefLocal(x), DefLocal(f), Get(x) ] + // Structure: Lambda -> Block -> [ Define(x), Define(f), Get(x) ] if let BoundKind::Lambda { body, .. } = &bound.kind { if let BoundKind::Block { exprs } = &body.kind { let x_decl = &exprs[0]; - if let BoundKind::DefLocal { captured_by, .. } = &x_decl.kind { + if let BoundKind::Define { captured_by, addr, .. } = &x_decl.kind { + assert!(matches!(addr, Address::Local(_))); assert!( !captured_by.is_empty(), "Variable 'x' should have capturers because it is used in lambda 'f'" ); } else { panic!( - "First expression in block should be DefLocal, got {:?}", + "First expression in block should be Define, got {:?}", x_decl.kind ); } @@ -553,13 +544,14 @@ mod tests { if let BoundKind::Lambda { body, .. } = &bound.kind { if let BoundKind::Block { exprs } = &body.kind { let x_decl = &exprs[0]; - if let BoundKind::DefLocal { captured_by, .. } = &x_decl.kind { + if let BoundKind::Define { captured_by, addr, .. } = &x_decl.kind { + assert!(matches!(addr, Address::Local(_))); assert!( captured_by.is_empty(), "Variable 'x' should NOT have any capturers" ); } else { - panic!("First expression should be DefLocal"); + panic!("First expression should be Define"); } } else { panic!("Lambda body should be a Block"); diff --git a/src/ast/compiler/bound_nodes.rs b/src/ast/compiler/bound_nodes.rs index 66d2ee0..ee00e00 100644 --- a/src/ast/compiler/bound_nodes.rs +++ b/src/ast/compiler/bound_nodes.rs @@ -9,6 +9,12 @@ pub enum Address { Global(u32), // Index in the global environment vector } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum DeclarationKind { + Variable, + Parameter, +} + /// Trait for DSL-specific AST extensions (like Pipe, Series-Access, etc.) pub trait BoundExtension: std::fmt::Debug { fn clone_box(&self) -> Box>; @@ -43,12 +49,6 @@ pub enum BoundKind { Nop, Constant(Value), - /// A positional parameter in a Lambda's parameter list. - Parameter { - name: Symbol, - slot: u32, - }, - // Variable Access (Resolved) Get { addr: Address, @@ -61,10 +61,11 @@ pub enum BoundKind { value: Box>, }, - // Variable Declaration (Local) - DefLocal { + // Variable Declaration (Unified for Local/Global/Parameter) + Define { name: Symbol, - slot: u32, + addr: Address, + kind: DeclarationKind, value: Box>, captured_by: Vec, }, @@ -75,13 +76,6 @@ pub enum BoundKind { else_br: Option>>, }, - // Global Definition (Locals are implicit by stack position) - DefGlobal { - name: Symbol, - global_index: u32, - value: Box>, - }, - /// A destructuring operation (can be a definition or an assignment depending on the pattern) Destructure { pattern: Box>, @@ -138,10 +132,6 @@ where match (self, other) { (BoundKind::Nop, BoundKind::Nop) => true, (BoundKind::Constant(a), BoundKind::Constant(b)) => a == b, - ( - BoundKind::Parameter { name: na, slot: sa }, - BoundKind::Parameter { name: nb, slot: sb }, - ) => na == nb && sa == sb, (BoundKind::Get { addr: aa, name: na }, BoundKind::Get { addr: ab, name: nb }) => { aa == ab && na == nb } @@ -156,19 +146,21 @@ where }, ) => aa == ab && va == vb, ( - BoundKind::DefLocal { + BoundKind::Define { name: na, - slot: sa, + addr: aa, + kind: ka, value: va, captured_by: ca, }, - BoundKind::DefLocal { + BoundKind::Define { name: nb, - slot: sb, + addr: ab, + kind: kb, value: vb, captured_by: cb, }, - ) => na == nb && sa == sb && va == vb && ca == cb, + ) => na == nb && aa == ab && ka == kb && va == vb && ca == cb, ( BoundKind::If { cond: ca, @@ -181,18 +173,6 @@ where else_br: eb, }, ) => ca == cb && ta == tb && ea == eb, - ( - BoundKind::DefGlobal { - name: na, - global_index: ga, - value: va, - }, - BoundKind::DefGlobal { - name: nb, - global_index: gb, - value: vb, - }, - ) => na == nb && ga == gb && va == vb, ( BoundKind::Destructure { pattern: pa, @@ -255,16 +235,16 @@ impl BoundKind { match self { BoundKind::Nop => "NOP".to_string(), BoundKind::Constant(v) => format!("CONST({})", v), - BoundKind::Parameter { name, slot } => format!("PARAM({}, Slot:{})", name.name, slot), BoundKind::Get { addr, name } => format!("GET({}, {:?})", name.name, addr), BoundKind::Set { addr, .. } => format!("SET({:?})", addr), - BoundKind::DefLocal { name, slot, .. } => { - format!("DEF_LOCAL({}, Slot:{})", name.name, slot) + BoundKind::Define { name, addr, kind, .. } => { + let k_str = match kind { + DeclarationKind::Variable => "VAR", + DeclarationKind::Parameter => "PARAM", + }; + format!("DEF_{}({}, {:?})", k_str, name.name, addr) } BoundKind::If { .. } => "IF".to_string(), - BoundKind::DefGlobal { - name, global_index, .. - } => format!("DEF_GLOBAL({}, Idx:{})", name.name, global_index), BoundKind::Destructure { .. } => "DESTRUCTURE".to_string(), BoundKind::Lambda { params, upvalues, .. diff --git a/src/ast/compiler/dumper.rs b/src/ast/compiler/dumper.rs index 24c54a9..096c2a2 100644 --- a/src/ast/compiler/dumper.rs +++ b/src/ast/compiler/dumper.rs @@ -73,12 +73,17 @@ impl Dumper { self.indent -= 1; } - BoundKind::DefLocal { + BoundKind::Define { name, - slot, + addr, + kind, value, captured_by, } => { + let k_str = match kind { + crate::ast::compiler::bound_nodes::DeclarationKind::Variable => "Variable", + crate::ast::compiler::bound_nodes::DeclarationKind::Parameter => "Parameter", + }; let capture_info = if captured_by.is_empty() { String::from("not captured") } else { @@ -86,8 +91,8 @@ impl Dumper { }; self.log( &format!( - "DefLocal (Name: '{}', Slot: {}, {})", - name.name, slot, capture_info + "Define {} (Name: '{}', Address: {:?}, {})", + k_str, name.name, addr, capture_info ), node, ); @@ -106,20 +111,6 @@ impl Dumper { self.indent -= 1; } - BoundKind::DefGlobal { - name, - global_index, - value, - } => { - self.log( - &format!("DefGlobal (Name: '{}', Index: {})", name.name, global_index), - node, - ); - self.indent += 1; - self.visit(value); - self.indent -= 1; - } - BoundKind::Destructure { pattern, value } => { self.log("Destructure", node); self.indent += 1; @@ -177,13 +168,6 @@ impl Dumper { self.indent -= 1; } - BoundKind::Parameter { name, slot } => { - self.log( - &format!("Parameter (Name: '{}', Slot: {})", name.name, slot), - node, - ); - } - BoundKind::Call { callee, args } => { self.log("Call", node); self.indent += 1; diff --git a/src/ast/compiler/lambda_collector.rs b/src/ast/compiler/lambda_collector.rs index ea4a2a1..9a65bda 100644 --- a/src/ast/compiler/lambda_collector.rs +++ b/src/ast/compiler/lambda_collector.rs @@ -22,13 +22,11 @@ impl<'a, T: Clone> LambdaCollector<'a, T> { } } - BoundKind::DefGlobal { - global_index, - value, - .. - } => { - // Register the full Lambda node as the template. - if let BoundKind::Lambda { .. } = &value.kind { + BoundKind::Define { addr, value, .. } => { + // Register global function definitions (lambdas) + if let Address::Global(global_index) = addr + && let BoundKind::Lambda { .. } = &value.kind + { self.registry .insert(*global_index, (*value).as_ref().clone()); } @@ -63,10 +61,6 @@ impl<'a, T: Clone> LambdaCollector<'a, T> { self.visit(body); } - BoundKind::DefLocal { value, .. } => { - self.visit(value); - } - BoundKind::Call { callee, args } => { self.visit(callee); self.visit(args); diff --git a/src/ast/compiler/optimizer.rs b/src/ast/compiler/optimizer.rs index bbabb6d..449a269 100644 --- a/src/ast/compiler/optimizer.rs +++ b/src/ast/compiler/optimizer.rs @@ -99,12 +99,15 @@ impl Optimizer { fn collect_pattern_usage(&self, node: &AnalyzedNode, info: &mut UsageInfo) { match &node.kind { - BoundKind::Parameter { slot, .. } => { - info.assigned_locals.insert(*slot); - } - BoundKind::DefGlobal { global_index, .. } => { - info.assigned_globals.insert(*global_index); - } + BoundKind::Define { addr, .. } => match addr { + Address::Local(slot) => { + info.assigned_locals.insert(*slot); + } + Address::Global(idx) => { + info.assigned_globals.insert(*idx); + } + _ => {} + }, BoundKind::Set { addr, .. } => match addr { Address::Local(slot) => { info.assigned_locals.insert(*slot); @@ -181,12 +184,40 @@ impl Optimizer { ) } - BoundKind::Parameter { ref name, slot } => { - let new_slot = sub.map_slot(slot); + BoundKind::Define { + ref name, + addr, + kind, + ref value, + ref captured_by, + } => { + let value = Box::new(self.visit_node(*value.clone(), sub, path)); + let new_addr = match addr { + Address::Local(slot) => { + if let BoundKind::Constant(val) = &value.kind { + sub.add_local(slot, val.clone()); + } else { + sub.locals.remove(&slot); + } + Address::Local(sub.map_slot(slot)) + } + Address::Global(idx) => { + if let BoundKind::Constant(val) = &value.kind { + sub.add_global(idx, val.clone()); + } else { + sub.globals.remove(&idx); + } + Address::Global(idx) + } + _ => addr, + }; ( - BoundKind::Parameter { + BoundKind::Define { name: name.clone(), - slot: new_slot, + addr: new_addr, + kind, + value, + captured_by: captured_by.clone(), }, node.ty.clone(), ) @@ -407,20 +438,19 @@ impl Optimizer { let is_last = i == last_idx; if self.enabled && !is_last { let removable = match &e.kind { - BoundKind::DefLocal { slot, value, .. } => { - !info.used_locals.contains(slot) - && !sub.captured_slots.contains(slot) - && value.ty.purity >= Purity::SideEffectFree - } - BoundKind::DefGlobal { - global_index, - value, - .. - } => { - !info.used_globals.contains(global_index) - && (value.ty.purity >= Purity::SideEffectFree - || matches!(value.kind, BoundKind::Lambda { .. })) - } + BoundKind::Define { addr, value, .. } => match addr { + Address::Local(slot) => { + !info.used_locals.contains(slot) + && !sub.captured_slots.contains(slot) + && value.ty.purity >= Purity::SideEffectFree + } + Address::Global(global_index) => { + !info.used_globals.contains(global_index) + && (value.ty.purity >= Purity::SideEffectFree + || matches!(value.kind, BoundKind::Lambda { .. })) + } + _ => false, + }, BoundKind::Set { addr: Address::Local(slot), value, @@ -536,61 +566,6 @@ impl Optimizer { ) } - BoundKind::DefLocal { - ref name, - slot, - ref value, - ref captured_by, - } => { - if !captured_by.is_empty() { - sub.captured_slots.insert(slot); - } - let value_opt = Box::new(self.visit_node((**value).clone(), sub, path)); - if let BoundKind::Constant(val) = &value_opt.kind { - sub.add_local(slot, val.clone()); - } else { - sub.locals.remove(&slot); - } - - let new_slot = sub.map_slot(slot); - ( - BoundKind::DefLocal { - name: name.clone(), - slot: new_slot, - value: value_opt, - captured_by: captured_by.clone(), - }, - node.ty.clone(), - ) - } - - BoundKind::DefGlobal { - ref name, - global_index, - ref value, - } => { - let value_opt = Box::new(self.visit_node((**value).clone(), sub, path)); - if let BoundKind::Constant(val) = &value_opt.kind - && self.is_inlinable_value(val, Some(global_index)) - { - sub.add_global(global_index, val.clone()); - } - let p = value_opt.ty.purity; - if p > Purity::Impure - && let Some(purity_rc) = &self.global_purity - { - purity_rc.borrow_mut().insert(global_index, p); - } - ( - BoundKind::DefGlobal { - name: name.clone(), - global_index, - value: value_opt, - }, - node.ty.clone(), - ) - } - BoundKind::Destructure { ref pattern, ref value, @@ -658,7 +633,7 @@ impl Optimizer { fn collect_parameter_slots(&self, node: &AnalyzedNode, sub: &mut SubstitutionMap) { match &node.kind { - BoundKind::Parameter { slot, .. } => { + BoundKind::Define { addr: Address::Local(slot), .. } => { sub.slot_mapping.insert(*slot, *slot); sub.next_slot = sub.next_slot.max(*slot + 1); } @@ -805,7 +780,7 @@ impl Optimizer { fn collect_parameter_slots_set(&self, node: &AnalyzedNode, slots: &mut HashSet) { match &node.kind { - BoundKind::Parameter { slot, .. } => { + BoundKind::Define { addr: Address::Local(slot), .. } => { slots.insert(*slot); } BoundKind::Tuple { elements } => { @@ -843,22 +818,22 @@ impl Optimizer { body_usage: &UsageInfo, ) { match &pattern.kind { - BoundKind::Parameter { slot, .. } => { - if let Some(arg) = args.get(*offset) { - if !body_usage.assigned_locals.contains(slot) { - if let BoundKind::Constant(val) = &arg.kind { - sub.add_local(*slot, val.clone()); - } else if let BoundKind::Lambda { upvalues, .. } = &arg.kind { - if upvalues.is_empty() { - sub.add_ast_local(*slot, arg.clone()); - } - } else if let BoundKind::Get { - addr: Address::Global(_), - .. - } = &arg.kind - { + BoundKind::Define { addr: Address::Local(slot), .. } => { + if let Some(arg) = args.get(*offset) + && !body_usage.assigned_locals.contains(slot) + { + if let BoundKind::Constant(val) = &arg.kind { + sub.add_local(*slot, val.clone()); + } else if let BoundKind::Lambda { upvalues, .. } = &arg.kind { + if upvalues.is_empty() { sub.add_ast_local(*slot, arg.clone()); } + } else if let BoundKind::Get { + addr: Address::Global(_), + .. + } = &arg.kind + { + sub.add_ast_local(*slot, arg.clone()); } } sub.slot_mapping.insert(*slot, *slot); @@ -1025,7 +1000,7 @@ impl Optimizer { self.collect_usage(v, info); } } - BoundKind::DefLocal { value, .. } | BoundKind::DefGlobal { value, .. } => { + BoundKind::Define { value, .. } => { self.collect_usage(value, info); } BoundKind::Expansion { bound_expanded, .. } => { @@ -1171,38 +1146,25 @@ impl SubstitutionMap { let args = Box::new(self.reindex_upvalues(*args, mapping)); (BoundKind::Call { callee, args }, node.ty.clone()) } - BoundKind::DefLocal { + BoundKind::Define { name, - slot, + addr, + kind, value, captured_by, } => { let value = Box::new(self.reindex_upvalues(*value, mapping)); ( - BoundKind::DefLocal { + BoundKind::Define { name, - slot, + addr, + kind, value, captured_by, }, node.ty.clone(), ) } - BoundKind::DefGlobal { - name, - global_index, - value, - } => { - let value = Box::new(self.reindex_upvalues(*value, mapping)); - ( - BoundKind::DefGlobal { - name, - global_index, - value, - }, - node.ty.clone(), - ) - } BoundKind::Set { addr, value } => { let value = Box::new(self.reindex_upvalues(*value, mapping)); (BoundKind::Set { addr, value }, node.ty.clone()) diff --git a/src/ast/compiler/specializer.rs b/src/ast/compiler/specializer.rs index 6d35082..994001c 100644 --- a/src/ast/compiler/specializer.rs +++ b/src/ast/compiler/specializer.rs @@ -104,34 +104,21 @@ impl Specializer { node.ty.clone(), ) } - BoundKind::DefLocal { + BoundKind::Define { name, - slot, + addr, + kind, value, captured_by, } => { let value = Box::new(self.visit_node(*value)); ( - BoundKind::DefLocal { - name, - slot, - value, - captured_by, - }, - node.ty.clone(), - ) - } - BoundKind::DefGlobal { - name, - global_index, - value, - } => { - let value = Box::new(self.visit_node(*value)); - ( - BoundKind::DefGlobal { - name, - global_index, + BoundKind::Define { + name: name.clone(), + addr, + kind, value, + captured_by: captured_by.clone(), }, node.ty.clone(), ) diff --git a/src/ast/compiler/tco.rs b/src/ast/compiler/tco.rs index 6ede986..56b4626 100644 --- a/src/ast/compiler/tco.rs +++ b/src/ast/compiler/tco.rs @@ -98,26 +98,19 @@ impl TCO { addr: *addr, value: Box::new(Self::transform(Rc::new((**value).clone()), false)), }, - BoundKind::DefLocal { + BoundKind::Define { name, - slot, + addr, + kind, value, captured_by, - } => BoundKind::DefLocal { + } => BoundKind::Define { name: name.clone(), - slot: *slot, + addr: *addr, + kind: *kind, value: Box::new(Self::transform(Rc::new((**value).clone()), false)), captured_by: captured_by.clone(), }, - BoundKind::DefGlobal { - name, - global_index, - value, - } => BoundKind::DefGlobal { - name: name.clone(), - global_index: *global_index, - value: Box::new(Self::transform(Rc::new((**value).clone()), false)), - }, BoundKind::Destructure { pattern, value } => BoundKind::Destructure { pattern: Box::new(Self::transform(Rc::new((**pattern).clone()), false)), value: Box::new(Self::transform(Rc::new((**value).clone()), false)), @@ -143,10 +136,6 @@ impl TCO { elements: new_elements, } } - BoundKind::Parameter { name, slot } => BoundKind::Parameter { - name: name.clone(), - slot: *slot, - }, BoundKind::Constant(v) => BoundKind::Constant(v.clone()), BoundKind::Get { addr, name } => BoundKind::Get { addr: *addr, diff --git a/src/ast/compiler/type_checker.rs b/src/ast/compiler/type_checker.rs index 10193ee..aedc980 100644 --- a/src/ast/compiler/type_checker.rs +++ b/src/ast/compiler/type_checker.rs @@ -140,25 +140,33 @@ impl TypeChecker { ctx: &mut TypeContext, ) -> Result { let (kind, ty) = match node.kind { - BoundKind::Parameter { name, slot } => { - ctx.set_local_type(slot, specialized_ty.clone()); - (BoundKind::Parameter { name, slot }, specialized_ty.clone()) - } - BoundKind::DefGlobal { - name, global_index, .. + BoundKind::Define { + name, + addr, + kind: decl_kind, + captured_by, + .. } => { - self.global_types - .borrow_mut() - .insert(global_index, specialized_ty.clone()); + match addr { + Address::Local(slot) => ctx.set_local_type(slot, specialized_ty.clone()), + Address::Global(global_index) => { + self.global_types + .borrow_mut() + .insert(global_index, specialized_ty.clone()); + } + _ => {} + } ( - BoundKind::DefGlobal { + BoundKind::Define { name, - global_index, + addr, + kind: decl_kind, value: Box::new(Node { identity: node.identity.clone(), kind: BoundKind::Nop, - ty: StaticType::Void, + ty: specialized_ty.clone(), }), + captured_by, }, specialized_ty.clone(), ) @@ -244,10 +252,37 @@ impl TypeChecker { (BoundKind::Constant(v), ty) } - BoundKind::Parameter { name, slot } => ( - BoundKind::Parameter { name, slot }, - ctx.get_type(Address::Local(slot)), - ), + BoundKind::Define { + name, + addr, + kind: decl_kind, + value, + captured_by, + } => { + let val_typed = self.check_node(*value, ctx)?; + let ty = val_typed.ty.clone(); + + match addr { + Address::Local(slot) => ctx.set_local_type(slot, ty.clone()), + Address::Global(global_index) => { + self.global_types + .borrow_mut() + .insert(global_index, ty.clone()); + } + _ => {} + } + + ( + BoundKind::Define { + name, + addr, + kind: decl_kind, + value: Box::new(val_typed), + captured_by, + }, + ty, + ) + } BoundKind::Get { addr, name } => { let ty = if let Address::Global(idx) = addr { @@ -259,7 +294,7 @@ impl TypeChecker { } else { ctx.get_type(addr) }; - (BoundKind::Get { addr, name }, ty) + (BoundKind::Get { addr, name: name.clone() }, ty) } BoundKind::Set { addr, value } => { @@ -281,48 +316,6 @@ impl TypeChecker { ) } - BoundKind::DefLocal { - name, - slot, - value, - captured_by, - } => { - let val_typed = self.check_node(*value, ctx)?; - let ty = val_typed.ty.clone(); - ctx.set_local_type(slot, ty.clone()); - - ( - BoundKind::DefLocal { - name, - slot, - value: Box::new(val_typed), - captured_by, - }, - ty, - ) - } - - BoundKind::DefGlobal { - name, - global_index, - value, - } => { - let val_typed = self.check_node(*value, ctx)?; - let ty = val_typed.ty.clone(); - self.global_types - .borrow_mut() - .insert(global_index, ty.clone()); - - ( - BoundKind::DefGlobal { - name, - global_index, - value: Box::new(val_typed), - }, - ty, - ) - } - BoundKind::Destructure { pattern, value } => { let val_typed = self.check_node(*value, ctx)?; let pat_typed = self.check_params(*pattern, &val_typed.ty, ctx)?; diff --git a/src/ast/vm.rs b/src/ast/vm.rs index 47db089..c5f83ed 100644 --- a/src/ast/vm.rs +++ b/src/ast/vm.rs @@ -103,7 +103,7 @@ impl VMObserver for TracingObserver { self.indent = self.indent.saturating_sub(1); let pad = self.pad(); match &node.kind { - BoundKind::DefLocal { .. } | BoundKind::Set { .. } | BoundKind::DefGlobal { .. } => { + BoundKind::Define { .. } | BoundKind::Set { .. } => { let s_pad = format!("{}| ", pad); self.logs.push(format!("{}--- Scope Status ---", s_pad)); self.logs.push(format!( @@ -266,20 +266,20 @@ impl VM { match &node.kind { BoundKind::Nop => Ok(Value::Void), BoundKind::Constant(v) => Ok(v.clone()), - BoundKind::Parameter { .. } => Ok(Value::Void), - BoundKind::DefGlobal { - global_index, + BoundKind::Define { + addr, value, + captured_by, .. } => { let val = self.eval_internal(obs, value)?; - let idx = *global_index as usize; - let mut globals = self.globals.borrow_mut(); - if idx >= globals.len() { - globals.resize(idx + 1, Value::Void); - } - globals[idx] = val.clone(); - Ok(val) + let final_val = if !captured_by.is_empty() && matches!(addr, Address::Local(_)) { + Value::Cell(Rc::new(RefCell::new(val))) + } else { + val + }; + self.set_value(*addr, final_val.clone())?; + Ok(final_val) } BoundKind::Destructure { pattern, value } => { let val = self.eval_internal(obs, value)?; @@ -299,29 +299,6 @@ impl VM { self.set_value(*addr, val.clone())?; Ok(val) } - BoundKind::DefLocal { - slot, - value, - captured_by, - .. - } => { - let val = self.eval_internal(obs, value)?; - let final_val = if !captured_by.is_empty() { - Value::Cell(Rc::new(RefCell::new(val))) - } else { - val - }; - let frame = self.frames.last().ok_or("No call frame")?; - let abs_index = frame.stack_base + (*slot as usize); - if abs_index == self.stack.len() { - self.stack.push(final_val.clone()); - } else if abs_index < self.stack.len() { - self.stack[abs_index] = final_val.clone(); - } else { - return Err(format!("Stack gap at local {}", slot)); - } - Ok(final_val) - } BoundKind::If { cond, then_br, @@ -689,30 +666,10 @@ impl VM { offset: &mut usize, ) -> Result<(), String> { match &pattern.kind { - BoundKind::Parameter { slot, .. } => { + BoundKind::Define { addr, .. } => { let val = values.get(*offset).cloned().unwrap_or(Value::Void); *offset += 1; - let frame = self.frames.last().ok_or("No call frame")?; - let abs_index = frame.stack_base + (*slot as usize); - if abs_index == self.stack.len() { - self.stack.push(val); - } else if abs_index < self.stack.len() { - self.stack[abs_index] = val; - } else { - return Err(format!("Stack gap during unpack at slot {}", slot)); - } - Ok(()) - } - BoundKind::DefGlobal { global_index, .. } => { - let val = values.get(*offset).cloned().unwrap_or(Value::Void); - *offset += 1; - let idx = *global_index as usize; - let mut globals = self.globals.borrow_mut(); - if idx >= globals.len() { - globals.resize(idx + 1, Value::Void); - } - globals[idx] = val; - Ok(()) + self.set_value(*addr, val) } BoundKind::Set { addr, .. } => { let val = values.get(*offset).cloned().unwrap_or(Value::Void);