Library

toolchain/ast

The shape of written Vader, as data.

3 files lib/toolchain/ast/ast.vader, lib/toolchain/ast/vaderdoc.vader, lib/toolchain/ast/walk.vader 146 exports

The public contract a build-time metaprogram reads. It lives outside vader/ because of what depends on it: a library shipping a generator must be able to walk declarations without depending on the compiler, and this module needs nothing from the compiler either: only toolchain/span, for where each node came from. Everything that INTERPRETS these nodes (resolve, typecheck, lower) stays in vader/.

It is the tree AS WRITTEN, before resolution: an IdentExpr("Id") is the name the author typed, not the type it denotes. A generator that needs to know whether that name is a primitive, an alias, an imported struct or a distinct newtype cannot answer it from here, see the note on resolved declarations in the TODO's toolchain item.

Layout note : declaration order is free, the resolver collects every decl name in a first pass before walking types in the second, so a union alias can sit before or after the variant structs it lists. Type-bearing fields are renamed ty (since type was historically a keyword) ; the dumper emits the JSON key as "type" so snapshots stay stable.

Types

Decl :: ImportDecl | FnDecl | StructDecl | EnumDecl | TraitDecl | ImplDecl | TypeAliasDecl | ConstDecl | AssertDecl

Anything that can appear at the top level of a file.

ImportBinding :: NamedNamespaceImport | DestructureImport | WildcardImport

What an import binds: a namespace alias, a modifier list, or nothing.

The three forms of SPEC §Modules: X :: import "p", import "p" { a as b }, and the bare import "p" wildcard.

ForForm :: InfiniteFor | WhileFor | InFor

Which of the three for shapes a loop is: for {}, for cond {}, for x in xs {}.

StringLitPart :: StringLitText | StringLitInterp

One piece of a string literal: literal text, or an interpolated expression.

IfElse :: IfElseIf | IfElseBlock

What follows an else: another if branch, or a final block.

Pattern :: IsPattern | StructPattern | WildcardPattern | EnumVariantPattern | LiteralPattern | RangePattern | OrPattern

Anything that can appear on the left of a match arm's ->.

LetBinding :: SimpleBinding | TupleBinding | WildcardBinding | RestBinding

What a :: / := binds: one name, a tuple destructure, _, or a rest binding.

AssignTarget :: PlaceTarget | WildcardTarget | RestTarget

One element of a [...] = value assignment: a place, _, or a ...rest tail.

PatternFieldValue :: PatternBinding | PatternLiteral

Inside a struct pattern, what a field is matched against: a binding or a literal.

CoalesceFallback :: Expr | ReturnStmt | BreakStmt | ContinueStmt

Right operand of ?? (null-coalescing). Either an ordinary value expression (must be assignable to the non-null result type) or a divergent statement (return / break / continue, typed never). The divergent forms are statements (not Expr variants) so they are carried here directly rather than through the Expr union.

TypeExpr :: IntLitExpr | FloatLitExpr | BoolLitExpr | NullLitExpr | CharLitExpr | StringLitExpr | IdentExpr | CallExpr | FieldExpr | IndexExpr | UnaryExpr | BinaryExpr | NullCoalesceExpr | IfExpr | MatchExpr | BlockExpr | LambdaExpr | StructLitExpr | SeqLitExpr | RangeExpr | CastExpr | GenericInstExpr | IntrinsicCallExpr | DotVariantExpr | FnTypeExpr | ArrayTypeExpr | AwaitExpr

A type AS WRITTEN: the same node set as Expr, deliberately.

Vader's type grammar is a subset of its expression grammar (i32, Foo<T>, A | B, fn(i32) -> bool, T[]), so the parser reuses the expression nodes rather than duplicating them. What counts as a type expression is decided by POSITION (the slot demanding a type) never by node shape; the alias exists to say so at each slot (StructField.ty: TypeExpr).

A reader must not assume an IdentExpr in type position denotes a type it can name: Id may be an alias, an imported struct or a distinct newtype, and only the resolver knows which.

Visibility :: enum

Whether a declaration carries export.

Variants

Public
No description.
Private
No description.
Program :: struct

One parsed source file.

module is null for a file with no module "..." header: an error the resolver reports rather than the parser.

Fields

file: string
No description.
span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
module: ModuleDecl | null = null

The module "..." declaration. Null when absent: the parser is tolerant ; the resolver's scan emits R2020 on absence.

decls: Decl[]
No description.
ModuleDecl :: struct

