kcl-ast vs kcl-ast-pretty: Understanding the Distinction in KCL's Compiler
The kcl-ast crate defines the core abstract syntax tree data structures that represent parsed KCL source code, while kcl-ast-pretty provides formatting utilities that convert these AST nodes into human-readable strings for debugging and tooling purposes.
The kcl-lang/kcl repository organizes its Rust compiler into discrete crates with single responsibilities. Two foundational crates—kcl-ast and kcl-ast-pretty—handle the representation and visualization of KCL programs. Understanding their separation is critical for developers building compiler passes, language tools, or IDE integrations.
Core Purpose of kcl-ast
The kcl-ast crate serves as the data model layer for the entire compiler pipeline. Located in crates/ast, this crate contains the canonical definitions of every node type that represents KCL source code after parsing.
Key responsibilities include:
- Defining fundamental types like
Node<T>,Pos,AstIndex,Program,Module,Stmt, andExpr - Providing low-level utilities for creating, cloning, and serializing AST nodes via
serde - Acting as the immutable structure that the parser builds and subsequent phases (type-checker, optimizer) manipulate
According to the source code in crates/ast/src/ast.rs, the Node<T> struct wraps every AST element with positional metadata, enabling precise error reporting throughout the compiler. This crate deliberately avoids any presentation logic to maintain a minimal dependency tree.
Core Purpose of kcl-ast-pretty
The kcl-ast-pretty crate implements the presentation layer for the AST. Located in crates/ast_pretty, it transforms the raw tree structures from kcl-ast into formatted, indented output suitable for human consumption.
Key functions include:
print_ast_module: Renders an entireProgramorModuleas a formatted stringprint_ast_node: Converts individualNode<T>instances to readable text- Supporting debug output and diagnostic formatting for the LSP and CLI tools
As implemented in kcl-ast-pretty, the crate depends on kcl-ast to access node definitions and uses serde_json for structured output formatting. The kcl format command and various test suites consume this crate to display program state without modifying the underlying AST.
Key Differences Between kcl-ast and kcl-ast-pretty
While both crates handle AST representation, they serve distinct architectural roles:
Dependencies and Relationships
kcl-astsits at the bottom of the dependency graph. It depends only on core libraries likeserde,uuid, andcompiler_base_span. No other AST-related crates depend on it cyclically.kcl-ast-prettyexplicitly depends onkcl-ast(declared incrates/ast_pretty/Cargo.toml) plus formatting utilities likeserde_jsonandpretty_assertionsfor testing.
Data vs. Presentation
kcl-aststores the structure—the what of the program (expressions, statements, literals).kcl-ast-prettyhandles the view—the how of displaying that structure to developers through formatted strings or JSON.
Compilation Phase Usage
- The parser (
crates/parser) constructskcl-astnodes during the initial parse phase. - The semantic analyzer (
crates/sema) and resolver manipulate these same structures. - Pretty-printing occurs optionally during formatting (
crates/tools/src/format/mod.rs) or debugging, walking the existing tree to emit text without altering nodes.
Architecture Flow: How They Work Together
The separation creates a clean pipeline from source code to human-readable output:
- Parsing: The parser reads
.kfiles and constructskcl-astnodes (Node<T>,Expr,Stmt) defined incrates/ast/src/ast.rs. - Analysis: The resolver and type-checker annotate or transform these structures, still operating purely on
kcl-asttypes. - Visualization: When the
kcl fmt --print-astcommand runs or the LSP needs to display a tree,crates/tools/src/format/mod.rsimportskcl_ast_pretty::print_ast_moduleto render the view.
This split ensures that core compiler logic remains lightweight, while tools like kcl-query, kcl-loader, and the LSP can pull in formatting capabilities only when needed.
Code Examples
Building AST Nodes with kcl-ast
The following example demonstrates creating an AST node using the core data structures:
use kcl_ast::node::Node;
use kcl_ast::ast::{Expr, NumberLit};
// Create a literal integer expression node
let expr = Expr::NumberLit(NumberLit { value: 42.0, suffix: None });
let node = Node::new(
expr,
"example.k".to_string(),
1, // line
5, // column
1, // end_line
7, // end_column
);
Pretty-Printing with kcl-ast-pretty
Convert loaded programs to readable format using the pretty-printing utilities:
use kcl_ast_pretty::print_ast_module;
use kcl_loader::load_program;
// Load a KCL program (returns a `Program` node)
let program = load_program("example.k").unwrap();
// Produce a nicely indented representation
let pretty = print_ast_module(&program);
println!("{}", pretty);
Integration in CLI Tools
The formatter tool demonstrates real-world usage within the KCL codebase:
// Inside crates/tools/src/format/mod.rs
use kcl_ast_pretty::print_ast_module;
use kcl_ast::ast::Program;
pub fn format_and_print(program: &Program) -> String {
// Apply any formatting passes, then pretty-print
print_ast_module(program)
}
Summary
kcl-astdefines the foundational data structures (Node<T>,Program,Expr) used throughout the KCL compiler pipeline, located incrates/ast/src/ast.rs.kcl-ast-prettyprovides human-readable formatting viaprint_ast_moduleandprint_ast_node, residing incrates/ast_pretty/src/lib.rs.- The dependency relationship flows one way:
kcl-ast-prettyrequireskcl-ast, but the core crate remains independent. - Use
kcl-astwhen building compiler passes or analyzing code structure; usekcl-ast-prettywhen implementing debugging tools, formatters, or diagnostic displays.
Frequently Asked Questions
Can kcl-ast be used independently of kcl-ast-pretty?
Yes. The kcl-ast crate has no dependency on kcl-ast-pretty and is used throughout the compiler for parsing, type-checking, and code generation without ever invoking pretty-printing logic. This design keeps the core compiler lightweight.
Does kcl-ast-pretty modify AST nodes during formatting?
No. Functions like print_ast_module take references to AST nodes and produce String output without mutating the underlying Node<T> structures. The crate is purely a read-only viewer of the tree.
Which crate should I import when building a custom formatter?
Import both. Your tool should use kcl-ast to represent the program structure and kcl-ast-pretty to generate the final formatted output, as demonstrated in crates/tools/src/format/mod.rs where the formatter applies transformations then calls print_ast_module.
Where are these crates declared in the KCL workspace?
Both crates are workspace members defined in the root Cargo.toml. kcl-ast is declared as kcl-ast = { path = "crates/ast" }, while kcl-ast-pretty uses kcl-ast-pretty = { path = "crates/ast_pretty" } and is re-exported via kcl-ast-pretty.workspace = true for consumption by other compiler crates.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →