Architecture

Inside the AHA! compiler — lexer, Pratt parser, type system, LLVM codegen, and JIT

Compiler Architecture

AHA! is a complete compiler in a single binary:

Source Code → Lexer → Parser (Pratt) → AST → Code Generator → LLVM IR → JIT Execution

Stages

StageModuleWhat it does
Lexersrc/lexer.rsTokenizes source: identifiers, integers, strings (with escapes), operators, line & block comments
Parsersrc/parser.rsPratt parser producing the AST — expression-oriented, with correct operator precedence
Type Systemsrc/types.rsAhaType + TypedValue; compile-time checks for binary and prefix operators
Codegensrc/codegen.rsLLVM IR generation via inkwell: functions (with return-type inference), loops, strings, arrays, C-runtime linkage
Driversrc/main.rsCLI entry point: lex → parse → codegen → print IR → JIT execute

Design Notes

  • LLVM 14 through the inkwell crate — no hand-rolled backend
  • Strings are {i8*, i64} structs; malloc, memcpy, and strcmp come from the linked C runtime
  • TypedValue: every codegen expression returns both an LLVM value and its AhaType, so type errors surface before the IR is built
  • Booleans compose with math: all comparison and logical operators produce i64 0/1, so is_even(n) * 100 needs no casts
  • JIT execution runs the generated IR inside the compiler process — no separate interpreter

How a Program Executes

  1. The lexer turns source text into a token stream.
  2. The Pratt parser builds an expression-oriented AST with correct precedence.
  3. The type system checks every binary and prefix operation.
  4. Codegen emits LLVM IR (functions, loops, strings, builtin calls) via inkwell.
  5. The driver links and JIT-executes the IR, printing the program result.