The module "<name>" decl that opens every .vader file. Carries the validated module name + its source span (the module keyword itself lives in the node's overall span).

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
name: string
No description.
name_span: Span
No description.
TypeParam :: struct

One entry of a [T: Bound = Default] list.

is_comptime_value marks a parameter that carries a VALUE rather than a type ([N: i64]), which the comptime engine substitutes.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
name: string
No description.
bound: TypeExpr | null
No description.
default: TypeExpr | null = null

Default type for this parameter, from <T = Default>. Honored when an impl supplies fewer trait-args than the trait declares: the trailing params fill from their defaults at impl materialization (front/resolver/materialize.vader::build_subst). Defaults on struct / fn / alias params parse but are not yet filled at their use sites (those instantiations error rather than default). null = no default.

is_comptime_value: bool
No description.
Decorator :: struct

An @name or @name(args) above a declaration.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
name: string
No description.
args: Expr[]
No description.
ImportDecl :: struct

An import statement, whatever its form, see ImportBinding.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
path: string
No description.
binding: ImportBinding
No description.
decorators: Decorator[]
No description.
NamedNamespaceImport :: struct

name :: import "...": namespace binding ; members reached via name.X.

Fields

name: string
No description.
DestructureImport :: struct

import "p" { x as y, z as _ }: a WILDCARD of p plus per-name modifiers: every listed source name is dropped from the wildcard ; x as y also rebinds it as y, z as _ is a pure exclusion. A plain name (no as) is an error (R2033): the wildcard already brings every export.

Fields

names: ImportName[]
No description.
trailing_comma: bool = false

True when the source wrote a trailing comma before }. Drives the formatter's Dart-style layout: present -> one name per line.

WildcardImport :: struct

bare import "...", wildcard : every function of the module becomes callable (prefix + UFCS) ; binds no name.

ImportName :: struct

One name or name as alias inside an import's modifier list.

alias is null for a bare name, which is R2033: a wildcard already brings it.

Fields

name: string
No description.
alias: string | null
No description.
span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
FnDecl :: struct

A function declaration, name :: fn(...) -> T { ... }.

Four flags mark functions the user did not write. sam_synthetic is a single-abstract-method lambda the parser desugared into an impl member; materialized a member declared for an impl from its trait (one it inherits, inherits, or an intrinsic stub); comptime_synthetic a declaration the comptime engine produced. And is_expression_bodied distinguishes f :: fn() = expr from a braced body, which the formatter needs and a generator emitting source should preserve.

Each is a plain bool defaulting to false, never bool | null (Vader has no optional fields) and the dumper emits one only when true.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
name: string
No description.
name_span: Span
No description.
visibility: Visibility
No description.
type_params: TypeParam[]
No description.
params: FnParam[]
No description.
return_type: TypeExpr | null
No description.
body: BlockExpr | null
No description.
decorators: Decorator[]
No description.
sam_synthetic: bool
No description.
is_expression_bodied: bool
No description.
materialized: bool

true when this FnDecl was declared for an impl from its trait rather than written in it : a member the impl inherits (inherits), or a stub of an @intrinsic impl.

comptime_synthetic: bool = false

true when this FnDecl is the __comptime_NAME helper the parser synthesises for the NAME :: @comptime <expr> const sugar (see desugar_comptime_const). The formatter skips it: the surface sugar is re-emitted from the paired ConstDecl.comptime_body instead. Defaults false : only the desugar sets it, every other constructor leaves it off.

trailing_comma: bool = false

True when the source wrote a trailing comma after the last parameter. Drives the formatter's Dart-style layout: present -> one param per line.

doc: DocComment | null = null
No description.
inherits: FnDecl | null = null

For a member an impl inherits from its trait, the trait's member whose default body it runs: the body was checked once in the trait, and is lowered for each impl from there. Null for any other function.

FnParam :: struct

One parameter of a function, lambda or trait method.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
name: string
No description.
name_span: Span

The name alone, where span covers the whole slot, decorators, a variadic ..., the type and the default included : what a rename rewrites. span stays the parameter's identity, the key of the side tables.

ty: TypeExpr | null
No description.
default_value: Expr | null
No description.
variadic: bool
No description.
decorators: Decorator[]

Decorators written before the parameter (@c_pointer tv: TimeVal).

StructDecl :: struct

A struct declaration, Name :: struct { ... }.

The node a generator walks most: fields in declaration order, each carrying its written type. name_span covers the name alone, which is what a diagnostic about the struct itself should point at.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
name: string
No description.
name_span: Span
No description.
visibility: Visibility
No description.
type_params: TypeParam[]
No description.
fields: StructField[]
No description.
decorators: Decorator[]
No description.
doc: DocComment | null = null
No description.
StructField :: struct

One field of a struct.

visibility is @internal: fields are public by default, so this is the opt-out. default backs T {} construction with the field omitted.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
name: string
No description.
ty: TypeExpr
No description.
visibility: Visibility
No description.
default: Expr | null
No description.
doc: DocComment | null = null
No description.
EnumDecl :: struct

An enum declaration, Name :: enum(u8) { A, B } or Name :: enum(Info) { A { .f = 1 } }.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
name: string
No description.
name_span: Span
No description.
visibility: Visibility
No description.
header: TypeExpr[]

The parenthesised header as written : empty, (width), (data) or (data, width). Which role a lone argument plays depends on what it resolves to, so the typechecker decides, not the parser.

variants: EnumVariant[]
No description.
decorators: Decorator[]
No description.
doc: DocComment | null = null
No description.
EnumVariant :: struct

One variant of an enum, with its explicit value when the source gave one.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
name: string
No description.
value: i64 | null
No description.
value_span: Span | null
No description.
data: StructLitItem[] | null = null

