Implementation Map
x2c translates its extensions into C expressions, statements, and runtime calls. This chapter identifies the parser, transforms, runtime modules, and tests for each feature.
To follow a feature from syntax to generated C, start with its entry below and read the files in the listed order.
What the features mean is documented elsewhere:
- language reference: syntax and behavior
- idioms: how to use each feature well
- standard library overview: runtime contracts
- architecture: the pipeline as a whole
The compiler API reference and runtime module reference describe individual functions and types.
Inspecting a feature’s lowering
To see how a compiler stage transforms a feature, dump the AST before and after
that stage. Take a foreach loop:
int sum(List numbers) {
int total = 0;
foreach(Var n, numbers) total += n;
return total;
}
Print the AST after lowering:
./builds/0/x2c translate --dump-transforms sum.x
(block (declare ("Var") (bindings (bind (binding 4 "n") ())))
(declare ("List")
(bindings
(op = (bind (binding 5 "_x2c_gensym_macro_object_0") ())
(expr ("List") (ident (binding 2 "numbers"))))))
(declare ("List")
(bindings
(op = (bind (binding 6 "_x2c_gensym_macro_cursor_0") ())
(expr ("List") (ident (binding 5 "_x2c_gensym_macro_object_0"))))))
(declare ("Var")
(bindings (bind (binding 7 "_x2c_gensym_macro_cursor_output_0") ())))
(at 20
(while
(expr (int)
(call ... (ident (binding 8 "List_try_next")))
(args (expr ("List") (ident (binding 5 "_x2c_gensym_macro_object_0")))
(expr (opt-ref "List") (op & ...))
(expr (opt-ref "Var") (op & ...)))))
(block ...))))
The built-in source macro in src/macros/macros.x, etc/builtin-macros.x, and
src/builtins.x has replaced foreach with declarations and a
while loop that calls List_try_next. The loop keeps the List, a cursor,
and the current element in generated locals; List_try_next advances the
cursor and stores the element through its reference arguments. The later
transform pass replaces total += n with the run-time compound assignment
helper for that scalar tag, and it passes the cursor and element by address.
Compare --dump-ast with --dump-transforms to see those changes. The full
set of dump flags is listed under compiler options.
Feature ownership
Collection and String literals
- Parse:
src/literals/literals.x - Lower/generate:
src/components/collection-literals.x,src/transform/transform.x,src/cache.x - Runtime:
lib/list/list.x,lib/array.x,lib/map.x,lib/string/string.x - Tests: literal-cache and mutable-empty fixtures, collection suites
- See also: collections
String interpolation
- Parse:
src/literals/literals.xfor$nameand${expr}, which are separate sites - Type/convert:
Compiler.convert_segment_to_stringinsrc/expressions/conversions.xselects the conversion for each segment. A segment that is already aVar, canonical or aliased, renders throughVar_strwhatever its run-time tag; a numeric segment takes its nearest declaredT_strconverter when one exists and is boxed and rendered throughVar_strotherwise - Lower/generate:
src/transform/transform.xconverts each insertion, thensrc/components/interpolation.xjoins them; see builtin components - Runtime:
lib/string/string.x, plusVar.strfor the boxed segments - Tests: interpolation suite
- See also: values
Symbol and Atom literals
- Tokenize:
lib/tokenizer.x, using the scanners inlib/scan.x - Parse:
src/literals/literals.x - Lower/generate:
src/emit/emit.x - Runtime:
lib/symbol.xfor immediateSymbols,lib/atom.xfor spellings that do not fit aSymbol - Tests: symbol suite and checked symbol example
- See also: symbols and atoms
Indexing and slicing
- Parse/type:
src/expressions/expressions.x,src/type.x - Lower:
src/components/bracket-access.xwith ordinary ordered-call and conversion operations fromsrc/transform/transform.x - Runtime: collection helpers plus the shared bounds normalizer in
lib/common.x - Tests: index/slice suite and checked indexing example
- See also: collections
Method-style calls
- Parse/type:
src/expressions/expressions.x,src/type.x - Lower:
src/transform/transform.x; a call that finds no member on a receiver withdelegatefields goes through the one field path that provides it, whichsrc/components/delegate-members.xfinds - Runtime: statically selected module function
- Tests: unit suites across runtime types and the delegate compiler fixtures
Protocol adoptions
- Parse, publish, and resolve declarations and adoptions, and choose each
member’s owner:
src/protocol/protocol.x; operator mappings:src/operator-ledger.x - Write each conformance’s adapters:
src/components/protocol-adapters.x; see builtin components - Runtime descriptors and their registration:
lib/dispatch.x; built-in adoptions:lib/protocols.x - Tests: protocol, adoption, and conformance compiler fixtures and the protocol-boundaries probe
- See also: protocols
Compile-time macros and decorators
- Parse, import, hygiene, and expand:
src/macros/macros.x - Compiler operations for
metacode, theCodeandTypemethods and thex2c_helpers:lib/meta.x - Macro values, their application, and macro-valued
caserecognition:lib/macrovalue/macrovalue.x - Compile-time Lisp boundary adapters:
etc/compiler-sdk.xlisp metaarguments and results:src/stage.x; a unit’smetagroup and in-process staging:src/meta-group/meta-group.x; the project helper:src/meta-project.xbuilds it,src/meta-helper-client.xcalls it, andetc/meta-helper.xanswers, with the compiler queries thattools/gen-meta-queries.shgenerates fromlib/meta.xintoetc/meta-queries.x- Embedded native bindings:
etc/lisp-bindings.x,etc/lisp-bindings.xlisp,lib/lisp-targets.x,lib/lisp/lisp.x, andlib/func.x - Tests: macro import, template, decorator, inline-Lisp, and inferred-binding
compiler fixtures; Lisp and
Funcsuites; compile-time-macros, decorators, and inline-lisp examples - See also: compile-time macros
Package imports and with names
- Parse:
src/parse/parse.x - Package name collection and resolution:
src/symtab/symtab.x,src/collect/collect.x - Manifest and native build ownership:
src/project/project.x,commands/build/build.x, andsrc/toolchain.x - Tests: import/package compiler fixtures and the import-greet example
- See also: packages and imports
Module blocks
- Splice the member files into the entry’s text:
Compiler.module_sourceinsrc/collect/collect.x, called for a unit’s text insrc/frontend.x, for every cold walk of an included file, and for the projectmetascan insrc/meta-project.x - Member positions: the unit’s
line_markersrows, read byCompiler.token_source,Compiler.token_column, andCompiler.text_sourceinsrc/diagnostics.x; a replayed compile-time effect records its site in the member’s own text throughCompiler.source_token - Member dependencies and the entry’s content hash:
FileWalkinsrc/collect/collect.x - The
modulestorage class:_module_storage_forminsrc/parse/units.xretypes the word asstaticunderCompiler.module_declaration - File-private statics: each marker row carries its file’s prefix from
_file_prefixinsrc/collect/collect.x;_declared_keyinsrc/symtab/symtab.xrespells a static’s key withCompiler.private_prefixandCompiler.declared_spelling, which records prefixed spellings so derived names keep theirs;Sym.getand_lookup_fromtry the current file’s key first, andCompiler.unprefixedrestores the short name for Var tags and descriptors - Tests: the
module-blockandmodule-storage-classcompiler fixtures - See also: module blocks
Exact Var-tag tests with is and is not
- Parse, type, and lower:
src/expressions/expressions.xtypes each test as aVar.is,Var.is_void, or constant-rowVar.is_rowcall;src/type.xsupplies the tag facts - Runtime tag representation:
lib/var/var.x,lib/common.x - Tests: is-type and is-not compiler fixtures plus
Varsuites - See also: exact Var-tag tests
List destructuring
- Parse declarations and binders:
src/parse/parse.x,src/statements.x - Type access:
src/type.x; lower:src/components/destructuring.x, dispatched fromsrc/transform/transform.x - Runtime source values:
lib/list/list.x - Tests: destructuring suite and list-destructuring compiler fixtures
Inline Lisp bindings
- Parse and expand
$lisp.bind,$lisp.binding, and$lisp.install:src/macros/macros.x,etc/lisp-bindings.x, andetc/lisp-bindings.xlisp - Runtime call boundary:
lib/lisp/lisp.x,lib/func.x - Tests: Lisp binding compiler fixtures, Lisp/
Funcsuites, and the inline-lisp example - See also: compile-time macros
Var boxing, conversion, operations, and dispatch
- Type selection:
src/type.x - Typedef identity and scopes:
src/symtab/symtab.x,src/statements.x - Conversion lowering:
src/expressions/expressions.x - Protocol operator selection:
src/expressions/expressions.x - Dynamic operators:
src/components/dynamic-operators.x - Truthiness and native emission:
src/transform/transform.x,src/emit/emit.x - Sentinel literal parsing and C spelling:
src/literals/literals.x,src/emit/emit.x; expression context distinguishes the literal from Cvoidtype positions - Runtime representation:
lib/common.x,lib/var/var.x,lib/scope/scope.x - Numeric metadata, conversion, and failure causes:
lib/varconvert.x; shared representation declarations:lib/common.x - Arithmetic, truthiness, and compound assignment:
lib/varops.x - Comparison policy and nonnumeric dispatch:
lib/dispatch.x; exact numeric comparison mechanics delegate toVar.integer_compareandVar.integer_floating_compare - Typedefs: declarations are file-scope; direct and chained aliases of
Varuse the same conversions and operators asVar - Numeric conversion: all 15 numeric tags use one implementation that raises
the appropriate
Errorcause on failure;long/ulong,llong/ullong, andldoublename nativelong,long long, andlong doublefamilies rather than fixed widths - Limits: numeric-to-
Stringconversion remains partial; other nonnumeric values use their declared conversions; helper-backed collection, enum, and bit-field compound assignment are unsupported; the C compiler checks ordinary C lvalue legality - Sentinel contract: equality, identity, exact
is void, and rendering inspectvoid; hashing, ordering, truthiness, iteration, conversion, arithmetic, and updates retain<void-op>behavior - Tests:
Var/File/VarOps suites and wide/custom, var-alias-crossings, var-numeric-lowering, var-numeric-conversions, var-native-lvalue-boundaries, var-truthy-void, var-nonnumeric-operator, var-unary-operator, var-helper-compound, var-enum-compound, var-bitfield-compound, and local-typedef compiler fixtures - See also: values and Var
Scalar declarations, literals, and arithmetic
- Parse:
src/parse/parse.x,src/literals/literals.x,src/expressions/expressions.x - Canonical type owner:
src/type.x - Conversion:
src/transform/transform.x,src/expressions/expressions.x - Runtime representation:
lib/var/var.x,lib/scope/scope.x - Tests: canonical scalar fixture, invalid-scalar and overflow diagnostics,
Varsuite - See also: values and Var
Lambdas
- Parse and resolve captures:
src/literals/literals.x,src/lambdas.x - Lower:
src/components/lambda-functions.x, dispatched fromsrc/transform/transform.x - Direct
Funccalls and conversions:src/callables/callables.x,src/expressions/expressions.x - Runtime:
lib/func.xand receiving callback APIs - Tests: captured-lambda and lambda-lowering fixtures, lambda and
Funcsuites
Foreach
- Parse and expand: built-in source macro support in
src/macros/macros.xandetc/builtin-macros.x; the expansion algorithm insrc/builtins.x - Lower/generate the expanded loop:
src/transform/transform.x,src/emit/emit.x - Runtime:
lib/iter.xand collection adapters;Iter.try_nextreturns the traversal status - Tests:
foreachfixture,Itersuite, and checked example - See also: iteration
Status-bearing Map operations
- Runtime owner:
lib/map.x - Literal boundary:
src/components/collection-literals.x; see builtin components - Generic routing:
lib/dispatch.x - Value-returning wrappers:
Map.getandMap.del - Cursor contract: structural mutation invalidates outstanding traversal state
- Tests:
MapandItersuites plus thevoid-sentinel and rawNullcoverage - See also: collections
Counted Array construction
- Runtime owner:
lib/array.xthroughArray.update_nandArray.push - Literal boundary:
src/components/collection-literals.x; see builtin components - Value contract: raw
Nullis data;voidis rejected - Tests:
Arraysuite and the counted-literal compiler fixture - See also: collections
Var values in printf-family formats
- Parse and type the call:
src/expressions/expressions.x - Lower:
src/components/printf-format.x; see builtin components - Runtime:
Var.convertinlib/varconvert.xandVar.strinlib/dispatch.x - Tests: the
printf-varcompiler fixtures - See also: values and Var
Match statement
- Parse:
src/statements.x - Lower:
src/components/pattern-match.x; see builtin components - Native emission:
src/emit/emit.x - Runtime:
lib/match/match.xand the plan modules listed in the runtime boundary; patterns and binding sets are ordinaryLists fromlib/list/list.x - Tests: match suites and checked nested example
- See also: pattern matching
String switch
- Parse:
src/statements.x - Lower:
src/components/string-switch.x; see builtin components - Tests: the
string-switchandrewrite-string-switchcompiler fixtures - See also: C control flow
Raise, filtered catch, finally, and defer
- Parse:
src/statements.x - Lower/generate:
src/transform/transform.x,src/components/raise.x,src/components/try-catch.x(see builtin components),src/cleanup/cleanup.x,src/emit/emit.x - Runtime:
lib/exception.ximplements the frames and jumps for transfer and cleanup;lib/error/error.xowns handlers, policy, watermarks, accumulated records, matching, and transferring registration lifetime - Tests: optimized
defer/try and filtered-catch compiler fixtures, exception/defer/Errorsuites, and fatal/floor subprocess probes - See also: errors and cleanup, and scopes and lifetime for what cleanup releases
Type-owned initialization
- Parse:
src/parse/parse.x - Lower/generate:
src/generate/generate.x,src/cache.x - Runtime: generated guard plus
TYPE.initialize() - Boundary: generation and cache staging lists the functions that check each guard
- Tests: type-initializer fixtures
Structured diagnostics
- Produce: all parser phases
- Collect/render:
src/diagnostics.x - Destination: standard error, written directly;
src/report.xsuspends the progress line first.--diagnostics-filealso writes JSON Lines diagnostics - Tests: parse-error, diagnostic-width, and invalid-list-splice fixtures plus the diagnostics suite
The exact location fields, one-based coordinates, token-width rendering,
CLI default of 20 errors, low-level one-error default, and reusable store
limit are documented in agents/logger-and-diagnostics-guide.md.
Compiler phase boundaries
The compiler pipeline gives the phase order and the modules in each phase, and module ownership lists each module’s responsibility.
Shared Lisp initialization
The compiler and Lisp.new() load the same etc/init.xlisp: the evaluator
primitives, macros, native bindings, and the standard algorithms (list
traversal, numeric wrappers, selectors, predicates, and pattern helpers).
The algorithms without callbacks are x2c functions in lib/lisp-init.x,
which that file binds by name; map, filter, and foldl stay in Lisp.
Those algorithms use fixed primitive operations internally; their public
Lisp names remain replaceable. In particular, rebinding car, cdr, or
cons does not change filter.
The compiler’s built-in macro algorithms are compiler functions in
src/builtins.x, bound into the shared compile-time session under the
names the built-in macros call. They are bound at the compiler-only
boundary; they are not part of Lisp.new(). Scope expansion, foreach lowering, and deferred class defaults
reuse the ordinary compiler queries and syntax builders.
Native Lisp signature and binding algorithms are compiler functions in
src/builtins.x under _x2c.binding_*, and etc/lisp-bindings.xlisp
defines the Lisp entry points over them. Importing that file loads only
functions. The compiler initializes binding rows and
sealed groups when it installs the binding macros for each translation unit,
so signature preloading cannot put mutable group state in the shared parent.