use crate::ast::nodes::{CompilerPhase, Node, NodeKind}; /// Human-readable AST dumper for the bound AST. pub struct Dumper { output: String, indent: usize, } impl Dumper { /// Produces a formatted string representation of the given bound AST node and its children. pub fn dump(node: &Node

) -> String { let mut dumper = Self { output: String::new(), indent: 0, }; dumper.visit(node); dumper.output } fn write_indent(&mut self) { for _ in 0..self.indent { self.output.push_str(" "); } } fn log(&mut self, label: &str, node: &Node

) { self.write_indent(); self.output.push_str(label); self.output .push_str(&format!(" \n", node.ty)); } fn visit(&mut self, node: &Node

) { match &node.kind { NodeKind::Nop => self.log("Nop", node), NodeKind::Constant(v) => { self.log(&format!("Constant: {}", v), node); } NodeKind::Identifier { symbol, binding } => { self.log(&format!("Identifier: {} ({:?})", symbol.name, binding), node) } NodeKind::FieldAccessor(k) => self.log(&format!("FieldAccessor: .{}", k.name()), node), NodeKind::GetField { rec, field } => { self.log(&format!("GetField: .{}", field.name()), node); self.indent += 1; self.visit(rec); self.indent -= 1; } NodeKind::Assign { target, value, info } => { self.log(&format!("Assign: {:?}", info), node); self.indent += 1; self.write_indent(); self.output.push_str("Target:\n"); self.visit(target); self.write_indent(); self.output.push_str("Value:\n"); self.visit(value); self.indent -= 1; } NodeKind::Def { pattern, value, info, } => { self.log(&format!("Def ({:?})", info), node); self.indent += 1; self.write_indent(); self.output.push_str("Pattern:\n"); self.visit(pattern); self.write_indent(); self.output.push_str("Value:\n"); self.visit(value); self.indent -= 1; } NodeKind::If { cond, then_br, else_br, } => { self.log("If", node); self.indent += 1; self.write_indent(); self.output.push_str("Condition:\n"); self.visit(cond); self.write_indent(); self.output.push_str("Then:\n"); self.visit(then_br); if let Some(e) = else_br { self.write_indent(); self.output.push_str("Else:\n"); self.visit(e); } self.indent -= 1; } NodeKind::Lambda { params, body, info, } => { self.log(&format!("Lambda ({:?})", info), node); self.indent += 1; self.write_indent(); self.output.push_str("Parameters:\n"); self.visit(params); self.visit(body); self.indent -= 1; } NodeKind::Call { callee, args } => { self.log("Call", node); self.indent += 1; self.write_indent(); self.output.push_str("Callee:\n"); self.visit(callee); self.write_indent(); self.output.push_str("Arguments:\n"); self.visit(args); self.indent -= 1; } NodeKind::Again { args } => { self.log("Again", node); self.indent += 1; self.visit(args); self.indent -= 1; } NodeKind::Pipe { inputs, lambda } => { self.log("Pipe", node); self.indent += 1; for input in inputs { self.visit(input); } self.visit(lambda); self.indent -= 1; } NodeKind::Block { exprs } => { self.log("Block", node); self.indent += 1; for expr in exprs { self.visit(expr); } self.indent -= 1; } NodeKind::Tuple { elements } => { self.log("Tuple", node); self.indent += 1; for el in elements { self.visit(el); } self.indent -= 1; } NodeKind::Record { fields, layout } => { self.log( &format!("Record (Layout: {:?})", layout), node, ); self.indent += 1; for (key, val) in fields { self.write_indent(); self.output.push_str("Key:\n"); self.indent += 1; self.visit(key); self.indent -= 1; self.write_indent(); self.output.push_str("Value:\n"); self.indent += 1; self.visit(val); self.indent -= 1; } self.indent -= 1; } NodeKind::Expansion { original_call, expanded, } => { self.log( &format!("Expansion (Original: {:?})", original_call.kind), node, ); self.indent += 1; self.visit(expanded); self.indent -= 1; } NodeKind::MacroDecl { name, params, body } => { self.log(&format!("MacroDecl: {}", name.name), node); self.indent += 1; self.visit(params); self.visit(body); self.indent -= 1; } NodeKind::Template(inner) => { self.log("Template", node); self.indent += 1; self.visit(inner); self.indent -= 1; } NodeKind::Placeholder(inner) => { self.log("Placeholder", node); self.indent += 1; self.visit(inner); self.indent -= 1; } NodeKind::Splice(inner) => { self.log("Splice", node); self.indent += 1; self.visit(inner); self.indent -= 1; } NodeKind::Extension(ext) => { self.log(&ext.display_name(), node); } NodeKind::Error => { self.log("ERROR_NODE", node); } } } }