diff --git a/src/ast/compiler/analyzer.rs b/src/ast/compiler/analyzer.rs index d5f6ef3..d05f574 100644 --- a/src/ast/compiler/analyzer.rs +++ b/src/ast/compiler/analyzer.rs @@ -1,4 +1,4 @@ -use crate::ast::compiler::bound_nodes::{ +use crate::ast::nodes::{ Address, AnalyzedNode, GlobalIdx, IdentifierBinding, Node, NodeKind, NodeMetrics, TypedNode, TypedPhase, }; diff --git a/src/ast/compiler/binder.rs b/src/ast/compiler/binder.rs index 04c4853..5e54425 100644 --- a/src/ast/compiler/binder.rs +++ b/src/ast/compiler/binder.rs @@ -1,9 +1,9 @@ -use crate::ast::compiler::bound_nodes::{ +use crate::ast::nodes::{ Address, AssignBinding, BoundPhase, DeclarationKind, DefBinding, GlobalIdx, - IdentifierBinding, LambdaBinding, Node, NodeKind, UpvalueIdx, VirtualId, + IdentifierBinding, LambdaBinding, Node, NodeKind, SyntaxKind, SyntaxNode, Symbol, + UpvalueIdx, VirtualId, }; use crate::ast::diagnostics::Diagnostics; -use crate::ast::nodes::{SyntaxKind, SyntaxNode, Symbol}; use crate::ast::types::{Identity, Purity, StaticType}; use std::collections::HashMap; use std::rc::Rc; diff --git a/src/ast/compiler/bound_nodes.rs b/src/ast/compiler/bound_nodes.rs deleted file mode 100644 index 867206d..0000000 --- a/src/ast/compiler/bound_nodes.rs +++ /dev/null @@ -1,524 +0,0 @@ -use crate::ast::nodes::Symbol; -use crate::ast::types::{Identity, StaticType, Value}; -use std::rc::Rc; -use std::sync::Arc; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct VirtualId(pub u32); - -impl std::fmt::Display for VirtualId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "V{}", self.0) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct StackOffset(pub u32); - -impl std::fmt::Display for StackOffset { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "S{}", self.0) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct UpvalueIdx(pub u32); - -impl std::fmt::Display for UpvalueIdx { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "U{}", self.0) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct GlobalIdx(pub u32); - -impl std::fmt::Display for GlobalIdx { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "G{}", self.0) - } -} - -#[derive(Debug, PartialEq, Eq, Hash)] -pub enum Address { - Local(L), // Local address (VirtualId or StackOffset) - Upvalue(UpvalueIdx), // Index in the closure's upvalue array - Global(GlobalIdx), // Index in the global environment vector -} - -impl Clone for Address { - fn clone(&self) -> Self { - match self { - Address::Local(l) => Address::Local(l.clone()), - Address::Upvalue(u) => Address::Upvalue(*u), - Address::Global(g) => Address::Global(*g), - } - } -} - -impl Copy for Address {} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum DeclarationKind { - Variable, - Parameter, -} - -pub trait CompilerPhase: std::fmt::Debug + 'static { - type Metadata: std::fmt::Debug + Clone + PartialEq; - type LocalAddress: std::fmt::Debug + Clone + Copy + PartialEq + Eq + std::hash::Hash; - - /// Semantic role and address of an identifier (reference vs. declaration). - type Binding: std::fmt::Debug + Clone + PartialEq; - /// Binding metadata for `def` nodes (captured_by info). - type DefInfo: std::fmt::Debug + Clone + PartialEq; - /// Target address for `assign` nodes. - type AssignInfo: std::fmt::Debug + Clone + PartialEq; - /// Closure metadata for `lambda` nodes (upvalues, positional count). - type LambdaInfo: std::fmt::Debug + Clone + PartialEq; - /// Record field layout for O(1) access. - type RecordLayout: std::fmt::Debug + Clone + PartialEq; -} - -// ── Phase-specific binding info types ────────────────────────────────────────── - -/// Semantic role of an identifier after binding. -#[derive(Debug, Clone, PartialEq)] -pub enum IdentifierBinding { - /// A variable reference (read access). - Reference(Address), - /// A variable or parameter declaration (write/bind target). - Declaration { - addr: Address, - kind: DeclarationKind, - }, -} - -/// Binding metadata attached to `def` nodes. -#[derive(Debug, Clone, PartialEq)] -pub struct DefBinding { - /// Identities of lambdas that capture this definition's variable. - pub captured_by: Vec, -} - -/// Target address attached to `assign` nodes. -/// `Some(addr)` for simple assignment, `None` for destructuring assignment -/// (where addresses live on the individual `Identifier` nodes in the target pattern). -#[derive(Debug, Clone, PartialEq)] -pub struct AssignBinding { - pub addr: Option>, -} - -/// Closure metadata attached to `lambda` nodes. -#[derive(Debug, Clone, PartialEq)] -pub struct LambdaBinding { - /// Addresses of captured variables from enclosing scopes. - pub upvalues: Vec>, - /// Number of positional parameters (None = variadic). - pub positional_count: Option, -} - -// ── SyntaxPhase ──────────────────────────────────────────────────────────────── - -/// The initial phase produced by the parser. All annotation slots are `()`. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct SyntaxPhase; -impl CompilerPhase for SyntaxPhase { - type Metadata = (); - type LocalAddress = (); - type Binding = (); - type DefInfo = (); - type AssignInfo = (); - type LambdaInfo = (); - type RecordLayout = (); -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct BoundPhase; -impl CompilerPhase for BoundPhase { - type Metadata = (); - type LocalAddress = VirtualId; - type Binding = IdentifierBinding; - type DefInfo = DefBinding; - type AssignInfo = AssignBinding; - type LambdaInfo = LambdaBinding; - type RecordLayout = Arc; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct TypedPhase; -impl CompilerPhase for TypedPhase { - type Metadata = StaticType; - type LocalAddress = VirtualId; - type Binding = IdentifierBinding; - type DefInfo = DefBinding; - type AssignInfo = AssignBinding; - type LambdaInfo = LambdaBinding; - type RecordLayout = Arc; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct AnalyzedPhase; -impl CompilerPhase for AnalyzedPhase { - type Metadata = NodeMetrics; - type LocalAddress = VirtualId; - type Binding = IdentifierBinding; - type DefInfo = DefBinding; - type AssignInfo = AssignBinding; - type LambdaInfo = LambdaBinding; - type RecordLayout = Arc; -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RuntimePhase; -impl CompilerPhase for RuntimePhase { - type Metadata = RuntimeMetadata; - type LocalAddress = StackOffset; - type Binding = IdentifierBinding; - type DefInfo = DefBinding; - type AssignInfo = AssignBinding; - type LambdaInfo = LambdaBinding; - type RecordLayout = Arc; -} - -/// Convenience alias for all post-binding phases that share the same -/// concrete binding, def, assign, lambda, and record-layout types. -/// Covers `BoundPhase`, `TypedPhase`, `AnalyzedPhase` (but not `SyntaxPhase` or `RuntimePhase`). -pub trait BoundLike: - CompilerPhase< - LocalAddress = VirtualId, - Binding = IdentifierBinding, - DefInfo = DefBinding, - AssignInfo = AssignBinding, - LambdaInfo = LambdaBinding, - RecordLayout = Arc, - > -{ -} - -impl