The { .f = v } block as written, checked against the header's data type ; null when the variant has none.

doc: DocComment | null = null
No description.
TraitDecl :: struct

A trait declaration.

members are its methods, each an FnDecl; one with a body is a default method.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
name: string
No description.
name_span: Span
No description.
visibility: Visibility
No description.
type_params: TypeParam[]
No description.
requires: TypeExpr | null

The supertrait bound, for either form: Numeric :: trait<T> = Add & Sub (alias form, members empty) or Hashable :: trait<T> : Hash & Eq { … } (methods plus composition). A parsed type expression: typically a BinaryExpr(.BitAnd) chain over trait names, though a single trait reference is valid too. null for a plain trait { … }.

members: FnDecl[]
No description.
decorators: Decorator[]
No description.
doc: DocComment | null = null
No description.
ImplDecl :: struct

An implements block, or its one-method short form.

for_type is the implementing type as written, trait_name the trait, which is a bare string rather than a node because a trait is always named, never computed.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
type_params: TypeParam[]
No description.
for_type: TypeExpr
No description.
trait_name: string
No description.
trait_name_span: Span
No description.
trait_args: TypeExpr[]
No description.
members: FnDecl[]
No description.
decorators: Decorator[]
No description.
doc: DocComment | null = null
No description.
TypeAliasDecl :: struct

A type alias, Name :: SomeType.

A generator resolving a written type must expect to meet one of these: the alias and its target are indistinguishable in an IdentExpr.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
name: string
No description.
name_span: Span
No description.
visibility: Visibility
No description.
type_params: TypeParam[]
No description.
aliased: TypeExpr
No description.
decorators: Decorator[]
No description.
doc: DocComment | null = null
No description.
ConstDecl :: struct

A module-level constant, NAME :: value or the typed NAME: T: value.

comptime_body holds the unevaluated expression for a @comptime const, whose value is filled in by the comptime engine.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
name: string
No description.
name_span: Span
No description.
visibility: Visibility
No description.
ty: TypeExpr | null
No description.
value: Expr
No description.
decorators: Decorator[]
No description.
comptime_body: Expr | null = null

The value a @comptime const was written with, when the parser gave it a __comptime_NAME helper to call (through_comptime_helper) : the formatter re-emits it rather than the call. Non-null marks such a const ; null for every other const. Holds the raw block/expression (pre-return- lift), so the exact source spelling round-trips.

comptime_as_decorator: bool = false

True when @comptime decorated the const (@comptime above NAME :: v) rather than following :: ; read with comptime_body.

doc: DocComment | null = null
No description.
AssertDecl :: struct

An @assert at the top level: a build-time invariant.

condition is evaluated by the comptime VM and the build fails with C4015 when it is false. Nothing is emitted at runtime.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
condition: Expr
No description.
message: string | null
No description.
message_span: Span | null

Where the message literal is written, so it prints in its own spelling.

decorators: Decorator[]
No description.
LetStmt :: struct

A local binding, x :: e or x := e.

mutable is the := form. Style treats a := that is never reassigned as a defect, so a generator should emit :: unless it writes to the slot.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
mutable: bool
No description.
binding: LetBinding
No description.
ty: TypeExpr | null
No description.
value: Expr
No description.
SimpleBinding :: struct

A local bound to one name: a leaf of the recursive binding tree, whose other leaf is WildcardBinding (ignores the slot) and whose only branch is TupleBinding (matches a tuple-typed value element-wise).

name_span covers the name alone: the precise target a rename needs, which the whole-binding span is too wide for.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
name: string
No description.
name_span: Span
No description.
TupleBinding :: struct

A destructuring local, [a, b] :: pair.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
elements: LetBinding[]
No description.
WildcardBinding :: struct

A discarded local, _ :: e.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
RestBinding :: struct

The ...rest tail of a destructuring local: collects every slot its sibling SimpleBindings did not consume into a fresh array.

Valid only as the LAST element of a TupleBinding whose source is array-typed.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
name: string
No description.
name_span: Span
No description.
DestructureAssignStmt :: struct

An assignment to several existing places at once, [a, b] = pair.

Not an AssignStmt over a literal target: its elements are not expressions, _ and ...rest only mean something here.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
targets: AssignTarget[]
No description.
value: Expr
No description.
PlaceTarget :: struct

A place written by a destructuring assignment: a name, a field or an index.

Any expression parses here; the typechecker refuses what is not a place.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
place: Expr
No description.
WildcardTarget :: struct

A discarded element of a destructuring assignment, _.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
RestTarget :: struct

The ...rest tail of a destructuring assignment: writes a fresh array of every element its siblings did not consume into place.

Valid only as the LAST target, over an array-typed source.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
place: Expr
No description.
AssignStmt :: struct

An assignment to an existing place, target = value.

lhs op= rhs parses to one too : value is lhs op rhs over the SAME lhs node as target, which compound_assign_op recognises.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
target: Expr
No description.
value: Expr
No description.
ExprStmt :: struct

An expression evaluated for its effect, its value discarded.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
expr: Expr
No description.
ReturnStmt :: struct

