Skip to main content

cjc_ast/
lib.rs

1//! Abstract Syntax Tree definitions for the CJC compiler.
2//!
3//! This crate defines the complete AST node taxonomy produced by [`cjc_parser`]:
4//! [`Program`], [`Stmt`]/[`StmtKind`], [`Expr`]/[`ExprKind`], [`Decl`]/[`DeclKind`],
5//! type expressions ([`TypeExpr`]/[`TypeExprKind`]), patterns ([`Pattern`]/[`PatternKind`]),
6//! and all supporting structures (identifiers, spans, operators, etc.).
7//!
8//! This is a **leaf crate** with zero internal dependencies, ensuring it can be
9//! consumed by every downstream stage of the compiler pipeline without cycles.
10//!
11//! # Submodules
12//!
13//! - [`visit`] — Read-only visitor trait and walk functions for AST traversal
14//! - [`metrics`] — Structural statistics (node counts, depths, feature flags)
15//! - [`validate`] — Lightweight structural validation before HIR lowering
16//! - [`inspect`] — Deterministic text dumps for debugging and testing
17//! - [`node_utils`] — Pure query methods on [`Expr`], [`Block`], and [`Program`]
18
19pub mod inspect;
20pub mod metrics;
21pub mod node_utils;
22pub mod validate;
23pub mod visit;
24
25use std::fmt;
26
27/// Source span: byte offset range in source code.
28/// Duplicated from cjc-diag to avoid circular dependency.
29/// AST is a leaf crate with no dependencies.
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
31pub struct Span {
32    pub start: usize,
33    pub end: usize,
34}
35
36impl Span {
37    /// Create a new span from a start and end byte offset.
38    pub fn new(start: usize, end: usize) -> Self {
39        Self { start, end }
40    }
41
42    /// Merge two spans into the smallest span that covers both.
43    ///
44    /// Takes the minimum start and maximum end of the two spans.
45    pub fn merge(self, other: Span) -> Span {
46        Span {
47            start: self.start.min(other.start),
48            end: self.end.max(other.end),
49        }
50    }
51
52    /// Create a dummy span at position `0..0` for use in tests and synthetic nodes.
53    pub fn dummy() -> Self {
54        Self { start: 0, end: 0 }
55    }
56}
57
58// ── Visibility ──────────────────────────────────────────────────
59
60/// Visibility qualifier for declarations and fields.
61/// `pub` makes an item publicly visible; the default is private.
62/// NOTE: Enforcement is deferred — single-file programs treat all items as
63/// public regardless of annotation. This enum is stored but not checked yet.
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65pub enum Visibility {
66    /// Item is visible outside its defining scope (`pub` keyword).
67    Public,
68    /// Item is visible only within its defining scope (default).
69    Private,
70}
71
72impl Default for Visibility {
73    fn default() -> Self {
74        Visibility::Private
75    }
76}
77
78// ── AST Node Types ──────────────────────────────────────────────
79
80/// Top-level program: a sequence of declarations.
81#[derive(Debug, Clone)]
82pub struct Program {
83    pub declarations: Vec<Decl>,
84}
85
86/// A declaration (top-level item).
87#[derive(Debug, Clone)]
88pub struct Decl {
89    pub kind: DeclKind,
90    pub span: Span,
91}
92
93/// The kind of a top-level declaration.
94///
95/// Each variant wraps a dedicated declaration struct that carries the
96/// variant-specific fields.
97#[derive(Debug, Clone)]
98pub enum DeclKind {
99    /// Struct declaration: `struct Foo { ... }`
100    Struct(StructDecl),
101    /// Class declaration: `class Foo { ... }` (mutable fields, heap-allocated)
102    Class(ClassDecl),
103    /// Record declaration: `record Foo { ... }` (immutable value type)
104    Record(RecordDecl),
105    /// Function declaration: `fn foo(...) { ... }`
106    Fn(FnDecl),
107    /// Trait declaration: `trait Foo { ... }`
108    Trait(TraitDecl),
109    /// Impl block: `impl Foo { ... }` or `impl Trait for Foo { ... }`
110    Impl(ImplDecl),
111    /// Enum declaration: `enum Foo { A, B(i64) }`
112    Enum(EnumDecl),
113    /// Top-level let binding: `let x = expr;`
114    Let(LetStmt),
115    /// Import declaration: `import path.to.module`
116    Import(ImportDecl),
117    /// Compile-time constant: `const NAME: Type = expr;`
118    Const(ConstDecl),
119    /// Top-level statement (expression statement, if, while, etc.)
120    Stmt(Stmt),
121}
122
123/// A compile-time constant declaration: `const PI: f64 = 3.14159;`
124///
125/// Constants must have an explicit type annotation and a value expression
126/// that can be evaluated at compile time.
127#[derive(Debug, Clone)]
128pub struct ConstDecl {
129    /// Constant name.
130    pub name: Ident,
131    /// Type annotation (required).
132    pub ty: TypeExpr,
133    /// Value expression (must be compile-time evaluable).
134    pub value: Box<Expr>,
135    /// Source span of the full declaration.
136    pub span: Span,
137}
138
139// ── Struct & Class ──────────────────────────────────────────────
140
141/// Struct declaration: `struct Point { x: f64, y: f64 }`
142///
143/// Structs are product types with named fields. By default, fields are
144/// mutable unless the binding is immutable.
145#[derive(Debug, Clone)]
146pub struct StructDecl {
147    /// Name of the struct.
148    pub name: Ident,
149    /// Generic type parameters (e.g., `<T>`).
150    pub type_params: Vec<TypeParam>,
151    /// Named fields with types and optional defaults.
152    pub fields: Vec<FieldDecl>,
153    /// Visibility qualifier (`pub` or private).
154    pub vis: Visibility,
155}
156
157/// Class declaration: `class Widget { ... }`
158///
159/// Classes are heap-allocated types with mutable fields, similar to structs
160/// but semantically intended for reference-identity objects.
161#[derive(Debug, Clone)]
162pub struct ClassDecl {
163    /// Name of the class.
164    pub name: Ident,
165    /// Generic type parameters.
166    pub type_params: Vec<TypeParam>,
167    /// Named fields with types and optional defaults.
168    pub fields: Vec<FieldDecl>,
169    /// Visibility qualifier.
170    pub vis: Visibility,
171}
172
173/// Record declaration: immutable value type.
174/// `record Point { x: f64, y: f64 }`
175/// Records are like structs but always immutable — field reassignment is a type error.
176#[derive(Debug, Clone)]
177pub struct RecordDecl {
178    pub name: Ident,
179    pub type_params: Vec<TypeParam>,
180    pub fields: Vec<FieldDecl>,
181    pub vis: Visibility,
182}
183
184// ── Enums ───────────────────────────────────────────────────
185
186/// Enum declaration: `enum Color { Red, Green, Blue(i64) }`
187///
188/// Enums are sum types with named variants. Each variant may carry
189/// zero or more positional payload types.
190#[derive(Debug, Clone)]
191pub struct EnumDecl {
192    /// Name of the enum.
193    pub name: Ident,
194    /// Generic type parameters.
195    pub type_params: Vec<TypeParam>,
196    /// Ordered list of variants.
197    pub variants: Vec<VariantDecl>,
198}
199
200/// A single variant within an [`EnumDecl`].
201///
202/// Unit variants have an empty `fields` vec; tuple-like variants list
203/// their payload types positionally.
204#[derive(Debug, Clone)]
205pub struct VariantDecl {
206    /// Name of the variant.
207    pub name: Ident,
208    /// Payload types for tuple-like variants. Empty for unit variants.
209    pub fields: Vec<TypeExpr>,
210    /// Source span of the variant declaration.
211    pub span: Span,
212}
213
214/// A named field within a struct, class, or record declaration.
215///
216/// Fields carry a type annotation and an optional default-value expression.
217#[derive(Debug, Clone)]
218pub struct FieldDecl {
219    /// Field name.
220    pub name: Ident,
221    /// Type annotation for the field.
222    pub ty: TypeExpr,
223    /// Optional default value expression.
224    pub default: Option<Expr>,
225    /// Visibility qualifier.
226    pub vis: Visibility,
227    /// Source span of the field declaration.
228    pub span: Span,
229}
230
231// ── Functions ───────────────────────────────────────────────────
232
233/// A decorator applied to a function declaration.
234///
235/// Syntax: `@decorator_name` or `@decorator_name(args...)`
236#[derive(Debug, Clone)]
237pub struct Decorator {
238    pub name: Ident,
239    pub args: Vec<Expr>,
240    pub span: Span,
241}
242
243/// Function declaration: `fn solve(x: f64, tol: f64 = 1e-6) -> f64 { ... }`
244///
245/// Represents a complete function definition including its signature, body,
246/// and metadata (NoGC flag, decorators, visibility).
247///
248/// Every new builtin must be registered in [`cjc_runtime::builtins`],
249/// [`cjc_eval`], and [`cjc_mir_exec`] (the "wiring pattern").
250#[derive(Debug, Clone)]
251pub struct FnDecl {
252    /// Function name.
253    pub name: Ident,
254    /// Generic type parameters.
255    pub type_params: Vec<TypeParam>,
256    /// Positional parameters with types, optional defaults, and variadic flag.
257    pub params: Vec<Param>,
258    /// Optional return-type annotation. `None` means the return type is inferred.
259    pub return_type: Option<TypeExpr>,
260    /// Function body block.
261    pub body: Block,
262    /// Whether this function is marked `@nogc` (no GC allocations allowed).
263    pub is_nogc: bool,
264    /// Effect annotation: `fn foo() -> i64 / pure { ... }`
265    /// `None` means "any effect" (backward compatible).
266    pub effect_annotation: Option<Vec<String>>,
267    /// Decorators applied to this function (e.g., `@log`, `@timed`).
268    pub decorators: Vec<Decorator>,
269    /// Visibility qualifier.
270    pub vis: Visibility,
271}
272
273/// Function signature without a body, used in [`TraitDecl`] method declarations.
274///
275/// Contains everything [`FnDecl`] has except the body block and metadata.
276#[derive(Debug, Clone)]
277pub struct FnSig {
278    /// Function name.
279    pub name: Ident,
280    /// Generic type parameters.
281    pub type_params: Vec<TypeParam>,
282    /// Positional parameters.
283    pub params: Vec<Param>,
284    /// Optional return-type annotation.
285    pub return_type: Option<TypeExpr>,
286    /// Source span of the signature.
287    pub span: Span,
288}
289
290#[derive(Debug, Clone)]
291pub struct Param {
292    pub name: Ident,
293    pub ty: TypeExpr,
294    /// Optional default value expression (e.g., `fn f(x: f64 = 1.0)`).
295    pub default: Option<Expr>,
296    /// Variadic parameter: `fn f(...args: f64)` collects remaining args into an array.
297    /// Only the last parameter may be variadic.
298    pub is_variadic: bool,
299    pub span: Span,
300}
301
302// ── Traits & Impls ──────────────────────────────────────────────
303
304/// Trait declaration: `trait Numeric { fn zero() -> Self; }`
305///
306/// Traits define abstract interfaces via method signatures.
307/// Implementors provide concrete method bodies via [`ImplDecl`].
308#[derive(Debug, Clone)]
309pub struct TraitDecl {
310    /// Trait name.
311    pub name: Ident,
312    /// Generic type parameters.
313    pub type_params: Vec<TypeParam>,
314    /// Super-trait bounds this trait extends.
315    pub super_traits: Vec<TypeExpr>,
316    /// Method signatures (no bodies).
317    pub methods: Vec<FnSig>,
318}
319
320/// Impl block: `impl Foo { ... }` or `impl Trait for Foo { ... }`
321///
322/// Associates method implementations with a target type, optionally
323/// satisfying a trait contract.
324#[derive(Debug, Clone)]
325pub struct ImplDecl {
326    /// Generic type parameters on the impl.
327    pub type_params: Vec<TypeParam>,
328    /// The type being implemented (e.g., `Foo<T>`).
329    pub target: TypeExpr,
330    /// Optional trait being implemented for the target type.
331    pub trait_ref: Option<TypeExpr>,
332    /// Method implementations.
333    pub methods: Vec<FnDecl>,
334    /// Source span of the impl block.
335    pub span: Span,
336}
337
338// ── Import ──────────────────────────────────────────────────────
339
340/// Import declaration: `import math.linalg` or `import stats as s`.
341///
342/// Brings names from other modules into scope. The `path` field contains
343/// the dot-separated segments and `alias` is an optional rename.
344#[derive(Debug, Clone)]
345pub struct ImportDecl {
346    /// Module path segments (e.g., `["math", "linalg"]`).
347    pub path: Vec<Ident>,
348    /// Optional alias (`as name`).
349    pub alias: Option<Ident>,
350}
351
352// ── Type Expressions ────────────────────────────────────────────
353
354/// A type expression in source code.
355///
356/// Wraps a [`TypeExprKind`] discriminant with a source [`Span`].
357/// Used in parameter types, return types, field annotations, and
358/// generic arguments.
359#[derive(Debug, Clone)]
360pub struct TypeExpr {
361    /// The kind of type expression.
362    pub kind: TypeExprKind,
363    /// Source span.
364    pub span: Span,
365}
366
367/// The kind of a type expression.
368///
369/// Covers named types, arrays, tuples, function types, and shape literals
370/// used in CJC's tensor type system.
371#[derive(Debug, Clone)]
372pub enum TypeExprKind {
373    /// Named type with optional generic arguments: `f64`, `Tensor<f32>`, `Vec<T>`.
374    Named {
375        /// The type name identifier.
376        name: Ident,
377        /// Generic type arguments (empty for non-generic types).
378        args: Vec<TypeArg>,
379    },
380    /// Fixed-size array type: `[T; N]`.
381    Array {
382        /// Element type.
383        elem: Box<TypeExpr>,
384        /// Array size expression (must be a compile-time constant).
385        size: Box<Expr>,
386    },
387    /// Tuple type: `(T, U, V)`.
388    Tuple(Vec<TypeExpr>),
389    /// Function type: `fn(T, U) -> V`.
390    Fn {
391        /// Parameter types.
392        params: Vec<TypeExpr>,
393        /// Return type.
394        ret: Box<TypeExpr>,
395    },
396    /// Shape literal in type position: `[M, N]` for tensor dimensions.
397    ShapeLit(Vec<ShapeDim>),
398}
399
400/// A type argument in a generic instantiation.
401///
402/// Generic parameters can accept types, expressions (for const generics),
403/// or shape dimensions (for tensor shapes).
404#[derive(Debug, Clone)]
405pub enum TypeArg {
406    /// A type argument: `Tensor<f64>`.
407    Type(TypeExpr),
408    /// An expression argument (const generic): `Matrix<3>`.
409    Expr(Expr),
410    /// A shape argument: `Tensor<[M, N]>`.
411    Shape(Vec<ShapeDim>),
412}
413
414/// A single dimension in a tensor shape specification.
415///
416/// Dimensions are either symbolic names resolved at compile time or
417/// literal integer constants.
418#[derive(Debug, Clone)]
419pub enum ShapeDim {
420    /// Symbolic dimension name (e.g., `M`, `batch`).
421    Name(Ident),
422    /// Literal integer dimension (e.g., `3`, `128`).
423    Lit(i64),
424}
425
426/// A generic type parameter declaration: `<T: Numeric>`.
427///
428/// Appears in function, struct, enum, trait, and impl declarations.
429#[derive(Debug, Clone)]
430pub struct TypeParam {
431    /// Parameter name (e.g., `T`).
432    pub name: Ident,
433    /// Trait bounds on the parameter.
434    pub bounds: Vec<TypeExpr>,
435    /// Source span.
436    pub span: Span,
437}
438
439// ── Statements ──────────────────────────────────────────────────
440
441/// A block of statements with an optional trailing expression.
442///
443/// Blocks are the body of functions, loops, and if-branches. The optional
444/// trailing `expr` is the block's value when used as an expression
445/// (e.g., `{ let x = 1; x + 1 }` evaluates to the trailing expression).
446#[derive(Debug, Clone)]
447pub struct Block {
448    /// Ordered list of statements in the block.
449    pub stmts: Vec<Stmt>,
450    /// Optional trailing expression (the block's value).
451    pub expr: Option<Box<Expr>>,
452    /// Source span of the entire block including braces.
453    pub span: Span,
454}
455
456/// A statement node in the AST.
457///
458/// Wraps a [`StmtKind`] discriminant with a source [`Span`].
459#[derive(Debug, Clone)]
460pub struct Stmt {
461    /// The kind of statement.
462    pub kind: StmtKind,
463    /// Source span.
464    pub span: Span,
465}
466
467/// The kind of a statement.
468#[derive(Debug, Clone)]
469pub enum StmtKind {
470    /// Variable binding: `let x = expr;` or `let mut x: T = expr;`
471    Let(LetStmt),
472    /// Expression statement: `foo();` (result discarded).
473    Expr(Expr),
474    /// Return statement: `return expr;` or bare `return;`.
475    Return(Option<Expr>),
476    /// Break out of the innermost loop.
477    Break,
478    /// Continue to the next iteration of the innermost loop.
479    Continue,
480    /// If statement (not to be confused with [`ExprKind::IfExpr`]).
481    If(IfStmt),
482    /// While loop: `while cond { ... }`
483    While(WhileStmt),
484    /// For loop: `for i in 0..n { ... }` or `for x in arr { ... }`
485    For(ForStmt),
486    /// NoGC block: `nogc { ... }` (disallows GC allocations inside).
487    NoGcBlock(Block),
488}
489
490/// Let binding statement: `let x = 1;` or `let mut y: f64 = 3.14;`
491#[derive(Debug, Clone)]
492pub struct LetStmt {
493    /// Binding name.
494    pub name: Ident,
495    /// Whether the binding is mutable (`let mut`).
496    pub mutable: bool,
497    /// Optional explicit type annotation.
498    pub ty: Option<TypeExpr>,
499    /// Initializer expression (required in CJC).
500    pub init: Box<Expr>,
501}
502
503/// If statement: `if cond { ... } else { ... }`
504///
505/// See also [`ExprKind::IfExpr`] for the expression form.
506#[derive(Debug, Clone)]
507pub struct IfStmt {
508    /// Condition expression (must evaluate to bool).
509    pub condition: Expr,
510    /// Then-branch block.
511    pub then_block: Block,
512    /// Optional else or else-if branch.
513    pub else_branch: Option<ElseBranch>,
514}
515
516/// The else clause of an if statement or expression.
517#[derive(Debug, Clone)]
518pub enum ElseBranch {
519    /// Chained else-if: `else if cond { ... }`
520    ElseIf(Box<IfStmt>),
521    /// Terminal else: `else { ... }`
522    Else(Block),
523}
524
525/// While loop statement: `while cond { ... }`
526#[derive(Debug, Clone)]
527pub struct WhileStmt {
528    /// Loop condition (re-evaluated each iteration).
529    pub condition: Expr,
530    /// Loop body.
531    pub body: Block,
532}
533
534/// For loop statement: `for i in 0..n { ... }` or `for x in arr { ... }`
535///
536/// Desugared to a while loop during HIR lowering.
537#[derive(Debug, Clone)]
538pub struct ForStmt {
539    /// Loop variable name.
540    pub ident: Ident,
541    /// Iteration source (range or expression).
542    pub iter: ForIter,
543    /// Loop body.
544    pub body: Block,
545}
546
547/// The iteration source for a `for` loop.
548#[derive(Debug, Clone)]
549pub enum ForIter {
550    /// Range form: `start..end` (exclusive end)
551    Range { start: Box<Expr>, end: Box<Expr> },
552    /// Expression form: `for x in expr` (array/tensor iteration)
553    Expr(Box<Expr>),
554}
555
556// ── Expressions ─────────────────────────────────────────────────
557
558/// An expression node in the AST.
559///
560/// Wraps an [`ExprKind`] discriminant with a source [`Span`].
561/// Expressions produce values and can appear in statement position,
562/// as function arguments, in let initializers, etc.
563#[derive(Debug, Clone)]
564pub struct Expr {
565    /// The kind of expression.
566    pub kind: ExprKind,
567    /// Source span.
568    pub span: Span,
569}
570
571/// The kind of an expression.
572///
573/// CJC supports 35+ expression variants covering literals, operators,
574/// control flow, data constructors, and pattern matching.
575#[derive(Debug, Clone)]
576pub enum ExprKind {
577    /// Integer literal: `42`
578    IntLit(i64),
579    /// Float literal: `3.14`
580    FloatLit(f64),
581    /// String literal: `"hello"`
582    StringLit(String),
583    /// Byte string literal: `b"hello"` — produces ByteSlice
584    ByteStringLit(Vec<u8>),
585    /// Byte char literal: `b'A'` — produces u8
586    ByteCharLit(u8),
587    /// Raw string literal: `r"hello\n"` — produces String (no escape processing)
588    RawStringLit(String),
589    /// Raw byte string literal: `br"hello\n"` — produces ByteSlice (no escape processing)
590    RawByteStringLit(Vec<u8>),
591    /// Format string literal: `f"hello {name}!"` — desugared into concat at parse time.
592    /// Stored as alternating literal segments and expression strings to format.
593    /// Each segment: `(literal_text, Option<expr>)` — literal then optional interp.
594    FStringLit(Vec<(String, Option<Box<Expr>>)>),
595    /// Regex literal: `/pattern/flags` — produces Regex
596    RegexLit { pattern: String, flags: String },
597    /// Tensor literal: `[| 1.0, 2.0; 3.0, 4.0 |]` — produces Tensor
598    /// `rows` contains each row as a Vec of expressions.
599    /// A 1-D tensor has a single row. `;` separates rows for 2-D.
600    TensorLit { rows: Vec<Vec<Expr>> },
601    /// Bool literal: `true`, `false`
602    BoolLit(bool),
603    /// Missing value literal: `NA`
604    NaLit,
605    /// Identifier: `x`, `foo`
606    Ident(Ident),
607    /// Binary operation: `a + b`
608    Binary {
609        op: BinOp,
610        left: Box<Expr>,
611        right: Box<Expr>,
612    },
613    /// Unary operation: `-x`, `!b`
614    Unary {
615        op: UnaryOp,
616        operand: Box<Expr>,
617    },
618    /// Function/method call: `foo(a, b)`
619    Call {
620        callee: Box<Expr>,
621        args: Vec<CallArg>,
622    },
623    /// Field access / method access: `x.foo`
624    Field {
625        object: Box<Expr>,
626        name: Ident,
627    },
628    /// Index: `a[i]`
629    Index {
630        object: Box<Expr>,
631        index: Box<Expr>,
632    },
633    /// Multi-index: `a[i, j]`
634    MultiIndex {
635        object: Box<Expr>,
636        indices: Vec<Expr>,
637    },
638    /// Assignment: `x = expr`
639    Assign {
640        target: Box<Expr>,
641        value: Box<Expr>,
642    },
643    /// Compound assignment: `x += e`, `x -= e`, etc.
644    /// Desugars to `x = x op e` during evaluation.
645    CompoundAssign {
646        op: BinOp,
647        target: Box<Expr>,
648        value: Box<Expr>,
649    },
650    /// If expression: `if cond { a } else { b }` used as a value
651    IfExpr {
652        condition: Box<Expr>,
653        then_block: Block,
654        else_branch: Option<ElseBranch>,
655    },
656    /// Pipe: `a |> f(b)`
657    Pipe {
658        left: Box<Expr>,
659        right: Box<Expr>,
660    },
661    /// Block expression: `{ stmts; expr }`
662    Block(Block),
663    /// Struct literal: `Foo { x: 1, y: 2 }`
664    StructLit {
665        name: Ident,
666        fields: Vec<FieldInit>,
667    },
668    /// Array literal: `[1, 2, 3]`
669    ArrayLit(Vec<Expr>),
670    /// Column reference in data DSL: `col("name")`
671    Col(String),
672    /// Lambda expression: `|x, y| x + y`
673    Lambda {
674        params: Vec<Param>,
675        body: Box<Expr>,
676    },
677    /// Match expression: `match expr { pat => expr, ... }`
678    Match {
679        scrutinee: Box<Expr>,
680        arms: Vec<MatchArm>,
681    },
682    /// Tuple literal: `(a, b, c)`
683    TupleLit(Vec<Expr>),
684    /// Type cast expression: `x as f64`, `y as i64`
685    Cast {
686        expr: Box<Expr>,
687        target_type: Ident,
688    },
689    /// Try operator: `expr?` — desugars to match on Result
690    Try(Box<Expr>),
691    /// Enum variant constructor: `Some(42)` or `None`
692    VariantLit {
693        enum_name: Option<Ident>,
694        variant: Ident,
695        fields: Vec<Expr>,
696    },
697}
698
699// ── Match Arms & Patterns ───────────────────────────────────────
700
701/// A single arm of a match expression: `pattern => body`
702#[derive(Debug, Clone)]
703pub struct MatchArm {
704    pub pattern: Pattern,
705    pub body: Expr,
706    pub span: Span,
707}
708
709/// A pattern for use in match arms.
710#[derive(Debug, Clone)]
711pub struct Pattern {
712    pub kind: PatternKind,
713    pub span: Span,
714}
715
716#[derive(Debug, Clone)]
717pub enum PatternKind {
718    /// Wildcard pattern: `_`
719    Wildcard,
720    /// Binding pattern: `x` (binds the matched value to `x`)
721    Binding(Ident),
722    /// Literal pattern: `42`, `3.14`, `true`, `"hello"`
723    LitInt(i64),
724    LitFloat(f64),
725    LitBool(bool),
726    LitString(String),
727    /// Tuple destructuring: `(a, b, c)`
728    Tuple(Vec<Pattern>),
729    /// Struct destructuring: `Point { x, y }` or `Point { x: px, y: py }`
730    Struct {
731        name: Ident,
732        fields: Vec<PatternField>,
733    },
734    /// Enum variant pattern: `Some(x)`, `None`, `Ok(v)`, `Err(e)`
735    Variant {
736        /// Optional enum name qualification (not needed for prelude enums)
737        enum_name: Option<Ident>,
738        variant: Ident,
739        fields: Vec<Pattern>,
740    },
741}
742
743/// A field pattern inside a struct pattern: `x` or `x: pat`
744#[derive(Debug, Clone)]
745pub struct PatternField {
746    pub name: Ident,
747    pub pattern: Option<Pattern>,
748    pub span: Span,
749}
750
751/// A function call argument, optionally named.
752///
753/// Positional: `f(42)`. Named: `f(x: 42)`.
754#[derive(Debug, Clone)]
755pub struct CallArg {
756    /// Optional argument name for named/keyword arguments.
757    pub name: Option<Ident>,
758    /// The argument value expression.
759    pub value: Expr,
760    /// Source span.
761    pub span: Span,
762}
763
764/// A field initializer in a struct literal: `x: expr`.
765#[derive(Debug, Clone)]
766pub struct FieldInit {
767    /// Field name.
768    pub name: Ident,
769    /// Field value expression.
770    pub value: Expr,
771    /// Source span.
772    pub span: Span,
773}
774
775// ── Operators ───────────────────────────────────────────────────
776
777/// Binary operator.
778///
779/// Covers arithmetic, comparison, logical, bitwise, and regex-match operators.
780/// Displayed via [`fmt::Display`] as the source-level symbol (e.g., `+`, `==`).
781#[derive(Debug, Clone, Copy, PartialEq, Eq)]
782pub enum BinOp {
783    /// Addition: `+`
784    Add,
785    /// Subtraction: `-`
786    Sub,
787    /// Multiplication: `*`
788    Mul,
789    /// Division: `/`
790    Div,
791    /// Modulo: `%`
792    Mod,
793    /// Exponentiation: `**`
794    Pow,
795    /// Equality: `==`
796    Eq,
797    /// Inequality: `!=`
798    Ne,
799    /// Less than: `<`
800    Lt,
801    /// Greater than: `>`
802    Gt,
803    /// Less than or equal: `<=`
804    Le,
805    /// Greater than or equal: `>=`
806    Ge,
807    /// Logical and: `&&`
808    And,
809    /// Logical or: `||`
810    Or,
811    /// Regex match: `~=`
812    Match,
813    /// Negative regex match: `!~`
814    NotMatch,
815    /// Bitwise and: `&`
816    BitAnd,
817    /// Bitwise or: `|`
818    BitOr,
819    /// Bitwise xor: `^`
820    BitXor,
821    /// Left shift: `<<`
822    Shl,
823    /// Right shift: `>>`
824    Shr,
825}
826
827impl fmt::Display for BinOp {
828    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
829        match self {
830            BinOp::Add => write!(f, "+"),
831            BinOp::Sub => write!(f, "-"),
832            BinOp::Mul => write!(f, "*"),
833            BinOp::Div => write!(f, "/"),
834            BinOp::Mod => write!(f, "%"),
835            BinOp::Pow => write!(f, "**"),
836            BinOp::Eq => write!(f, "=="),
837            BinOp::Ne => write!(f, "!="),
838            BinOp::Lt => write!(f, "<"),
839            BinOp::Gt => write!(f, ">"),
840            BinOp::Le => write!(f, "<="),
841            BinOp::Ge => write!(f, ">="),
842            BinOp::And => write!(f, "&&"),
843            BinOp::Or => write!(f, "||"),
844            BinOp::Match => write!(f, "~="),
845            BinOp::NotMatch => write!(f, "!~"),
846            BinOp::BitAnd => write!(f, "&"),
847            BinOp::BitOr => write!(f, "|"),
848            BinOp::BitXor => write!(f, "^"),
849            BinOp::Shl => write!(f, "<<"),
850            BinOp::Shr => write!(f, ">>"),
851        }
852    }
853}
854
855/// Unary operator.
856///
857/// Displayed via [`fmt::Display`] as the source-level symbol.
858#[derive(Debug, Clone, Copy, PartialEq, Eq)]
859pub enum UnaryOp {
860    /// Arithmetic negation: `-x`
861    Neg,
862    /// Logical not: `!b`
863    Not,
864    /// Bitwise not: `~x`
865    BitNot,
866}
867
868impl fmt::Display for UnaryOp {
869    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
870        match self {
871            UnaryOp::Neg => write!(f, "-"),
872            UnaryOp::Not => write!(f, "!"),
873            UnaryOp::BitNot => write!(f, "~"),
874        }
875    }
876}
877
878// ── Identifier ──────────────────────────────────────────────────
879
880/// An identifier with its source span.
881///
882/// Used for variable names, function names, type names, field names, etc.
883#[derive(Debug, Clone, PartialEq, Eq, Hash)]
884pub struct Ident {
885    /// The identifier text.
886    pub name: String,
887    /// Source span where this identifier appears.
888    pub span: Span,
889}
890
891impl Ident {
892    /// Create a new identifier with an explicit source span.
893    pub fn new(name: impl Into<String>, span: Span) -> Self {
894        Self {
895            name: name.into(),
896            span,
897        }
898    }
899
900    /// Create a dummy identifier with a zero span, for use in tests and synthetic AST nodes.
901    pub fn dummy(name: impl Into<String>) -> Self {
902        Self {
903            name: name.into(),
904            span: Span::dummy(),
905        }
906    }
907}
908
909impl fmt::Display for Ident {
910    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
911        write!(f, "{}", self.name)
912    }
913}
914
915// ── Pretty Printer ──────────────────────────────────────────────
916
917/// Pretty-printer that converts an AST back into human-readable CJC source.
918///
919/// Produces deterministic, indented output suitable for debugging and
920/// round-trip verification.
921///
922/// # Examples
923///
924/// ```rust,ignore
925/// use cjc_ast::PrettyPrinter;
926///
927/// let source = PrettyPrinter::new().print_program(&program);
928/// println!("{}", source);
929/// ```
930pub struct PrettyPrinter {
931    indent: usize,
932    output: String,
933}
934
935impl PrettyPrinter {
936    /// Create a new pretty-printer with zero indentation.
937    pub fn new() -> Self {
938        Self {
939            indent: 0,
940            output: String::new(),
941        }
942    }
943
944    /// Consume the printer and return the pretty-printed source for an entire program.
945    ///
946    /// # Arguments
947    ///
948    /// * `program` - The AST program to pretty-print.
949    ///
950    /// # Returns
951    ///
952    /// A `String` containing the formatted CJC source code.
953    pub fn print_program(mut self, program: &Program) -> String {
954        for decl in &program.declarations {
955            self.print_decl(decl);
956            self.output.push('\n');
957        }
958        self.output
959    }
960
961    fn indent_str(&self) -> String {
962        "    ".repeat(self.indent)
963    }
964
965    fn print_decl(&mut self, decl: &Decl) {
966        match &decl.kind {
967            DeclKind::Struct(s) => self.print_struct(s),
968            DeclKind::Class(c) => self.print_class(c),
969            DeclKind::Record(r) => self.print_record(r),
970            DeclKind::Fn(f) => self.print_fn(f),
971            DeclKind::Trait(t) => self.print_trait(t),
972            DeclKind::Impl(i) => self.print_impl(i),
973            DeclKind::Enum(e) => self.print_enum(e),
974            DeclKind::Let(l) => {
975                self.output.push_str(&self.indent_str());
976                self.print_let(l);
977            }
978            DeclKind::Import(i) => self.print_import(i),
979            DeclKind::Const(c) => {
980                self.output.push_str(&self.indent_str());
981                self.output.push_str("const ");
982                self.output.push_str(&c.name.name);
983                self.output.push_str(": ");
984                self.print_type_expr(&c.ty);
985                self.output.push_str(" = ");
986                self.print_expr(&c.value);
987                self.output.push(';');
988            }
989            DeclKind::Stmt(s) => {
990                self.output.push_str(&self.indent_str());
991                self.print_stmt(s);
992            }
993        }
994    }
995
996    fn print_struct(&mut self, s: &StructDecl) {
997        self.output.push_str(&self.indent_str());
998        self.output.push_str(&format!("struct {}", s.name));
999        self.print_type_params(&s.type_params);
1000        self.output.push_str(" {\n");
1001        self.indent += 1;
1002        for field in &s.fields {
1003            self.output
1004                .push_str(&format!("{}{}: ", self.indent_str(), field.name));
1005            self.print_type_expr(&field.ty);
1006            self.output.push('\n');
1007        }
1008        self.indent -= 1;
1009        self.output.push_str(&format!("{}}}", self.indent_str()));
1010    }
1011
1012    fn print_class(&mut self, c: &ClassDecl) {
1013        self.output.push_str(&self.indent_str());
1014        self.output.push_str(&format!("class {}", c.name));
1015        self.print_type_params(&c.type_params);
1016        self.output.push_str(" {\n");
1017        self.indent += 1;
1018        for field in &c.fields {
1019            self.output
1020                .push_str(&format!("{}{}: ", self.indent_str(), field.name));
1021            self.print_type_expr(&field.ty);
1022            self.output.push('\n');
1023        }
1024        self.indent -= 1;
1025        self.output.push_str(&format!("{}}}", self.indent_str()));
1026    }
1027
1028    fn print_record(&mut self, r: &RecordDecl) {
1029        self.output.push_str(&self.indent_str());
1030        self.output.push_str(&format!("record {}", r.name));
1031        self.print_type_params(&r.type_params);
1032        self.output.push_str(" {\n");
1033        self.indent += 1;
1034        for field in &r.fields {
1035            self.output
1036                .push_str(&format!("{}{}: ", self.indent_str(), field.name));
1037            self.print_type_expr(&field.ty);
1038            self.output.push('\n');
1039        }
1040        self.indent -= 1;
1041        self.output.push_str(&format!("{}}}", self.indent_str()));
1042    }
1043
1044    fn print_fn(&mut self, f: &FnDecl) {
1045        self.output.push_str(&self.indent_str());
1046        if f.is_nogc {
1047            self.output.push_str("nogc ");
1048        }
1049        self.output.push_str(&format!("fn {}", f.name));
1050        self.print_type_params(&f.type_params);
1051        self.output.push('(');
1052        for (i, param) in f.params.iter().enumerate() {
1053            if i > 0 {
1054                self.output.push_str(", ");
1055            }
1056            if param.is_variadic {
1057                self.output.push_str("...");
1058            }
1059            self.output.push_str(&format!("{}: ", param.name));
1060            self.print_type_expr(&param.ty);
1061        }
1062        self.output.push(')');
1063        if let Some(ref ret) = f.return_type {
1064            self.output.push_str(" -> ");
1065            self.print_type_expr(ret);
1066        }
1067        self.output.push(' ');
1068        self.print_block(&f.body);
1069    }
1070
1071    fn print_trait(&mut self, t: &TraitDecl) {
1072        self.output.push_str(&self.indent_str());
1073        self.output.push_str(&format!("trait {}", t.name));
1074        self.print_type_params(&t.type_params);
1075        if !t.super_traits.is_empty() {
1076            self.output.push_str(": ");
1077            for (i, st) in t.super_traits.iter().enumerate() {
1078                if i > 0 {
1079                    self.output.push_str(" + ");
1080                }
1081                self.print_type_expr(st);
1082            }
1083        }
1084        self.output.push_str(" {\n");
1085        self.indent += 1;
1086        for method in &t.methods {
1087            self.output.push_str(&self.indent_str());
1088            self.output.push_str(&format!("fn {}", method.name));
1089            self.print_type_params(&method.type_params);
1090            self.output.push('(');
1091            for (i, p) in method.params.iter().enumerate() {
1092                if i > 0 {
1093                    self.output.push_str(", ");
1094                }
1095                self.output.push_str(&format!("{}: ", p.name));
1096                self.print_type_expr(&p.ty);
1097            }
1098            self.output.push(')');
1099            if let Some(ref ret) = method.return_type {
1100                self.output.push_str(" -> ");
1101                self.print_type_expr(ret);
1102            }
1103            self.output.push_str(";\n");
1104        }
1105        self.indent -= 1;
1106        self.output.push_str(&format!("{}}}", self.indent_str()));
1107    }
1108
1109    fn print_impl(&mut self, i: &ImplDecl) {
1110        self.output.push_str(&self.indent_str());
1111        self.output.push_str("impl");
1112        self.print_type_params(&i.type_params);
1113        self.output.push(' ');
1114        self.print_type_expr(&i.target);
1115        if let Some(ref tr) = i.trait_ref {
1116            self.output.push_str(" : ");
1117            self.print_type_expr(tr);
1118        }
1119        self.output.push_str(" {\n");
1120        self.indent += 1;
1121        for method in &i.methods {
1122            self.print_fn(method);
1123            self.output.push('\n');
1124        }
1125        self.indent -= 1;
1126        self.output.push_str(&format!("{}}}", self.indent_str()));
1127    }
1128
1129    fn print_import(&mut self, i: &ImportDecl) {
1130        self.output.push_str(&self.indent_str());
1131        self.output.push_str("import ");
1132        let path: Vec<&str> = i.path.iter().map(|id| id.name.as_str()).collect();
1133        self.output.push_str(&path.join("."));
1134        if let Some(ref alias) = i.alias {
1135            self.output.push_str(&format!(" as {}", alias));
1136        }
1137    }
1138
1139    fn print_enum(&mut self, e: &EnumDecl) {
1140        self.output.push_str(&self.indent_str());
1141        self.output.push_str(&format!("enum {}", e.name));
1142        self.print_type_params(&e.type_params);
1143        self.output.push_str(" {\n");
1144        self.indent += 1;
1145        for variant in &e.variants {
1146            self.output.push_str(&self.indent_str());
1147            self.output.push_str(&variant.name.name);
1148            if !variant.fields.is_empty() {
1149                self.output.push('(');
1150                for (i, f) in variant.fields.iter().enumerate() {
1151                    if i > 0 {
1152                        self.output.push_str(", ");
1153                    }
1154                    self.print_type_expr(f);
1155                }
1156                self.output.push(')');
1157            }
1158            self.output.push_str(",\n");
1159        }
1160        self.indent -= 1;
1161        self.output.push_str(&format!("{}}}", self.indent_str()));
1162    }
1163
1164    fn print_type_params(&mut self, params: &[TypeParam]) {
1165        if params.is_empty() {
1166            return;
1167        }
1168        self.output.push('<');
1169        for (i, param) in params.iter().enumerate() {
1170            if i > 0 {
1171                self.output.push_str(", ");
1172            }
1173            self.output.push_str(&param.name.name);
1174            if !param.bounds.is_empty() {
1175                self.output.push_str(": ");
1176                for (j, bound) in param.bounds.iter().enumerate() {
1177                    if j > 0 {
1178                        self.output.push_str(" + ");
1179                    }
1180                    self.print_type_expr(bound);
1181                }
1182            }
1183        }
1184        self.output.push('>');
1185    }
1186
1187    fn print_type_expr(&mut self, ty: &TypeExpr) {
1188        match &ty.kind {
1189            TypeExprKind::Named { name, args } => {
1190                self.output.push_str(&name.name);
1191                if !args.is_empty() {
1192                    self.output.push('<');
1193                    for (i, arg) in args.iter().enumerate() {
1194                        if i > 0 {
1195                            self.output.push_str(", ");
1196                        }
1197                        match arg {
1198                            TypeArg::Type(t) => self.print_type_expr(t),
1199                            TypeArg::Expr(e) => self.print_expr(e),
1200                            TypeArg::Shape(dims) => self.print_shape(dims),
1201                        }
1202                    }
1203                    self.output.push('>');
1204                }
1205            }
1206            TypeExprKind::Array { elem, size } => {
1207                self.output.push('[');
1208                self.print_type_expr(elem);
1209                self.output.push_str("; ");
1210                self.print_expr(size);
1211                self.output.push(']');
1212            }
1213            TypeExprKind::Tuple(elems) => {
1214                self.output.push('(');
1215                for (i, elem) in elems.iter().enumerate() {
1216                    if i > 0 {
1217                        self.output.push_str(", ");
1218                    }
1219                    self.print_type_expr(elem);
1220                }
1221                self.output.push(')');
1222            }
1223            TypeExprKind::Fn { params, ret } => {
1224                self.output.push_str("fn(");
1225                for (i, p) in params.iter().enumerate() {
1226                    if i > 0 {
1227                        self.output.push_str(", ");
1228                    }
1229                    self.print_type_expr(p);
1230                }
1231                self.output.push_str(") -> ");
1232                self.print_type_expr(ret);
1233            }
1234            TypeExprKind::ShapeLit(dims) => {
1235                self.print_shape(dims);
1236            }
1237        }
1238    }
1239
1240    fn print_shape(&mut self, dims: &[ShapeDim]) {
1241        self.output.push('[');
1242        for (i, dim) in dims.iter().enumerate() {
1243            if i > 0 {
1244                self.output.push_str(", ");
1245            }
1246            match dim {
1247                ShapeDim::Name(n) => self.output.push_str(&n.name),
1248                ShapeDim::Lit(v) => self.output.push_str(&v.to_string()),
1249            }
1250        }
1251        self.output.push(']');
1252    }
1253
1254    fn print_block(&mut self, block: &Block) {
1255        self.output.push_str("{\n");
1256        self.indent += 1;
1257        for stmt in &block.stmts {
1258            self.print_stmt(stmt);
1259        }
1260        if let Some(ref expr) = block.expr {
1261            self.output.push_str(&self.indent_str());
1262            self.print_expr(expr);
1263            self.output.push('\n');
1264        }
1265        self.indent -= 1;
1266        self.output.push_str(&format!("{}}}", self.indent_str()));
1267    }
1268
1269    fn print_stmt(&mut self, stmt: &Stmt) {
1270        match &stmt.kind {
1271            StmtKind::Let(l) => {
1272                self.output.push_str(&self.indent_str());
1273                self.print_let(l);
1274            }
1275            StmtKind::Expr(e) => {
1276                self.output.push_str(&self.indent_str());
1277                self.print_expr(e);
1278                self.output.push_str(";\n");
1279            }
1280            StmtKind::Return(e) => {
1281                self.output.push_str(&self.indent_str());
1282                self.output.push_str("return");
1283                if let Some(expr) = e {
1284                    self.output.push(' ');
1285                    self.print_expr(expr);
1286                }
1287                self.output.push_str(";\n");
1288            }
1289            StmtKind::Break => {
1290                self.output.push_str(&self.indent_str());
1291                self.output.push_str("break;\n");
1292            }
1293            StmtKind::Continue => {
1294                self.output.push_str(&self.indent_str());
1295                self.output.push_str("continue;\n");
1296            }
1297            StmtKind::If(if_stmt) => {
1298                self.output.push_str(&self.indent_str());
1299                self.print_if(if_stmt);
1300                self.output.push('\n');
1301            }
1302            StmtKind::While(w) => {
1303                self.output.push_str(&self.indent_str());
1304                self.output.push_str("while ");
1305                self.print_expr(&w.condition);
1306                self.output.push(' ');
1307                self.print_block(&w.body);
1308                self.output.push('\n');
1309            }
1310            StmtKind::For(f) => {
1311                self.output.push_str(&self.indent_str());
1312                self.output.push_str("for ");
1313                self.output.push_str(&f.ident.name);
1314                self.output.push_str(" in ");
1315                match &f.iter {
1316                    ForIter::Range { start, end } => {
1317                        self.print_expr(start);
1318                        self.output.push_str("..");
1319                        self.print_expr(end);
1320                    }
1321                    ForIter::Expr(expr) => {
1322                        self.print_expr(expr);
1323                    }
1324                }
1325                self.output.push(' ');
1326                self.print_block(&f.body);
1327                self.output.push('\n');
1328            }
1329            StmtKind::NoGcBlock(block) => {
1330                self.output.push_str(&self.indent_str());
1331                self.output.push_str("nogc ");
1332                self.print_block(block);
1333                self.output.push('\n');
1334            }
1335        }
1336    }
1337
1338    fn print_let(&mut self, l: &LetStmt) {
1339        self.output.push_str("let ");
1340        if l.mutable {
1341            self.output.push_str("mut ");
1342        }
1343        self.output.push_str(&l.name.name);
1344        if let Some(ref ty) = l.ty {
1345            self.output.push_str(": ");
1346            self.print_type_expr(ty);
1347        }
1348        self.output.push_str(" = ");
1349        self.print_expr(&l.init);
1350        self.output.push_str(";\n");
1351    }
1352
1353    fn print_if(&mut self, if_stmt: &IfStmt) {
1354        self.output.push_str("if ");
1355        self.print_expr(&if_stmt.condition);
1356        self.output.push(' ');
1357        self.print_block(&if_stmt.then_block);
1358        if let Some(ref else_branch) = if_stmt.else_branch {
1359            self.output.push_str(" else ");
1360            match else_branch {
1361                ElseBranch::ElseIf(elif) => self.print_if(elif),
1362                ElseBranch::Else(block) => self.print_block(block),
1363            }
1364        }
1365    }
1366
1367    fn print_expr(&mut self, expr: &Expr) {
1368        match &expr.kind {
1369            ExprKind::IntLit(v) => self.output.push_str(&v.to_string()),
1370            ExprKind::FloatLit(v) => {
1371                let s = v.to_string();
1372                self.output.push_str(&s);
1373                if !s.contains('.') {
1374                    self.output.push_str(".0");
1375                }
1376            }
1377            ExprKind::StringLit(s) => {
1378                self.output.push('"');
1379                self.output.push_str(s);
1380                self.output.push('"');
1381            }
1382            ExprKind::ByteStringLit(bytes) => {
1383                self.output.push_str("b\"");
1384                for &b in bytes {
1385                    if b.is_ascii_graphic() || b == b' ' {
1386                        self.output.push(b as char);
1387                    } else {
1388                        self.output.push_str(&format!("\\x{:02x}", b));
1389                    }
1390                }
1391                self.output.push('"');
1392            }
1393            ExprKind::ByteCharLit(b) => {
1394                self.output.push_str(&format!("b'\\x{:02x}'", b));
1395            }
1396            ExprKind::RawStringLit(s) => {
1397                self.output.push_str("r\"");
1398                self.output.push_str(s);
1399                self.output.push('"');
1400            }
1401            ExprKind::RawByteStringLit(bytes) => {
1402                self.output.push_str("br\"");
1403                for &b in bytes {
1404                    self.output.push(b as char);
1405                }
1406                self.output.push('"');
1407            }
1408            ExprKind::FStringLit(segments) => {
1409                // Pretty-print as f"..."
1410                self.output.push_str("f\"");
1411                for (lit, interp) in segments {
1412                    self.output.push_str(&lit.replace('"', "\\\""));
1413                    if let Some(expr) = interp {
1414                        self.output.push('{');
1415                        self.print_expr(expr);
1416                        self.output.push('}');
1417                    }
1418                }
1419                self.output.push('"');
1420            }
1421            ExprKind::RegexLit { pattern, flags } => {
1422                self.output.push('/');
1423                self.output.push_str(pattern);
1424                self.output.push('/');
1425                self.output.push_str(flags);
1426            }
1427            ExprKind::TensorLit { rows } => {
1428                self.output.push_str("[| ");
1429                for (ri, row) in rows.iter().enumerate() {
1430                    if ri > 0 {
1431                        self.output.push_str("; ");
1432                    }
1433                    for (ci, expr) in row.iter().enumerate() {
1434                        if ci > 0 {
1435                            self.output.push_str(", ");
1436                        }
1437                        self.print_expr(expr);
1438                    }
1439                }
1440                self.output.push_str(" |]");
1441            }
1442            ExprKind::BoolLit(b) => self.output.push_str(if *b { "true" } else { "false" }),
1443            ExprKind::NaLit => self.output.push_str("NA"),
1444            ExprKind::Ident(id) => self.output.push_str(&id.name),
1445            ExprKind::Binary { op, left, right } => {
1446                self.output.push('(');
1447                self.print_expr(left);
1448                self.output.push_str(&format!(" {} ", op));
1449                self.print_expr(right);
1450                self.output.push(')');
1451            }
1452            ExprKind::Unary { op, operand } => {
1453                self.output.push_str(&format!("{}", op));
1454                self.print_expr(operand);
1455            }
1456            ExprKind::Call { callee, args } => {
1457                self.print_expr(callee);
1458                self.output.push('(');
1459                for (i, arg) in args.iter().enumerate() {
1460                    if i > 0 {
1461                        self.output.push_str(", ");
1462                    }
1463                    if let Some(ref name) = arg.name {
1464                        self.output.push_str(&format!("{}: ", name));
1465                    }
1466                    self.print_expr(&arg.value);
1467                }
1468                self.output.push(')');
1469            }
1470            ExprKind::Field { object, name } => {
1471                self.print_expr(object);
1472                self.output.push('.');
1473                self.output.push_str(&name.name);
1474            }
1475            ExprKind::Index { object, index } => {
1476                self.print_expr(object);
1477                self.output.push('[');
1478                self.print_expr(index);
1479                self.output.push(']');
1480            }
1481            ExprKind::MultiIndex { object, indices } => {
1482                self.print_expr(object);
1483                self.output.push('[');
1484                for (i, idx) in indices.iter().enumerate() {
1485                    if i > 0 {
1486                        self.output.push_str(", ");
1487                    }
1488                    self.print_expr(idx);
1489                }
1490                self.output.push(']');
1491            }
1492            ExprKind::Assign { target, value } => {
1493                self.print_expr(target);
1494                self.output.push_str(" = ");
1495                self.print_expr(value);
1496            }
1497            ExprKind::CompoundAssign { op, target, value } => {
1498                self.print_expr(target);
1499                self.output.push_str(&format!(" {}= ", op));
1500                self.print_expr(value);
1501            }
1502            ExprKind::IfExpr { condition, then_block, else_branch } => {
1503                self.output.push_str("if ");
1504                self.print_expr(condition);
1505                self.output.push_str(" ");
1506                self.print_block(then_block);
1507                if let Some(eb) = else_branch {
1508                    self.output.push_str(" else ");
1509                    match eb {
1510                        ElseBranch::ElseIf(elif) => {
1511                            // Print as if statement
1512                            self.output.push_str("if ...");
1513                        }
1514                        ElseBranch::Else(block) => {
1515                            self.print_block(block);
1516                        }
1517                    }
1518                }
1519            }
1520            ExprKind::Pipe { left, right } => {
1521                self.print_expr(left);
1522                self.output.push_str(" |> ");
1523                self.print_expr(right);
1524            }
1525            ExprKind::Block(block) => {
1526                self.print_block(block);
1527            }
1528            ExprKind::StructLit { name, fields } => {
1529                self.output.push_str(&format!("{} {{ ", name));
1530                for (i, field) in fields.iter().enumerate() {
1531                    if i > 0 {
1532                        self.output.push_str(", ");
1533                    }
1534                    self.output.push_str(&format!("{}: ", field.name));
1535                    self.print_expr(&field.value);
1536                }
1537                self.output.push_str(" }");
1538            }
1539            ExprKind::ArrayLit(elems) => {
1540                self.output.push('[');
1541                for (i, elem) in elems.iter().enumerate() {
1542                    if i > 0 {
1543                        self.output.push_str(", ");
1544                    }
1545                    self.print_expr(elem);
1546                }
1547                self.output.push(']');
1548            }
1549            ExprKind::Col(name) => {
1550                self.output.push_str(&format!("col(\"{}\")", name));
1551            }
1552            ExprKind::Lambda { params, body } => {
1553                self.output.push('|');
1554                for (i, p) in params.iter().enumerate() {
1555                    if i > 0 {
1556                        self.output.push_str(", ");
1557                    }
1558                    self.output.push_str(&format!("{}: ", p.name));
1559                    self.print_type_expr(&p.ty);
1560                }
1561                self.output.push_str("| ");
1562                self.print_expr(body);
1563            }
1564            ExprKind::Match { scrutinee, arms } => {
1565                self.output.push_str("match ");
1566                self.print_expr(scrutinee);
1567                self.output.push_str(" {\n");
1568                self.indent += 1;
1569                for arm in arms {
1570                    self.output.push_str(&self.indent_str());
1571                    self.print_pattern(&arm.pattern);
1572                    self.output.push_str(" => ");
1573                    self.print_expr(&arm.body);
1574                    self.output.push_str(",\n");
1575                }
1576                self.indent -= 1;
1577                self.output.push_str(&format!("{}}}", self.indent_str()));
1578            }
1579            ExprKind::TupleLit(elems) => {
1580                self.output.push('(');
1581                for (i, elem) in elems.iter().enumerate() {
1582                    if i > 0 {
1583                        self.output.push_str(", ");
1584                    }
1585                    self.print_expr(elem);
1586                }
1587                self.output.push(')');
1588            }
1589            ExprKind::Try(inner) => {
1590                self.print_expr(inner);
1591                self.output.push('?');
1592            }
1593            ExprKind::VariantLit {
1594                enum_name,
1595                variant,
1596                fields,
1597            } => {
1598                if let Some(ref en) = enum_name {
1599                    self.output.push_str(&en.name);
1600                    self.output.push_str("::");
1601                }
1602                self.output.push_str(&variant.name);
1603                if !fields.is_empty() {
1604                    self.output.push('(');
1605                    for (i, f) in fields.iter().enumerate() {
1606                        if i > 0 {
1607                            self.output.push_str(", ");
1608                        }
1609                        self.print_expr(f);
1610                    }
1611                    self.output.push(')');
1612                }
1613            }
1614            ExprKind::Cast { expr, target_type } => {
1615                self.print_expr(expr);
1616                self.output.push_str(" as ");
1617                self.output.push_str(&target_type.name);
1618            }
1619        }
1620    }
1621
1622    fn print_pattern(&mut self, pattern: &Pattern) {
1623        match &pattern.kind {
1624            PatternKind::Wildcard => self.output.push('_'),
1625            PatternKind::Binding(id) => self.output.push_str(&id.name),
1626            PatternKind::LitInt(v) => self.output.push_str(&v.to_string()),
1627            PatternKind::LitFloat(v) => self.output.push_str(&v.to_string()),
1628            PatternKind::LitBool(b) => {
1629                self.output.push_str(if *b { "true" } else { "false" })
1630            }
1631            PatternKind::LitString(s) => {
1632                self.output.push('"');
1633                self.output.push_str(s);
1634                self.output.push('"');
1635            }
1636            PatternKind::Tuple(pats) => {
1637                self.output.push('(');
1638                for (i, p) in pats.iter().enumerate() {
1639                    if i > 0 {
1640                        self.output.push_str(", ");
1641                    }
1642                    self.print_pattern(p);
1643                }
1644                self.output.push(')');
1645            }
1646            PatternKind::Struct { name, fields } => {
1647                self.output.push_str(&name.name);
1648                self.output.push_str(" { ");
1649                for (i, f) in fields.iter().enumerate() {
1650                    if i > 0 {
1651                        self.output.push_str(", ");
1652                    }
1653                    self.output.push_str(&f.name.name);
1654                    if let Some(ref pat) = f.pattern {
1655                        self.output.push_str(": ");
1656                        self.print_pattern(pat);
1657                    }
1658                }
1659                self.output.push_str(" }");
1660            }
1661            PatternKind::Variant {
1662                enum_name,
1663                variant,
1664                fields,
1665            } => {
1666                if let Some(ref en) = enum_name {
1667                    self.output.push_str(&en.name);
1668                    self.output.push_str("::");
1669                }
1670                self.output.push_str(&variant.name);
1671                if !fields.is_empty() {
1672                    self.output.push('(');
1673                    for (i, p) in fields.iter().enumerate() {
1674                        if i > 0 {
1675                            self.output.push_str(", ");
1676                        }
1677                        self.print_pattern(p);
1678                    }
1679                    self.output.push(')');
1680                }
1681            }
1682        }
1683    }
1684}
1685
1686impl Default for PrettyPrinter {
1687    fn default() -> Self {
1688        Self::new()
1689    }
1690}