Skip to content

v2.ast

Constants #

const empty_expr = Expr(EmptyExpr(0))
const empty_stmt = Stmt(EmptyStmt(0))
const invalid_flat_node_id = FlatNodeId(-1)
const flag_is_public = u8(1) << 0

flag bit positions used by FlatNode.flags. Bits are reused per variant; see add_* helpers below for the exact mapping.

const flag_is_mut = u8(1) << 1
const flag_is_method = u8(1) << 2
const flag_is_static = u8(1) << 3
const flag_is_union = u8(1) << 4
const flag_is_gated = u8(1) << 5
const flag_is_aliased = u8(1) << 6 // ImportStmt
const flag_defer_func = u8(1) << 7 // DeferStmt.mode == .function
const flag_field_is_module_mut = u8(1) << 2 // FieldDecl (reuse method bit)
const flag_field_is_interface_method = u8(1) << 3 // FieldDecl (reuse static bit)
const flag_is_count = u8(1) << 6 // SqlExpr (reuse aliased bit)
const flag_is_create = u8(1) << 7 // SqlExpr (reuse defer bit)

fn arena_caps_for_bytes #

fn arena_caps_for_bytes(total_bytes i64) (int, int, int)

arena_caps_for_bytes returns (nodes_cap, edges_cap, strings_cap) sized from total source-byte estimate. Calibrated against the v2 self-host parse: ~150 nodes/KB, ~170 edges/KB, ~5 unique strings/KB. Floors match the default seed caps so tiny inputs don't waste arena space.

fn count_legacy_nodes #

fn count_legacy_nodes(files []File) int

count_legacy_nodes returns the total legacy node count used by the walker.

fn flatten_files #

fn flatten_files(files []File) FlatAst

flatten_files converts recursive v2 AST files into a flat, index-based graph.

fn legacy_ast_stats #

fn legacy_ast_stats(files []File) LegacyAstStats

legacy_ast_stats estimates dynamic memory and node counts for the recursive AST.

fn new_flat_builder #

fn new_flat_builder() FlatBuilder

new_flat_builder returns a fresh FlatBuilder seeded with reasonable arena capacities. Callers may resize after measuring (b.flat.nodes.grow_cap, ...).

fn new_flat_builder_with_capacity #

fn new_flat_builder_with_capacity(nodes_cap int, edges_cap int, strings_cap int) FlatBuilder

new_flat_builder_with_capacity lets callers pre-size the three arenas up front when an estimate is available (e.g. derived from total source size). Empirically the v2 self-host produces ~150 nodes/KB, ~165 edges/KB and ~5 unique strings/KB; supplying tight caps avoids the geometric realloc churn that dominates the streaming parse path.

fn DeferMode.from #

fn DeferMode.from[W](input W) !DeferMode

fn FlatNodeKind.from #

fn FlatNodeKind.from[W](input W) !FlatNodeKind

fn Language.from #

fn Language.from[W](input W) !Language

fn StringInterFormat.from #

fn StringInterFormat.from[W](input W) !StringInterFormat

fn StringInterFormat.from_u8 #

fn StringInterFormat.from_u8(c u8) StringInterFormat

fn StringLiteralKind.from #

fn StringLiteralKind.from[W](input W) !StringLiteralKind

fn StringLiteralKind.from_string_tinyv #

fn StringLiteralKind.from_string_tinyv(s string) StringLiteralKind

Todo: allow overriding this method in main v compilerthat is why this method was renamed from from_string

type Expr #

type Expr = ArrayInitExpr
	| AsCastExpr
	| AssocExpr
	| BasicLiteral
	| CallExpr
	| CallOrCastExpr
	| CastExpr
	| ComptimeExpr
	| EmptyExpr
	| FieldInit
	| FnLiteral
	| GenericArgOrIndexExpr
	| GenericArgs
	| Ident
	| IfExpr
	| IfGuardExpr
	| IndexExpr
	| InfixExpr
	| InitExpr
	| Keyword
	| KeywordOperator
	| LambdaExpr
	| LifetimeExpr
	| LockExpr
	| MapInitExpr
	| MatchExpr
	| ModifierExpr
	| OrExpr
	| ParenExpr
	| PostfixExpr
	| PrefixExpr
	| RangeExpr
	| SelectExpr
	| SelectorExpr
	| SqlExpr
	| StringInterLiteral
	| StringLiteral
	| Tuple
	| Type
	| UnsafeExpr

fn (Expr) name #

fn (expr Expr) name() string

Todo: fix this, should be only what is needed

fn (Expr) pos #

fn (expr Expr) pos() token.Pos

type FlatNodeId #

type FlatNodeId = int

FlatAst is a contiguous, index-based AST representation. Every node lives in a single nodes[] table; relationships are encoded via edges[] ranges instead of heap-allocated sumtype payloads. The schema is designed to be LOSSLESS: every field of every legacy AST variant is preserved either as a kind-specific bit/enum in the cell, or as a child node reachable through edges. token.Pos is stored inline (8 bytes) per node to preserve diagnostics without an extra interning layer.

type Stmt #

type Stmt = AsmStmt
	| AssertStmt
	| AssignStmt
	| BlockStmt
	| ComptimeStmt
	| ConstDecl
	| DeferStmt
	| Directive
	| EmptyStmt
	| EnumDecl
	| ExprStmt
	| FlowControlStmt
	| FnDecl
	| ForInStmt
	| ForStmt
	| GlobalDecl
	| ImportStmt
	| InterfaceDecl
	| LabelStmt
	| ModuleStmt
	| ReturnStmt
	| StructDecl
	| TypeDecl
	| []Attribute

Todo: decide if this going to be done like this (FieldInit)

type Type #

type Type = AnonStructType
	| ArrayFixedType
	| ArrayType
	| ChannelType
	| FnType
	| GenericType
	| MapType
	| NilType
	| NoneType
	| OptionType
	| PointerType
	| ResultType
	| ThreadType
	| TupleType

Todo: (re)implement nested sumtype like TS (was removed from v)currently need to cast to type in parser.type. Should I leave like this or add these directly to Expr until nesting is implemented?

fn (Type) name #

fn (t Type) name() string

fn ([]Attribute) has #

fn (attributes []Attribute) has(name string) bool

fn ([]Expr) name_list #

fn (exprs []Expr) name_list() string

enum DeferMode #

enum DeferMode {
	scoped   // default: defer to end of current scope
	function // defer(fn): defer to end of function
}

enum FlatNodeKind #

enum FlatNodeKind {
	file
	stmt_asm
	stmt_assert
	stmt_assign
	stmt_block
	stmt_comptime
	stmt_const_decl
	stmt_defer
	stmt_directive
	stmt_empty
	stmt_enum_decl
	stmt_expr
	stmt_flow_control
	stmt_fn_decl
	stmt_for_in
	stmt_for
	stmt_global_decl
	stmt_import
	stmt_interface_decl
	stmt_label
	stmt_module
	stmt_return
	stmt_struct_decl
	stmt_type_decl
	stmt_attributes
	expr_array_init
	expr_as_cast
	expr_assoc
	expr_basic_literal
	expr_call
	expr_call_or_cast
	expr_cast
	expr_comptime
	expr_empty
	expr_fn_literal
	expr_generic_arg_or_index
	expr_generic_args
	expr_ident
	expr_if
	expr_if_guard
	expr_index
	expr_infix
	expr_init
	expr_keyword
	expr_keyword_operator
	expr_lambda
	expr_lifetime
	expr_lock
	expr_map_init
	expr_match
	expr_modifier
	expr_or
	expr_paren
	expr_postfix
	expr_prefix
	expr_range
	expr_select
	expr_selector
	expr_sql
	expr_string_inter
	expr_string
	expr_tuple
	expr_unsafe
	typ_anon_struct
	typ_array_fixed
	typ_array
	typ_channel
	typ_fn
	typ_generic
	typ_map
	typ_nil
	typ_none
	typ_option
	typ_pointer
	typ_result
	typ_thread
	typ_tuple
	aux_attribute
	aux_field_init
	aux_field_decl
	aux_parameter
	aux_match_branch
	aux_string_inter
	aux_list   // ordered list grouping: edges are the items
	aux_string // single interned string carrier (used where a node needs an extra string slot)
	aux_int    // single integer carrier (used where a node needs an extra int slot)
}

FlatNodeKind is a dense tag for every stored AST node variant.

enum Language #

enum Language {
	v
	c
	js
}

fn (Language) str #

fn (lang Language) str() string

enum StringInterFormat #

enum StringInterFormat {
	unformatted
	binary
	character
	decimal
	exponent
	exponent_short
	float
	hex
	octal
	pointer_address
	string
}

fn (StringInterFormat) str #

fn (sif StringInterFormat) str() string

enum StringLiteralKind #

enum StringLiteralKind {
	c
	js
	raw
	v
}

fn (StringLiteralKind) str #

fn (s StringLiteralKind) str() string

struct AnonStructType #

struct AnonStructType {
pub:
	generic_params []Expr
	embedded       []Expr
	fields         []FieldDecl
}

