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.
This commit is contained in:
Michael Schimmel
2026-02-25 10:45:36 +01:00
parent f995aaf81b
commit c256a8a992
11 changed files with 280 additions and 464 deletions
+2
View File
@@ -1,3 +1,5 @@
;; Benchmark: 962ns
;; Benchmark-Repeat: 2089
(do (do
(def pipe (fn [conf] (def pipe (fn [conf]
(do (do
+9 -33
View File
@@ -31,8 +31,8 @@ impl<'a> Analyzer<'a> {
fn collect_globals(&mut self, node: &TypedNode) { fn collect_globals(&mut self, node: &TypedNode) {
match &node.kind { match &node.kind {
BoundKind::DefGlobal { BoundKind::Define {
global_index, addr: Address::Global(global_index),
value, value,
.. ..
} => { } => {
@@ -61,13 +61,6 @@ impl<'a> Analyzer<'a> {
let (new_kind, purity) = match &node.kind { let (new_kind, purity) = match &node.kind {
BoundKind::Constant(v) => (BoundKind::Constant(v.clone()), Purity::Pure), BoundKind::Constant(v) => (BoundKind::Constant(v.clone()), Purity::Pure),
BoundKind::Nop => (BoundKind::Nop, 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 } => { BoundKind::Get { addr, name } => {
let p = match addr { let p = match addr {
@@ -96,18 +89,20 @@ impl<'a> Analyzer<'a> {
) )
} }
BoundKind::DefLocal { BoundKind::Define {
name, name,
slot, addr,
kind,
value, value,
captured_by, captured_by,
} => { } => {
let val_m = self.visit(Rc::new((**value).clone())); let val_m = self.visit(Rc::new((**value).clone()));
let p = val_m.ty.purity; let p = val_m.ty.purity;
( (
BoundKind::DefLocal { BoundKind::Define {
name: name.clone(), name: name.clone(),
slot: *slot, addr: *addr,
kind: *kind,
value: Box::new(val_m), value: Box::new(val_m),
captured_by: captured_by.clone(), 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 { BoundKind::If {
cond, cond,
then_br, then_br,
@@ -327,9 +305,7 @@ impl NodeExt for BoundKind<crate::ast::types::StaticType> {
f(e); f(e);
} }
} }
BoundKind::DefLocal { value, .. } BoundKind::Define { value, .. } | BoundKind::Set { value, .. } => {
| BoundKind::DefGlobal { value, .. }
| BoundKind::Set { value, .. } => {
f(value); f(value);
} }
BoundKind::Lambda { params, body, .. } => { BoundKind::Lambda { params, body, .. } => {
+76 -84
View File
@@ -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::nodes::{Node, Symbol, UntypedKind};
use crate::ast::types::{Identity, StaticType}; use crate::ast::types::{Identity, StaticType};
use std::cell::RefCell; use std::cell::RefCell;
@@ -110,6 +110,26 @@ impl Binder {
binder.bind(node) binder.bind(node)
} }
fn declare_variable(
&mut self,
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))
}
}
pub fn bind(&mut self, node: &Node<UntypedKind>) -> Result<BoundNode, String> { pub fn bind(&mut self, node: &Node<UntypedKind>) -> Result<BoundNode, String> {
match &node.kind { match &node.kind {
UntypedKind::Nop => Ok(self.make_node(node.identity.clone(), BoundKind::Nop)), UntypedKind::Nop => Ok(self.make_node(node.identity.clone(), BoundKind::Nop)),
@@ -157,55 +177,33 @@ impl Binder {
UntypedKind::Def { target, value } => { UntypedKind::Def { target, value } => {
// Special case: Single identifier (to support recursion) // Special case: Single identifier (to support recursion)
if let UntypedKind::Parameter(ref name) = target.kind { if let UntypedKind::Parameter(ref name) = target.kind {
let slot_or_idx = if self.functions.len() == 1 { let addr = self.declare_variable(
let mut globals = self.globals.borrow_mut(); name,
if globals.contains_key(name) { crate::ast::compiler::bound_nodes::DeclarationKind::Variable,
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 val_node = self.bind(value)?; 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(
Ok(self.make_node( node.identity.clone(),
node.identity.clone(), BoundKind::Define {
BoundKind::DefGlobal { name: name.clone(),
name: name.clone(), addr,
global_index: slot_or_idx, kind: crate::ast::compiler::bound_nodes::DeclarationKind::Variable,
value: Box::new(val_node), value: Box::new(val_node),
}, captured_by,
)) },
} 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,
},
))
}
} else { } else {
// Complex Destructuring Pattern // Complex Destructuring Pattern
// NOTE: Destructuring definitions are NOT recursive by default // NOTE: Destructuring definitions are NOT recursive by default
// (the variables are only available AFTER the definition) // (the variables are only available AFTER the definition)
let val_node = self.bind(value)?; 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( Ok(self.make_node(
node.identity.clone(), node.identity.clone(),
@@ -246,7 +244,7 @@ impl Binder {
self.functions.push(FunctionCompiler::new()); self.functions.push(FunctionCompiler::new());
// 1. Bind the parameter pattern/tuple // 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 // 2. Bind the body
let body_bound = self.bind(body)?; let body_bound = self.bind(body)?;
@@ -256,7 +254,10 @@ impl Binder {
// 3. Static optimization: count total parameters needed in flat argument list // 3. Static optimization: count total parameters needed in flat argument list
fn count_params(node: &BoundNode) -> Option<u32> { fn count_params(node: &BoundNode) -> Option<u32> {
match &node.kind { match &node.kind {
BoundKind::Parameter { .. } => Some(1), BoundKind::Define {
kind: DeclarationKind::Parameter,
..
} => Some(1),
BoundKind::Tuple { elements } => { BoundKind::Tuple { elements } => {
let mut total = 0; let mut total = 0;
for e in elements { for e in elements {
@@ -411,46 +412,35 @@ impl Binder {
Err(format!("Undefined variable '{}'", sym.name)) Err(format!("Undefined variable '{}'", sym.name))
} }
fn bind_pattern(&mut self, node: &Node<UntypedKind>) -> Result<BoundNode, String> { fn bind_pattern(
&mut self,
node: &Node<UntypedKind>,
kind: DeclarationKind,
) -> Result<BoundNode, String> {
match &node.kind { match &node.kind {
UntypedKind::Parameter(sym) => { UntypedKind::Parameter(sym) => {
if self.functions.len() == 1 { let addr = self.declare_variable(sym, kind)?;
// Global Definition in pattern let captured_by = self
let mut globals = self.globals.borrow_mut(); .capture_map
if globals.contains_key(sym) { .get(&node.identity)
return Err(format!( .cloned()
"Global variable '{}' is already defined.", .unwrap_or_default();
sym.name
)); Ok(self.make_node(
} node.identity.clone(),
let idx = globals.len() as u32; BoundKind::Define {
globals.insert(sym.clone(), idx); name: sym.clone(),
// For Global Destructuring, we return a DefGlobal with Nop value as it's a pattern part addr,
Ok(self.make_node( kind,
node.identity.clone(), value: Box::new(self.make_node(node.identity.clone(), BoundKind::Nop)),
BoundKind::DefGlobal { captured_by,
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,
},
))
}
} }
UntypedKind::Tuple { elements } => { UntypedKind::Tuple { elements } => {
let mut bound_elems = Vec::new(); let mut bound_elems = Vec::new();
for e in elements { for e in elements {
bound_elems.push(self.bind_pattern(e)?); bound_elems.push(self.bind_pattern(e, kind)?);
} }
Ok(self.make_node( Ok(self.make_node(
node.identity.clone(), node.identity.clone(),
@@ -518,18 +508,19 @@ mod tests {
let globals = Rc::new(RefCell::new(HashMap::new())); let globals = Rc::new(RefCell::new(HashMap::new()));
let bound = Binder::bind_root(globals, &untyped).unwrap(); 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::Lambda { body, .. } = &bound.kind {
if let BoundKind::Block { exprs } = &body.kind { if let BoundKind::Block { exprs } = &body.kind {
let x_decl = &exprs[0]; 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!( assert!(
!captured_by.is_empty(), !captured_by.is_empty(),
"Variable 'x' should have capturers because it is used in lambda 'f'" "Variable 'x' should have capturers because it is used in lambda 'f'"
); );
} else { } else {
panic!( panic!(
"First expression in block should be DefLocal, got {:?}", "First expression in block should be Define, got {:?}",
x_decl.kind x_decl.kind
); );
} }
@@ -553,13 +544,14 @@ mod tests {
if let BoundKind::Lambda { body, .. } = &bound.kind { if let BoundKind::Lambda { body, .. } = &bound.kind {
if let BoundKind::Block { exprs } = &body.kind { if let BoundKind::Block { exprs } = &body.kind {
let x_decl = &exprs[0]; 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!( assert!(
captured_by.is_empty(), captured_by.is_empty(),
"Variable 'x' should NOT have any capturers" "Variable 'x' should NOT have any capturers"
); );
} else { } else {
panic!("First expression should be DefLocal"); panic!("First expression should be Define");
} }
} else { } else {
panic!("Lambda body should be a Block"); panic!("Lambda body should be a Block");
+23 -43
View File
@@ -9,6 +9,12 @@ pub enum Address {
Global(u32), // Index in the global environment vector 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.) /// Trait for DSL-specific AST extensions (like Pipe, Series-Access, etc.)
pub trait BoundExtension<T>: std::fmt::Debug { pub trait BoundExtension<T>: std::fmt::Debug {
fn clone_box(&self) -> Box<dyn BoundExtension<T>>; fn clone_box(&self) -> Box<dyn BoundExtension<T>>;
@@ -43,12 +49,6 @@ pub enum BoundKind<T = ()> {
Nop, Nop,
Constant(Value), Constant(Value),
/// A positional parameter in a Lambda's parameter list.
Parameter {
name: Symbol,
slot: u32,
},
// Variable Access (Resolved) // Variable Access (Resolved)
Get { Get {
addr: Address, addr: Address,
@@ -61,10 +61,11 @@ pub enum BoundKind<T = ()> {
value: Box<BoundNode<T>>, value: Box<BoundNode<T>>,
}, },
// Variable Declaration (Local) // Variable Declaration (Unified for Local/Global/Parameter)
DefLocal { Define {
name: Symbol, name: Symbol,
slot: u32, addr: Address,
kind: DeclarationKind,
value: Box<BoundNode<T>>, value: Box<BoundNode<T>>,
captured_by: Vec<Identity>, captured_by: Vec<Identity>,
}, },
@@ -75,13 +76,6 @@ pub enum BoundKind<T = ()> {
else_br: Option<Box<BoundNode<T>>>, else_br: Option<Box<BoundNode<T>>>,
}, },
// Global Definition (Locals are implicit by stack position)
DefGlobal {
name: Symbol,
global_index: u32,
value: Box<BoundNode<T>>,
},
/// A destructuring operation (can be a definition or an assignment depending on the pattern) /// A destructuring operation (can be a definition or an assignment depending on the pattern)
Destructure { Destructure {
pattern: Box<BoundNode<T>>, pattern: Box<BoundNode<T>>,
@@ -138,10 +132,6 @@ where
match (self, other) { match (self, other) {
(BoundKind::Nop, BoundKind::Nop) => true, (BoundKind::Nop, BoundKind::Nop) => true,
(BoundKind::Constant(a), BoundKind::Constant(b)) => a == b, (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 }) => { (BoundKind::Get { addr: aa, name: na }, BoundKind::Get { addr: ab, name: nb }) => {
aa == ab && na == nb aa == ab && na == nb
} }
@@ -156,19 +146,21 @@ where
}, },
) => aa == ab && va == vb, ) => aa == ab && va == vb,
( (
BoundKind::DefLocal { BoundKind::Define {
name: na, name: na,
slot: sa, addr: aa,
kind: ka,
value: va, value: va,
captured_by: ca, captured_by: ca,
}, },
BoundKind::DefLocal { BoundKind::Define {
name: nb, name: nb,
slot: sb, addr: ab,
kind: kb,
value: vb, value: vb,
captured_by: cb, captured_by: cb,
}, },
) => na == nb && sa == sb && va == vb && ca == cb, ) => na == nb && aa == ab && ka == kb && va == vb && ca == cb,
( (
BoundKind::If { BoundKind::If {
cond: ca, cond: ca,
@@ -181,18 +173,6 @@ where
else_br: eb, else_br: eb,
}, },
) => ca == cb && ta == tb && ea == 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 { BoundKind::Destructure {
pattern: pa, pattern: pa,
@@ -255,16 +235,16 @@ impl<T> BoundKind<T> {
match self { match self {
BoundKind::Nop => "NOP".to_string(), BoundKind::Nop => "NOP".to_string(),
BoundKind::Constant(v) => format!("CONST({})", v), 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::Get { addr, name } => format!("GET({}, {:?})", name.name, addr),
BoundKind::Set { addr, .. } => format!("SET({:?})", addr), BoundKind::Set { addr, .. } => format!("SET({:?})", addr),
BoundKind::DefLocal { name, slot, .. } => { BoundKind::Define { name, addr, kind, .. } => {
format!("DEF_LOCAL({}, Slot:{})", name.name, slot) let k_str = match kind {
DeclarationKind::Variable => "VAR",
DeclarationKind::Parameter => "PARAM",
};
format!("DEF_{}({}, {:?})", k_str, name.name, addr)
} }
BoundKind::If { .. } => "IF".to_string(), BoundKind::If { .. } => "IF".to_string(),
BoundKind::DefGlobal {
name, global_index, ..
} => format!("DEF_GLOBAL({}, Idx:{})", name.name, global_index),
BoundKind::Destructure { .. } => "DESTRUCTURE".to_string(), BoundKind::Destructure { .. } => "DESTRUCTURE".to_string(),
BoundKind::Lambda { BoundKind::Lambda {
params, upvalues, .. params, upvalues, ..
+9 -25
View File
@@ -73,12 +73,17 @@ impl Dumper {
self.indent -= 1; self.indent -= 1;
} }
BoundKind::DefLocal { BoundKind::Define {
name, name,
slot, addr,
kind,
value, value,
captured_by, 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() { let capture_info = if captured_by.is_empty() {
String::from("not captured") String::from("not captured")
} else { } else {
@@ -86,8 +91,8 @@ impl Dumper {
}; };
self.log( self.log(
&format!( &format!(
"DefLocal (Name: '{}', Slot: {}, {})", "Define {} (Name: '{}', Address: {:?}, {})",
name.name, slot, capture_info k_str, name.name, addr, capture_info
), ),
node, node,
); );
@@ -106,20 +111,6 @@ impl Dumper {
self.indent -= 1; 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 } => { BoundKind::Destructure { pattern, value } => {
self.log("Destructure", node); self.log("Destructure", node);
self.indent += 1; self.indent += 1;
@@ -177,13 +168,6 @@ impl Dumper {
self.indent -= 1; self.indent -= 1;
} }
BoundKind::Parameter { name, slot } => {
self.log(
&format!("Parameter (Name: '{}', Slot: {})", name.name, slot),
node,
);
}
BoundKind::Call { callee, args } => { BoundKind::Call { callee, args } => {
self.log("Call", node); self.log("Call", node);
self.indent += 1; self.indent += 1;
+5 -11
View File
@@ -22,13 +22,11 @@ impl<'a, T: Clone> LambdaCollector<'a, T> {
} }
} }
BoundKind::DefGlobal { BoundKind::Define { addr, value, .. } => {
global_index, // Register global function definitions (lambdas)
value, if let Address::Global(global_index) = addr
.. && let BoundKind::Lambda { .. } = &value.kind
} => { {
// Register the full Lambda node as the template.
if let BoundKind::Lambda { .. } = &value.kind {
self.registry self.registry
.insert(*global_index, (*value).as_ref().clone()); .insert(*global_index, (*value).as_ref().clone());
} }
@@ -63,10 +61,6 @@ impl<'a, T: Clone> LambdaCollector<'a, T> {
self.visit(body); self.visit(body);
} }
BoundKind::DefLocal { value, .. } => {
self.visit(value);
}
BoundKind::Call { callee, args } => { BoundKind::Call { callee, args } => {
self.visit(callee); self.visit(callee);
self.visit(args); self.visit(args);
+77 -115
View File
@@ -99,12 +99,15 @@ impl Optimizer {
fn collect_pattern_usage(&self, node: &AnalyzedNode, info: &mut UsageInfo) { fn collect_pattern_usage(&self, node: &AnalyzedNode, info: &mut UsageInfo) {
match &node.kind { match &node.kind {
BoundKind::Parameter { slot, .. } => { BoundKind::Define { addr, .. } => match addr {
info.assigned_locals.insert(*slot); Address::Local(slot) => {
} info.assigned_locals.insert(*slot);
BoundKind::DefGlobal { global_index, .. } => { }
info.assigned_globals.insert(*global_index); Address::Global(idx) => {
} info.assigned_globals.insert(*idx);
}
_ => {}
},
BoundKind::Set { addr, .. } => match addr { BoundKind::Set { addr, .. } => match addr {
Address::Local(slot) => { Address::Local(slot) => {
info.assigned_locals.insert(*slot); info.assigned_locals.insert(*slot);
@@ -181,12 +184,40 @@ impl Optimizer {
) )
} }
BoundKind::Parameter { ref name, slot } => { BoundKind::Define {
let new_slot = sub.map_slot(slot); 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(), name: name.clone(),
slot: new_slot, addr: new_addr,
kind,
value,
captured_by: captured_by.clone(),
}, },
node.ty.clone(), node.ty.clone(),
) )
@@ -407,20 +438,19 @@ impl Optimizer {
let is_last = i == last_idx; let is_last = i == last_idx;
if self.enabled && !is_last { if self.enabled && !is_last {
let removable = match &e.kind { let removable = match &e.kind {
BoundKind::DefLocal { slot, value, .. } => { BoundKind::Define { addr, value, .. } => match addr {
!info.used_locals.contains(slot) Address::Local(slot) => {
&& !sub.captured_slots.contains(slot) !info.used_locals.contains(slot)
&& value.ty.purity >= Purity::SideEffectFree && !sub.captured_slots.contains(slot)
} && value.ty.purity >= Purity::SideEffectFree
BoundKind::DefGlobal { }
global_index, Address::Global(global_index) => {
value, !info.used_globals.contains(global_index)
.. && (value.ty.purity >= Purity::SideEffectFree
} => { || matches!(value.kind, BoundKind::Lambda { .. }))
!info.used_globals.contains(global_index) }
&& (value.ty.purity >= Purity::SideEffectFree _ => false,
|| matches!(value.kind, BoundKind::Lambda { .. })) },
}
BoundKind::Set { BoundKind::Set {
addr: Address::Local(slot), addr: Address::Local(slot),
value, 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 { BoundKind::Destructure {
ref pattern, ref pattern,
ref value, ref value,
@@ -658,7 +633,7 @@ impl Optimizer {
fn collect_parameter_slots(&self, node: &AnalyzedNode, sub: &mut SubstitutionMap) { fn collect_parameter_slots(&self, node: &AnalyzedNode, sub: &mut SubstitutionMap) {
match &node.kind { match &node.kind {
BoundKind::Parameter { slot, .. } => { BoundKind::Define { addr: Address::Local(slot), .. } => {
sub.slot_mapping.insert(*slot, *slot); sub.slot_mapping.insert(*slot, *slot);
sub.next_slot = sub.next_slot.max(*slot + 1); 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<u32>) { fn collect_parameter_slots_set(&self, node: &AnalyzedNode, slots: &mut HashSet<u32>) {
match &node.kind { match &node.kind {
BoundKind::Parameter { slot, .. } => { BoundKind::Define { addr: Address::Local(slot), .. } => {
slots.insert(*slot); slots.insert(*slot);
} }
BoundKind::Tuple { elements } => { BoundKind::Tuple { elements } => {
@@ -843,22 +818,22 @@ impl Optimizer {
body_usage: &UsageInfo, body_usage: &UsageInfo,
) { ) {
match &pattern.kind { match &pattern.kind {
BoundKind::Parameter { slot, .. } => { BoundKind::Define { addr: Address::Local(slot), .. } => {
if let Some(arg) = args.get(*offset) { if let Some(arg) = args.get(*offset)
if !body_usage.assigned_locals.contains(slot) { && !body_usage.assigned_locals.contains(slot)
if let BoundKind::Constant(val) = &arg.kind { {
sub.add_local(*slot, val.clone()); if let BoundKind::Constant(val) = &arg.kind {
} else if let BoundKind::Lambda { upvalues, .. } = &arg.kind { sub.add_local(*slot, val.clone());
if upvalues.is_empty() { } else if let BoundKind::Lambda { upvalues, .. } = &arg.kind {
sub.add_ast_local(*slot, arg.clone()); if upvalues.is_empty() {
}
} else if let BoundKind::Get {
addr: Address::Global(_),
..
} = &arg.kind
{
sub.add_ast_local(*slot, arg.clone()); 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); sub.slot_mapping.insert(*slot, *slot);
@@ -1025,7 +1000,7 @@ impl Optimizer {
self.collect_usage(v, info); self.collect_usage(v, info);
} }
} }
BoundKind::DefLocal { value, .. } | BoundKind::DefGlobal { value, .. } => { BoundKind::Define { value, .. } => {
self.collect_usage(value, info); self.collect_usage(value, info);
} }
BoundKind::Expansion { bound_expanded, .. } => { BoundKind::Expansion { bound_expanded, .. } => {
@@ -1171,38 +1146,25 @@ impl SubstitutionMap {
let args = Box::new(self.reindex_upvalues(*args, mapping)); let args = Box::new(self.reindex_upvalues(*args, mapping));
(BoundKind::Call { callee, args }, node.ty.clone()) (BoundKind::Call { callee, args }, node.ty.clone())
} }
BoundKind::DefLocal { BoundKind::Define {
name, name,
slot, addr,
kind,
value, value,
captured_by, captured_by,
} => { } => {
let value = Box::new(self.reindex_upvalues(*value, mapping)); let value = Box::new(self.reindex_upvalues(*value, mapping));
( (
BoundKind::DefLocal { BoundKind::Define {
name, name,
slot, addr,
kind,
value, value,
captured_by, captured_by,
}, },
node.ty.clone(), 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 } => { BoundKind::Set { addr, value } => {
let value = Box::new(self.reindex_upvalues(*value, mapping)); let value = Box::new(self.reindex_upvalues(*value, mapping));
(BoundKind::Set { addr, value }, node.ty.clone()) (BoundKind::Set { addr, value }, node.ty.clone())
+8 -21
View File
@@ -104,34 +104,21 @@ impl Specializer {
node.ty.clone(), node.ty.clone(),
) )
} }
BoundKind::DefLocal { BoundKind::Define {
name, name,
slot, addr,
kind,
value, value,
captured_by, captured_by,
} => { } => {
let value = Box::new(self.visit_node(*value)); let value = Box::new(self.visit_node(*value));
( (
BoundKind::DefLocal { BoundKind::Define {
name, name: name.clone(),
slot, addr,
value, kind,
captured_by,
},
node.ty.clone(),
)
}
BoundKind::DefGlobal {
name,
global_index,
value,
} => {
let value = Box::new(self.visit_node(*value));
(
BoundKind::DefGlobal {
name,
global_index,
value, value,
captured_by: captured_by.clone(),
}, },
node.ty.clone(), node.ty.clone(),
) )
+6 -17
View File
@@ -98,26 +98,19 @@ impl TCO {
addr: *addr, addr: *addr,
value: Box::new(Self::transform(Rc::new((**value).clone()), false)), value: Box::new(Self::transform(Rc::new((**value).clone()), false)),
}, },
BoundKind::DefLocal { BoundKind::Define {
name, name,
slot, addr,
kind,
value, value,
captured_by, captured_by,
} => BoundKind::DefLocal { } => BoundKind::Define {
name: name.clone(), name: name.clone(),
slot: *slot, addr: *addr,
kind: *kind,
value: Box::new(Self::transform(Rc::new((**value).clone()), false)), value: Box::new(Self::transform(Rc::new((**value).clone()), false)),
captured_by: captured_by.clone(), 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 { BoundKind::Destructure { pattern, value } => BoundKind::Destructure {
pattern: Box::new(Self::transform(Rc::new((**pattern).clone()), false)), pattern: Box::new(Self::transform(Rc::new((**pattern).clone()), false)),
value: Box::new(Self::transform(Rc::new((**value).clone()), false)), value: Box::new(Self::transform(Rc::new((**value).clone()), false)),
@@ -143,10 +136,6 @@ impl TCO {
elements: new_elements, elements: new_elements,
} }
} }
BoundKind::Parameter { name, slot } => BoundKind::Parameter {
name: name.clone(),
slot: *slot,
},
BoundKind::Constant(v) => BoundKind::Constant(v.clone()), BoundKind::Constant(v) => BoundKind::Constant(v.clone()),
BoundKind::Get { addr, name } => BoundKind::Get { BoundKind::Get { addr, name } => BoundKind::Get {
addr: *addr, addr: *addr,
+52 -59
View File
@@ -140,25 +140,33 @@ impl TypeChecker {
ctx: &mut TypeContext, ctx: &mut TypeContext,
) -> Result<TypedNode, String> { ) -> Result<TypedNode, String> {
let (kind, ty) = match node.kind { let (kind, ty) = match node.kind {
BoundKind::Parameter { name, slot } => { BoundKind::Define {
ctx.set_local_type(slot, specialized_ty.clone()); name,
(BoundKind::Parameter { name, slot }, specialized_ty.clone()) addr,
} kind: decl_kind,
BoundKind::DefGlobal { captured_by,
name, global_index, .. ..
} => { } => {
self.global_types match addr {
.borrow_mut() Address::Local(slot) => ctx.set_local_type(slot, specialized_ty.clone()),
.insert(global_index, specialized_ty.clone()); Address::Global(global_index) => {
self.global_types
.borrow_mut()
.insert(global_index, specialized_ty.clone());
}
_ => {}
}
( (
BoundKind::DefGlobal { BoundKind::Define {
name, name,
global_index, addr,
kind: decl_kind,
value: Box::new(Node { value: Box::new(Node {
identity: node.identity.clone(), identity: node.identity.clone(),
kind: BoundKind::Nop, kind: BoundKind::Nop,
ty: StaticType::Void, ty: specialized_ty.clone(),
}), }),
captured_by,
}, },
specialized_ty.clone(), specialized_ty.clone(),
) )
@@ -244,10 +252,37 @@ impl TypeChecker {
(BoundKind::Constant(v), ty) (BoundKind::Constant(v), ty)
} }
BoundKind::Parameter { name, slot } => ( BoundKind::Define {
BoundKind::Parameter { name, slot }, name,
ctx.get_type(Address::Local(slot)), 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 } => { BoundKind::Get { addr, name } => {
let ty = if let Address::Global(idx) = addr { let ty = if let Address::Global(idx) = addr {
@@ -259,7 +294,7 @@ impl TypeChecker {
} else { } else {
ctx.get_type(addr) ctx.get_type(addr)
}; };
(BoundKind::Get { addr, name }, ty) (BoundKind::Get { addr, name: name.clone() }, ty)
} }
BoundKind::Set { addr, value } => { 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 } => { BoundKind::Destructure { pattern, value } => {
let val_typed = self.check_node(*value, ctx)?; let val_typed = self.check_node(*value, ctx)?;
let pat_typed = self.check_params(*pattern, &val_typed.ty, ctx)?; let pat_typed = self.check_params(*pattern, &val_typed.ty, ctx)?;
+13 -56
View File
@@ -103,7 +103,7 @@ impl VMObserver for TracingObserver {
self.indent = self.indent.saturating_sub(1); self.indent = self.indent.saturating_sub(1);
let pad = self.pad(); let pad = self.pad();
match &node.kind { match &node.kind {
BoundKind::DefLocal { .. } | BoundKind::Set { .. } | BoundKind::DefGlobal { .. } => { BoundKind::Define { .. } | BoundKind::Set { .. } => {
let s_pad = format!("{}| ", pad); let s_pad = format!("{}| ", pad);
self.logs.push(format!("{}--- Scope Status ---", s_pad)); self.logs.push(format!("{}--- Scope Status ---", s_pad));
self.logs.push(format!( self.logs.push(format!(
@@ -266,20 +266,20 @@ impl VM {
match &node.kind { match &node.kind {
BoundKind::Nop => Ok(Value::Void), BoundKind::Nop => Ok(Value::Void),
BoundKind::Constant(v) => Ok(v.clone()), BoundKind::Constant(v) => Ok(v.clone()),
BoundKind::Parameter { .. } => Ok(Value::Void), BoundKind::Define {
BoundKind::DefGlobal { addr,
global_index,
value, value,
captured_by,
.. ..
} => { } => {
let val = self.eval_internal(obs, value)?; let val = self.eval_internal(obs, value)?;
let idx = *global_index as usize; let final_val = if !captured_by.is_empty() && matches!(addr, Address::Local(_)) {
let mut globals = self.globals.borrow_mut(); Value::Cell(Rc::new(RefCell::new(val)))
if idx >= globals.len() { } else {
globals.resize(idx + 1, Value::Void); val
} };
globals[idx] = val.clone(); self.set_value(*addr, final_val.clone())?;
Ok(val) Ok(final_val)
} }
BoundKind::Destructure { pattern, value } => { BoundKind::Destructure { pattern, value } => {
let val = self.eval_internal(obs, value)?; let val = self.eval_internal(obs, value)?;
@@ -299,29 +299,6 @@ impl VM {
self.set_value(*addr, val.clone())?; self.set_value(*addr, val.clone())?;
Ok(val) 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 { BoundKind::If {
cond, cond,
then_br, then_br,
@@ -689,30 +666,10 @@ impl VM {
offset: &mut usize, offset: &mut usize,
) -> Result<(), String> { ) -> Result<(), String> {
match &pattern.kind { match &pattern.kind {
BoundKind::Parameter { slot, .. } => { BoundKind::Define { addr, .. } => {
let val = values.get(*offset).cloned().unwrap_or(Value::Void); let val = values.get(*offset).cloned().unwrap_or(Value::Void);
*offset += 1; *offset += 1;
let frame = self.frames.last().ok_or("No call frame")?; self.set_value(*addr, val)
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(())
} }
BoundKind::Set { addr, .. } => { BoundKind::Set { addr, .. } => {
let val = values.get(*offset).cloned().unwrap_or(Value::Void); let val = values.get(*offset).cloned().unwrap_or(Value::Void);