A return, with no value for a void function.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
value: Expr | null
No description.
YieldStmt :: struct

yield expr inside a generator fn body: emit one element and suspend. Always carries a value (unlike return, which may be bare); the empty / exhausted case is a bare return or falling off the end. value must coerce to the T of the generator's -> Iterator<T> return.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
value: Expr
No description.
ForStmt :: struct

A loop in any of its three forms, see ForForm.

label is the loop-jump target of break <label> / continue <label>.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
label: string | null
No description.
form: ForForm
No description.
body: BlockExpr
No description.
is_comptime: bool = false

@comptime for x in <arr> { … }: unroll at lower time. False for every other form.

InfiniteFor :: struct

The for { ... } form: no condition, exited by break or return.

WhileFor :: struct

The for cond { ... } form.

Fields

cond: Expr
No description.
InFor :: struct

The for x in xs { ... } form.

Fields

loop_var: LoopVar
No description.
iter: Expr
No description.
LoopVar :: NamedVar | DestructureVar | DiscardVar

The loop variable of a for … in …. A union so the mutually exclusive shapes can't be miscombined and no sentinel / span-geometry heuristic is needed downstream: each pass matches on the variant. Kept structural on the AST (not desugared at parse) so vader fmt round-trips every sugar.

NamedVar :: struct

for x in …, and the explicit discard for _ in coll (name == "_").

Fields

name: string
No description.
span: Span
No description.
DestructureVar :: struct

for [k, v] in …: the leaves bind against the iterable's element type.

Fields

pattern: LetBinding
No description.
DiscardVar :: struct

for <range>: no user variable is written (the iterable is the range itself). Also the lower-synthesised varless for <coll> (while→for sugar).

BreakStmt :: struct

A break, optionally naming the loop to leave.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
label: string | null
No description.
ContinueStmt :: struct

A continue, optionally naming the loop to resume.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
label: string | null
No description.
DeferStmt :: struct

A defer, running its body when the enclosing scope exits.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
body: DeferBody
No description.
DeferStmtBody :: struct

A defer deferring one statement.

Fields

stmt: Stmt
No description.
DeferBlockBody :: struct

A defer deferring a block.

Fields

block: BlockExpr
No description.
Stmt :: LetStmt | AssignStmt | DestructureAssignStmt | ExprStmt | ReturnStmt | YieldStmt | ForStmt | BreakStmt | ContinueStmt | DeferStmt

Anything that can appear as a statement in a block.

Declared AFTER its variant structs, as DeferBody is: the resolver collects every decl name before resolving types, so either order works and this one reads top-down.

DeferBody :: DeferStmtBody | DeferBlockBody

What a defer defers: one statement, or a block.

IntLitExpr :: struct

An integer literal.

Stored as u64 whatever the written base. The literal is FREE (it adopts the surrounding concrete numeric type) so its node carries no width.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
value: u64

Unsigned magnitude, full u64 range (the snapshot format renders the value as a decimal string with the trailing n so 0..u64.MAX all round-trip losslessly).

negative: bool = false

A - written against the literal: the parser reads -5 as one value, so -128 is checked as the least i8 rather than as the negation of a 128 no i8 holds, and -5.to_string() is "-5". -(5) and - 5 stay negations.

FloatLitExpr :: struct

A float literal.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
value: f64

Signed as written: the parser reads a - against the literal into it (IntLitExpr.negative).

BoolLitExpr :: struct

true or false.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
value: bool
No description.
NullLitExpr :: struct

The null literal.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
CharLitExpr :: struct

A character literal, stored as its codepoint.

Free like an integer literal: in an integer context it coerces to that width carrying the codepoint.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
value: u32
No description.
StringLitExpr :: struct

A string literal, as the sequence of its parts.

Always a part list, even with no interpolation, so a reader never has to handle two shapes. A generator emitting source must re-escape $, which opens an interpolation.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
parts: StringLitPart[]
No description.
StringLitText :: struct

A run of literal text inside a string literal.

Fields

value: string
No description.
span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
StringLitInterp :: struct

An interpolated ${...} inside a string literal.

Fields

expr: Expr
No description.
span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
IdentExpr :: struct

A bare name, in value or type position.

implicit_dot marks the leading-dot spelling (.Variant), where resolution defers to the surrounding context. is_type_param_intro marks a dollar-prefixed name introducing a type parameter rather than referring to one.

Both are plain bools defaulting to false, and the dumper emits their JSON keys (implicitDot / isTypeParamIntro) only when true.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
name: string
No description.
implicit_dot: bool
No description.
is_type_param_intro: bool
No description.
CallExpr :: struct

A call, callee(args).

callee is an arbitrary expression, so this covers f(x), a.f(x) (whose callee is a FieldExpr) and P.f(x) alike: UFCS is not distinguished here.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
callee: Expr
No description.
type_args: TypeExpr[] = []

The type arguments written on the call (f<i64>(x), x.f<i64>(y)) : the callee's type parameters, first ones first. Empty when the call infers them.

args: CallArg[]
No description.
trailing_comma: bool = false

