Overview & Prerequisites
This section is the orientation. It costs you one or two evenings and it makes every later section cheaper. Do not skip it and start at Lab 1 — the labs assume the vocabulary, the milestone numbering, the crate layout, and the working protocol established here.
The Chapters in This Section
| Chapter | What it gives you | Time |
|---|---|---|
| A Hitchhiker's Guide to Language Runtimes | The 65-year lineage of every idea you are about to implement, and who to blame for each one | 60 min |
| The Warm-Up: An Evening With Lua | Hands-on Lua 5.4, plus four experiments that reveal semantics you will have to implement | 2–3 h |
| Milestone 0: The Runtime Mental Model | The single most important chapter in this section. Twelve claims about how runtimes work, each with an experiment | 2 h |
| The Rust Crate Design | The module tree, the dependency rules, the tooling, and why it is one crate | 45 min |
| The Roadmap: Fifteen Milestones | M0–M14, thirty labs, and the exact definition of "done" for each | 30 min |
| The Weekly Learning Plan | A 16-week calendar you can actually follow, with the honest time sinks marked | 20 min |
| The Teaching Method | The nine-part concept treatment, the twelve-part lab step, the Trace, and the Predict-First protocol | 30 min |
Read them in that order. mental-model.md is the one that pays for the whole section.
Prerequisites, Concretely
The introduction states these loosely. Here they are as a checklist you can actually fail.
Rust
You should be able to answer these without looking anything up. If three or more are unfamiliar, spend a week on the Rust book's chapters 4, 10, 15, and 16 first.
-
What does
&mutguarantee that&does not, and what does the compiler do with that guarantee? -
Why does
Vec<T>invalidate references onpush? -
What is the difference between
Box<T>,Rc<T>, and&Tin terms of who frees the memory? -
What does
RefCell<T>move from compile time to run time, and what is the failure mode? -
When does an
enumin Rust cost more than its largest variant? - What is a lifetime parameter on a struct actually constraining?
-
Why can a
HashMap<K, V>not hand you&mut Vfor two different keys at once?
Every one of those questions is load-bearing in this curriculum. Question 2 decides your heap design. Question 3 decides your GC. Question 7 is the reason Section 4 is hard.
Note: You do not need to be good at
unsafe. Ember contains nounsafein its default configuration — that is a deliberate design constraint and one of the more interesting ones, because "a tracing garbage collector with nounsafe" sounds impossible until you see the trick. Section 7 introducesunsafein exactly two optional places, each with a documented invariant and a test.
Systems literacy
- You know roughly what a CPU cache is and why pointer chasing is slow.
- You have profiled something at least once, with any profiler.
- You can read a stack trace and say what "the stack" is.
Dynamic-language literacy
- You have used a dynamic language with first-class functions.
- You know what a hash map is at the level of "keys go in buckets."
If you have never written Lua specifically, the warm-up closes that gap in an evening. Lua is a small language; that is most of its appeal, and it is why it is the right thing to imitate.
What You Need Installed
# Required
rustc --version # 1.75 or newer; edition 2021
cargo --version
# Required before Section 6
cargo install cargo-fuzz # fuzzing the lexer, parser, and VM
cargo install cargo-criterion # statistically honest benchmarks
cargo install cargo-audit # dependency advisories
# Recommended
cargo install cargo-deny # licence + advisory policy, §6
cargo install flamegraph # §7; needs `perf` on Linux, works via dtrace on macOS
rustup component add clippy rustfmt
# For the warm-up and for differential comparison against real Lua
lua -v # 5.4.x (brew install lua / apt install lua5.4)
cargo-fuzz requires a nightly toolchain:
rustup toolchain install nightly
You will not need nightly for anything else. Ember itself builds on stable.
Tip: On macOS,
cargo flamegraphneedsdtrace, which needs either SIP partially disabled orsudo. If that is a fight you do not want, Section 7 also gives you aperf-free measurement path usingcriterionplus explicit instruction counters built into the VM — which is arguably the better tool anyway, because it is deterministic.
The Two Directories You Must Maintain
These are deliverables. They are checked at the capstone rubric, and the curriculum tells you exactly when to add to each.
docs/learning/
One file per subsystem, written after you finish the corresponding lab, in your own words. The curriculum's own explanations do not count — the point is to force retrieval.
docs/learning/
├── 01-lexer.md
├── 02-parser.md
├── 03-ast.md
├── 04-interpreter.md
├── 05-bytecode.md
├── 06-vm.md
├── 07-call-frames.md
├── 08-tables.md
├── 09-closures.md
├── 10-upvalues.md
├── 11-gc.md
├── 12-embedding.md
├── 13-sandboxing.md
├── 14-performance.md
└── 15-jit.md
Each answers the same nine questions, in under 800 words:
What is this?
Why does it exist?
How does ours work?
What alternatives exist?
What does real Lua do?
What should I pay attention to?
What bugs usually happen here?
What performance issues matter?
What should I read next?
Keep them short. They are notes to your future self, not papers. The single most useful one is "what bugs usually happen here", because you will write it immediately after being bitten.
docs/adr/
One Architecture Decision Record per significant choice, written at the moment of the decision. Four headings, under 400 words:
# ADR-007: Insertion-ordered hash part in tables
## Context
What forced the decision. What we knew and did not know at the time.
## Options
A, B, C — each with its actual cost, not a strawman.
## Decision
What we chose, in one sentence, in the active voice.
## Consequences
What this makes easy, what it makes hard, and what would make us revisit it.
The curriculum names fourteen ADRs you will write. They are indexed in the appendix. A reconstructed rationale is fiction — write it when the decision is fresh, even if it is four sentences long.
How This Curriculum Differs From "Crafting Interpreters"
Many readers arrive here having read Robert Nystrom's Crafting Interpreters, which is excellent and which this curriculum openly builds on. The differences are worth stating so you know what you are getting:
| Crafting Interpreters | This curriculum | |
|---|---|---|
| Language | Java (jlox) and C (clox) | Rust throughout |
| Two implementations | Tree walker in Java, VM in C — separate books, separate code | Both in one crate, and the tree walker is kept as a differential-testing oracle |
| GC | Mark-and-sweep with raw pointers and an object header | Mark-and-sweep over a slot table with generation-checked handles, no unsafe |
| Values | Tagged union, then NaN boxing | Tagged union by default; NaN boxing measured, not assumed |
| Embedding | Not covered | Section 5 — a real host API, host objects, capabilities |
| Sandboxing | Not covered | Section 5 — budgets, limits, and a written threat model |
| Optimization | One chapter | Section 7 — inline caches, specialization, and a Cranelift JIT, all benchmark-gated |
| Rust-specific problems | N/A | Called out explicitly: the object graph vs. the borrow checker is the central Rust lesson |
If you have read Crafting Interpreters, Sections 1–3 will move fast and Section 4 onward will be new. Read it alongside; it is free online and it is the best second opinion you can get.
The One Rule
Nothing is done until you have observed it.
"It compiles" is not a status report. Neither is "the tests pass" if you never looked at what the tests assert. Every lab ends with something you can see — a token dump, a tree, a disassembly, a stack trace, a heap census, a flamegraph. Look at it. That habit is the actual deliverable.
Validation / Self-check
- Which chapter in this section is the one to read most carefully, and why?
- Name the two directories you must maintain and what triggers a new entry in each.
- What are the four headings of an ADR, and why must it be written at the time of the decision?
- Why does Ember avoid
unsafe, and which subsystem makes that constraint interesting? - What is the difference between this curriculum's treatment of the tree-walking interpreter and Crafting Interpreters' treatment of jlox?
- State the One Rule, and give an example of violating it that you have personally committed.