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:
@@ -1,3 +1,5 @@
|
||||
;; Benchmark: 962ns
|
||||
;; Benchmark-Repeat: 2089
|
||||
(do
|
||||
(def pipe (fn [conf]
|
||||
(do
|
||||
|
||||
@@ -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, .. } => {
|
||||
|
||||
+59
-67
@@ -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)?;
|
||||
|
||||
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 {
|
||||
BoundKind::Define {
|
||||
name: name.clone(),
|
||||
slot: slot_or_idx,
|
||||
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
|
||||
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::DefGlobal {
|
||||
BoundKind::Define {
|
||||
name: sym.clone(),
|
||||
global_index: idx,
|
||||
addr,
|
||||
kind,
|
||||
value: Box::new(self.make_node(node.identity.clone(), BoundKind::Nop)),
|
||||
captured_by,
|
||||
},
|
||||
))
|
||||
} 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 } => {
|
||||
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");
|
||||
|
||||
@@ -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, ..
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -99,12 +99,15 @@ impl Optimizer {
|
||||
|
||||
fn collect_pattern_usage(&self, node: &AnalyzedNode, info: &mut UsageInfo) {
|
||||
match &node.kind {
|
||||
BoundKind::Parameter { slot, .. } => {
|
||||
BoundKind::Define { addr, .. } => match addr {
|
||||
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 {
|
||||
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, .. } => {
|
||||
BoundKind::Define { addr, value, .. } => match addr {
|
||||
Address::Local(slot) => {
|
||||
!info.used_locals.contains(slot)
|
||||
&& !sub.captured_slots.contains(slot)
|
||||
&& value.ty.purity >= Purity::SideEffectFree
|
||||
}
|
||||
BoundKind::DefGlobal {
|
||||
global_index,
|
||||
value,
|
||||
..
|
||||
} => {
|
||||
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,9 +818,10 @@ 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) {
|
||||
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 {
|
||||
@@ -860,7 +836,6 @@ impl Optimizer {
|
||||
sub.add_ast_local(*slot, arg.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
sub.slot_mapping.insert(*slot, *slot);
|
||||
sub.next_slot = sub.next_slot.max(*slot + 1);
|
||||
*offset += 1;
|
||||
@@ -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())
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
..
|
||||
} => {
|
||||
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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user