pub fn (expr Expr) str() string { return match expr { Ident { expr.name } SelectorExpr { expr.lhs.str() + '.' + expr.rhs.name } else { 'missing Expr.str() for ${expr.type_name()}' // expr.str() } } }

struct ArrayFixedType #

struct ArrayFixedType {
pub:
	len       Expr = empty_expr
	elem_type Expr = empty_expr
}

struct ArrayInitExpr #

struct ArrayInitExpr {
pub mut:
	typ         Expr = empty_expr
	exprs       []Expr
	init        Expr = empty_expr
	cap         Expr = empty_expr
	len         Expr = empty_expr
	update_expr Expr = empty_expr // `a` in `[...a, 3, 4]`
	pos         token.Pos
}

Expressions

struct ArrayType #

struct ArrayType {
pub:
	elem_type Expr = empty_expr
}

Type Nodes

struct AsCastExpr #

struct AsCastExpr {
pub:
	expr Expr
	typ  Expr
	pos  token.Pos
}

struct AsmStmt #

struct AsmStmt {
pub:
	arch string
}

Statements

struct AssertStmt #

struct AssertStmt {
pub:
	expr  Expr
	extra Expr = empty_expr
}

struct AssignStmt #

struct AssignStmt {
pub:
	op  token.Token
	lhs []Expr
	rhs []Expr
	pos token.Pos
}

struct AssocExpr #

struct AssocExpr {
pub:
	typ    Expr
	expr   Expr
	fields []FieldInit
	pos    token.Pos
}

struct Attribute #

struct Attribute {
pub:
	name          string
	value         Expr
	comptime_cond Expr
	pos           token.Pos
}

struct BasicLiteral #

struct BasicLiteral {
pub:
	kind  token.Token
	value string
	pos   token.Pos
}

struct BlockStmt #

struct BlockStmt {
pub:
	stmts []Stmt
}

struct CallExpr #

struct CallExpr {
pub mut:
	lhs Expr
pub:
	args []Expr
	pos  token.Pos
}

struct CallOrCastExpr #

struct CallOrCastExpr {
pub mut:
	lhs  Expr
	expr Expr
pub:
	pos token.Pos
}

struct CastExpr #

struct CastExpr {
pub mut:
	typ  Expr
	expr Expr
pub:
	pos token.Pos
}

struct ChannelType #

struct ChannelType {
pub:
	// s255: cap defaults to empty_expr (like ThreadType/OptionType/etc.). The
	// parser omits cap for a bare `chan T` (type.v: `ChannelType{elem_type: ...}`),
	// which previously left it a zero-valued Expr (invalid sum-type tag, null
	// payload). Encoding that via FlatBuilder.add_expr crashes the arm64 self-host
	// — an exhaustive match on the unmatched tag falls into the first arm
	// (ArrayInitExpr) and derefs the null payload (same class as s251).
	cap       Expr = empty_expr
	elem_type Expr = empty_expr
}

struct ComptimeExpr #

struct ComptimeExpr {
pub:
	expr Expr
	pos  token.Pos
}

struct ComptimeStmt #

struct ComptimeStmt {
pub:
	stmt Stmt
}

struct ConstDecl #

struct ConstDecl {
pub:
	is_public bool
	fields    []FieldInit
}

struct Cursor #

struct Cursor {
pub:
	flat &FlatAst = unsafe { nil }
	id   FlatNodeId
}

Cursor is a lightweight, by-value handle pointing at one FlatNode inside a FlatAst. Consumers walk the AST via match c.kind() {} and descend via c.edge(i) / c.list_at(i) without rehydrating to ast.Stmt / ast.Expr.

A Cursor is 16 bytes: an &FlatAst pointer plus a FlatNodeId. It is safe to copy, store in arrays, and pass by value. An "invalid" Cursor (id < 0) is used as a sentinel where the legacy AST would use empty_stmt / empty_expr.

fn (Cursor) is_valid #

fn (c Cursor) is_valid() bool

fn (Cursor) kind #

fn (c Cursor) kind() FlatNodeKind

fn (Cursor) pos #

fn (c Cursor) pos() token.Pos

fn (Cursor) flags #

fn (c Cursor) flags() u8

fn (Cursor) flag #

fn (c Cursor) flag(bit u8) bool

fn (Cursor) aux #

fn (c Cursor) aux() u16

fn (Cursor) extra_int #

fn (c Cursor) extra_int() int

fn (Cursor) extra_str #

fn (c Cursor) extra_str() string

extra_str interprets the node's extra field as an interned string id. Use only on kinds where the schema documents extra as a string slot (e.g. stmt_directive's value, stmt_import's alias).

fn (Cursor) name #

fn (c Cursor) name() string

name returns the interned primary string (FlatNode.name_id) for this node. Most kinds use this for identifiers, type names, fn names, etc.

fn (Cursor) name_id #

fn (c Cursor) name_id() int

fn (Cursor) ident #

fn (c Cursor) ident() Ident

ident reads an expr_ident cursor directly into an Ident.

fn (Cursor) import_stmt #

fn (c Cursor) import_stmt() ImportStmt

import_stmt reads a stmt_import cursor directly into an ImportStmt.

fn (Cursor) fn_decl_signature #

fn (c Cursor) fn_decl_signature() FnDecl

fn_decl_signature reads a stmt_fn_decl cursor into a body-less FnDecl. This mirrors FlatAst.decode_fn_decl_signature without going through FlatReader.

fn (Cursor) fn_decl #

fn (c Cursor) fn_decl() FnDecl

fn_decl reads a stmt_fn_decl cursor into a legacy FnDecl. Unlike fn_decl_signature, this materializes the body statements for consumers that still use legacy statement walkers internally.

fn (Cursor) stmt #

fn (c Cursor) stmt() Stmt

stmt reads a cursor through FlatAst.decode_stmt. This is the escape hatch for legacy statement walkers; prefer cursor-specific readers when possible.

fn (Cursor) expr #

fn (c Cursor) expr() Expr

expr reads a cursor through FlatAst.decode_expr. This is the escape hatch for legacy expression walkers; prefer cursor-specific readers when possible.

fn (Cursor) type_expr #

fn (c Cursor) type_expr() Expr

type_expr reads a type-expression cursor into the legacy Expr shape used by signature consumers. It is intentionally narrower than FlatReader.read_expr: non-type payloads such as field defaults or statement bodies stay omitted.

fn (Cursor) edge_count #

fn (c Cursor) edge_count() int

fn (Cursor) edge #

fn (c Cursor) edge(i int) Cursor

edge returns a Cursor over the i-th direct child edge of this node. Out-of- range indices return an invalid Cursor (id == invalid_flat_node_id), which callers can detect via c.is_valid(). This matches FlatReader's behaviour where r.edge(n, i) may return invalid_flat_node_id for missing slots.

fn (Cursor) list_at #

fn (c Cursor) list_at(edge_i int) CursorList

list_at treats edge i as a reference to an aux_list node and returns a CursorList over its children. The flat schema represents list-typed fields (e.g. StructDecl.fields, FnDecl.stmts, EnumDecl.attributes) as a single edge to an aux_list whose children are the actual list items. Use edge() for fields stored as direct child edges of the parent (e.g. AssignStmt's LHS/RHS, AssertStmt's expr/extra).

fn (Cursor) for_body_list #

fn (c Cursor) for_body_list() CursorList

for_body_list views a stmt_for node's body as a CursorList. The stmt_for flat layout is edges [init, cond, post, body_stmt_0, body_stmt_1, ...] — the body is trailing edges of the for-node itself, NOT a separate aux_list — so the body list is this node's children from edge index 3 onward.

fn (Cursor) attribute_expr #

fn (c Cursor) attribute_expr() Expr

attribute_expr reads the small expression subset used inside attributes. Attribute payloads are normally identifiers or strings; type_expr handles the type-like fallback cases without opening the full FlatReader.

fn (Cursor) attribute #

fn (c Cursor) attribute() Attribute

attribute reads an aux_attribute cursor into the legacy Attribute shape.

fn (Cursor) field_init #

fn (c Cursor) field_init() FieldInit

field_init reads an aux_field_init cursor. Field values are still legacy expression consumers today, so this materializes only the value expression, not the parent declaration.

fn (Cursor) field_decl #

fn (c Cursor) field_decl(decode_value bool) FieldDecl

field_decl reads an aux_field_decl cursor. Set decode_value to false when a caller only needs declaration metadata and type expressions.

fn (Cursor) const_decl #

fn (c Cursor) const_decl() ConstDecl

const_decl reads a stmt_const_decl cursor.

fn (Cursor) enum_decl #

fn (c Cursor) enum_decl(decode_values bool) EnumDecl

enum_decl reads a stmt_enum_decl cursor. Set decode_values to false when only field names/attributes are needed.

fn (Cursor) global_decl #

fn (c Cursor) global_decl(decode_values bool) GlobalDecl

global_decl reads a stmt_global_decl cursor. Set decode_values to false when only field metadata and declared types are needed.

fn (Cursor) interface_decl #

fn (c Cursor) interface_decl() InterfaceDecl

interface_decl reads a stmt_interface_decl cursor.

fn (Cursor) struct_decl #

fn (c Cursor) struct_decl() StructDecl

struct_decl reads a stmt_struct_decl cursor.

fn (Cursor) type_decl #

fn (c Cursor) type_decl() TypeDecl

type_decl reads a stmt_type_decl cursor.

struct CursorList #

struct CursorList {
pub:
	flat      &FlatAst = unsafe { nil }
	parent_id FlatNodeId
	// offset skips the first `offset` child edges of `parent_id`. Default 0 (the
	// whole child list). Lets a trailing edge range be viewed as a list when the
	// items are direct child edges of a node rather than an aux_list — e.g. a
	// ForStmt body lives in edges [3..] of the stmt_for node itself (see
	// `Cursor.for_body_list`).
	offset int
}

CursorList is a view over the children of an aux_list node. It is the flat equivalent of []ast.Stmt / []ast.Expr / []FieldDecl etc., except no slice is materialised — at(i) decodes one child at a time.

fn (CursorList) len #

fn (l CursorList) len() int

fn (CursorList) at #

fn (l CursorList) at(i int) Cursor

fn (CursorList) type_exprs #

fn (l CursorList) type_exprs() []Expr

type_exprs reads every item in a cursor list through Cursor.type_expr.

fn (CursorList) stmts #

fn (l CursorList) stmts() []Stmt

stmts reads every item in a cursor list through FlatAst.decode_stmt. This is the escape hatch for legacy statement walkers; prefer cursor-specific readers when the caller only needs a declaration signature or metadata.

fn (CursorList) attributes #

fn (l CursorList) attributes() []Attribute

attributes reads every aux_attribute in a cursor list.

fn (CursorList) import_stmts #

fn (l CursorList) import_stmts() []ImportStmt

import_stmts reads every stmt_import in a cursor list.

fn (CursorList) field_inits #

fn (l CursorList) field_inits() []FieldInit

field_inits reads every aux_field_init in a cursor list.

fn (CursorList) field_decls #

fn (l CursorList) field_decls(decode_values bool) []FieldDecl

field_decls reads every aux_field_decl in a cursor list.

struct DeferStmt #

struct DeferStmt {
pub:
	mode  DeferMode
	stmts []Stmt
}

struct Directive #

struct Directive {
pub:
	name    string
	value   string
	ct_cond string // optional comptime condition e.g. 'linux', 'darwin' for `#include linux <pty.h>`
}

#flag / #include

struct EnumDecl #

struct EnumDecl {
pub:
	attributes []Attribute
	is_public  bool
	name       string
	as_type    Expr = empty_expr
	fields     []FieldDecl
}

struct ExprStmt #

struct ExprStmt {
pub mut:
	expr Expr
}

struct FieldDecl #

struct FieldDecl {
pub:
	name                string
	typ                 Expr = empty_expr // can be empty as used for const (unless we use something else)
	value               Expr = empty_expr
	attributes          []Attribute
	is_public           bool
	is_mut              bool
	is_module_mut       bool
	is_interface_method bool
}

struct FieldInit #

struct FieldInit {
pub:
	name string
pub mut:
	value Expr
}

struct File #

struct File {
pub:
	attributes     []Attribute
	mod            string
	name           string
	stmts          []Stmt
	imports        []ImportStmt
	selector_names map[int]string
}

File (AST container)

struct FileCursor #

struct FileCursor {
pub:
	flat &FlatAst = unsafe { nil }
	idx  int // index into flat.files
}

FileCursor is a typed wrapper over a FlatFile entry. It exposes the file-level metadata (name, mod, selector_names) and the three top-level child lists (attributes, imports, stmts) without rehydrating a full ast.File.

fn (FileCursor) flat_file #

fn (fc FileCursor) flat_file() FlatFile

fn (FileCursor) root #

fn (fc FileCursor) root() Cursor

root returns a Cursor positioned at this file's root FlatNode (kind == .file).

fn (FileCursor) name #

fn (fc FileCursor) name() string

fn (FileCursor) mod #

fn (fc FileCursor) mod() string

fn (FileCursor) selector_names #

fn (fc FileCursor) selector_names() map[int]string

fn (FileCursor) attrs #

fn (fc FileCursor) attrs() CursorList

attrs returns the file's top-level attribute list (edge 0 of the file node).

fn (FileCursor) imports #

fn (fc FileCursor) imports() CursorList

imports returns the file's top-level import list (edge 1 of the file node).

fn (FileCursor) stmts #

fn (fc FileCursor) stmts() CursorList

stmts returns the file's top-level statement list (edge 2 of the file node).

struct FlatAst #

struct FlatAst {
pub mut:
	files   []FlatFile
	nodes   []FlatNode
	edges   []FlatEdge
	strings []string
}

FlatAst is a contiguous AST graph representation.

fn (FlatAst) child_at #

fn (flat &FlatAst) child_at(parent FlatNodeId, i int) FlatNodeId

child_at returns the i-th child of parent (0-indexed), or invalid_flat_node_id.

fn (FlatAst) count_nodes_by_kind #

fn (flat &FlatAst) count_nodes_by_kind() map[string]int

count_nodes_by_kind returns a tally of how many nodes exist of each kind. Useful for spotting structural overhead (e.g., aux_list wrappers).

fn (FlatAst) count_reachable_nodes #

fn (flat &FlatAst) count_reachable_nodes() int

count_reachable_nodes traverses from file roots and counts unique reachable nodes.

fn (FlatAst) decode_expr #

fn (flat &FlatAst) decode_expr(id FlatNodeId) Expr

decode_expr is the Expr analogue of decode_stmt.

fn (FlatAst) decode_fn_decl_signature #

fn (flat &FlatAst) decode_fn_decl_signature(id FlatNodeId) FnDecl

decode_fn_decl_signature rehydrates a FnDecl with stmts = [] — the body is left empty. Callers that walk the body via Cursor (e.g. markused) can use this to avoid the per-fn body decode, which dominates collect_defs time in flat mode. Returns an empty FnDecl for ids that don't point at a stmt_fn_decl node.

fn (FlatAst) decode_stmt #

fn (flat &FlatAst) decode_stmt(id FlatNodeId) Stmt

decode_stmt rehydrates a single legacy ast.Stmt from a FlatNodeId. Useful for cursor-driven consumers that walk the flat graph via Cursor and only need to materialize a typed Stmt for the specific decls they hand to helpers still keyed on legacy ADTs. Returns empty_stmt for invalid ids.

fn (FlatAst) file_cursor #

fn (flat &FlatAst) file_cursor(idx int) FileCursor

file_cursor returns a FileCursor over the i-th FlatFile in this FlatAst.

fn (FlatAst) file_cursors #

fn (flat &FlatAst) file_cursors() []FileCursor

file_cursors returns one FileCursor per FlatFile. Allocates an int-sized array; for hot loops prefer for i in 0 .. flat.files.len { flat.file_cursor(i) }.

fn (FlatAst) file_mod #

fn (flat &FlatAst) file_mod(ff FlatFile) string

file_mod returns the module name for a FlatFile via the interned strings.

fn (FlatAst) file_name #

fn (flat &FlatAst) file_name(ff FlatFile) string

file_name returns the source filename for a FlatFile.

fn (FlatAst) node_type_name #

fn (flat &FlatAst) node_type_name(node_id FlatNodeId) string

node_type_name returns the short type-name tag associated with a flat node.

fn (FlatAst) signature #

fn (flat &FlatAst) signature() string

signature returns a canonical, content-addressed string representation of the flat AST. Two flat ASTs produced from the same legacy AST must produce identical signatures — this is the round-trip lossless invariant.

The signature includes per-node fields (kind, flags, aux, extra, pos) and resolves all interned strings to their text content, so signatures are independent of the order in which the intern table was populated.

fn (FlatAst) stats #

fn (flat &FlatAst) stats() FlatAstStats

stats returns aggregate shape and estimated memory usage for FlatAst.

fn (FlatAst) string_at #

fn (flat &FlatAst) string_at(idx int) string

string_at returns the interned string at idx, or empty when out of range.

fn (FlatAst) subtree_signature #

fn (flat &FlatAst) subtree_signature(node_id FlatNodeId) string

subtree_signature returns the same canonical, content-addressed string as signature() but rooted at a single node id rather than the file roots. Useful for tests that want to pin the shape of a specific subtree (e.g. the FlatBuilder.prepend_to_fn_body bit-equality test) without managing a file root or worrying about intern-order leakage in the .file node's extra slot.

fn (FlatAst) to_files #

fn (flat &FlatAst) to_files() []File

to_files materializes a FlatAst back into legacy []File. This is the inverse of flatten_files() and is used for round-trip verification. Reading happens lazily (one node at a time) so callers can also walk a flat AST without ever rehydrating the legacy form.

fn (FlatAst) to_files_range #

fn (flat &FlatAst) to_files_range(start int, end int) []File

to_files_range rehydrates the FlatFiles in [start, end) without touching the rest of the FlatAst. Used by the streaming builder, where each parse_batch appends to a shared FlatBuilder and only needs to return the freshly added files to the caller.

struct FlatAstStats #

struct FlatAstStats {
pub:
	file_roots     int
	nodes          int
	edges          int
	strings        int
	string_bytes   u64
	bytes_estimate u64
}

FlatAstStats captures high-level memory and shape metrics.

struct FlatBuilder #

struct FlatBuilder {
pub mut:
	flat FlatAst
mut:
	string_ids    map[string]int
	empty_list_id FlatNodeId = invalid_flat_node_id
	empty_expr_id FlatNodeId = invalid_flat_node_id
	empty_stmt_id FlatNodeId = invalid_flat_node_id
}

FlatBuilder is the incremental builder behind FlatAst. It is public so front-ends (parser, type checker, ...) can append nodes directly without going through the legacy recursive AST. The legacy converters (add_expr, add_stmt, ...) remain internal to this module and are exposed via the append_file(File) shim used during the Phase 2 transition.

fn (FlatBuilder) take_flat #

fn (mut b FlatBuilder) take_flat() FlatAst

take_flat moves the built flat graph out and releases transient builder-only indexes. The returned FlatAst keeps owning its arena arrays.

fn (FlatBuilder) append_file #

fn (mut b FlatBuilder) append_file(file File) FlatNodeId

append_file converts one legacy File into flat nodes and registers it as a root. Designed for streaming use: the caller can drop the legacy file immediately after this returns, capping peak memory at ~one file's legacy AST plus the cumulative flat representation.

fn (FlatBuilder) append_file_with_stmt_ids #

fn (mut b FlatBuilder) append_file_with_stmt_ids(file File, stmt_ids []FlatNodeId) FlatNodeId

append_file_with_stmt_ids registers a file root whose stmt list is built from FlatNodeIds that were already emitted into this builder by a previous per-stmt pass (e.g. the transformer's flat-write path). Attributes and imports are still consumed from the legacy file because they are not subject to transformer rewrites; emitting them here keeps the file shape bit-equal to add_file's output.

fn (FlatBuilder) append_file_with_flat_attrs_and_stmt_ids #

fn (mut b FlatBuilder) append_file_with_flat_attrs_and_stmt_ids(name string, mod string, selector_names map[int]string, attrs_id FlatNodeId, imports []ImportStmt, stmt_ids []FlatNodeId) FlatNodeId

append_file_with_flat_attrs_and_stmt_ids registers a file root whose attributes and stmt list were already emitted into this builder. Imports are still accepted as legacy values because import handling is not transformed.

fn (FlatBuilder) append_file_with_flat_lists_and_stmt_ids #

fn (mut b FlatBuilder) append_file_with_flat_lists_and_stmt_ids(name string, mod string, selector_names map[int]string, attrs_id FlatNodeId, imports_id FlatNodeId, stmt_ids []FlatNodeId) FlatNodeId

append_file_with_flat_lists_and_stmt_ids registers a file root whose attributes, imports, and stmt list were already emitted into this builder.

fn (FlatBuilder) append_flat #

fn (mut b FlatBuilder) append_flat(src &FlatAst) int

append_flat copies an entire src FlatAst (nodes, edges, strings, file roots) into this builder, relocating every node id / edge target and re-interning every string so the merged result is structurally identical to src decoded standalone. Returns the node-id offset applied to all of src's nodes (a src node id x maps to merged id x + offset).

This is the merge primitive behind the flat parallel transform: each worker emits into its own FlatBuilder, then the main thread concatenates the workers' outputs via append_flat (replacing the legacy per-worker ast.File rehydrate-then-flatten). Relocation rules — verified against the canonical decoder (flat_reader.v):- edge.child_id : + node_offset (invalid_flat_node_id stays invalid)

  • node.first_edge: + edge_offset
  • node.name_id : re-interned via the string remap (-1 stays -1)
  • node.extra : re-interned ONLY for the three kinds that store a string id there (file mod, stmt_directive value, stmt_import alias); every other kind packs ints/counts/flags/list- boundaries in extra (lhs_len, cap_len, keys_len, width/ precision, aux_int value, ...) → copied verbatim (relocation-invariant)- node.aux / pos : copied verbatim (aux is a token/sub-kind enum; pos.id is globally unique across the merged inputs, and selector_names is keyed by pos.id so it needs no remap)- file.file_id : + node_offset; name_idx/mod_idx re-interned; selector_names copied (cloned for ownership)

fn (FlatBuilder) copy_subtree_from #

fn (mut b FlatBuilder) copy_subtree_from(src &FlatAst, root FlatNodeId) FlatNodeId

copy_subtree_from copies the subtree rooted at root from src into this builder, re-interning strings and rebuilding child edges recursively.

fn (FlatBuilder) emit_stmt #

fn (mut b FlatBuilder) emit_stmt(stmt Stmt) FlatNodeId

emit_stmt is the public wrapper around the legacy stmt-to-flat conversion. Future sessions of the transformer-writes-flat port reach for this when a stmt variant still falls back to legacy emission; the long-term goal is for transform_stmt_to_flat (in v2.transformer) to stop calling it as each stmt arm gets a direct-emit replacement.

fn (FlatBuilder) append_file_stmts #

fn (mut b FlatBuilder) append_file_stmts(file_idx int, extra_stmt_ids []FlatNodeId) FlatNodeId

append_file_stmts re-emits the file root for flat.files[file_idx] with extra_stmt_ids appended to the existing stmts list. The file's existing attrs and imports edges are reused as-is (no re-emit) — only the stmts list (file root edge 2) is rebuilt. Updates flat.files[file_idx] in place to point at the new file root and returns its FlatNodeId.

Append-only: the old file root remains in flat.nodes as garbage (never reachable from flat.files). Callers must not retain the previous file_id.

Designed for the post-pass mutation pattern (s144..s149 _parts extracts). inject_embed_file_helper-equivalent + inject_test_main-equivalent + generated_fns_parts core/module/user splices all need to append a list of pre-emitted stmt nodes to a specific file's stmt list. The transformer's upcoming post_pass_to_flat wires each of those into one call of this helper.

Bit-equal to append_file(file_with_extended_stmts) w.r.t. the signature() walk: the file root's edge list (attrs_list_id, imports_list_id, new_stmts_list_id) names the same logical children, and signature() only follows reachable edges from the file root.

fn (FlatBuilder) prepend_file_stmts #

fn (mut b FlatBuilder) prepend_file_stmts(file_idx int, prepended_stmt_ids []FlatNodeId) FlatNodeId

prepend_file_stmts re-emits the file root for flat.files[file_idx] with prepended_stmt_ids placed BEFORE the existing stmts list. The file's existing attrs and imports edges are reused as-is (no re-emit) — only the stmts list (file root edge 2) is rebuilt. Updates flat.files[file_idx] in place to point at the new file root and returns its FlatNodeId.

Sibling of append_file_stmts — same shape, opposite order. Designed for inject_live_reload's file-level prepend (c_decls + global_decls go BEFORE the existing file stmts).

Append-only: the old file root remains in flat.nodes as garbage (never reachable from flat.files). Callers must not retain the previous file_id.

fn (FlatBuilder) replace_file_stmt #

fn (mut b FlatBuilder) replace_file_stmt(file_idx int, stmt_idx int, new_stmt_id FlatNodeId) FlatNodeId

replace_file_stmt re-emits the file root for flat.files[file_idx] with the stmt at stmt_idx replaced by new_stmt_id. The file's existing attrs and imports edges are reused as-is (no re-emit); only the stmts list (file root edge 2) is rebuilt with the substitution applied. Updates flat.files[file_idx] in place to point at the new file root and returns its FlatNodeId.

Companion primitive to prepend_to_fn_body: that primitive emits a NEW fn_decl_id (the old fn is unreachable garbage) but cannot rewire the surrounding file. replace_file_stmt is the cross-stitching call that puts the new id back into the file's stmts list. Together they support the prepend-style post_pass mutations (inject_main_runtime_const_init_calls is the first user, s155).

Append-only: the old file root remains in flat.nodes as garbage (never reachable from flat.files). Callers must not retain the previous file_id.

fn (FlatBuilder) prepend_to_fn_body #

fn (mut b FlatBuilder) prepend_to_fn_body(fn_decl_id FlatNodeId, extra_stmt_ids []FlatNodeId) FlatNodeId

prepend_to_fn_body re-emits a stmt_fn_decl with extra_stmt_ids prepended to its body. The original FnDecl's receiver/typ/attrs edges (0/1/2) and its metadata (name_id, extra, aux, flags, pos) are reused verbatim; only the stmts list (edge 3) is rebuilt as extras + old_children. Returns the FlatNodeId of the NEW stmt_fn_decl — the old one remains in flat.nodes as garbage. Callers must thread the returned id back into wherever the old FnDecl was referenced (typically a file's stmts list).

Designed for the prepend-style post_pass mutations:- inject_main_runtime_const_init_calls (prepends __v_init_consts_*() calls to the top of main)- inject_live_reload (prepends a reload-check to nested ForStmt bodies; the same body-rebuild shape applies to non-FnDecl callsites too, but the FnDecl case is the immediate need so this primitive lands first).

Bit-equal to add_stmt(FnDecl{... stmts: extras_then_old}) w.r.t. signature(): the new node has identical name_id/extra/aux/pos/flags and edges = [old_receiver, old_typ, old_attrs, new_stmts_list].

fn (FlatBuilder) prepend_to_for_body #

fn (mut b FlatBuilder) prepend_to_for_body(for_stmt_id FlatNodeId, extra_stmt_ids []FlatNodeId) FlatNodeId

prepend_to_for_body re-emits a stmt_for with extra_stmt_ids prepended to its body. The original ForStmt's init/cond/post edges (0/1/2) and pos are reused verbatim; the body stmts (edges 3..edge_count) are rebuilt as extras + old_body_stmts. Returns the FlatNodeId of the NEW stmt_for — the old one remains in flat.nodes as garbage. Callers must thread the returned id back into wherever the old ForStmt was referenced.

Body-stmt encoding difference vs prepend_to_fn_body: ForStmt encodes body stmts as INLINE edges starting at index 3 (no list child), whereas FnDecl's body stmts live inside a .aux_list at edge 3. So prepend_to_for_body rebuilds the for's edge list directly — no intermediate list node.

Designed for inject_live_reload, which prepends a reload-check stmt to the body of every ForStmt found in every function. Combined with prepend_to_fn_body (s154) and replace_file_stmt (s155), this primitive closes the cross-stitching chain needed for the recursive live-reload splice: for each ForStmt change, rebuild the for, rebuild the enclosing FnDecl, rewire the enclosing file's stmts list.

fn (FlatBuilder) replace_fn_body_stmts #

fn (mut b FlatBuilder) replace_fn_body_stmts(fn_decl_id FlatNodeId, new_body_stmt_ids []FlatNodeId) FlatNodeId

replace_fn_body_stmts re-emits a stmt_fn_decl with its body stmts list fully REPLACED by new_body_stmt_ids. The original FnDecl's receiver/typ/ attrs edges (0/1/2) and metadata (name_id, extra, aux, flags, pos) are reused verbatim; only the stmts list (edge 3) is rebuilt as a fresh aux_list over new_body_stmt_ids. Returns the FlatNodeId of the NEW stmt_fn_decl — the old one remains in flat.nodes as garbage. Callers must thread the returned id back into wherever the old FnDecl was referenced (typically a file's stmts list).

Companion primitive to prepend_to_fn_body (s154). Where prepend_to_fn_body adds extras to the head of the existing body, replace_fn_body_stmts gives callers full control over the new body — used by inject_live_reload which combines preamble prepend (main fn only) + per-ForStmt prepend (every fn) + per-stmt call rewriting (every fn) into ONE new body. The caller computes the new body stmt ids first (mixing freshly-emitted stmts with ids returned by prepend_to_for_body and unchanged legacy stmt ids), then hands them off here for a one-shot FnDecl rebuild.

Bit-equal to add_stmt(FnDecl{... stmts: new_body}) w.r.t. signature(): the new node has identical name_id/extra/aux/pos/flags and edges = [old_receiver, old_typ, old_attrs, new_stmts_list].

fn (FlatBuilder) emit_expr #

fn (mut b FlatBuilder) emit_expr(expr Expr) FlatNodeId

emit_expr is the public wrapper around the legacy expr-to-flat conversion. The flat-write port reaches for this when an expr variant still falls back to legacy emission. Phase 4 sessions replace non-leaf arms in transform_expr_to_flat one at a time with direct-emit logic that no longer reaches for this helper.

fn (FlatBuilder) emit_attribute_list #

fn (mut b FlatBuilder) emit_attribute_list(attrs []Attribute) FlatNodeId

emit_attribute_list emits an aux_list of attribute flat nodes, bit-equal to the encoding produced by add_stmt for stmts that carry attributes. Empty inputs return the shared empty-list sentinel.

fn (FlatBuilder) emit_aux_list_from_ids #

fn (mut b FlatBuilder) emit_aux_list_from_ids(ids []FlatNodeId) FlatNodeId

emit_aux_list_from_ids builds an aux_list whose children are FlatNodeIds already present in this builder. Empty inputs return the shared empty-list sentinel.

fn (FlatBuilder) emit_field_decl_by_ids #

fn (mut b FlatBuilder) emit_field_decl_by_ids(field FieldDecl, typ_id FlatNodeId, value_id FlatNodeId, attrs_id FlatNodeId) FlatNodeId

emit_field_decl_by_ids emits an aux_field_decl node from already-flat child FlatNodeIds. Used by the flat-write port for stmts that carry FieldDecls (GlobalDecl, StructDecl, ...) once their typ/value expressions have been emitted directly. Mirrors the add_field_decl encoding exactly.

fn (FlatBuilder) emit_global_decl_by_ids #

fn (mut b FlatBuilder) emit_global_decl_by_ids(is_public bool, attrs_id FlatNodeId, fields_id FlatNodeId) FlatNodeId

emit_global_decl_by_ids emits a stmt_global_decl node from already-flat child FlatNodeIds (the attribute list and field-decl list). Mirrors the add_stmt(GlobalDecl) encoding exactly, including the flag_is_public bit.

fn (FlatBuilder) emit_field_init_by_id #

fn (mut b FlatBuilder) emit_field_init_by_id(name string, value_id FlatNodeId) FlatNodeId

emit_field_init_by_id emits an aux_field_init node from an already-flat value FlatNodeId. Used by the flat-write port for ConstDecl when the field's value expression has been emitted directly. Mirrors the add_field_init encoding exactly.

fn (FlatBuilder) emit_const_decl_by_ids #

fn (mut b FlatBuilder) emit_const_decl_by_ids(is_public bool, fields_id FlatNodeId) FlatNodeId

emit_const_decl_by_ids emits a stmt_const_decl node from an already-flat fields list FlatNodeId. Mirrors the add_stmt(ConstDecl) encoding exactly, including the flag_is_public bit when is_public is true.

fn (FlatBuilder) emit_return_stmt_by_ids #

fn (mut b FlatBuilder) emit_return_stmt_by_ids(expr_ids []FlatNodeId) FlatNodeId

emit_return_stmt_by_ids emits a stmt_return node from a slice of already-flat returned-expression FlatNodeIds. Mirrors the add_stmt(ReturnStmt) encoding exactly: pos is the zero token.Pos{} the legacy add_stmt arm uses, edges are the returned exprs in order. Used by the flat-write port to direct-emit the outer ast.ReturnStmt wrapper.

fn (FlatBuilder) emit_expr_stmt_by_id #

fn (mut b FlatBuilder) emit_expr_stmt_by_id(expr_id FlatNodeId) FlatNodeId

emit_expr_stmt_by_id emits a stmt_expr node from an already-flat FlatNodeId child. Mirrors the add_stmt(ExprStmt) encoding exactly: pos is the zero token.Pos{} the legacy add_stmt arm uses, single edge to the expression. Used by the flat-write port to direct-emit the ast.ExprStmt wrapper at every expression-statement site.

fn (FlatBuilder) emit_label_stmt_by_id #

fn (mut b FlatBuilder) emit_label_stmt_by_id(name string, stmt_id FlatNodeId) FlatNodeId

emit_label_stmt_by_id emits a stmt_label node from an already-flat FlatNodeId child stmt. Mirrors the add_stmt(LabelStmt) encoding exactly: pos is the zero token.Pos{} the legacy add_stmt arm uses, name is interned, single edge to the labelled stmt. Used by the flat-write port to direct-emit the ast.LabelStmt wrapper.

fn (FlatBuilder) emit_block_stmt_by_ids #

fn (mut b FlatBuilder) emit_block_stmt_by_ids(stmt_ids []FlatNodeId) FlatNodeId

emit_block_stmt_by_ids emits a stmt_block node from a slice of already-flat child stmt FlatNodeIds. Mirrors the add_stmt(BlockStmt) encoding exactly: pos is the zero token.Pos{} the legacy add_stmt arm uses, edges are the inner stmts in order. Used by the flat-write port to direct-emit the ast.BlockStmt wrapper.

fn (FlatBuilder) emit_assert_stmt_by_id #

fn (mut b FlatBuilder) emit_assert_stmt_by_id(expr_id FlatNodeId) FlatNodeId

emit_assert_stmt_by_id emits a stmt_assert node from an already-flat child expr FlatNodeId. Mirrors the add_stmt(AssertStmt) encoding exactly: pos is the zero token.Pos{} the legacy add_stmt arm uses, edges are [expr_id, empty_expr_id]. The legacy fallback path in transform_stmt rebuilds AssertStmt{expr: transformed} without setting extra, so the extra slot is always the default empty_expr — emit that via the cached add_expr(empty_expr). Used by the flat-write port to direct-emit the ast.AssertStmt fallback wrapper (most assert stmts are expanded in transform_stmts and never reach the dispatch arm).

fn (FlatBuilder) emit_for_stmt_by_ids #

fn (mut b FlatBuilder) emit_for_stmt_by_ids(init_id FlatNodeId, cond_id FlatNodeId, post_id FlatNodeId, stmt_ids []FlatNodeId) FlatNodeId

emit_for_stmt_by_ids emits a stmt_for node from already-flat init/post stmt FlatNodeIds, cond expr FlatNodeId, and body stmt FlatNodeIds. Mirrors the add_stmt(ForStmt) encoding exactly: pos = token.Pos{} the legacy arm uses, edges = [init, cond, post, body_stmts...].

fn (FlatBuilder) emit_for_in_stmt_by_ids #

fn (mut b FlatBuilder) emit_for_in_stmt_by_ids(key_id FlatNodeId, value_id FlatNodeId, expr_id FlatNodeId) FlatNodeId

emit_for_in_stmt_by_ids emits a stmt_for_in node from already-flat key, value, and iterable expression FlatNodeIds. Mirrors add_stmt(ForInStmt).

fn (FlatBuilder) emit_flow_control_stmt #

fn (mut b FlatBuilder) emit_flow_control_stmt(op token.Token, label string) FlatNodeId

emit_flow_control_stmt emits a stmt_flow_control node. Mirrors add_stmt(FlowControlStmt): label in name_id, op in aux, no edges.

fn (FlatBuilder) emit_map_init_expr_by_ids #

fn (mut b FlatBuilder) emit_map_init_expr_by_ids(typ_id FlatNodeId, key_ids []FlatNodeId, val_ids []FlatNodeId, pos token.Pos) FlatNodeId

emit_map_init_expr_by_ids emits an expr_map_init node from already-flat type FlatNodeId and parallel slices of key/value expression FlatNodeIds (with key_ids.len == val_ids.len). Mirrors the add_expr(MapInitExpr) encoding exactly: aux1=-1, aux2=keys.len, edges = [typ, keys..., vals...]. The flat-write port for transform_map_init_expr's identity branch (eval-backend map literal) uses this to skip the ast.MapInitExpr wrapper struct allocation.

fn (FlatBuilder) emit_if_expr_by_ids #

fn (mut b FlatBuilder) emit_if_expr_by_ids(cond_id FlatNodeId, else_id FlatNodeId, stmt_ids []FlatNodeId, pos token.Pos) FlatNodeId

emit_if_expr_by_ids emits an expr_if node from already-flat cond, else, and stmt FlatNodeIds. Mirrors the add_expr(IfExpr) encoding exactly: edges = [cond, else_expr, stmts...]. The flat-write port for transform_if_expr's identity branch (no value-position lowering: any ast.IfExpr returned by the helper — recursive normalisation, smartcast rewrite, default transformed_if rebuild) uses this to skip the ast.IfExpr wrapper struct allocation.

fn (FlatBuilder) emit_call_expr_by_ids #

fn (mut b FlatBuilder) emit_call_expr_by_ids(lhs_id FlatNodeId, arg_ids []FlatNodeId, pos token.Pos) FlatNodeId

emit_call_expr_by_ids emits an expr_call node from already-flat lhs and args expression FlatNodeIds. Mirrors the add_expr(CallExpr) encoding exactly: edges = [lhs, args...]. The flat-write port for transform_call_expr's many identity-shape rebuild branches (default fallback, generic-math inline result, smartcast method, etc.) uses this to skip the ast.CallExpr wrapper struct allocation.

fn (FlatBuilder) emit_infix_expr_by_ids #

fn (mut b FlatBuilder) emit_infix_expr_by_ids(op token.Token, lhs_id FlatNodeId, rhs_id FlatNodeId, pos token.Pos) FlatNodeId

emit_infix_expr_by_ids emits an expr_infix node from already-flat lhs and rhs expression FlatNodeIds. Mirrors the add_expr(InfixExpr) encoding exactly: aux1=-1, aux2=-1, meta=u16(op), edges = [lhs, rhs]. The flat-write port for transform_infix_expr's identity branch (no rewrite triggered: just transform(lhs)/transform(rhs) rebuild) uses this to skip the ast.InfixExpr wrapper struct allocation.

fn (FlatBuilder) emit_keyword_operator_by_ids #

fn (mut b FlatBuilder) emit_keyword_operator_by_ids(op token.Token, expr_ids []FlatNodeId, pos token.Pos) FlatNodeId

emit_keyword_operator_by_ids emits an expr_keyword_operator node from already-flat operand expression FlatNodeIds. Mirrors add_expr(KeywordOperator) exactly: aux1=-1, aux2=-1, meta=u16(op), edges = exprs.

fn (FlatBuilder) emit_array_init_expr_by_ids #

fn (mut b FlatBuilder) emit_array_init_expr_by_ids(typ_id FlatNodeId, init_id FlatNodeId, cap_id FlatNodeId, len_id FlatNodeId, update_expr_id FlatNodeId, expr_ids []FlatNodeId, pos token.Pos) FlatNodeId

emit_array_init_expr_by_ids emits an expr_array_init node from already-flat type/init/cap/len/update expression FlatNodeIds and a slice of already-flat element expression FlatNodeIds. Mirrors the add_expr(ArrayInitExpr) encoding exactly: edges = [typ, init, cap, len, update_expr, exprs...]. The flat-write port for transform_array_init_expr's identity branches (invalid data, fixed array, eval-backend dynamic array) uses this to skip the ast.ArrayInitExpr wrapper struct allocation.

fn (FlatBuilder) emit_array_type_by_elem_id #

fn (mut b FlatBuilder) emit_array_type_by_elem_id(elem_type_id FlatNodeId) FlatNodeId

emit_array_type_by_elem_id emits a typ_array node from an already-flat element type expression FlatNodeId. Mirrors add_type(ArrayType).

fn (FlatBuilder) emit_assign_stmt_by_ids #

fn (mut b FlatBuilder) emit_assign_stmt_by_ids(op token.Token, lhs_ids []FlatNodeId, rhs_ids []FlatNodeId, pos token.Pos) FlatNodeId

emit_assign_stmt_by_ids emits a stmt_assign node from already-flat lhs/rhs expression FlatNodeIds. Mirrors the add_stmt(AssignStmt) encoding exactly: aux1=-1, aux2=lhs.len (lhs/rhs boundary in edges), meta=u16(op), edges = lhs in order followed by rhs in order.

fn (FlatBuilder) emit_comptime_stmt_by_id #

fn (mut b FlatBuilder) emit_comptime_stmt_by_id(stmt_id FlatNodeId) FlatNodeId

emit_comptime_stmt_by_id emits a stmt_comptime node wrapping an already-flat child stmt FlatNodeId. Mirrors the add_stmt(ComptimeStmt) encoding exactly: pos is the zero token.Pos{} the legacy add_stmt arm uses, single edge to the inner stmt. Used by the flat-write port to direct-emit the ast.ComptimeStmt wrapper (the $for branch — the non-$for branch drops the wrapper entirely and recurses).

fn (FlatBuilder) emit_defer_stmt_by_ids #

fn (mut b FlatBuilder) emit_defer_stmt_by_ids(mode DeferMode, stmt_ids []FlatNodeId) FlatNodeId

emit_defer_stmt_by_ids emits a stmt_defer node from a slice of already-flat child stmt FlatNodeIds. Mirrors the add_stmt(DeferStmt) encoding exactly: pos is the zero token.Pos{} the legacy add_stmt arm uses, flags carry flag_defer_func when mode is .function, edges are the inner stmts in order. Used by the flat-write port to direct-emit the ast.DeferStmt wrapper.

fn (FlatBuilder) emit_parameter #

fn (mut b FlatBuilder) emit_parameter(param Parameter) FlatNodeId

emit_parameter is the pub wrapper over the private add_parameter, used by the flat-write port when an FnDecl's receiver is emitted directly.

fn (FlatBuilder) emit_type #

fn (mut b FlatBuilder) emit_type(typ Type) FlatNodeId

emit_type is the pub wrapper over the private add_type, used by the flat-write port when an FnDecl's signature is emitted directly. The FnDecl encoding wraps FnType as Type(stmt.typ) so callers convert.

fn (FlatBuilder) emit_ident_by_name #

fn (mut b FlatBuilder) emit_ident_by_name(name string, pos token.Pos) FlatNodeId

emit_ident_by_name emits an expr_ident node from a name string and pos. Mirrors the add_expr(Ident) encoding exactly: name is interned into the data_id slot, extra is -1, no edges. Used by the flat-write port to direct-emit synthesised ast.Ident{name, pos} wrappers (smartcast rewrites, module/enum lookups, unsafe { nil }, ...).

fn (FlatBuilder) emit_basic_literal_by_value #

fn (mut b FlatBuilder) emit_basic_literal_by_value(kind token.Token, value string, pos token.Pos) FlatNodeId

emit_basic_literal_by_value emits an expr_basic_literal node from a kind/value/pos. Mirrors the add_expr(BasicLiteral) encoding exactly: value is interned into the data_id slot, extra is -1, meta packs the kind token, no edges. Used by the flat-write port to direct-emit synthesised ast.BasicLiteral{kind, value, pos} wrappers ($if res {...} → false, etc.).

fn (FlatBuilder) emit_string_literal_by_value #

fn (mut b FlatBuilder) emit_string_literal_by_value(kind StringLiteralKind, value string, pos token.Pos) FlatNodeId

emit_string_literal_by_value emits an expr_string node from a kind/value/pos. Mirrors the add_expr(StringLiteral) encoding exactly: value is interned into the data_id slot, extra is -1, meta packs the StringLiteralKind, no edges. Used by the flat-write port to direct-emit synthesised ast.StringLiteral{kind, value, pos} wrappers ($typeof(x) → V type name string literal, etc.).

fn (FlatBuilder) emit_paren_expr_by_id #

fn (mut b FlatBuilder) emit_paren_expr_by_id(inner_id FlatNodeId, pos token.Pos) FlatNodeId

emit_paren_expr_by_id emits an expr_paren node from an already-flat inner expression FlatNodeId. Mirrors the add_expr(ParenExpr) encoding exactly.

fn (FlatBuilder) emit_prefix_expr_by_id #

fn (mut b FlatBuilder) emit_prefix_expr_by_id(op token.Token, inner_id FlatNodeId, pos token.Pos) FlatNodeId

emit_prefix_expr_by_id emits an expr_prefix node from an already-flat inner expression FlatNodeId. Mirrors the add_expr(PrefixExpr) encoding exactly: the operator token is packed into the meta u16.

fn (FlatBuilder) emit_modifier_expr_by_id #

fn (mut b FlatBuilder) emit_modifier_expr_by_id(kind token.Token, inner_id FlatNodeId, pos token.Pos) FlatNodeId

emit_modifier_expr_by_id emits an expr_modifier node from an already-flat inner expression FlatNodeId. Mirrors the add_expr(ModifierExpr) encoding exactly: the modifier kind token is packed into the meta u16.

fn (FlatBuilder) emit_postfix_expr_by_id #

fn (mut b FlatBuilder) emit_postfix_expr_by_id(op token.Token, inner_id FlatNodeId, pos token.Pos) FlatNodeId

emit_postfix_expr_by_id emits an expr_postfix node from an already-flat inner expression FlatNodeId. Mirrors the add_expr(PostfixExpr) encoding exactly: the operator token is packed into the meta u16.

fn (FlatBuilder) emit_cast_expr_by_ids #

fn (mut b FlatBuilder) emit_cast_expr_by_ids(typ_id FlatNodeId, expr_id FlatNodeId, pos token.Pos) FlatNodeId

emit_cast_expr_by_ids emits an expr_cast node from already-flat type expression and inner expression FlatNodeIds. Mirrors the add_expr(CastExpr) encoding exactly: edge[0] = typ, edge[1] = expr.

fn (FlatBuilder) emit_as_cast_expr_by_ids #

fn (mut b FlatBuilder) emit_as_cast_expr_by_ids(expr_id FlatNodeId, typ_id FlatNodeId, pos token.Pos) FlatNodeId

emit_as_cast_expr_by_ids emits an expr_as_cast node from already-flat inner expression and type expression FlatNodeIds. Mirrors the add_expr(AsCastExpr) encoding exactly: edge[0] = expr, edge[1] = typ.

fn (FlatBuilder) emit_sql_expr_by_id #

fn (mut b FlatBuilder) emit_sql_expr_by_id(table_name string, is_count bool, is_create bool, expr_id FlatNodeId, pos token.Pos) FlatNodeId

emit_sql_expr_by_id emits an expr_sql node from an already-flat inner expression FlatNodeId. Mirrors the add_expr(SqlExpr) encoding exactly: table_name interned into aux1, is_count/is_create packed into flags, single edge to inner expr.

fn (FlatBuilder) emit_unsafe_expr_by_ids #

fn (mut b FlatBuilder) emit_unsafe_expr_by_ids(stmt_ids []FlatNodeId, pos token.Pos) FlatNodeId

emit_unsafe_expr_by_ids emits an expr_unsafe node from already-flat stmt FlatNodeIds. Mirrors the add_expr(UnsafeExpr) encoding exactly: edges are the body stmts in order.

fn (FlatBuilder) emit_lambda_expr_by_ids #

fn (mut b FlatBuilder) emit_lambda_expr_by_ids(inner_id FlatNodeId, arg_ids []FlatNodeId, pos token.Pos) FlatNodeId

emit_lambda_expr_by_ids emits an expr_lambda node from an already-flat inner expression FlatNodeId and a slice of already-flat arg FlatNodeIds (each arg is an Ident). Mirrors the add_expr(LambdaExpr) encoding exactly: edge[0] is the inner expression, edge[1..] are the args.

fn (FlatBuilder) emit_comptime_expr_by_id #

fn (mut b FlatBuilder) emit_comptime_expr_by_id(inner_id FlatNodeId, pos token.Pos) FlatNodeId

emit_comptime_expr_by_id emits an expr_comptime node from an already-flat inner expression FlatNodeId. Mirrors the add_expr(ComptimeExpr) encoding exactly: a single edge to the inner expression.

fn (FlatBuilder) emit_index_expr_by_ids #

fn (mut b FlatBuilder) emit_index_expr_by_ids(lhs_id FlatNodeId, expr_id FlatNodeId, is_gated bool, pos token.Pos) FlatNodeId

emit_index_expr_by_ids emits an expr_index node from already-flat lhs and index expression FlatNodeIds. Mirrors the add_expr(IndexExpr) encoding exactly: edge[0] is the lhs, edge[1] is the index expression, and the is_gated flag is packed into the flags byte.

fn (FlatBuilder) emit_selector_expr_by_ids #

fn (mut b FlatBuilder) emit_selector_expr_by_ids(lhs_id FlatNodeId, rhs_id FlatNodeId, pos token.Pos) FlatNodeId

emit_selector_expr_by_ids emits an expr_selector node from an already-flat lhs expression and an already-flat rhs Ident expression. Mirrors the add_expr(SelectorExpr) encoding exactly: edge[0] is the lhs expr, edge[1] is the rhs (an Ident emitted as expr_ident).

fn (FlatBuilder) emit_init_expr_by_ids #

fn (mut b FlatBuilder) emit_init_expr_by_ids(typ_id FlatNodeId, field_ids []FlatNodeId, pos token.Pos) FlatNodeId

emit_init_expr_by_ids emits an expr_init node from an already-flat type FlatNodeId and a slice of already-flat aux_field_init FlatNodeIds. Mirrors the add_expr(InitExpr) encoding exactly: edge[0] is the type, edge[1..] are the field-init aux nodes. The flat-write port for struct literals uses this together with emit_field_init_by_id to avoid materialising an ast.InitExpr wrapper on the default path.

fn (FlatBuilder) emit_fn_literal_by_ids #

fn (mut b FlatBuilder) emit_fn_literal_by_ids(typ_id FlatNodeId, captured_var_ids []FlatNodeId, stmt_ids []FlatNodeId, pos token.Pos) FlatNodeId

emit_fn_literal_by_ids emits an expr_fn_literal node from an already-flat FnType FlatNodeId, slice of already-flat captured_var FlatNodeIds, and slice of already-flat stmt FlatNodeIds. Mirrors the add_expr(FnLiteral) encoding exactly: edge[0] is the type, edge[1..1+captured.len] are the captured vars, edge[1+captured.len..] are the stmts; captured_vars.len is packed into extra so the boundary is recoverable.

fn (FlatBuilder) emit_string_inter_by_ids #

fn (mut b FlatBuilder) emit_string_inter_by_ids(format StringInterFormat, width int, precision int, expr_id FlatNodeId, format_expr_id FlatNodeId, resolved_fmt string) FlatNodeId

emit_string_inter_by_ids emits an aux_string_inter node from already-flat inter expression and format_expr FlatNodeIds. Mirrors add_string_inter exactly: edge[0] = expr, edge[1] = format_expr, edge[2] = width, edge[3] = precision; the format token packs into the meta u16; resolved_fmt interns into name.

fn (FlatBuilder) emit_string_inter_literal_by_ids #

fn (mut b FlatBuilder) emit_string_inter_literal_by_ids(kind StringLiteralKind, values []string, inter_ids []FlatNodeId, pos token.Pos) FlatNodeId

emit_string_inter_literal_by_ids emits an expr_string_inter node from a verbatim values []string and a slice of already-flat StringInter FlatNodeIds. Mirrors the add_expr(StringInterLiteral) encoding exactly: edge[0] = values list (built via make_list_strings), edge[1] = inters list (built from the supplied FlatNodeIds via the standard aux_list shape).

fn (FlatBuilder) emit_fn_decl_by_ids #

fn (mut b FlatBuilder) emit_fn_decl_by_ids(name string, is_public bool, is_method bool, is_static bool, language Language, pos token.Pos, receiver_id FlatNodeId, typ_id FlatNodeId, attrs_id FlatNodeId, stmts_id FlatNodeId) FlatNodeId

emit_fn_decl_by_ids emits a stmt_fn_decl node from already-flat child FlatNodeIds (receiver parameter, FnType, attribute list, stmt list). Mirrors the add_stmt(FnDecl) encoding exactly, including the flag_is_public / flag_is_method / flag_is_static bits and the language enum carried in the meta u16.

struct FlatEdge #

struct FlatEdge {
pub:
	child_id FlatNodeId
}

FlatEdge represents a parent->child relationship.

struct FlatFile #

struct FlatFile {
pub:
	file_id        FlatNodeId
	name_idx       int
	mod_idx        int
	selector_names map[int]string
}

FlatFile maps a source file to its flat root node and original selector map.

struct FlatNode #

struct FlatNode {
pub mut:
	kind       FlatNodeKind // 1 byte: variant tag
	flags      u8           // 1 byte: bit-packed booleans (see flag_* consts)
	aux        u16          // 2 bytes: token.Token or sub-kind enum (variant-specific)
	name_id    int          // 4 bytes: primary interned string id (-1 if none)
	extra      int          // 4 bytes: secondary slot (interned string id, packed ints, or list boundary)
	pos        token.Pos    // 8 bytes: inline source position
	first_edge int          // 4 bytes: start offset into FlatAst.edges
	edge_count int          // 4 bytes: number of child edges
}

FlatNode is the compiler-grade flat cell. 28 bytes of payload, 32-byte aligned. Carries inline pos for diagnostics and four side-channel slots (flags, aux, name_id, extra) for variant data.

struct FlowControlStmt #

struct FlowControlStmt {
pub:
	op    token.Token
	label string
}

struct FnDecl #

struct FnDecl {
pub:
	attributes []Attribute
	is_public  bool
	is_method  bool
	is_static  bool
	receiver   Parameter
	language   Language = .v
	name       string
	typ        FnType
	stmts      []Stmt
	pos        token.Pos
}

enum FnArributes { method static }

struct FnLiteral #

struct FnLiteral {
pub:
	typ           FnType
	captured_vars []Expr
	stmts         []Stmt
	pos           token.Pos
}

anon fn / closure

struct FnType #

struct FnType {
pub:
	generic_params []Expr
	params         []Parameter
pub mut:
	return_type Expr = empty_expr
}

fn (FnType) str #

fn (ft &FnType) str() string

struct ForInStmt #

struct ForInStmt {
pub mut:
	// key   		 string
	// value 		 string
	// value_is_mut bool
	// expr	     Expr
	// TODO:
	key   Expr = empty_expr
	value Expr
	expr  Expr
}

Note: used as the initializer for ForStmt

struct ForStmt #

struct ForStmt {
pub mut:
	init  Stmt = empty_stmt // initialization
	cond  Expr = empty_expr // condition
	post  Stmt = empty_stmt // post iteration (afterthought)
	stmts []Stmt
}

struct GenericArgOrIndexExpr #

struct GenericArgOrIndexExpr {
pub:
	lhs  Expr
	expr Expr
	pos  token.Pos
}

struct GenericArgs #

struct GenericArgs {
pub:
	lhs  Expr
	args []Expr // concrete types and lifetimes
	pos  token.Pos
}

struct GenericType #

struct GenericType {
pub:
	name   Expr = empty_expr
	params []Expr
}

struct GlobalDecl #

struct GlobalDecl {
pub:
	attributes []Attribute
	fields     []FieldDecl
	is_public  bool
}

struct Ident #

struct Ident {
pub mut:
	pos  token.Pos
	name string
}

fn (Ident) str #

fn (ident &Ident) str() string

struct IfExpr #

struct IfExpr {
pub mut:
	cond      Expr = empty_expr
	else_expr Expr = empty_expr
	stmts     []Stmt
	pos       token.Pos
}

struct IfGuardExpr #

struct IfGuardExpr {
pub:
	stmt AssignStmt
	pos  token.Pos
}

struct ImportStmt #

struct ImportStmt {
pub:
	name       string
	alias      string
	is_aliased bool
	symbols    []Expr
}

struct IndexExpr #

struct IndexExpr {
pub mut:
	lhs      Expr
	expr     Expr
	is_gated bool
	pos      token.Pos
}

struct InfixExpr #

struct InfixExpr {
pub mut:
	op  token.Token
	lhs Expr
	rhs Expr
	pos token.Pos
}

struct InitExpr #

struct InitExpr {
pub mut:
	typ    Expr
	fields []FieldInit
	pos    token.Pos
}

struct InterfaceDecl #

struct InterfaceDecl {
pub:
	is_public      bool
	attributes     []Attribute
	name           string
	generic_params []Expr
	embedded       []Expr
	fields         []FieldDecl
}

struct Keyword #

struct Keyword {
pub:
	tok token.Token
}

struct KeywordOperator #

struct KeywordOperator {
pub:
	op    token.Token
	exprs []Expr
	pos   token.Pos
}

struct LabelStmt #

struct LabelStmt {
pub:
	name string
	stmt Stmt = empty_stmt
}

struct LambdaExpr #

struct LambdaExpr {
pub:
	args []Ident
	expr Expr
	pos  token.Pos
}

struct LegacyAstStats #

struct LegacyAstStats {
pub mut:
	files          int
	expr_nodes     int
	stmt_nodes     int
	type_nodes     int
	aux_nodes      int
	node_bytes     u64
	array_bytes    u64
	string_entries int
	string_bytes   u64
	// allocs counts distinct heap allocations the GC must track: every
	// sumtype variant payload, every dynamic array (spine), and every
	// string buffer. Flat AST collapses these to a handful of arenas.
	allocs         u64
	bytes_estimate u64
}

LegacyAstStats captures estimated dynamic memory and node shape for the existing AST.

struct LifetimeExpr #

struct LifetimeExpr {
pub:
	name string
	pos  token.Pos
}

struct LockExpr #

struct LockExpr {
pub:
	lock_exprs  []Expr
	rlock_exprs []Expr
	stmts       []Stmt
	pos         token.Pos
}

struct MapInitExpr #

struct MapInitExpr {
pub:
	typ  Expr = empty_expr
	keys []Expr
	vals []Expr
	pos  token.Pos
}

struct MapType #

struct MapType {
pub:
	key_type   Expr = empty_expr
	value_type Expr = empty_expr
}

struct MatchBranch #

struct MatchBranch {
pub:
	cond  []Expr
	stmts []Stmt
	pos   token.Pos
}

struct MatchExpr #

struct MatchExpr {
pub:
	expr     Expr
	branches []MatchBranch
	pos      token.Pos
}

fn (MatchExpr) desugar #

fn (match_expr &MatchExpr) desugar() Expr

Note: this is just a very naive example of how it could possibly work.actual implementation may work during AST -> IR (or not). it may also need type information which we don't have here. as I said, just an example.

struct ModifierExpr #

struct ModifierExpr {
pub mut:
	kind token.Token
	expr Expr
	pos  token.Pos
}

Todo: possibly merge modifiers into a bitfield wheremultiple modifiers are used. this could also be used for struct decl mut:, pub mut: etc. consider this [flag] pub enum Modifier { .atomic .global .mutable .public .shared .static .volatile }

struct ModuleStmt #

struct ModuleStmt {
pub:
	name string
}

struct NilType #

struct NilType {}

struct NoneType #

struct NoneType {}

struct OptionType #

struct OptionType {
pub:
	base_type Expr = empty_expr
}

struct OrExpr #

struct OrExpr {
pub:
	expr  Expr
	stmts []Stmt
	pos   token.Pos
}

pub fn (expr ModifierExpr) unwrap() Expr { return expr.expr }

fn (OrExpr) desugar #

fn (or_expr &OrExpr) desugar() Expr

struct Parameter #

struct Parameter {
pub mut:
	name   string
	typ    Expr
	is_mut bool
	pos    token.Pos
}

fn (Parameter) name_str #

fn (p Parameter) name_str() string

name_str returns the parameter name.

struct ParenExpr #

struct ParenExpr {
pub:
	expr Expr
	pos  token.Pos
}

struct PointerType #

struct PointerType {
pub:
	base_type Expr = empty_expr
	lifetime  string
}

struct PostfixExpr #

struct PostfixExpr {
pub:
	op   token.Token
	expr Expr
	pos  token.Pos
}

struct PrefixExpr #

struct PrefixExpr {
pub mut:
	op   token.Token
	expr Expr
	pos  token.Pos
}

struct RangeExpr #

struct RangeExpr {
pub:
	op    token.Token // `..` exclusive | `...` inclusive
	start Expr
	end   Expr
	pos   token.Pos
}

struct ResultType #

struct ResultType {
pub:
	base_type Expr = empty_expr
}

struct ReturnStmt #

struct ReturnStmt {
pub:
	exprs []Expr
}

struct SelectExpr #

struct SelectExpr {
pub:
	pos   token.Pos
	stmt  Stmt
	stmts []Stmt
	next  Expr = empty_expr
}

struct SelectorExpr #

struct SelectorExpr {
pub mut:
	lhs Expr
	rhs Ident
	pos token.Pos
}

fn (SelectorExpr) leftmost #

fn (se SelectorExpr) leftmost() Expr

fn (SelectorExpr) name #

fn (se SelectorExpr) name() string

pub fn (expr Expr) str() string { return 'Expr.str() - ${expr.type_name()}' }

struct SqlExpr #

struct SqlExpr {
pub:
	expr       Expr
	table_name string
	is_count   bool
	is_create  bool
	pos        token.Pos
}

struct StringInter #

struct StringInter {
pub:
	format    StringInterFormat
	width     int
	precision int
	expr      Expr
	// TEMP: prob removed once individual
	// fields are set, precision etc
	format_expr  Expr = empty_expr
	resolved_fmt string // resolved sprintf format specifier (e.g. '%d', '%s', '%lld'), set by transformer
}

struct StringInterLiteral #

struct StringInterLiteral {
pub:
	kind   StringLiteralKind
	values []string
	inters []StringInter
	pos    token.Pos
}

struct StringLiteral #

struct StringLiteral {
pub:
	kind  StringLiteralKind
	value string
	pos   token.Pos
}

Note: I'm using two nodes StringLiteral & StringInterLiteralto avoid the extra array allocations when not needed.

struct StructDecl #

struct StructDecl {
pub:
	attributes     []Attribute
	is_public      bool
	is_union       bool
	implements     []Expr
	embedded       []Expr
	language       Language = .v
	name           string
	generic_params []Expr
	fields         []FieldDecl
	pos            token.Pos
}

struct ThreadType #

struct ThreadType {
pub:
	elem_type Expr = empty_expr
}

struct Tuple #

struct Tuple {
pub:
	exprs []Expr
	pos   token.Pos
}

struct TupleType #

struct TupleType {
pub:
	types []Expr
}

struct TypeDecl #

struct TypeDecl {
pub:
	is_public      bool
	language       Language
	name           string
	generic_params []Expr
	base_type      Expr = empty_expr
	variants       []Expr
}

struct UnsafeExpr #

struct UnsafeExpr {
pub:
	stmts []Stmt
	pos   token.Pos
}