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

Compiler Internals

This section is for those curious about how the Flint compiler works under the hood. Understanding the internals is not required to use Flint. If you are here to write firmware, skip to Getting Started.

The Big Picture

Flint’s compiler is implemented in Rust and structured as a set of library crates under crates/ in the repository. The main crates are:

CrateRole
flint-cliThe flint binary and argument parsing
flint-driverCommand orchestration and pipeline execution
flint-lexerTokenization
flint-parserParsing, CST construction, error recovery
flint-syntaxShared token kinds, spans, CST/AST node types
flint-checkSemantic analysis: symbol resolution, type checking, ownership
flint-lowerHIR and FIR lowering, type inference, ownership analysis, CFG
flint-backendRP2040-specific machine lowering and Thumb v6-M code generation
flint-diagnosticsDiagnostic types, human-readable and JSON rendering
flint-manifestflint.toml parsing and validation
flint-lspLanguage server: completion, diagnostics, navigation, editor features
flint-elfELF image packaging
flint-uf2UF2 image packaging

Pipeline at a Glance

Source (.fl files)
      │
      ▼
   Lexer            ← flint-lexer
      │
      ▼
   Parser           ← flint-parser
      │
      ▼
   CST → AST        ← flint-syntax, flint-parser
      │
      ▼
  Resolver          ← flint-check
  Type Checker      ← flint-check / flint-lower
      │
      ▼
    HIR             ← flint-lower (high-level IR)
      │
      ▼
    FIR             ← flint-lower (target-independent IR)
      │
      ▼
Machine Lowering    ← flint-backend (target-specific)
      │
      ▼
  Code Gen          ← flint-backend (Thumb / ARM instruction emission)
      │
      ▼
  ELF / BIN / UF2   ← flint-backend, flint-elf, flint-uf2

The key architectural property is that FIR is target-independent. Everything above FIR is shared across all targets. Everything below FIR is per-target.

Design Goals

  • No external toolchain dependencies. The compiler emits machine code directly. No GCC, LLVM, or external assembler.
  • Fast compilation. MCU programs are small. Compilation should be in tens of milliseconds, not seconds.
  • Good diagnostics. Errors point at real source locations with clear messages. JSON output for tooling.
  • Recoverable parsing. The parser continues after errors so you see multiple diagnostics in one run.

Self-Hosted Standard Library

Where possible, the standard library (micro/*, std/*, board/*) is written in Flint source. The compiler and runtime provide privileged backing implementations for things Flint source cannot express (allocator hooks, startup glue, target intrinsics), but high-level APIs are Flint.

This keeps the language honest: the standard library is an ordinary user of the language, not a hidden exception to it.