Source wrote a trailing comma before ): formatter keeps it exploded.

CallArg :: struct

One argument of a call.

name is set for a named argument, spread for the ...xs form.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
name: string | null
No description.
value: Expr
No description.
spread: bool

Reserved for argument-spread f(...xs), not parsed yet, so always false today. The consumers (printer / dump / ufcs) already honour it so the feature only needs parse_call_args to set it.

FieldExpr :: struct

A member access, target.field.

is_numeric marks a tuple index (t.0), whose "field" is a position.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
target: Expr
No description.
field: string
No description.
field_span: Span
No description.
is_numeric: bool
No description.
IndexExpr :: struct

An index, target[index].

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
target: Expr
No description.
index: Expr
No description.
UnaryOp :: enum(u8)

Which prefix operator a UnaryExpr applies.

Variants

Neg
No description.
Not
No description.
BitNot
No description.
UnaryExpr :: struct

A prefix operator applied to one operand.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
op: UnaryOp
No description.
operand: Expr
No description.
BinaryOp :: enum(u8)

Which infix operator a BinaryExpr applies.

Variants

Add
No description.
Sub
No description.
Mul
No description.
Div
No description.
Mod
No description.
Shl
No description.
Shr
No description.
BitAnd
No description.
BitOr
No description.
BitXor
No description.
And
No description.
Or
No description.
Eq
No description.
Neq
No description.
Lt
No description.
Lte
No description.
Gt
No description.
Gte
No description.
Is
No description.
In
No description.
NotIn
No description.
Same

=== / !== : the same object, not an equal value.

NotSame
No description.
AddWrap

+% / -% / *% : integer arithmetic that wraps around its width.

SubWrap
No description.
MulWrap
No description.
BinaryExpr :: struct

An infix operator applied to two operands.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
op: BinaryOp
No description.
left: Expr
No description.
right: Expr
No description.
NullCoalesceExpr :: struct

Null-coalescing left ?? fallback. left must be typed T | null ; the expression yields T (null subtracted). fallback supplies the value when left is null : either a value expression assignable to T, or a divergent statement (return / break / continue, typed never). Lowers to _t :: left ; if _t is null { fallback } else { _t }, so the existing narrowing engine refines the result to T.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
left: Expr
No description.
fallback: CoalesceFallback
No description.
IfExpr :: struct

An if, in statement or value position.

One node for both: in value position the blocks' trailing expressions are the result, so a generator emitting a conditional value writes this.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
cond: Expr
No description.
then_block: BlockExpr
No description.
else_branch: IfElse | null
No description.
IfElseIf :: struct

An else if, holding the next branch.

Fields

branch: IfExpr
No description.
IfElseBlock :: struct

A final else block.

Fields

block: BlockExpr
No description.
MatchExpr :: struct

A match over a scrutinee.

partial is @partial: the match is knowingly non-exhaustive; unreachable is @unreachable: the uncovered variants are impossible and trap if reached.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
scrutinee: Expr
No description.
arms: MatchArm[]
No description.
partial: bool
No description.
unreachable: bool = false
No description.
binding: SimpleBinding | null = null

match x :: e { … }: the name the scrutinee is bound to, visible in every arm and guard and narrowed by each arm. Its name_span is the declaration the resolver mints the symbol at.

MatchArm :: struct

One arm of a match, with its optional if guard.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
pattern: Pattern
No description.
guard: Expr | null
No description.
body: Expr
No description.
BlockExpr :: struct

A braced block.

trailing is the block's value when it ends in an expression rather than a statement, which is what makes a block usable in value position.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
stmts: Stmt[]
No description.
trailing: Expr | null
No description.
LambdaExpr :: struct

A lambda, (x: i32) -> x + 1.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
params: FnParam[]
No description.
return_type: TypeExpr | null
No description.
body: BlockExpr
No description.
trailing_comma: bool = false

True when the source wrote a trailing comma after the last parameter.

StructLitExpr :: struct

A struct literal, Point { .x = 1 }.

items mixes fields and spreads in SOURCE order, which a generator must preserve: a later field overrides an earlier spread.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
type_name: TypeExpr
No description.
items: (StructLitField | StructLitSpread)[]
No description.
trailing_comma: bool = false

True when the source wrote a trailing comma before }. The formatter reads it as a "keep exploded" directive (Dart-style block layout).

StructLitItem :: StructLitField | StructLitSpread

One entry of a struct literal: a field, or a spread.

StructLitField :: struct

A .name = value entry of a struct literal.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
name: string
No description.
name_span: Span
No description.
value: Expr
No description.
StructLitSpread :: struct

A ...expr entry of a struct literal.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
expr: Expr
No description.
SeqLitExpr :: struct

An array or tuple literal, [a, b, c].

One node for both: the parser does not commit to array or tuple, and the typechecker decides from context.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
elements: Expr[]
No description.
trailing_comma: bool = false

True when the source wrote a trailing comma before ]. Drives the formatter's Dart-style layout: present -> one element per line.

RangeExpr :: struct

A range, a..<b or a..=b.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
inclusive: bool
No description.
lower: Expr
No description.
upper: Expr
No description.
AwaitExpr :: struct

