Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Compilation Pipeline

The compiler transforms .ink source files into bytecode through six phases:

Phase 1: Discovery + Parse    (brink-db, brink-syntax)    per-file    -> CST -> AST
Phase 2: HIR Lowering          (brink-ir::hir)             per-file    -> HIR
Phase 3: Analysis              (brink-analyzer)            cross-file  -> symbol resolution, types
Phase 4: LIR Lowering          (brink-ir::lir)             cross-file  -> unified LIR program
Phase 5: Bytecode Codegen      (brink-codegen-inkb)        per-container -> StoryData
Phase 6: Output                (brink-format)              -> .inkb / .inkt

The LSP runs phases 1-3. The compiler runs all phases.

Phase 1: Discovery + Parse

ProjectDb::discover() finds all .ink files starting from the entry point, following INCLUDE directives. Each file is parsed by brink-syntax into a lossless CST (via rowan) and then into a typed AST. The parser uses error recovery and always produces output, even for malformed input.

Phase 2: HIR Lowering

The AST is lowered to HIR (High-level Intermediate Representation) per-file. This phase handles weave folding — converting the flat sequence of choices and gathers in ink source into a container tree. Implicit structure like root containers and auto-entering the first stitch is materialized here.

Phase 3: Analysis

Cross-file semantic analysis merges per-file symbol manifests into a unified symbol index, resolves names, and performs type checking. The project database (brink-db) supports incremental updates for the LSP.

Phase 4: LIR Lowering

Per-file HIR plus analysis resolutions are lowered into a unified LIR (Low-level IR) program. The LIR is a flat, container-oriented representation ready for bytecode emission. Container planning, label allocation, and instruction selection happen here.

Phase 5: Bytecode Codegen

brink-codegen-inkb walks the LIR and emits bytecode per container, producing the StoryData structure: containers with bytecode, line tables, variable definitions, list definitions, address labels, and external function declarations. All cross-definition references use DefinitionId, resolved at link time by the runtime.

Phase 6: Output

StoryData can be serialized to .inkb (binary format for production) or .inkt (human-readable text dump for debugging).

Entry points

FunctionDescription
compile_path(path)Full pipeline from a file path
compile(entry, read_file)Full pipeline with a custom file reader (for WASM, tests)
compile_to_json(entry, read_file)Stop at LIR, emit .ink.json format (for diffing against inklecate)
compile_string_to_json(source)Quick JSON emit from a source string

Converter pipeline

A separate pipeline exists for processing inklecate’s output: .ink.json -> parse (brink-json) -> convert (brink-converter) -> StoryData. This is the known-good reference used for validating the native compiler’s output.