Refactor lambda binding and parameter handling

Introduce `BoundKind::Parameter` to represent function parameters.
Modify `Binder` to correctly handle parameters within lambda
definitions, ensuring they are only defined within function scopes.
Update `LambdaCollector` to register the body of lambdas as templates
for global definitions.
Adjust `Dumper` to accurately represent lambda parameters.
Update `Specializer` and `TCO` to handle the new `BoundKind::Parameter`.
Refactor `Call` and `TailCall` to use a single `args` node, often a
tuple.
Adjust type signatures in RTL to use `StaticType::Tuple` for function
parameters.
This commit is contained in:
Michael Schimmel
2026-02-20 12:14:22 +01:00
parent 8d6d3be5c2
commit e2279f214b
17 changed files with 497 additions and 247 deletions
+36 -23
View File
@@ -21,11 +21,23 @@ impl<T> Clone for Box<dyn BoundExtension<T>> {
}
}
/// Type alias for a node that has been bound. Defaults to untyped (T = ()).
pub type BoundNode<T = ()> = Node<BoundKind<T>, T>;
/// Type alias for a node that has been fully type-checked.
pub type TypedNode = BoundNode<StaticType>;
#[derive(Debug, Clone)]
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,
@@ -35,53 +47,53 @@ pub enum BoundKind<T = ()> {
// Variable Update (Assignment)
Set {
addr: Address,
value: Box<Node<BoundKind<T>, T>>,
value: Box<BoundNode<T>>,
},
// Variable Declaration (Local)
DefLocal {
name: Symbol,
slot: u32,
value: Box<Node<BoundKind<T>, T>>,
value: Box<BoundNode<T>>,
captured_by: Vec<Identity>,
},
If {
cond: Box<Node<BoundKind<T>, T>>,
then_br: Box<Node<BoundKind<T>, T>>,
else_br: Option<Box<Node<BoundKind<T>, T>>>,
cond: Box<BoundNode<T>>,
then_br: 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<Node<BoundKind<T>, T>>,
value: Box<BoundNode<T>>,
},
Lambda {
param_count: u32,
params: Box<BoundNode<T>>,
// The list of variables captured from enclosing scopes
upvalues: Vec<Address>,
body: Rc<Node<BoundKind<T>, T>>,
body: Rc<BoundNode<T>>,
},
Call {
callee: Box<Node<BoundKind<T>, T>>,
args: Vec<Node<BoundKind<T>, T>>,
callee: Box<BoundNode<T>>,
args: Box<BoundNode<T>>,
},
TailCall {
callee: Box<Node<BoundKind<T>, T>>,
args: Vec<Node<BoundKind<T>, T>>,
callee: Box<BoundNode<T>>,
args: Box<BoundNode<T>>,
},
Block {
exprs: Vec<Node<BoundKind<T>, T>>,
exprs: Vec<BoundNode<T>>,
},
Tuple {
elements: Vec<Node<BoundKind<T>, T>>,
elements: Vec<BoundNode<T>>,
},
Map {
@@ -93,7 +105,7 @@ pub enum BoundKind<T = ()> {
/// The original call from the untyped AST.
original_call: Rc<Node<crate::ast::nodes::UntypedKind>>,
/// The result of binding the expanded AST.
bound_expanded: Box<Node<BoundKind<T>, T>>,
bound_expanded: Box<BoundNode<T>>,
},
/// DSL-specific extension slot
@@ -101,25 +113,26 @@ pub enum BoundKind<T = ()> {
}
/// A single entry in a Map literal (Key-Value pair)
pub type MapEntry<T> = (Node<BoundKind<T>, T>, Node<BoundKind<T>, T>);
/// Type alias for a node that has been bound (addresses resolved) but not yet type-checked.
pub type BoundNode = Node<BoundKind<()>, ()>;
/// Type alias for a node that has been fully type-checked and is ready for execution.
pub type TypedNode = Node<BoundKind<StaticType>, StaticType>;
pub type MapEntry<T> = (BoundNode<T>, BoundNode<T>);
impl<T> BoundKind<T> {
pub fn display_name(&self) -> String {
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::If { .. } => "IF".to_string(),
BoundKind::DefGlobal { name, global_index, .. } => format!("DEF_GLOBAL({}, Idx:{})", name.name, global_index),
BoundKind::Lambda { upvalues, .. } => format!("LAMBDA(Captures:{})", upvalues.len()),
BoundKind::Lambda { params, upvalues, .. } => {
let p_str = match &params.kind {
BoundKind::Tuple { elements } => format!("p:{}", elements.len()),
_ => "p:1".to_string(),
};
format!("LAMBDA({}, Captures:{})", p_str, upvalues.len())
},
BoundKind::Call { .. } => "CALL".to_string(),
BoundKind::TailCall { .. } => "T-CALL".to_string(),
BoundKind::Block { .. } => "BLOCK".to_string(),