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
(def pipe (fn [conf]
(do
+9 -33
View File
@@ -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<crate::ast::types::StaticType> {
f(e);
}
}
BoundKind::DefLocal { value, .. }
| BoundKind::DefGlobal { value, .. }
| BoundKind::Set { value, .. } => {
BoundKind::Define { value, .. } | BoundKind::Set { value, .. } => {
f(value);
}
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::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<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> {
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<u32> {
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<UntypedKind>) -> Result<BoundNode, String> {
fn bind_pattern(
&mut self,
node: &Node<UntypedKind>,
kind: DeclarationKind,
) -> Result<BoundNode, String> {
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");
+23 -43
View File
@@ -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<T>: std::fmt::Debug {
fn clone_box(&self) -> Box<dyn BoundExtension<T>>;
@@ -43,12 +49,6 @@ pub enum BoundKind<T = ()> {
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<T = ()> {
value: Box<BoundNode<T>>,
},
// Variable Declaration (Local)
DefLocal {
// Variable Declaration (Unified for Local/Global/Parameter)
Define {
name: Symbol,
slot: u32,
addr: Address,
kind: DeclarationKind,
value: Box<BoundNode<T>>,
captured_by: Vec<Identity>,
},
@@ -75,13 +76,6 @@ pub enum BoundKind<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)
Destructure {
pattern: Box<BoundNode<T>>,
@@ -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<T> BoundKind<T> {
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, ..
+9 -25
View File
@@ -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;
+5 -11
View File
@@ -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);
+77 -115
View File
@@ -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<u32>) {
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())
+8 -21
View File
@@ -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(),
)
+6 -17
View File
@@ -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,
+52 -59
View File
@@ -140,25 +140,33 @@ impl TypeChecker {
ctx: &mut TypeContext,
) -> Result<TypedNode, String> {
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)?;
+13 -56
View File
@@ -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);