await e: suspend the enclosing async fn until e's async result is ready, then produce it. A single-operand prefix wrapper; carries no error semantics of its own.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
inner: Expr
No description.
CastExpr :: struct

An explicit conversion, T(value).

Only a genuine width or representation change needs one: a free literal adopts its context, so a cast around one is a style defect.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
target: TypeExpr
No description.
value: Expr
No description.
GenericInstExpr :: struct

A generic type with its arguments written, Box<i32> : in a type, as a struct literal's name, as the owner of a static member call (Bag<T>.make()). A call's own type arguments are CallExpr.type_args.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
callee: Expr
No description.
type_args: TypeExpr[]
No description.
IntrinsicCallExpr :: struct

A call to a compiler intrinsic: @size_of(T), @type_name(T).

name is the intrinsic ident WITHOUT the leading @. The recognised set lives in vader/front/parser/intrinsics.vader, and the parser mints this node only for a known name: an unknown @name(...) in expression position raises P1014.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
name: string
No description.
name_span: Span
No description.
args: Expr[]
No description.
trailing_comma: bool = false
No description.
DotVariantExpr :: struct

A bare .Variant, whose enum type comes from context.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
variant: string
No description.
variant_span: Span
No description.
IsPattern :: struct

A type test in a pattern, is T. inner nests a further pattern.

Binds nothing: the arm reads the scrutinee, narrowed in place, or the name the match header gives it (MatchExpr.binding).

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
ty: TypeExpr
No description.
inner: Pattern | null
No description.
StructPattern :: struct

A struct destructuring pattern.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
fields: StructPatternField[]
No description.
StructPatternField :: struct

One field of a struct pattern.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
name: string
No description.
name_span: Span
No description.
value: PatternFieldValue
No description.
PatternBinding :: struct

A struct-pattern field bound to a name.

Fields

name: string
No description.
span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
PatternLiteral :: struct

A struct-pattern field matched against a literal.

Fields

value: Expr
No description.
WildcardPattern :: struct

The _ pattern.

On a closed union this silences the exhaustiveness check, which is why the style guide forbids it in value position there.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
EnumVariantPattern :: struct

A pattern matching one enum variant, .Variant.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
variant: string
No description.
LiteralPattern :: struct

Match a literal value : 'a' -> …, 42 -> …, "ok" -> …, etc. The inner value is the parsed literal as an Expr ; the lowerer emits scrutinee == value as the arm predicate.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
value: Expr
No description.
RangePattern :: struct

Range pattern : 'a'..='z' -> …, 0..<10 -> …. Matches when a scalar scrutinee falls in the range. inclusive = ..= (upper bound included), else ..< (excluded). The bounds are literal scalar exprs (char / int) of the scrutinee's type ; the lowerer emits scrutinee >= lower && scrutinee <(=) upper. Binds nothing, and (like a literal pattern over an open scalar domain) exhausts nothing.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
inclusive: bool
No description.
lower: Expr
No description.
upper: Expr
No description.
OrPattern :: struct

Or-pattern : .A | .B -> …, 1 | 2 | 3 -> …. Matches when ANY alternative matches. Parsed from pipe-separated patterns in a match arm. The is A | B form does NOT produce this: there the type parser folds A | B into a single union IsPattern (equivalent narrowing + exhaustiveness). The alternatives are value-level (enum variants / literals) and bind nothing.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
patterns: Pattern[]
No description.
FnTypeExpr :: struct

A function type as written, fn(i32) -> bool: type-only, with no value-side counterpart.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
params: TypeExpr[]
No description.
return_type: TypeExpr | null
No description.
ArrayTypeExpr :: struct

An array type as written, T[]: type-only.

The bracketed form [T1, T2] parses as a SeqLitExpr (tuple type) instead.

Fields

span: Span
No description.
id: i64 = UNASSIGNED_NODE_ID
No description.
element: TypeExpr
No description.
DocComment :: struct

The /// lines written right above a declaration, a struct field or an enum variant: its vaderdoc.

Only a parse that asks for docs fills one (parse_source_with_docs in vader/front/parser): the parse_source a build runs leaves every doc null, so a build pays nothing for comments it never reads. A plain // or /* */ comment between the lines and the declaration detaches them; blank lines do not.

Fields

lines: DocCommentLine[]

One per /// line, in source order. Never empty.

DocCommentLine :: struct

One /// line of a DocComment.

Fields

text: string

What follows the three slashes, as written: the space after them included.

span: Span

The whole comment, slashes included.

DocSections :: struct

A vaderdoc split by its tags.

Fields

prose: string

The lines outside every tag, as written, trimmed of the blank lines around them: CommonMark.

params: DocParam[]

One per @param, in source order.

returns: string[]

One text per @return.

errors: string[]

One text per @error.

example: string[]

The lines under @example, as written: indented, hidden ones included.

DocParam :: struct

What one @param says.

Fields

name: string

The parameter it names (doc_param_name).

text: string

The rest, its continuation lines joined; "" when the name stands alone.

ExampleLine :: struct

