Start here
Introduction
Every program you have ever run started as text. Something had to turn that text into the electrical switching of a processor: a compiler, an interpreter, or, more often than you would think, a chain of both. This site follows that journey step by step with Wahoo, a tiny language from the Mushroom Kingdom whose real compiler runs in your browser.
In this chapter
Chapter 00: Compiled, interpreted, or both? →Open the playgroundLearn Wahoo in five minutes
world 1-1 is where it starts, coin declares a variable, run is a counting loop, power_up adds to a counter, question is an if and wahoo(...) prints. Press Run: the text is lexed, parsed, type-checked, optimised and turned into WebAssembly by a compiler written in Rust, which is itself running here as WebAssembly.The journey in one picture
A compiler is a pipeline. Each stage takes the program in one shape and hands it to the next in a shape that is a little closer to the machine: characters become tokens, tokens become a tree, the tree gets meaning (names resolved, types checked), meaning becomes instructions, instructions get faster, and finally something runs them. The chapters follow that order:
-
00
Models 1949 – today
Compiled, interpreted, or both?
A processor only understands machine code. There are two ways to get a program written in text to it: translate the whole thing beforehand, or read it and act it out as you go. Almost every real language uses a mixture of both.
- Compiler vs. interpreter
- Bytecode and virtual machines
- Just-in-time compilation
- Transpilers
- Bootstrapping
-
01
Lex 1956 – 1975
From characters to words
To a compiler, a program arrives as a long string of characters. The first phase, the lexer, reads them one by one and groups them into tokens: keywords, names, numbers, symbols. It is the simplest phase, and it rests on one of the cleanest results in computer science.
- Tokens and lexemes
- Regular expressions
- Finite automata
- Maximal munch
- Error recovery
-
02
Parse 1956 – 1975
From words to trees
Tokens come in a flat line, but programs are nested: expressions inside expressions, blocks inside loops inside functions. The parser recovers that structure as a tree, guided by a grammar, a notion borrowed from linguistics in the 1950s.
- Context-free grammars
- BNF
- Abstract syntax trees
- Recursive descent
- Pratt parsing
- LL and LR
-
03
Check 1958 – today
Does it make sense?
A program can be perfectly grammatical and still meaningless: a name nobody declared, a number used as a condition, a function that forgets to return. The checker resolves every name and gives every expression a type, so that these mistakes are caught before the program ever runs.
- Scopes and symbol tables
- Type checking
- Type inference
- Desugaring
- Conservative analysis
-
04
Generate 1957 – today
From meaning to instructions
The checked program says what must happen; the code generator decides how, in the vocabulary of the target machine. For WebAssembly that machine is a stack machine: expressions become sequences of pushes and operations, and loops become blocks you can only jump out of or back to the top of.
- Intermediate representations
- Stack machines
- Lowering control flow
- Memory layout
- Register allocation
-
05
Optimise 1957 – today
Doing less, faster
An optimiser rewrites a program into a cheaper one that behaves exactly the same. Some rewrites are obvious, like computing 2 × 60 at compile time; others need a careful analysis of how values flow through the program. All of them live under one rule: nobody must be able to tell the difference.
- The as-if rule
- Constant folding
- Dead code elimination
- Data-flow analysis
- Undefined behaviour
-
06
Run 1945 – today
Who actually runs it?
The compiler's last act is to write a file of bytes. Turning those bytes into a running program is the job of another piece of software: a loader, a virtual machine or, for Wahoo, the WebAssembly engine in your browser, which checks the module, compiles it once more and runs it inside a sandbox.
- Stored-program computers
- Loading and linking
- WebAssembly
- Validation and sandboxing
- Tiered compilation
Compiled, interpreted… or both?
“Python is interpreted, C is compiled” is the kind of sentence that is half true. Python is compiled to bytecode before it runs; Java is compiled twice; JavaScript starts out interpreted and is recompiled to machine code while it runs; TypeScript is compiled into another programming language. Chapter 00 takes a dozen real languages apart and shows where, in each of them, the text stops being text. The rest of the site builds one complete compiler, phase by phase, so that every word in those diagrams has a concrete, inspectable meaning.
| Phase | Question it answers | In Wahoo's compiler | Where |
|---|---|---|---|
| Lexing | Which words are in this text? | lexer.rs: characters → tokens | 01 |
| Parsing | How do the words fit together? | parser.rs: tokens → syntax tree | 02 |
| Semantic analysis | Does it make sense? | checker.rs: scopes and types | 03 |
| Code generation | What must the machine do? | codegen.rs, wasm.rs: WebAssembly | 04 |
| Optimisation | Can it do less? | optimizer.rs: folding, dead code | 05 |
| Execution | Who runs it, and how? | your browser's Wasm engine | 06 |
Why Mario?
Because a language you have never seen forces you to look at it the way a compiler does: as text with rules. In Wahoo, programs are played as worlds (1-1, then 1-2…), functions are pipes you go down and come back from with a value at the flag, whole numbers are coins, booleans are star and goomba, and a division by zero makes you fall into a pit. Underneath the costume it is a real, statically typed language with recursion, loops, scopes and a compiler with good error messages. The language page has the whole of it on one screen.
How to read this site
In order, like a short book, or jump straight to the phase you are curious about: each chapter stands on its own. Every interactive figure uses the same compiler as the playground, so whatever you type is processed for real, not simulated. The source of everything (compiler, command-line tool, this site) is on GitHub, small enough to read in an evening.