BoundLike for P where - P: CompilerPhase< - LocalAddress = VirtualId, - Binding = IdentifierBinding, - DefInfo = DefBinding, - AssignInfo = AssignBinding, - LambdaInfo = LambdaBinding, - RecordLayout = Arc, - > -{ -} - -/// A unified AST node, decorated with phase-specific information P. -/// Replaces both `SyntaxNode` (parser output) and the old bound AST node. -#[derive(Debug, PartialEq)] -pub struct Node { - pub identity: Identity, - pub kind: NodeKind

, - pub ty: P::Metadata, -} - -impl Clone for Node

{ - fn clone(&self) -> Self { - Self { - identity: self.identity.clone(), - kind: self.kind.clone(), - ty: self.ty.clone(), - } - } -} - -pub type TypedNode = Node; - -#[derive(Debug, Clone, PartialEq)] -pub struct NodeMetrics { - pub original: Rc, - pub purity: crate::ast::types::Purity, - pub is_recursive: bool, -} - -pub type AnalyzedNode = Node; - -#[derive(Clone)] -pub struct RuntimeMetadata { - pub ty: StaticType, - pub is_tail: bool, - pub original: Rc, - pub stack_size: u32, -} - -impl std::fmt::Debug for RuntimeMetadata { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Metadata") - .field("ty", &self.ty) - .field("is_tail", &self.is_tail) - .field("stack_size", &self.stack_size) - .finish() - } -} - -impl PartialEq for RuntimeMetadata { - fn eq(&self, other: &Self) -> bool { - self.ty == other.ty && self.is_tail == other.is_tail && Rc::ptr_eq(&self.original, &other.original) && self.stack_size == other.stack_size - } -} - -pub type ExecNode = Node; - -pub type GlobalFunctionRegistry = std::collections::HashMap>>; -pub type GlobalAnalyzedRegistry = std::collections::HashMap>; - -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() - } -} - -// ── NodeKind

: Unified AST node kind ───────────────────────────────────────── - -/// A key-value pair in a record literal: `(key_node, value_node)`. -pub type RecordFieldPair

= (Rc>, Rc>); - -/// Unified AST node kind, replacing both `SyntaxKind` and `BoundKind