A line of an example, as a reader sees it.

Fields

text: string

The line without the indentation the shown lines share, and without the # of a hidden line.

hidden: bool = false

Whether the line sets the example up: a reader sees it only in the whole example.

Node :: Decl | Expr | Stmt | Pattern

Any node inspect hands its visitor: a declaration, an expression (a type expression included, TypeExpr being the same union), a statement or a pattern.

Walk :: enum

What the visitor of inspect answers for the node it was handed.

Variants

Descend

Visit the node's children next.

Skip

Leave the node's children out, and go on with the rest of the walk.

Stop

End the whole walk.

Functions

coalesce_fallback_expr :: fn(f: CoalesceFallback) -> Expr | null

The value expression a read-only expression walker should descend into for a ?? fallback : the fallback expression itself, the value of a return <expr>, or null for a bare return / break / continue. Passes that also need to visit the statement node itself (id assignment, typecheck, formatting) destructure CoalesceFallback directly instead.

Parameters

fCoalesceFallback No description.

Returns

Expr | null
assign_places :: fn(s: DestructureAssignStmt) -> Expr[]

The places a destructuring assignment writes, in order: every target but _.

For the walkers that visit a statement's sub-expressions and have no use for each element's kind.

Parameters

sDestructureAssignStmt No description.

Returns

Expr[]
decorators_have :: fn(decs: Decorator[], name: string) -> bool

Whether decs carries the decorator called name.

Here rather than in each pass: six modules open-coded this loop, and a decorator's presence is a question about the AST, which is what this module owns.

Parameters

decsDecorator[] the declaration's decorators.
namestring the decorator name, without the @.

Returns

bool
find_decorator :: fn(decs: Decorator[], name: string) -> Decorator | null

The decorator called name among decs, the first when several are.

Parameters

decsDecorator[] the declaration's decorators.
namestring the decorator name, without the @.

Returns

Decorator | null
c_type_of :: fn(decs: Decorator[]) -> string

The C type a @c_type("…") among decs names, or "" when none does or its argument is not one plain string.

Parameters

decsDecorator[] the decorators of an @extern declaration or of one parameter.

Returns

string
extern_symbol_of :: fn(decl: FnDecl) -> string

The C symbol an @extern declaration binds: the last argument of its @extern (@extern("c_name"), @extern(LIBRARY, "c_name")), else the name the declaration declares.

Parameters

declFnDecl the bodyless function declaration.

Returns

string
c_header_of :: fn(decl: FnDecl) -> string

The header an @extern declaration's own @c_header names, verbatim with its brackets, or "" when it carries none.

Parameters

declFnDecl the bodyless function declaration.

Returns

string
extern_header :: fn(decl: FnDecl, library: CLibrary | null) -> string

The header that owns the prototype of an @extern declaration: its own @c_header, else the header of the library it names. "" when none does.

The backend INCLUDES that header instead of synthesising a prototype: the header already has the real one, and a synthesised one that differs is a conflicting declaration the C compiler refuses outright.

Parameters

declFnDecl the bodyless function declaration.
libraryCLibrary | null the CLibrary it names, as evaluated ; null for none.

Returns

string
c_struct_spelling :: fn(decs: Decorator[], struct_name: string) -> string

The C type a struct declaration mirrors, or "" when it carries no @c_struct.

A bare @c_struct names the C type after the struct, read as a typedef name: Color mirrors Color. The argument spells a C type whose name differs (@c_struct("struct pollfd")). An argument that is not one plain string reads as ""; the parser reports it (P1032, P1033).

Parameters

decsDecorator[] the struct's decorators.
struct_namestring the name the struct declares, never its mangled form.

Returns

string
decl_name_span :: fn(decl: Decl) -> Span | null

The span of the name decl declares.

Parameters

declDecl a declaration.

Returns

Span | null null for an impl, an assert or an import, which declare no name.
decl_decorators :: fn(decl: Decl) -> Decorator[]

The decorators written above decl.

Parameters

declDecl a declaration.

Returns

decl_is_public :: fn(decl: Decl) -> bool

Whether decl carries export.

Parameters

declDecl a declaration.

Returns

bool false for an impl, an assert or an import, which take no export.
body_source :: fn(fd: FnDecl) -> FnDecl

The declaration whose body fd runs: for a member an impl inherits, the trait's member (inherits), whose default body it is ; fd itself otherwise. A reader of a member's body goes through it, or sees an inherited member as bodyless.

Parameters

fdFnDecl a function declaration.

Returns

compound_assign_op :: fn(s: AssignStmt) -> BinaryOp | null

The operator of a compound assignment lhs op= rhs, or null for a plain one.

target and value.left are one node, so they carry one span ; a hand-written a = a + 1 reads an a of its own, at another position. A pass that evaluates lhs's operands once, or prints the op= back, keys on this, and a pass that copies an assignment keeps the two sides one node.

Parameters

sAssignStmt the assignment.

Returns

BinaryOp | null the arithmetic operator the op= spells, or null.
is_arith_op :: fn(op: BinaryOp) -> bool

