feat: Add compact AST dump
Introduce a new `dump_ast_compact` function for the environment and Dumper. This function provides a simplified, human-readable representation of the AST, focusing on inferred types and purity markers instead of detailed debug information. This change adds: - A `compact` flag to the `Dumper` struct. - The `dump_compact` method to the `Dumper`. - The `dump_ast_compact` method to the `Environment`. - A new `dump_ast_compact` command-line argument for the `ast` binary. - A new MCP server endpoint `dump_ast_compact`. - A `CompactMetadata` trait to abstract over different metadata types for compact display. - Updates to documentation and CLI help messages.
This commit is contained in:
+64
-16
@@ -1,17 +1,33 @@
|
||||
use crate::ast::nodes::{CompilerPhase, Node, NodeKind};
|
||||
use crate::ast::nodes::{CompactMetadata, CompilerPhase, Node, NodeKind};
|
||||
|
||||
/// Human-readable AST dumper for the bound AST.
|
||||
pub struct Dumper {
|
||||
output: String,
|
||||
indent: usize,
|
||||
/// When `true`, emits a compact format suitable for GUI display:
|
||||
/// type annotations via `Display` and purity symbols instead of raw debug structs.
|
||||
compact: bool,
|
||||
}
|
||||
|
||||
impl Dumper {
|
||||
/// Produces a formatted string representation of the given bound AST node and its children.
|
||||
/// Produces a verbose debug representation of the given AST node and its children.
|
||||
pub fn dump<P: CompilerPhase>(node: &Node<P>) -> String {
|
||||
let mut dumper = Self {
|
||||
output: String::new(),
|
||||
indent: 0,
|
||||
compact: false,
|
||||
};
|
||||
dumper.visit(node);
|
||||
dumper.output
|
||||
}
|
||||
|
||||
/// Produces a compact, human-readable representation suitable for GUI display.
|
||||
/// Shows inferred types and purity (`!` / `~`) instead of raw debug structs.
|
||||
pub fn dump_compact<P: CompilerPhase>(node: &Node<P>) -> String {
|
||||
let mut dumper = Self {
|
||||
output: String::new(),
|
||||
indent: 0,
|
||||
compact: true,
|
||||
};
|
||||
dumper.visit(node);
|
||||
dumper.output
|
||||
@@ -26,8 +42,16 @@ impl Dumper {
|
||||
fn log<P: CompilerPhase>(&mut self, label: &str, node: &Node<P>) {
|
||||
self.write_indent();
|
||||
self.output.push_str(label);
|
||||
self.output
|
||||
.push_str(&format!(" <Metadata: {:?}>\n", node.ty));
|
||||
if self.compact {
|
||||
if let Some(annotation) = node.ty.compact_label() {
|
||||
self.output.push_str(" → ");
|
||||
self.output.push_str(&annotation);
|
||||
}
|
||||
} else {
|
||||
self.output
|
||||
.push_str(&format!(" <Metadata: {:?}>", node.ty));
|
||||
}
|
||||
self.output.push('\n');
|
||||
}
|
||||
|
||||
fn visit<P: CompilerPhase>(&mut self, node: &Node<P>) {
|
||||
@@ -37,7 +61,12 @@ impl Dumper {
|
||||
self.log(&format!("Constant: {}", v), node);
|
||||
}
|
||||
NodeKind::Identifier { symbol, binding } => {
|
||||
self.log(&format!("Identifier: {} ({:?})", symbol.name, binding), node)
|
||||
let label = if self.compact {
|
||||
format!("Identifier: {}", symbol.name)
|
||||
} else {
|
||||
format!("Identifier: {} ({:?})", symbol.name, binding)
|
||||
};
|
||||
self.log(&label, node);
|
||||
}
|
||||
|
||||
NodeKind::FieldAccessor(k) => self.log(&format!("FieldAccessor: .{}", k.name()), node),
|
||||
@@ -50,7 +79,12 @@ impl Dumper {
|
||||
}
|
||||
|
||||
NodeKind::Assign { target, value, info } => {
|
||||
self.log(&format!("Assign: {:?}", info), node);
|
||||
let label = if self.compact {
|
||||
"Assign".to_string()
|
||||
} else {
|
||||
format!("Assign: {:?}", info)
|
||||
};
|
||||
self.log(&label, node);
|
||||
self.indent += 1;
|
||||
self.write_indent();
|
||||
self.output.push_str("Target:\n");
|
||||
@@ -66,7 +100,12 @@ impl Dumper {
|
||||
value,
|
||||
info,
|
||||
} => {
|
||||
self.log(&format!("Def ({:?})", info), node);
|
||||
let label = if self.compact {
|
||||
"Def".to_string()
|
||||
} else {
|
||||
format!("Def ({:?})", info)
|
||||
};
|
||||
self.log(&label, node);
|
||||
self.indent += 1;
|
||||
self.write_indent();
|
||||
self.output.push_str("Pattern:\n");
|
||||
@@ -106,7 +145,12 @@ impl Dumper {
|
||||
body,
|
||||
info,
|
||||
} => {
|
||||
self.log(&format!("Lambda ({:?})", info), node);
|
||||
let label = if self.compact {
|
||||
"Lambda".to_string()
|
||||
} else {
|
||||
format!("Lambda ({:?})", info)
|
||||
};
|
||||
self.log(&label, node);
|
||||
self.indent += 1;
|
||||
|
||||
self.write_indent();
|
||||
@@ -157,10 +201,12 @@ impl Dumper {
|
||||
}
|
||||
|
||||
NodeKind::Record { fields, layout } => {
|
||||
self.log(
|
||||
&format!("Record (Layout: {:?})", layout),
|
||||
node,
|
||||
);
|
||||
let label = if self.compact {
|
||||
"Record".to_string()
|
||||
} else {
|
||||
format!("Record (Layout: {:?})", layout)
|
||||
};
|
||||
self.log(&label, node);
|
||||
self.indent += 1;
|
||||
for (key, val) in fields {
|
||||
self.write_indent();
|
||||
@@ -181,10 +227,12 @@ impl Dumper {
|
||||
original_call,
|
||||
expanded,
|
||||
} => {
|
||||
self.log(
|
||||
&format!("Expansion (Original: {:?})", original_call.kind),
|
||||
node,
|
||||
);
|
||||
let label = if self.compact {
|
||||
"Expansion".to_string()
|
||||
} else {
|
||||
format!("Expansion (Original: {:?})", original_call.kind)
|
||||
};
|
||||
self.log(&label, node);
|
||||
self.indent += 1;
|
||||
self.visit(expanded);
|
||||
self.indent -= 1;
|
||||
|
||||
Reference in New Issue
Block a user