`. -/// -/// The structure is always consistent with the syntax the user wrote. -/// Phase-specific information is carried in `P::*` annotation slots, -/// which are `()` in `SyntaxPhase` and concrete types in later phases. -#[derive(Debug)] -pub enum NodeKind { - Nop, - Constant(Value), - Identifier { - symbol: Symbol, - binding: P::Binding, - }, - FieldAccessor(crate::ast::types::Keyword), - If { - cond: Rc>, - then_br: Rc>, - else_br: Option>>, - }, - Def { - pattern: Rc>, - value: Rc>, - info: P::DefInfo, - }, - Assign { - target: Rc>, - value: Rc>, - info: P::AssignInfo, - }, - Lambda { - params: Rc>, - body: Rc>, - info: P::LambdaInfo, - }, - Call { - callee: Rc>, - args: Rc>, - }, - Again { - args: Rc>, - }, - Pipe { - inputs: Vec>>, - lambda: Rc>, - }, - Block { - exprs: Vec>>, - }, - Tuple { - elements: Vec>>, - }, - Record { - fields: Vec>, - layout: P::RecordLayout, - }, - /// Macro declaration (only valid in `SyntaxPhase`). - MacroDecl { - name: Symbol, - params: Rc>, - body: Rc>, - }, - /// Quasiquote template (only valid in `SyntaxPhase`). - Template(Rc>), - /// Unquote placeholder inside a template (only valid in `SyntaxPhase`). - Placeholder(Rc>), - /// Splice placeholder inside a template (only valid in `SyntaxPhase`). - Splice(Rc>), - /// Optimized field access (only created during lowering for `RuntimePhase`). - GetField { - rec: Rc>, - field: crate::ast::types::Keyword, - }, - /// Expanded macro call, preserving the original call for debugging. - Expansion { - original_call: Rc>, - expanded: Rc>, - }, - Error, - Extension(Box>), -} - -impl Clone for NodeKind

{ - fn clone(&self) -> Self { - match self { - NodeKind::Nop => NodeKind::Nop, - NodeKind::Constant(v) => NodeKind::Constant(v.clone()), - NodeKind::Identifier { symbol, binding } => NodeKind::Identifier { - symbol: symbol.clone(), - binding: binding.clone(), - }, - NodeKind::FieldAccessor(k) => NodeKind::FieldAccessor(*k), - NodeKind::If { cond, then_br, else_br } => NodeKind::If { - cond: cond.clone(), - then_br: then_br.clone(), - else_br: else_br.clone(), - }, - NodeKind::Def { pattern, value, info } => NodeKind::Def { - pattern: pattern.clone(), - value: value.clone(), - info: info.clone(), - }, - NodeKind::Assign { target, value, info } => NodeKind::Assign { - target: target.clone(), - value: value.clone(), - info: info.clone(), - }, - NodeKind::Lambda { params, body, info } => NodeKind::Lambda { - params: params.clone(), - body: body.clone(), - info: info.clone(), - }, - NodeKind::Call { callee, args } => NodeKind::Call { - callee: callee.clone(), - args: args.clone(), - }, - NodeKind::Again { args } => NodeKind::Again { args: args.clone() }, - NodeKind::Pipe { inputs, lambda } => NodeKind::Pipe { - inputs: inputs.clone(), - lambda: lambda.clone(), - }, - NodeKind::Block { exprs } => NodeKind::Block { exprs: exprs.clone() }, - NodeKind::Tuple { elements } => NodeKind::Tuple { elements: elements.clone() }, - NodeKind::Record { fields, layout } => NodeKind::Record { - fields: fields.clone(), - layout: layout.clone(), - }, - NodeKind::GetField { rec, field } => NodeKind::GetField { - rec: rec.clone(), - field: *field, - }, - NodeKind::MacroDecl { name, params, body } => NodeKind::MacroDecl { - name: name.clone(), - params: params.clone(), - body: body.clone(), - }, - NodeKind::Template(inner) => NodeKind::Template(inner.clone()), - NodeKind::Placeholder(inner) => NodeKind::Placeholder(inner.clone()), - NodeKind::Splice(inner) => NodeKind::Splice(inner.clone()), - NodeKind::Expansion { original_call, expanded } => NodeKind::Expansion { - original_call: original_call.clone(), - expanded: expanded.clone(), - }, - NodeKind::Error => NodeKind::Error, - NodeKind::Extension(ext) => NodeKind::Extension(ext.clone()), - } - } -} - -impl PartialEq for NodeKind

{ - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (NodeKind::Nop, NodeKind::Nop) => true, - (NodeKind::Constant(a), NodeKind::Constant(b)) => a == b, - (NodeKind::Identifier { symbol: sa, binding: ba }, NodeKind::Identifier { symbol: sb, binding: bb }) => { - sa == sb && ba == bb - } - (NodeKind::FieldAccessor(a), NodeKind::FieldAccessor(b)) => a == b, - (NodeKind::If { cond: ca, then_br: ta, else_br: ea }, NodeKind::If { cond: cb, then_br: tb, else_br: eb }) => { - Rc::ptr_eq(ca, cb) && Rc::ptr_eq(ta, tb) && match (ea, eb) { - (Some(a), Some(b)) => Rc::ptr_eq(a, b), - (None, None) => true, - _ => false, - } - } - (NodeKind::Def { pattern: pa, value: va, info: ia }, NodeKind::Def { pattern: pb, value: vb, info: ib }) => { - Rc::ptr_eq(pa, pb) && Rc::ptr_eq(va, vb) && ia == ib - } - (NodeKind::Assign { target: ta, value: va, info: ia }, NodeKind::Assign { target: tb, value: vb, info: ib }) => { - Rc::ptr_eq(ta, tb) && Rc::ptr_eq(va, vb) && ia == ib - } - (NodeKind::Lambda { params: pa, body: ba, info: ia }, NodeKind::Lambda { params: pb, body: bb, info: ib }) => { - Rc::ptr_eq(pa, pb) && Rc::ptr_eq(ba, bb) && ia == ib - } - (NodeKind::Call { callee: ca, args: aa }, NodeKind::Call { callee: cb, args: ab }) => { - Rc::ptr_eq(ca, cb) && Rc::ptr_eq(aa, ab) - } - (NodeKind::Again { args: aa }, NodeKind::Again { args: ab }) => Rc::ptr_eq(aa, ab), - (NodeKind::Pipe { inputs: ia, lambda: la }, NodeKind::Pipe { inputs: ib, lambda: lb }) => { - ia.len() == ib.len() - && ia.iter().zip(ib.iter()).all(|(a, b)| Rc::ptr_eq(a, b)) - && Rc::ptr_eq(la, lb) - } - (NodeKind::Block { exprs: ea }, NodeKind::Block { exprs: eb }) => { - ea.len() == eb.len() && ea.iter().zip(eb.iter()).all(|(a, b)| Rc::ptr_eq(a, b)) - } - (NodeKind::Tuple { elements: ea }, NodeKind::Tuple { elements: eb }) => { - ea.len() == eb.len() && ea.iter().zip(eb.iter()).all(|(a, b)| Rc::ptr_eq(a, b)) - } - (NodeKind::Record { fields: fa, layout: la }, NodeKind::Record { fields: fb, layout: lb }) => { - la == lb - && fa.len() == fb.len() - && fa.iter().zip(fb.iter()).all(|((ka, va), (kb, vb))| Rc::ptr_eq(ka, kb) && Rc::ptr_eq(va, vb)) - } - (NodeKind::GetField { rec: ra, field: fa }, NodeKind::GetField { rec: rb, field: fb }) => { - Rc::ptr_eq(ra, rb) && fa == fb - } - (NodeKind::MacroDecl { name: na, params: pa, body: ba }, NodeKind::MacroDecl { name: nb, params: pb, body: bb }) => { - na == nb && Rc::ptr_eq(pa, pb) && Rc::ptr_eq(ba, bb) - } - (NodeKind::Template(a), NodeKind::Template(b)) => Rc::ptr_eq(a, b), - (NodeKind::Placeholder(a), NodeKind::Placeholder(b)) => Rc::ptr_eq(a, b), - (NodeKind::Splice(a), NodeKind::Splice(b)) => Rc::ptr_eq(a, b), - (NodeKind::Expansion { original_call: ca, expanded: ea }, NodeKind::Expansion { original_call: cb, expanded: eb }) => { - Rc::ptr_eq(ca, cb) && Rc::ptr_eq(ea, eb) - } - (NodeKind::Error, NodeKind::Error) => true, - _ => false, - } - } -} - -impl NodeKind

{ - pub fn display_name(&self) -> String { - match self { - NodeKind::Nop => "NOP".to_string(), - NodeKind::Constant(v) => format!("CONST({})", v), - NodeKind::Identifier { symbol, .. } => format!("ID({})", symbol.name), - NodeKind::FieldAccessor(k) => format!("FIELD_ACCESSOR(.{})", k.name()), - NodeKind::If { .. } => "IF".to_string(), - NodeKind::Def { .. } => "DEF".to_string(), - NodeKind::Assign { .. } => "ASSIGN".to_string(), - NodeKind::Lambda { .. } => "LAMBDA".to_string(), - NodeKind::Call { .. } => "CALL".to_string(), - NodeKind::Again { .. } => "AGAIN".to_string(), - NodeKind::Pipe { .. } => "PIPE".to_string(), - NodeKind::Block { .. } => "BLOCK".to_string(), - NodeKind::Tuple { elements } => format!("TUPLE({})", elements.len()), - NodeKind::Record { fields, .. } => format!("RECORD({})", fields.len()), - NodeKind::GetField { field, .. } => format!("GET_FIELD(.{})", field.name()), - NodeKind::MacroDecl { name, .. } => format!("MACRO({})", name.name), - NodeKind::Template(_) => "TEMPLATE".to_string(), - NodeKind::Placeholder(_) => "PLACEHOLDER".to_string(), - NodeKind::Splice(_) => "SPLICE".to_string(), - NodeKind::Expansion { .. } => "EXPANSION".to_string(), - NodeKind::Extension(ext) => ext.display_name(), - NodeKind::Error => "ERROR".to_string(), - } - } -} diff --git a/src/ast/compiler/captures.rs b/src/ast/compiler/captures.rs index 3d6dada..72d0c69 100644 --- a/src/ast/compiler/captures.rs +++ b/src/ast/compiler/captures.rs @@ -1,4 +1,4 @@ -use crate::ast::compiler::bound_nodes::{CompilerPhase, DefBinding, Node, NodeKind}; +use crate::ast::nodes::{CompilerPhase, DefBinding, Node, NodeKind}; use crate::ast::types::Identity; use std::collections::HashMap; use std::rc::Rc; diff --git a/src/ast/compiler/dumper.rs b/src/ast/compiler/dumper.rs index e6b6ccc..0c4735d 100644 --- a/src/ast/compiler/dumper.rs +++ b/src/ast/compiler/dumper.rs @@ -1,4 +1,4 @@ -use crate::ast::compiler::bound_nodes::{CompilerPhase, Node, NodeKind}; +use crate::ast::nodes::{CompilerPhase, Node, NodeKind}; /// Human-readable AST dumper for the bound AST. pub struct Dumper { diff --git a/src/ast/compiler/lambda_collector.rs b/src/ast/compiler/lambda_collector.rs index 8af592e..c76f064 100644 --- a/src/ast/compiler/lambda_collector.rs +++ b/src/ast/compiler/lambda_collector.rs @@ -1,4 +1,4 @@ -use crate::ast::compiler::bound_nodes::{ +use crate::ast::nodes::{ Address, BoundLike, GlobalIdx, IdentifierBinding, Node, NodeKind, }; use std::collections::HashMap; diff --git a/src/ast/compiler/lowering.rs b/src/ast/compiler/lowering.rs index 552a4e9..0006ef1 100644 --- a/src/ast/compiler/lowering.rs +++ b/src/ast/compiler/lowering.rs @@ -1,4 +1,4 @@ -use crate::ast::compiler::bound_nodes::{ +use crate::ast::nodes::{ Address, AnalyzedNode, AssignBinding, ExecNode, IdentifierBinding, LambdaBinding, Node, NodeKind, RuntimeMetadata, StackOffset, VirtualId, diff --git a/src/ast/compiler/macros.rs b/src/ast/compiler/macros.rs index 454e646..7ddfeb8 100644 --- a/src/ast/compiler/macros.rs +++ b/src/ast/compiler/macros.rs @@ -642,7 +642,7 @@ impl MacroExpander { #[cfg(test)] mod tests { use super::*; - use crate::ast::compiler::bound_nodes::Address; + use crate::ast::nodes::Address; use crate::ast::compiler::Binder; use crate::ast::parser::Parser; use crate::ast::types::{Object, Value}; @@ -788,7 +788,7 @@ mod tests { locals.insert( Symbol::from("*"), crate::ast::compiler::binder::LocalInfo { - addr: Address::Local(crate::ast::compiler::bound_nodes::VirtualId(0)), + addr: Address::Local(crate::ast::nodes::VirtualId(0)), identity: crate::ast::types::NodeIdentity::new(crate::ast::types::SourceLocation { line: 0, col: 0, diff --git a/src/ast/compiler/mod.rs b/src/ast/compiler/mod.rs index a1f4931..0ab40f9 100644 --- a/src/ast/compiler/mod.rs +++ b/src/ast/compiler/mod.rs @@ -1,21 +1,20 @@ -pub mod analyzer; -pub mod binder; -pub mod bound_nodes; -pub mod captures; -pub mod dumper; -pub mod lambda_collector; -pub mod macros; -pub mod optimizer; -pub mod specializer; -pub mod lowering; -pub mod type_checker; - -pub use binder::*; -pub use bound_nodes::*; -pub use captures::*; -pub use dumper::*; -pub use macros::*; -pub use optimizer::*; -pub use specializer::*; -pub use lowering::*; -pub use type_checker::*; +pub mod analyzer; +pub mod binder; +pub mod captures; +pub mod dumper; +pub mod lambda_collector; +pub mod macros; +pub mod optimizer; +pub mod specializer; +pub mod lowering; +pub mod type_checker; + +pub use crate::ast::nodes::*; +pub use binder::*; +pub use captures::*; +pub use dumper::*; +pub use macros::*; +pub use optimizer::*; +pub use specializer::*; +pub use lowering::*; +pub use type_checker::*; diff --git a/src/ast/compiler/optimizer/engine.rs b/src/ast/compiler/optimizer/engine.rs index 0574930..ede9262 100644 --- a/src/ast/compiler/optimizer/engine.rs +++ b/src/ast/compiler/optimizer/engine.rs @@ -1,4 +1,4 @@ -use crate::ast::compiler::bound_nodes::{ +use crate::ast::nodes::{ Address, AnalyzedNode, AssignBinding, GlobalAnalyzedRegistry, IdentifierBinding, LambdaBinding, Node, NodeKind, UpvalueIdx, }; @@ -756,7 +756,7 @@ impl Optimizer { } /// Extracts the address from a Def pattern node (when it's a simple Identifier with Declaration binding). - fn extract_def_addr(pattern: &AnalyzedNode) -> Option> { + fn extract_def_addr(pattern: &AnalyzedNode) -> Option> { if let NodeKind::Identifier { binding: IdentifierBinding::Declaration { addr, .. }, .. diff --git a/src/ast/compiler/optimizer/folder.rs b/src/ast/compiler/optimizer/folder.rs index d938051..7356c2e 100644 --- a/src/ast/compiler/optimizer/folder.rs +++ b/src/ast/compiler/optimizer/folder.rs @@ -1,4 +1,4 @@ -use crate::ast::compiler::bound_nodes::{ +use crate::ast::nodes::{ Address, AnalyzedNode, IdentifierBinding, Node, NodeKind, NodeMetrics, }; use crate::ast::types::{Purity, RecordLayout, StaticType, Value}; diff --git a/src/ast/compiler/optimizer/inliner.rs b/src/ast/compiler/optimizer/inliner.rs index c0afbba..7531512 100644 --- a/src/ast/compiler/optimizer/inliner.rs +++ b/src/ast/compiler/optimizer/inliner.rs @@ -1,4 +1,4 @@ -use crate::ast::compiler::bound_nodes::{ +use crate::ast::nodes::{ Address, AnalyzedNode, IdentifierBinding, NodeKind, VirtualId, }; use crate::ast::types::{Purity, Value}; diff --git a/src/ast/compiler/optimizer/substitution_map.rs b/src/ast/compiler/optimizer/substitution_map.rs index 021a0f1..53d3ec7 100644 --- a/src/ast/compiler/optimizer/substitution_map.rs +++ b/src/ast/compiler/optimizer/substitution_map.rs @@ -1,4 +1,4 @@ -use crate::ast::compiler::bound_nodes::{ +use crate::ast::nodes::{ Address, AnalyzedNode, AssignBinding, IdentifierBinding, LambdaBinding, Node, NodeKind, UpvalueIdx, VirtualId, }; diff --git a/src/ast/compiler/optimizer/utils.rs b/src/ast/compiler/optimizer/utils.rs index 0d45efd..33c4396 100644 --- a/src/ast/compiler/optimizer/utils.rs +++ b/src/ast/compiler/optimizer/utils.rs @@ -1,4 +1,4 @@ -use crate::ast::compiler::bound_nodes::{ +use crate::ast::nodes::{ Address, AnalyzedNode, GlobalIdx, IdentifierBinding, NodeKind, VirtualId, }; diff --git a/src/ast/compiler/specializer.rs b/src/ast/compiler/specializer.rs index 07be732..7893ee1 100644 --- a/src/ast/compiler/specializer.rs +++ b/src/ast/compiler/specializer.rs @@ -1,4 +1,4 @@ -use crate::ast::compiler::bound_nodes::{ +use crate::ast::nodes::{ Address, AnalyzedNode, AnalyzedPhase, IdentifierBinding, Node, NodeKind, NodeMetrics, VirtualId, }; use crate::ast::types::{Purity, Signature, StaticType, Value}; diff --git a/src/ast/compiler/type_checker.rs b/src/ast/compiler/type_checker.rs index 0b13a7a..17a992d 100644 --- a/src/ast/compiler/type_checker.rs +++ b/src/ast/compiler/type_checker.rs @@ -1,4 +1,4 @@ -use crate::ast::compiler::bound_nodes::{ +use crate::ast::nodes::{ Address, AssignBinding, BoundLike, DefBinding, IdentifierBinding, LambdaBinding, Node, NodeKind, TypedNode, TypedPhase, VirtualId, }; @@ -84,7 +84,7 @@ impl TypeChecker { pub fn check( &self, - node: &Node, + node: &Node, arg_types: &[StaticType], diag: &mut Diagnostics, ) -> TypedNode { diff --git a/src/ast/environment.rs b/src/ast/environment.rs index 5139f4a..1f22380 100644 --- a/src/ast/environment.rs +++ b/src/ast/environment.rs @@ -9,7 +9,7 @@ use std::collections::{HashMap, HashSet}; use std::path::{Path, PathBuf}; use std::rc::Rc; -use crate::ast::compiler::bound_nodes::{ +use crate::ast::nodes::{ Address, AnalyzedNode, ExecNode, GlobalAnalyzedRegistry, GlobalFunctionRegistry, GlobalIdx, LambdaBinding, Node, NodeKind, VirtualId, }; @@ -93,7 +93,7 @@ struct EnvFunctionRegistry { } impl FunctionRegistry for EnvFunctionRegistry { - fn resolve(&self, addr: Address) -> Option>> { + fn resolve(&self, addr: Address) -> Option>> { if let Address::Global(idx) = addr { self.analyzed_registry.borrow().get(&idx).cloned() } else { @@ -722,7 +722,7 @@ impl Environment { let optimization = self.optimization; let compiler = Rc::new( - move |func_template: Rc>, + move |func_template: Rc>, arg_types: &[StaticType]| -> Result<(Value, StaticType), String> { let mut diag = Diagnostics::new(); diff --git a/src/ast/nodes.rs b/src/ast/nodes.rs index f6eac8d..a7ce0f5 100644 --- a/src/ast/nodes.rs +++ b/src/ast/nodes.rs @@ -1,8 +1,10 @@ -use crate::ast::compiler::bound_nodes::{Node, NodeKind, SyntaxPhase}; -use crate::ast::types::{Identity, Object}; +use crate::ast::types::{Identity, Object, StaticType, Value}; use std::any::Any; use std::fmt::Debug; use std::rc::Rc; +use std::sync::Arc; + +// ── Symbol ───────────────────────────────────────────────────────────────────── /// A name with an optional context for macro hygiene. #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -31,6 +33,236 @@ impl From<&str> for Symbol { } } +// ── Address types ────────────────────────────────────────────────────────────── + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct VirtualId(pub u32); + +impl std::fmt::Display for VirtualId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "V{}", self.0) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct StackOffset(pub u32); + +impl std::fmt::Display for StackOffset { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "S{}", self.0) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct UpvalueIdx(pub u32); + +impl std::fmt::Display for UpvalueIdx { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "U{}", self.0) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct GlobalIdx(pub u32); + +impl std::fmt::Display for GlobalIdx { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "G{}", self.0) + } +} + +#[derive(Debug, PartialEq, Eq, Hash)] +pub enum Address { + Local(L), // Local address (VirtualId or StackOffset) + Upvalue(UpvalueIdx), // Index in the closure's upvalue array + Global(GlobalIdx), // Index in the global environment vector +} + +impl Clone for Address { + fn clone(&self) -> Self { + match self { + Address::Local(l) => Address::Local(l.clone()), + Address::Upvalue(u) => Address::Upvalue(*u), + Address::Global(g) => Address::Global(*g), + } + } +} + +impl Copy for Address {} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum DeclarationKind { + Variable, + Parameter, +} + +// ── CompilerPhase trait ──────────────────────────────────────────────────────── + +pub trait CompilerPhase: std::fmt::Debug + 'static { + type Metadata: std::fmt::Debug + Clone + PartialEq; + type LocalAddress: std::fmt::Debug + Clone + Copy + PartialEq + Eq + std::hash::Hash; + + /// Semantic role and address of an identifier (reference vs. declaration). + type Binding: std::fmt::Debug + Clone + PartialEq; + /// Binding metadata for `def` nodes (captured_by info). + type DefInfo: std::fmt::Debug + Clone + PartialEq; + /// Target address for `assign` nodes. + type AssignInfo: std::fmt::Debug + Clone + PartialEq; + /// Closure metadata for `lambda` nodes (upvalues, positional count). + type LambdaInfo: std::fmt::Debug + Clone + PartialEq; + /// Record field layout for O(1) access. + type RecordLayout: std::fmt::Debug + Clone + PartialEq; +} + +// ── Phase-specific binding info types ────────────────────────────────────────── + +/// Semantic role of an identifier after binding. +#[derive(Debug, Clone, PartialEq)] +pub enum IdentifierBinding { + /// A variable reference (read access). + Reference(Address), + /// A variable or parameter declaration (write/bind target). + Declaration { + addr: Address, + kind: DeclarationKind, + }, +} + +/// Binding metadata attached to `def` nodes. +#[derive(Debug, Clone, PartialEq)] +pub struct DefBinding { + /// Identities of lambdas that capture this definition's variable. + pub captured_by: Vec, +} + +/// Target address attached to `assign` nodes. +/// `Some(addr)` for simple assignment, `None` for destructuring assignment +/// (where addresses live on the individual `Identifier` nodes in the target pattern). +#[derive(Debug, Clone, PartialEq)] +pub struct AssignBinding { + pub addr: Option>, +} + +/// Closure metadata attached to `lambda` nodes. +#[derive(Debug, Clone, PartialEq)] +pub struct LambdaBinding { + /// Addresses of captured variables from enclosing scopes. + pub upvalues: Vec>, + /// Number of positional parameters (None = variadic). + pub positional_count: Option, +} + +// ── Compiler phases ──────────────────────────────────────────────────────────── + +/// The initial phase produced by the parser. All annotation slots are `()`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SyntaxPhase; +impl CompilerPhase for SyntaxPhase { + type Metadata = (); + type LocalAddress = (); + type Binding = (); + type DefInfo = (); + type AssignInfo = (); + type LambdaInfo = (); + type RecordLayout = (); +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct BoundPhase; +impl CompilerPhase for BoundPhase { + type Metadata = (); + type LocalAddress = VirtualId; + type Binding = IdentifierBinding; + type DefInfo = DefBinding; + type AssignInfo = AssignBinding; + type LambdaInfo = LambdaBinding; + type RecordLayout = Arc; +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TypedPhase; +impl CompilerPhase for TypedPhase { + type Metadata = StaticType; + type LocalAddress = VirtualId; + type Binding = IdentifierBinding; + type DefInfo = DefBinding; + type AssignInfo = AssignBinding; + type LambdaInfo = LambdaBinding; + type RecordLayout = Arc; +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct AnalyzedPhase; +impl CompilerPhase for AnalyzedPhase { + type Metadata = NodeMetrics; + type LocalAddress = VirtualId; + type Binding = IdentifierBinding; + type DefInfo = DefBinding; + type AssignInfo = AssignBinding; + type LambdaInfo = LambdaBinding; + type RecordLayout = Arc; +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct RuntimePhase; +impl CompilerPhase for RuntimePhase { + type Metadata = RuntimeMetadata; + type LocalAddress = StackOffset; + type Binding = IdentifierBinding; + type DefInfo = DefBinding; + type AssignInfo = AssignBinding; + type LambdaInfo = LambdaBinding; + type RecordLayout = Arc; +} + +/// Convenience alias for all post-binding phases that share the same +/// concrete binding, def, assign, lambda, and record-layout types. +/// Covers `BoundPhase`, `TypedPhase`, `AnalyzedPhase` (but not `SyntaxPhase` or `RuntimePhase`). +pub trait BoundLike: + CompilerPhase< + LocalAddress = VirtualId, + Binding = IdentifierBinding, + DefInfo = DefBinding, + AssignInfo = AssignBinding, + LambdaInfo = LambdaBinding, + RecordLayout = Arc, + > +{ +} + +impl

BoundLike for P where + P: CompilerPhase< + LocalAddress = VirtualId, + Binding = IdentifierBinding, + DefInfo = DefBinding, + AssignInfo = AssignBinding, + LambdaInfo = LambdaBinding, + RecordLayout = Arc, + > +{ +} + +// ── Node

──────────────────────────────────────────────────────────────────── + +/// A unified AST node, decorated with phase-specific information P. +/// Replaces both `SyntaxNode` (parser output) and the old bound AST node. +#[derive(Debug, PartialEq)] +pub struct Node { + pub identity: Identity, + pub kind: NodeKind

, + pub ty: P::Metadata, +} + +impl Clone for Node

{ + fn clone(&self) -> Self { + Self { + identity: self.identity.clone(), + kind: self.kind.clone(), + ty: self.ty.clone(), + } + } +} + /// Type alias: the parser AST is now `Node`. pub type SyntaxNode = Node; @@ -46,7 +278,63 @@ impl Object for Node { } } -/// The base for custom node types (extensions) +pub type TypedNode = Node; + +#[derive(Debug, Clone, PartialEq)] +pub struct NodeMetrics { + pub original: Rc, + pub purity: crate::ast::types::Purity, + pub is_recursive: bool, +} + +pub type AnalyzedNode = Node; + +#[derive(Clone)] +pub struct RuntimeMetadata { + pub ty: StaticType, + pub is_tail: bool, + pub original: Rc, + pub stack_size: u32, +} + +impl std::fmt::Debug for RuntimeMetadata { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Metadata") + .field("ty", &self.ty) + .field("is_tail", &self.is_tail) + .field("stack_size", &self.stack_size) + .finish() + } +} + +impl PartialEq for RuntimeMetadata { + fn eq(&self, other: &Self) -> bool { + self.ty == other.ty + && self.is_tail == other.is_tail + && Rc::ptr_eq(&self.original, &other.original) + && self.stack_size == other.stack_size + } +} + +pub type ExecNode = Node; + +pub type GlobalFunctionRegistry = std::collections::HashMap>>; +pub type GlobalAnalyzedRegistry = std::collections::HashMap>; + +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() + } +} + +// ── CustomNode ───────────────────────────────────────────────────────────────── + +/// The base for custom node types (extensions). pub trait CustomNode: Debug { fn display_name(&self) -> &'static str; fn clone_box(&self) -> Box; @@ -63,3 +351,248 @@ impl PartialEq for Box { false } } + +// ── NodeKind

──────────────────────────────────────────────────────────────── + +/// A key-value pair in a record literal: `(key_node, value_node)`. +pub type RecordFieldPair

= (Rc>, Rc>); + +/// Unified AST node kind, replacing both `SyntaxKind` and `BoundKind

