Add symbol name to bound kinds
The `Get`, `DefLocal`, and `DefGlobal` bound kinds now store the symbol name associated with the variable. This information is useful for debugging and provides more context in the compiled output.
This commit is contained in:
@@ -104,7 +104,10 @@ impl Binder {
|
||||
|
||||
UntypedKind::Identifier(sym) => {
|
||||
let addr = self.resolve_variable(sym)?;
|
||||
Ok(self.make_node(node.identity.clone(), BoundKind::Get(addr)))
|
||||
Ok(self.make_node(node.identity.clone(), BoundKind::Get {
|
||||
addr,
|
||||
name: sym.clone()
|
||||
}))
|
||||
},
|
||||
|
||||
UntypedKind::If { cond, then_br, else_br } => {
|
||||
@@ -143,12 +146,14 @@ impl Binder {
|
||||
// 3. Return Node
|
||||
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(&node.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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::rc::Rc;
|
||||
use crate::ast::types::{Value, StaticType, Identity};
|
||||
use crate::ast::nodes::Node;
|
||||
use crate::ast::nodes::{Node, Symbol};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum Address {
|
||||
@@ -27,7 +27,10 @@ pub enum BoundKind<T = ()> {
|
||||
Constant(Value),
|
||||
|
||||
// Variable Access (Resolved)
|
||||
Get(Address),
|
||||
Get {
|
||||
addr: Address,
|
||||
name: Symbol,
|
||||
},
|
||||
|
||||
// Variable Update (Assignment)
|
||||
Set {
|
||||
@@ -37,6 +40,7 @@ pub enum BoundKind<T = ()> {
|
||||
|
||||
// Variable Declaration (Local)
|
||||
DefLocal {
|
||||
name: Symbol,
|
||||
slot: u32,
|
||||
value: Box<Node<BoundKind<T>, T>>,
|
||||
captured_by: Vec<Identity>,
|
||||
@@ -50,6 +54,7 @@ pub enum BoundKind<T = ()> {
|
||||
|
||||
// Global Definition (Locals are implicit by stack position)
|
||||
DefGlobal {
|
||||
name: Symbol,
|
||||
global_index: u32,
|
||||
value: Box<Node<BoundKind<T>, T>>,
|
||||
},
|
||||
@@ -109,11 +114,11 @@ impl<T> BoundKind<T> {
|
||||
match self {
|
||||
BoundKind::Nop => "NOP".to_string(),
|
||||
BoundKind::Constant(v) => format!("CONST({})", v),
|
||||
BoundKind::Get(addr) => format!("GET({:?})", addr),
|
||||
BoundKind::Get { addr, name } => format!("GET({}, {:?})", name.name, addr),
|
||||
BoundKind::Set { addr, .. } => format!("SET({:?})", addr),
|
||||
BoundKind::DefLocal { slot, .. } => format!("DEF_LOCAL(Slot:{})", slot),
|
||||
BoundKind::DefLocal { name, slot, .. } => format!("DEF_LOCAL({}, Slot:{})", name.name, slot),
|
||||
BoundKind::If { .. } => "IF".to_string(),
|
||||
BoundKind::DefGlobal { global_index, .. } => format!("DEF_GLOBAL(Idx:{})", global_index),
|
||||
BoundKind::DefGlobal { name, global_index, .. } => format!("DEF_GLOBAL({}, Idx:{})", name.name, global_index),
|
||||
BoundKind::Lambda { upvalues, .. } => format!("LAMBDA(Captures:{})", upvalues.len()),
|
||||
BoundKind::Call { .. } => "CALL".to_string(),
|
||||
BoundKind::TailCall { .. } => "T-CALL".to_string(),
|
||||
|
||||
@@ -35,7 +35,7 @@ impl Dumper {
|
||||
match &node.kind {
|
||||
BoundKind::Nop => self.log("Nop", node),
|
||||
BoundKind::Constant(v) => self.log(&format!("Constant: {}", v), node),
|
||||
BoundKind::Get(addr) => self.log(&format!("Get: {:?}", addr), node),
|
||||
BoundKind::Get { addr, name } => self.log(&format!("Get: {} ({:?})", name.name, addr), node),
|
||||
|
||||
BoundKind::Set { addr, value } => {
|
||||
self.log(&format!("Set: {:?}", addr), node);
|
||||
@@ -44,13 +44,13 @@ impl Dumper {
|
||||
self.indent -= 1;
|
||||
}
|
||||
|
||||
BoundKind::DefLocal { slot, value, captured_by } => {
|
||||
BoundKind::DefLocal { name, slot, value, captured_by } => {
|
||||
let capture_info = if captured_by.is_empty() {
|
||||
String::from("not captured")
|
||||
} else {
|
||||
format!("captured by {} lambdas", captured_by.len())
|
||||
};
|
||||
self.log(&format!("DefLocal (Slot: {}, {})", slot, capture_info), node);
|
||||
self.log(&format!("DefLocal (Name: '{}', Slot: {}, {})", name.name, slot, capture_info), node);
|
||||
|
||||
self.indent += 1;
|
||||
if !captured_by.is_empty() {
|
||||
@@ -64,8 +64,8 @@ impl Dumper {
|
||||
self.indent -= 1;
|
||||
}
|
||||
|
||||
BoundKind::DefGlobal { global_index, value } => {
|
||||
self.log(&format!("DefGlobal (Index: {})", global_index), node);
|
||||
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;
|
||||
|
||||
@@ -69,13 +69,13 @@ impl Specializer {
|
||||
let body = Rc::new(self.visit_node((*body).clone()));
|
||||
(BoundKind::Lambda { param_count, upvalues, body }, node.ty)
|
||||
},
|
||||
BoundKind::DefLocal { slot, value, captured_by } => {
|
||||
BoundKind::DefLocal { name, slot, value, captured_by } => {
|
||||
let value = Box::new(self.visit_node(*value));
|
||||
(BoundKind::DefLocal { slot, value, captured_by }, node.ty)
|
||||
(BoundKind::DefLocal { name, slot, value, captured_by }, node.ty)
|
||||
},
|
||||
BoundKind::DefGlobal { global_index, value } => {
|
||||
BoundKind::DefGlobal { name, global_index, value } => {
|
||||
let value = Box::new(self.visit_node(*value));
|
||||
(BoundKind::DefGlobal { global_index, value }, node.ty)
|
||||
(BoundKind::DefGlobal { name, global_index, value }, node.ty)
|
||||
},
|
||||
BoundKind::Set { addr, value } => {
|
||||
let value = Box::new(self.visit_node(*value));
|
||||
@@ -111,7 +111,7 @@ impl Specializer {
|
||||
let new_args: Vec<TypedNode> = args.into_iter().map(|a| self.visit_node(a)).collect();
|
||||
|
||||
// 2. Check if this call is a candidate (Callee is Get(Address))
|
||||
let address = if let BoundKind::Get(addr) = &new_callee.kind {
|
||||
let address = if let BoundKind::Get { addr, .. } = &new_callee.kind {
|
||||
*addr
|
||||
} else {
|
||||
// Not a direct call to a named function/variable
|
||||
@@ -195,6 +195,7 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::ast::types::{Identity, NodeIdentity, SourceLocation, StaticType, Value, Signature};
|
||||
use crate::ast::compiler::bound_nodes::{BoundKind, Address, BoundNode, TypedNode};
|
||||
use crate::ast::nodes::Symbol;
|
||||
use std::rc::Rc;
|
||||
|
||||
fn make_identity() -> Identity {
|
||||
@@ -235,6 +236,7 @@ mod tests {
|
||||
// Setup Registry with a function definition
|
||||
let mut registry = MockRegistry::new();
|
||||
let addr = Address::Local(0);
|
||||
let name = Symbol::from("test_func");
|
||||
|
||||
// Def: (fn [x] x) -- generic identity
|
||||
let func_node = BoundNode {
|
||||
@@ -257,7 +259,7 @@ mod tests {
|
||||
let spec = Specializer::new(Some(Rc::new(registry)), Some(compiler), None);
|
||||
|
||||
// Call(Get(Local(0)), [Arg(Int)])
|
||||
let callee = make_typed_node(BoundKind::Get(addr), StaticType::Any);
|
||||
let callee = make_typed_node(BoundKind::Get { addr, name: name.clone() }, StaticType::Any);
|
||||
let arg = make_typed_node(BoundKind::Constant(Value::Int(1)), StaticType::Int);
|
||||
|
||||
let call_node = make_typed_node(
|
||||
@@ -285,10 +287,12 @@ mod tests {
|
||||
#[test]
|
||||
fn test_specialize_skips_unknown_types() {
|
||||
let spec = Specializer::new(None, None, None);
|
||||
let name0 = Symbol::from("f");
|
||||
let name1 = Symbol::from("x");
|
||||
|
||||
// Call(Get(Local(0)), [Get(Local(1))]) where arg is Any
|
||||
let callee = make_typed_node(BoundKind::Get(Address::Local(0)), StaticType::Function(Box::new(Signature { params: vec![StaticType::Any], ret: StaticType::Void })));
|
||||
let arg = make_typed_node(BoundKind::Get(Address::Local(1)), StaticType::Any);
|
||||
let callee = make_typed_node(BoundKind::Get { addr: Address::Local(0), name: name0 }, StaticType::Function(Box::new(Signature { params: vec![StaticType::Any], ret: StaticType::Void })));
|
||||
let arg = make_typed_node(BoundKind::Get { addr: Address::Local(1), name: name1 }, StaticType::Any);
|
||||
|
||||
let call_node = make_typed_node(
|
||||
BoundKind::Call { callee: Box::new(callee), args: vec![arg] },
|
||||
@@ -299,7 +303,7 @@ mod tests {
|
||||
|
||||
// Should remain a generic Call because arg type is Any
|
||||
if let BoundKind::Call { callee, .. } = result.kind {
|
||||
if let BoundKind::Get(_) = callee.kind {
|
||||
if let BoundKind::Get { .. } = callee.kind {
|
||||
// Correct: Still a Get, not a Constant(Function)
|
||||
} else {
|
||||
panic!("Expected generic Call to Get, got {:?}", callee.kind);
|
||||
@@ -315,6 +319,7 @@ mod tests {
|
||||
let spec = Specializer::new(None, None, None);
|
||||
|
||||
let addr = Address::Local(0);
|
||||
let name = Symbol::from("cached_func");
|
||||
let arg_types = vec![StaticType::Int];
|
||||
let key = MonoCacheKey { address: addr, arg_types: arg_types.clone() };
|
||||
|
||||
@@ -325,7 +330,7 @@ mod tests {
|
||||
spec.cache.borrow_mut().insert(key, (specialized_val.clone(), ret_ty.clone()));
|
||||
|
||||
// Create the call node: Call(Get(0), [Arg(Int)])
|
||||
let callee = make_typed_node(BoundKind::Get(addr), StaticType::Any);
|
||||
let callee = make_typed_node(BoundKind::Get { addr, name }, StaticType::Any);
|
||||
let arg = make_typed_node(BoundKind::Constant(Value::Int(1)), StaticType::Int);
|
||||
|
||||
let call_node = make_typed_node(
|
||||
|
||||
@@ -95,15 +95,15 @@ impl TCO {
|
||||
..node
|
||||
}
|
||||
},
|
||||
BoundKind::DefLocal { slot, value, captured_by } => {
|
||||
BoundKind::DefLocal { name, slot, value, captured_by } => {
|
||||
Node {
|
||||
kind: BoundKind::DefLocal { slot, value: Box::new(Self::transform(*value, false)), captured_by },
|
||||
kind: BoundKind::DefLocal { name, slot, value: Box::new(Self::transform(*value, false)), captured_by },
|
||||
..node
|
||||
}
|
||||
},
|
||||
BoundKind::DefGlobal { global_index, value } => {
|
||||
BoundKind::DefGlobal { name, global_index, value } => {
|
||||
Node {
|
||||
kind: BoundKind::DefGlobal { global_index, value: Box::new(Self::transform(*value, false)) },
|
||||
kind: BoundKind::DefGlobal { name, global_index, value: Box::new(Self::transform(*value, false)) },
|
||||
..node
|
||||
}
|
||||
},
|
||||
|
||||
@@ -63,13 +63,13 @@ impl TypeChecker {
|
||||
(BoundKind::Constant(v), ty)
|
||||
},
|
||||
|
||||
BoundKind::Get(addr) => {
|
||||
BoundKind::Get { addr, name } => {
|
||||
let ty = if let Address::Global(idx) = addr {
|
||||
self.global_types.borrow().get(&idx).cloned().unwrap_or(StaticType::Any)
|
||||
} else {
|
||||
ctx.get_type(addr)
|
||||
};
|
||||
(BoundKind::Get(addr), ty)
|
||||
(BoundKind::Get { addr, name }, ty)
|
||||
},
|
||||
|
||||
BoundKind::Set { addr, value } => {
|
||||
@@ -85,20 +85,20 @@ impl TypeChecker {
|
||||
(BoundKind::Set { addr, value: Box::new(val_typed) }, ty)
|
||||
},
|
||||
|
||||
BoundKind::DefLocal { slot, value, captured_by } => {
|
||||
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 { slot, value: Box::new(val_typed), captured_by }, ty)
|
||||
(BoundKind::DefLocal { name, slot, value: Box::new(val_typed), captured_by }, ty)
|
||||
},
|
||||
|
||||
BoundKind::DefGlobal { global_index, value } => {
|
||||
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 { global_index, value: Box::new(val_typed) }, ty)
|
||||
(BoundKind::DefGlobal { name, global_index, value: Box::new(val_typed) }, ty)
|
||||
},
|
||||
|
||||
BoundKind::If { cond, then_br, else_br } => {
|
||||
|
||||
+6
-6
@@ -102,7 +102,7 @@ macro_rules! dispatch_eval {
|
||||
BoundKind::Nop => Ok(Value::Void),
|
||||
BoundKind::Constant(v) => Ok(v.clone()),
|
||||
|
||||
BoundKind::DefGlobal { global_index, value } => {
|
||||
BoundKind::DefGlobal { global_index, value, .. } => {
|
||||
let val = $self.$eval_method($($observer,)? value)?;
|
||||
let idx = *global_index as usize;
|
||||
let mut globals = $self.globals.borrow_mut();
|
||||
@@ -113,7 +113,7 @@ macro_rules! dispatch_eval {
|
||||
Ok(val)
|
||||
},
|
||||
|
||||
BoundKind::Get(addr) => $self.get_value(*addr),
|
||||
BoundKind::Get { addr, .. } => $self.get_value(*addr),
|
||||
|
||||
BoundKind::Set { addr, value } => {
|
||||
let val = $self.$eval_method($($observer,)? value)?;
|
||||
@@ -121,7 +121,7 @@ macro_rules! dispatch_eval {
|
||||
Ok(val)
|
||||
},
|
||||
|
||||
BoundKind::DefLocal { slot, value, captured_by } => {
|
||||
BoundKind::DefLocal { slot, value, captured_by, .. } => {
|
||||
let val = $self.$eval_method($($observer,)? value)?;
|
||||
let final_val = if !captured_by.is_empty() {
|
||||
Value::Cell(Rc::new(RefCell::new(val)))
|
||||
@@ -454,7 +454,7 @@ impl VM {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::ast::nodes::Node;
|
||||
use crate::ast::nodes::{Node, Symbol};
|
||||
use crate::ast::types::{SourceLocation, NodeIdentity, StaticType};
|
||||
|
||||
fn make_dummy_identity() -> Rc<NodeIdentity> {
|
||||
@@ -531,7 +531,7 @@ mod tests {
|
||||
callee: Box::new(Node {
|
||||
identity: id.clone(),
|
||||
ty: StaticType::Any,
|
||||
kind: BoundKind::Get(Address::Local(1)),
|
||||
kind: BoundKind::Get { addr: Address::Local(1), name: Symbol::from("f") },
|
||||
}),
|
||||
args: vec![],
|
||||
},
|
||||
@@ -540,7 +540,7 @@ mod tests {
|
||||
Node {
|
||||
identity: id.clone(),
|
||||
ty: StaticType::Int,
|
||||
kind: BoundKind::Get(Address::Local(0)),
|
||||
kind: BoundKind::Get { addr: Address::Local(0), name: Symbol::from("x") },
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user