use crate::ast::nodes::{Node, Symbol}; use crate::ast::types::{Identity, StaticType, Value}; use std::rc::Rc; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Address { Local(u32), // Stack-Slot index (relative to frame base) Upvalue(u32), // Index in the closure's upvalue array Global(u32), // Index in the global environment vector } /// Trait for DSL-specific AST extensions (like Pipe, Series-Access, etc.) pub trait BoundExtension: std::fmt::Debug { fn clone_box(&self) -> Box>; fn display_name(&self) -> String; } impl Clone for Box> { fn clone(&self) -> Self { self.clone_box() } } /// Type alias for a node that has been bound. Defaults to untyped (T = ()). pub type BoundNode = Node, T>; /// Type alias for a node that has been fully type-checked. pub type TypedNode = BoundNode; /// Metrics collected during the analysis phase. #[derive(Debug, Clone, PartialEq)] pub struct NodeMetrics { pub original: Rc, pub purity: crate::ast::types::Purity, pub is_recursive: bool, } /// Type alias for a node that has been analyzed. pub type AnalyzedNode = BoundNode; #[derive(Debug, Clone)] pub enum BoundKind { Nop, Constant(Value), /// A positional parameter in a Lambda's parameter list. Parameter { name: Symbol, slot: u32, }, // Variable Access (Resolved) Get { addr: Address, name: Symbol, }, // Variable Update (Assignment) Set { addr: Address, value: Box>, }, // Variable Declaration (Local) DefLocal { name: Symbol, slot: u32, value: Box>, captured_by: Vec, }, If { cond: Box>, then_br: Box>, else_br: Option>>, }, // Global Definition (Locals are implicit by stack position) DefGlobal { name: Symbol, global_index: u32, value: Box>, }, /// A destructuring definition (can be local or global depending on the pattern) DefDestructure { pattern: Box>, value: Box>, }, Lambda { params: Rc>, // The list of variables captured from enclosing scopes upvalues: Vec
, body: Rc>, /// Static optimization: number of positional parameters if the pattern is flat. positional_count: Option, }, Call { callee: Box>, args: Box>, }, Again { args: Box>, }, Block { exprs: Vec>, }, Tuple { elements: Vec>, }, Record { fields: Vec>, }, /// An expanded macro call, preserving the original call for debugging and UI. Expansion { /// The original call from the untyped AST. original_call: Rc>, /// The result of binding the expanded AST. bound_expanded: Box>, }, /// DSL-specific extension slot Extension(Box>), } impl PartialEq for BoundKind where T: PartialEq, { fn eq(&self, other: &Self) -> bool { 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 } ( BoundKind::Set { addr: aa, value: va, }, BoundKind::Set { addr: ab, value: vb, }, ) => aa == ab && va == vb, ( BoundKind::DefLocal { name: na, slot: sa, value: va, captured_by: ca, }, BoundKind::DefLocal { name: nb, slot: sb, value: vb, captured_by: cb, }, ) => na == nb && sa == sb && va == vb && ca == cb, ( BoundKind::If { cond: ca, then_br: ta, else_br: ea, }, BoundKind::If { cond: cb, then_br: tb, 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::DefDestructure { pattern: pa, value: va, }, BoundKind::DefDestructure { pattern: pb, value: vb, }, ) => pa == pb && va == vb, ( BoundKind::Lambda { params: pa, upvalues: ua, body: ba, positional_count: pca, }, BoundKind::Lambda { params: pb, upvalues: ub, body: bb, positional_count: pcb, }, ) => pa == pb && ua == ub && ba == bb && pca == pcb, ( BoundKind::Call { callee: ca, args: aa, }, BoundKind::Call { callee: cb, args: ab, }, ) => ca == cb && aa == ab, (BoundKind::Again { args: aa }, BoundKind::Again { args: ab }) => aa == ab, (BoundKind::Block { exprs: ea }, BoundKind::Block { exprs: eb }) => ea == eb, (BoundKind::Tuple { elements: ea }, BoundKind::Tuple { elements: eb }) => ea == eb, (BoundKind::Record { fields: fa }, BoundKind::Record { fields: fb }) => fa == fb, ( BoundKind::Expansion { original_call: oa, bound_expanded: ba, }, BoundKind::Expansion { original_call: ob, bound_expanded: bb, }, ) => Rc::ptr_eq(oa, ob) && ba == bb, (BoundKind::Extension(_), BoundKind::Extension(_)) => false, // Currently no equality for extensions _ => false, } } } /// A single field in a Record literal (Key-Value pair) pub type RecordField = (BoundNode, BoundNode); impl BoundKind { 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::DefDestructure { .. } => "DEF_DESTRUCTURE".to_string(), BoundKind::Lambda { params, upvalues, .. } => { let p_str = match ¶ms.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::Again { .. } => "AGAIN".to_string(), BoundKind::Block { .. } => "BLOCK".to_string(), BoundKind::Tuple { elements } => format!("TUPLE({})", elements.len()), BoundKind::Record { fields } => format!("RECORD({})", fields.len()), BoundKind::Expansion { .. } => "EXPANSION".to_string(), BoundKind::Extension(ext) => ext.display_name(), } } }