Refactor: Use new NodeKind and clean up Binder definitions

The Binder and related types have been refactored to use the new
`NodeKind` enum instead of the previous `BoundKind`. This commit updates
all references to use the new structure, ensuring consistency across the
compiler's AST representation.

Key changes include:

- Replacing `BoundKind` with `NodeKind` in the Binder's `bind` and
  `visit` methods.
- Updating pattern matching and field access to reflect the new enum
  variants (e.g., `NodeKind::Def` instead of `BoundKind::Define`).
- Adjusting identifier bindings to use the new `IdentifierBinding` enum.
- Reflecting changes in `DefBinding`, `AssignBinding`, and
  `LambdaBinding` structures.
- Ensuring all newly created nodes use `NodeKind` and the appropriate
  metadata.
This commit is contained in:
2026-03-21 14:12:14 +01:00
parent 99fef2fc86
commit e65402364d
20 changed files with 6523 additions and 6068 deletions
+101 -88
View File
@@ -1,4 +1,4 @@
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, ExecNode, StackOffset};
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, ExecNode, IdentifierBinding, NodeKind, StackOffset};
use crate::ast::types::{Object, Value};
use std::any::Any;
use std::cell::RefCell;
@@ -105,7 +105,7 @@ impl VMObserver for TracingObserver {
self.indent = self.indent.saturating_sub(1);
let pad = self.pad();
match &node.kind {
BoundKind::Define { .. } | BoundKind::Set { .. } => {
NodeKind::Def { .. } | NodeKind::Assign { .. } => {
let s_pad = format!("{}| ", pad);
self.logs.push(format!("{}--- Scope Status ---", s_pad));
self.logs.push(format!(
@@ -303,58 +303,76 @@ impl VM {
#[inline(always)]
fn eval_core<O: VMObserver>(&mut self, obs: &mut O, node: &ExecNode) -> Result<Value, String> {
match &node.kind {
BoundKind::Nop => Ok(Value::Void),
BoundKind::Constant(v) => Ok(v.clone()),
BoundKind::Define {
addr,
value,
captured_by,
..
} => {
NodeKind::Nop => Ok(Value::Void),
NodeKind::Constant(v) => Ok(v.clone()),
NodeKind::Def { pattern, value, info } => {
let val = self.eval_internal(obs, value)?;
let mut needs_cell_wrap = false;
if !captured_by.is_empty()
&& let Address::Local(slot) = addr
{
let frame = self.frames.last().unwrap();
let abs_index = frame.stack_base + (slot.0 as usize);
// Robustness Fix: If the slot is already a Cell (due to forward capture
// in a recursive scenario or complex pre-allocation), don't wrap it again.
// This prevents Cell(Cell(Value)) nesting which causes type errors.
if abs_index >= self.stack.len() || !matches!(self.stack[abs_index], Value::Cell(_)) {
needs_cell_wrap = true;
match &pattern.kind {
NodeKind::Identifier { binding, .. } => {
let addr = match binding {
IdentifierBinding::Declaration { addr, .. } | IdentifierBinding::Reference(addr) => *addr,
};
let mut needs_cell_wrap = false;
if !info.captured_by.is_empty()
&& let Address::Local(slot) = addr
{
let frame = self.frames.last().unwrap();
let abs_index = frame.stack_base + (slot.0 as usize);
// Robustness Fix: If the slot is already a Cell (due to forward capture
// in a recursive scenario or complex pre-allocation), don't wrap it again.
// This prevents Cell(Cell(Value)) nesting which causes type errors.
if abs_index >= self.stack.len() || !matches!(self.stack[abs_index], Value::Cell(_)) {
needs_cell_wrap = true;
}
}
let store_val = if needs_cell_wrap {
Value::Cell(Rc::new(RefCell::new(val.clone())))
} else {
val.clone()
};
self.set_value(addr, store_val)?;
}
_ => {
// Destructuring (was Destructure variant)
let mut offset = 0;
if let Some(vals) = val.as_slice() {
self.unpack(pattern.as_ref(), vals, &mut offset)?;
} else {
self.unpack(pattern.as_ref(), std::slice::from_ref(&val), &mut offset)?;
}
}
}
let store_val = if needs_cell_wrap {
Value::Cell(Rc::new(RefCell::new(val.clone())))
} else {
val.clone()
};
self.set_value(*addr, store_val)?;
// Define always evaluates to the unwrapped value for immediate use.
// Def always evaluates to the unwrapped value for immediate use.
Ok(val)
}
BoundKind::Destructure { pattern, value } => {
NodeKind::Assign { target, value, info } => {
let val = self.eval_internal(obs, value)?;
let mut offset = 0;
// Destructuring works on tuples/vectors, or single values wrapped in a slice
if let Some(vals) = val.as_slice() {
self.unpack(pattern.as_ref(), vals, &mut offset)?;
if let Some(addr) = info.addr {
self.set_value(addr, val.clone())?;
} else {
self.unpack(pattern.as_ref(), std::slice::from_ref(&val), &mut offset)?;
// Destructuring assign
let mut offset = 0;
if let Some(vals) = val.as_slice() {
self.unpack(target.as_ref(), vals, &mut offset)?;
} else {
self.unpack(target.as_ref(), std::slice::from_ref(&val), &mut offset)?;
}
}
Ok(val)
}
BoundKind::Get { addr, .. } => self.get_value(*addr),
NodeKind::Identifier { binding, .. } => {
match binding {
IdentifierBinding::Reference(addr) | IdentifierBinding::Declaration { addr, .. } => self.get_value(*addr),
}
}
BoundKind::FieldAccessor(k) => Ok(Value::FieldAccessor(*k)),
NodeKind::FieldAccessor(k) => Ok(Value::FieldAccessor(*k)),
BoundKind::GetField { rec, field } => {
NodeKind::GetField { rec, field } => {
let rec_val = self.eval_internal(obs, rec)?;
match rec_val {
@@ -395,12 +413,7 @@ impl VM {
}
}
BoundKind::Set { addr, value } => {
let val = self.eval_internal(obs, value)?;
self.set_value(*addr, val.clone())?;
Ok(val)
}
BoundKind::If {
NodeKind::If {
cond,
then_br,
else_br,
@@ -414,10 +427,9 @@ impl VM {
Ok(Value::Void)
}
}
BoundKind::Pipe {
NodeKind::Pipe {
inputs,
lambda,
out_type,
} => {
use crate::ast::rtl::streams::StreamNode;
@@ -464,25 +476,24 @@ impl VM {
// Delegate to the RTL Factory for specialized buffer instantiation
let node =
crate::ast::rtl::streams::build_pipeline_node(obs_streams, executor, out_type);
crate::ast::rtl::streams::build_pipeline_node(obs_streams, executor, &node.ty.ty);
Ok(Value::Object(node))
}
BoundKind::Block { exprs } => {
NodeKind::Block { exprs } => {
let mut last = Value::Void;
for e in exprs {
last = self.eval_internal(obs, e)?;
}
Ok(last)
}
BoundKind::Lambda {
NodeKind::Lambda {
params,
upvalues,
body,
positional_count,
info,
} => {
let mut captured = Vec::with_capacity(upvalues.len());
for addr in upvalues {
let mut captured = Vec::with_capacity(info.upvalues.len());
for addr in &info.upvalues {
captured.push(self.capture_upvalue(*addr)?);
}
let stack_size = node.ty.stack_size;
@@ -491,12 +502,12 @@ impl VM {
body.ty.original.clone(),
body.clone(),
captured,
*positional_count,
info.positional_count,
stack_size,
);
Ok(Value::Object(Rc::new(closure)))
}
BoundKind::Call { callee, args } => {
NodeKind::Call { callee, args } => {
let func_val = self.eval_internal(obs, callee)?;
let base = self.stack.len();
@@ -654,7 +665,7 @@ impl VM {
} else {
let args_for_unpack = self.stack[base..].to_vec();
self.stack.truncate(base);
if let BoundKind::Tuple { elements } =
if let NodeKind::Tuple { elements } =
&closure.parameter_node.kind
{
let mut offset = 0;
@@ -755,7 +766,7 @@ impl VM {
}
}
}
BoundKind::Again { args } => {
NodeKind::Again { args } => {
let base = self.stack.len();
if let Err(e) = self.eval_args_to_stack(obs, args) {
self.stack.truncate(base);
@@ -774,16 +785,16 @@ impl VM {
Err("'again' called outside of a closure".to_string())
}
}
BoundKind::Tuple { elements } => {
NodeKind::Tuple { elements } => {
let mut vals = Vec::with_capacity(elements.len());
for e in elements {
vals.push(self.eval_internal(obs, e)?);
}
Ok(Value::make_tuple(vals))
}
BoundKind::Record { layout, values } => {
let mut evaluated_values = Vec::with_capacity(values.len());
for v in values {
NodeKind::Record { fields, layout } => {
let mut evaluated_values = Vec::with_capacity(fields.len());
for (_, v) in fields {
evaluated_values.push(self.eval_internal(obs, v)?);
}
Ok(Value::Record(
@@ -791,11 +802,11 @@ impl VM {
std::rc::Rc::new(evaluated_values),
))
}
BoundKind::Expansion { bound_expanded, .. } => {
let mut curr = bound_expanded;
NodeKind::Expansion { expanded, .. } => {
let mut curr = expanded;
if !O::ACTIVE {
while let BoundKind::Expansion {
bound_expanded: next,
while let NodeKind::Expansion {
expanded: next,
..
} = &curr.kind
{
@@ -804,11 +815,15 @@ impl VM {
}
self.eval_internal(obs, curr)
}
BoundKind::Extension(ext) => Err(format!(
NodeKind::Extension(ext) => Err(format!(
"Execution of extension '{}' not implemented yet",
ext.display_name()
)),
BoundKind::Error => Err("Cannot execute a poisoned AST node".to_string()),
NodeKind::Error => Err("Cannot execute a poisoned AST node".to_string()),
// Syntax-only variants that should never appear in runtime phase
NodeKind::MacroDecl { .. } | NodeKind::Template(_) | NodeKind::Placeholder(_) | NodeKind::Splice(_) => {
Err("Syntax-only node reached the VM".to_string())
}
}
}
@@ -818,12 +833,12 @@ impl VM {
args: &ExecNode,
) -> Result<(), String> {
match &args.kind {
BoundKind::Tuple { elements } => {
NodeKind::Tuple { elements } => {
for e in elements {
let mut curr = e.as_ref();
if !O::ACTIVE {
while let BoundKind::Expansion {
bound_expanded: next,
while let NodeKind::Expansion {
expanded: next,
..
} = &curr.kind
{
@@ -832,7 +847,7 @@ impl VM {
}
match &curr.kind {
BoundKind::Constant(v) if !O::ACTIVE => self.stack.push(v.clone()),
NodeKind::Constant(v) if !O::ACTIVE => self.stack.push(v.clone()),
_ => {
let val = self.eval_internal(obs, curr)?;
self.stack.push(val);
@@ -841,7 +856,7 @@ impl VM {
}
Ok(())
}
BoundKind::Constant(v) => {
NodeKind::Constant(v) => {
if let Some(slice) = v.as_slice() {
self.stack.extend_from_slice(slice);
} else {
@@ -849,11 +864,11 @@ impl VM {
}
Ok(())
}
BoundKind::Expansion { bound_expanded, .. } => {
let mut curr = bound_expanded;
NodeKind::Expansion { expanded, .. } => {
let mut curr = expanded;
if !O::ACTIVE {
while let BoundKind::Expansion {
bound_expanded: next,
while let NodeKind::Expansion {
expanded: next,
..
} = &curr.kind
{
@@ -1008,17 +1023,15 @@ impl VM {
offset: &mut usize,
) -> Result<(), String> {
match &pattern.kind {
BoundKind::Define { addr, .. } => {
NodeKind::Identifier { binding, .. } => {
let addr = match binding {
IdentifierBinding::Declaration { addr, .. } | IdentifierBinding::Reference(addr) => *addr,
};
let val = values.get(*offset).cloned().unwrap_or(Value::Void);
*offset += 1;
self.set_value(*addr, val)
self.set_value(addr, val)
}
BoundKind::Set { addr, .. } => {
let val = values.get(*offset).cloned().unwrap_or(Value::Void);
*offset += 1;
self.set_value(*addr, val)
}
BoundKind::Tuple { elements } => {
NodeKind::Tuple { elements } => {
if let Some(sub_values) = values.get(*offset).and_then(|v| v.as_slice()) {
*offset += 1;
let mut sub_offset = 0;