`. +/// +/// The structure is always consistent with the syntax the user wrote. +/// Phase-specific information is carried in `P::*` annotation slots, +/// which are `()` in `SyntaxPhase` and concrete types in later phases. +#[derive(Debug)] +pub enum NodeKind { + Nop, + Constant(Value), + Identifier { + symbol: Symbol, + binding: P::Binding, + }, + FieldAccessor(crate::ast::types::Keyword), + If { + cond: Rc>, + then_br: Rc>, + else_br: Option>>, + }, + Def { + pattern: Rc>, + value: Rc>, + info: P::DefInfo, + }, + Assign { + target: Rc>, + value: Rc>, + info: P::AssignInfo, + }, + Lambda { + params: Rc>, + body: Rc>, + info: P::LambdaInfo, + }, + Call { + callee: Rc>, + args: Rc>, + }, + Again { + args: Rc>, + }, + Pipe { + inputs: Vec>>, + lambda: Rc>, + }, + Block { + exprs: Vec>>, + }, + Tuple { + elements: Vec>>, + }, + Record { + fields: Vec>, + layout: P::RecordLayout, + }, + /// Macro declaration (only valid in `SyntaxPhase`). + MacroDecl { + name: Symbol, + params: Rc>, + body: Rc>, + }, + /// Quasiquote template (only valid in `SyntaxPhase`). + Template(Rc>), + /// Unquote placeholder inside a template (only valid in `SyntaxPhase`). + Placeholder(Rc>), + /// Splice placeholder inside a template (only valid in `SyntaxPhase`). + Splice(Rc>), + /// Optimized field access (only created during lowering for `RuntimePhase`). + GetField { + rec: Rc>, + field: crate::ast::types::Keyword, + }, + /// Expanded macro call, preserving the original call for debugging. + Expansion { + original_call: Rc>, + expanded: Rc>, + }, + Error, + Extension(Box>), +} + +impl Clone for NodeKind

{ + fn clone(&self) -> Self { + match self { + NodeKind::Nop => NodeKind::Nop, + NodeKind::Constant(v) => NodeKind::Constant(v.clone()), + NodeKind::Identifier { symbol, binding } => NodeKind::Identifier { + symbol: symbol.clone(), + binding: binding.clone(), + }, + NodeKind::FieldAccessor(k) => NodeKind::FieldAccessor(*k), + NodeKind::If { cond, then_br, else_br } => NodeKind::If { + cond: cond.clone(), + then_br: then_br.clone(), + else_br: else_br.clone(), + }, + NodeKind::Def { pattern, value, info } => NodeKind::Def { + pattern: pattern.clone(), + value: value.clone(), + info: info.clone(), + }, + NodeKind::Assign { target, value, info } => NodeKind::Assign { + target: target.clone(), + value: value.clone(), + info: info.clone(), + }, + NodeKind::Lambda { params, body, info } => NodeKind::Lambda { + params: params.clone(), + body: body.clone(), + info: info.clone(), + }, + NodeKind::Call { callee, args } => NodeKind::Call { + callee: callee.clone(), + args: args.clone(), + }, + NodeKind::Again { args } => NodeKind::Again { args: args.clone() }, + NodeKind::Pipe { inputs, lambda } => NodeKind::Pipe { + inputs: inputs.clone(), + lambda: lambda.clone(), + }, + NodeKind::Block { exprs } => NodeKind::Block { exprs: exprs.clone() }, + NodeKind::Tuple { elements } => NodeKind::Tuple { elements: elements.clone() }, + NodeKind::Record { fields, layout } => NodeKind::Record { + fields: fields.clone(), + layout: layout.clone(), + }, + NodeKind::GetField { rec, field } => NodeKind::GetField { + rec: rec.clone(), + field: *field, + }, + NodeKind::MacroDecl { name, params, body } => NodeKind::MacroDecl { + name: name.clone(), + params: params.clone(), + body: body.clone(), + }, + NodeKind::Template(inner) => NodeKind::Template(inner.clone()), + NodeKind::Placeholder(inner) => NodeKind::Placeholder(inner.clone()), + NodeKind::Splice(inner) => NodeKind::Splice(inner.clone()), + NodeKind::Expansion { original_call, expanded } => NodeKind::Expansion { + original_call: original_call.clone(), + expanded: expanded.clone(), + }, + NodeKind::Error => NodeKind::Error, + NodeKind::Extension(ext) => NodeKind::Extension(ext.clone()), + } + } +} + +impl PartialEq for NodeKind

{ + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (NodeKind::Nop, NodeKind::Nop) => true, + (NodeKind::Constant(a), NodeKind::Constant(b)) => a == b, + (NodeKind::Identifier { symbol: sa, binding: ba }, NodeKind::Identifier { symbol: sb, binding: bb }) => { + sa == sb && ba == bb + } + (NodeKind::FieldAccessor(a), NodeKind::FieldAccessor(b)) => a == b, + (NodeKind::If { cond: ca, then_br: ta, else_br: ea }, NodeKind::If { cond: cb, then_br: tb, else_br: eb }) => { + Rc::ptr_eq(ca, cb) && Rc::ptr_eq(ta, tb) && match (ea, eb) { + (Some(a), Some(b)) => Rc::ptr_eq(a, b), + (None, None) => true, + _ => false, + } + } + (NodeKind::Def { pattern: pa, value: va, info: ia }, NodeKind::Def { pattern: pb, value: vb, info: ib }) => { + Rc::ptr_eq(pa, pb) && Rc::ptr_eq(va, vb) && ia == ib + } + (NodeKind::Assign { target: ta, value: va, info: ia }, NodeKind::Assign { target: tb, value: vb, info: ib }) => { + Rc::ptr_eq(ta, tb) && Rc::ptr_eq(va, vb) && ia == ib + } + (NodeKind::Lambda { params: pa, body: ba, info: ia }, NodeKind::Lambda { params: pb, body: bb, info: ib }) => { + Rc::ptr_eq(pa, pb) && Rc::ptr_eq(ba, bb) && ia == ib + } + (NodeKind::Call { callee: ca, args: aa }, NodeKind::Call { callee: cb, args: ab }) => { + Rc::ptr_eq(ca, cb) && Rc::ptr_eq(aa, ab) + } + (NodeKind::Again { args: aa }, NodeKind::Again { args: ab }) => Rc::ptr_eq(aa, ab), + (NodeKind::Pipe { inputs: ia, lambda: la }, NodeKind::Pipe { inputs: ib, lambda: lb }) => { + ia.len() == ib.len() + && ia.iter().zip(ib.iter()).all(|(a, b)| Rc::ptr_eq(a, b)) + && Rc::ptr_eq(la, lb) + } + (NodeKind::Block { exprs: ea }, NodeKind::Block { exprs: eb }) => { + ea.len() == eb.len() && ea.iter().zip(eb.iter()).all(|(a, b)| Rc::ptr_eq(a, b)) + } + (NodeKind::Tuple { elements: ea }, NodeKind::Tuple { elements: eb }) => { + ea.len() == eb.len() && ea.iter().zip(eb.iter()).all(|(a, b)| Rc::ptr_eq(a, b)) + } + (NodeKind::Record { fields: fa, layout: la }, NodeKind::Record { fields: fb, layout: lb }) => { + la == lb + && fa.len() == fb.len() + && fa.iter().zip(fb.iter()).all(|((ka, va), (kb, vb))| Rc::ptr_eq(ka, kb) && Rc::ptr_eq(va, vb)) + } + (NodeKind::GetField { rec: ra, field: fa }, NodeKind::GetField { rec: rb, field: fb }) => { + Rc::ptr_eq(ra, rb) && fa == fb + } + (NodeKind::MacroDecl { name: na, params: pa, body: ba }, NodeKind::MacroDecl { name: nb, params: pb, body: bb }) => { + na == nb && Rc::ptr_eq(pa, pb) && Rc::ptr_eq(ba, bb) + } + (NodeKind::Template(a), NodeKind::Template(b)) => Rc::ptr_eq(a, b), + (NodeKind::Placeholder(a), NodeKind::Placeholder(b)) => Rc::ptr_eq(a, b), + (NodeKind::Splice(a), NodeKind::Splice(b)) => Rc::ptr_eq(a, b), + (NodeKind::Expansion { original_call: ca, expanded: ea }, NodeKind::Expansion { original_call: cb, expanded: eb }) => { + Rc::ptr_eq(ca, cb) && Rc::ptr_eq(ea, eb) + } + (NodeKind::Error, NodeKind::Error) => true, + _ => false, + } + } +} + +impl NodeKind

{ + pub fn display_name(&self) -> String { + match self { + NodeKind::Nop => "NOP".to_string(), + NodeKind::Constant(v) => format!("CONST({})", v), + NodeKind::Identifier { symbol, .. } => format!("ID({})", symbol.name), + NodeKind::FieldAccessor(k) => format!("FIELD_ACCESSOR(.{})", k.name()), + NodeKind::If { .. } => "IF".to_string(), + NodeKind::Def { .. } => "DEF".to_string(), + NodeKind::Assign { .. } => "ASSIGN".to_string(), + NodeKind::Lambda { .. } => "LAMBDA".to_string(), + NodeKind::Call { .. } => "CALL".to_string(), + NodeKind::Again { .. } => "AGAIN".to_string(), + NodeKind::Pipe { .. } => "PIPE".to_string(), + NodeKind::Block { .. } => "BLOCK".to_string(), + NodeKind::Tuple { elements } => format!("TUPLE({})", elements.len()), + NodeKind::Record { fields, .. } => format!("RECORD({})", fields.len()), + NodeKind::GetField { field, .. } => format!("GET_FIELD(.{})", field.name()), + NodeKind::MacroDecl { name, .. } => format!("MACRO({})", name.name), + NodeKind::Template(_) => "TEMPLATE".to_string(), + NodeKind::Placeholder(_) => "PLACEHOLDER".to_string(), + NodeKind::Splice(_) => "SPLICE".to_string(), + NodeKind::Expansion { .. } => "EXPANSION".to_string(), + NodeKind::Extension(ext) => ext.display_name(), + NodeKind::Error => "ERROR".to_string(), + } + } +} diff --git a/src/ast/vm.rs b/src/ast/vm.rs index 1093d39..8e6f5f7 100644 --- a/src/ast/vm.rs +++ b/src/ast/vm.rs @@ -1,4 +1,4 @@ -use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, ExecNode, IdentifierBinding, NodeKind, StackOffset}; +use crate::ast::nodes::{Address, AnalyzedNode, ExecNode, IdentifierBinding, NodeKind, StackOffset}; use crate::ast::types::{Object, Value}; use std::any::Any; use std::cell::RefCell; diff --git a/tests/error_recovery.rs b/tests/error_recovery.rs index 76885bb..2510765 100644 --- a/tests/error_recovery.rs +++ b/tests/error_recovery.rs @@ -1,4 +1,4 @@ -use myc::ast::compiler::bound_nodes::TypedNode; +use myc::ast::nodes::TypedNode; use myc::ast::environment::Environment; use myc::ast::types::StaticType;