Whether op is an arithmetic operator a compound assignment spells : + - * / %, and the wrapping +% -% *%.

Parameters

opBinaryOp the operator.

Returns

bool
int_literal_value :: fn(literal: IntLitExpr) -> i64

The value of an integer literal as an i64: a magnitude past i64 as its bits, the least i64 from its magnitude 2^63.

Parameters

literalIntLitExpr the literal.

Returns

i64
int_literal_text :: fn(literal: IntLitExpr) -> string

An integer literal in decimal, signed as written: -128, 300.

Parameters

literalIntLitExpr the literal.

Returns

string
string_literal_text :: fn(e: Expr) -> string | null

The text of e when it is a string literal of one run of text, with no interpolation: what a name spelled out at build time reads (@field(x, "n")).

Parameters

eExpr any expression.

Returns

string | null null for anything else, an interpolation included.
binary_op_symbol :: fn(op: BinaryOp) -> string

The operator as the source spells it, "+" for Add : what a diagnostic quotes and the formatter prints.

Parameters

opBinaryOp the operator.

Returns

string
unary_op_symbol :: fn(op: UnaryOp) -> string

The operator as the source spells it, "-" for Neg.

Parameters

opUnaryOp the operator.

Returns

string
collect_bitor_variants :: fn(e: Expr) -> Expr[]

Flatten a T | U | V | … BitOr BinaryExpr chain into its variant list, in source order. Non-BitOr expressions are returned as a single-element list. Used by vader/tools/fmt and vader/front/typecheck to avoid hand-rolling the same recursion on each side.

Parameters

eExpr No description.

Returns

Expr[]
doc_text :: fn(doc: DocComment | null) -> string

The text of doc: its lines joined by \n, each without its /// and the one space that usually follows.

Parameters

docDocComment | null a vaderdoc block, or null for none.

Returns

string "" for null.
decl_doc :: fn(decl: Decl) -> DocComment | null

The vaderdoc written above decl.

Parameters

declDecl a declaration.

Returns

DocComment | null null when it has none, when the parse did not keep docs, and for an import or an assert, which take none.
doc_sections :: fn(text: string) -> DocSections

Split the vaderdoc text by its tags.

A tag opens a line and runs until the next tag or a blank line: the lines under it join its text, wherever they are indented. A non-tag line after a blank one is prose again. @example runs to the end, and text on its own line is the example's first line.

Parameters

textstring a vaderdoc, as doc_text gives it.

Returns

Example

expand
import "std/io"
import "toolchain/ast"
s :: doc_sections("Add.\n\n@param a  the first.\n@return the sum.")
println(s.params[0].name + ": " + s.returns[0])
s :: doc_sections("Add.\n\n@param a  the first.\n@return the sum.")
println(s.params[0].name + ": " + s.returns[0])
doc_tag :: fn(line: string) -> string

The vaderdoc tag line opens, or "": @param, @return, @error or @example, followed by a blank or the end of the line, so @params opens none.

Parameters

linestring a doc line, past its /// and its leading blanks.

Returns

string
doc_param_name :: fn(rest: string) -> string

The parameter a @param names: the identifier its text opens with, "" when it opens with none.

Parameters

reststring the text after the tag, past its blanks.

Returns

string
shown_example :: fn(sections: DocSections) -> string

The example of sections as a reader sees it: without the lines that open with # , which set it up so that it compiles, and without the indentation the shown lines share.

Parameters

sectionsDocSections a split vaderdoc.

Returns

string "" without an example.
example_lines :: fn(sections: DocSections) -> ExampleLine[]

The lines of the example of sections, hidden ones included, without the blank lines around them.

Parameters

sectionsDocSections a split vaderdoc.

Returns

ExampleLine[] none without an example.
inspect :: fn(n: Node, visit: fn(Node) -> Walk) -> bool

Walk n and every node under it, root first, children in source order.

Every child is reached: type positions (a parameter's type, a cast's target, an is pattern's type), decorator arguments, lambda and defer bodies, the statement a ?? falls back to. A node shared with another field is reached once: the place of a compound assignment x op= y is the left operand of its value, and a @comptime const leaves its comptime_body and its type to the helper fn the parser synthesised, which holds both. What is not a node (a binding, a field name) is for the visitor to read on the node that carries it.

Parameters

nNode the root.
visitfn(Node) -> Walk called on every node reached ; its answer steers the walk.

Returns

bool true when the visitor answered Stop.

Example

names: string[]: []
inspect(decl, (n) -> {
    if n is IdentExpr {
        names.push(n.name)
    }
    return .Descend
})

Constants

UNASSIGNED_NODE_ID: i64: 0

Sentinel id on a node the parser has just minted.

Node ids are assigned in a later pass (vader/front/parser::assign_program_ids), which replaces this with a fresh unique value (≥ 1), so a freshly parsed tree carries the sentinel everywhere. A generator reading a typechecked tree sees real ids; one building nodes by hand leaves them at the default: it is every node's .id default, so a construction may omit the field.

Written by vader doc. Icons: Codicons, CC BY 4.0. Fonts: Atkinson Hyperlegible, JetBrains Mono, OFL.