Step 01 · Developer experience matters
A compiler that's correct but cryptic loses to one that's slightly less powerful but obviously helpful. Compare:
$ old-compiler
error: syntax error
$ rustc-style
error[E0202]: expected expression, got `;`
--> example.rs:5:11
|
5 | print 1 + ;
| ^
| help: try a number, a variable, or `(`
Same parser bug; vastly different debugging experience. The investment that pays off:
- Source spans on every AST node. Tokens carry
(start, length); AST nodes inherit and merge them. - Structured diagnostics:
(severity, code, message, span, hint)rather than a string. This lets:- The compiler suggest fix-its (
hint). - IDEs render squigglies precisely (span).
clippy-style tools filter by code.
- The compiler suggest fix-its (
- Error recovery: parsers continue past errors so users see all problems in one pass, not "fix → recompile → fix → recompile".
- Tooling ecosystem:
fmt,ast,repl,lspare first-class citizens that share the same parser & diagnostics.
This lab implements the foundation. cp-16's capstone wires it into the full compiler frontend.
Why the CLI is one binary with subcommands
minilang run|fmt|ast|repl instead of minilang-run, minilang-fmt, etc:
- Single install footprint.
- Shared option parsing & shared error format.
- Easier to add
minilang check,minilang test,minilang doclater.
This is the design cargo, go, git, dotnet, and dart all
converged on for the same reasons.