Frontend

The Abstract Syntax Tree

The representation every later phase is written against: node design, traversal, the visitor as the standard shape of a pass, and why the AST outlives the parser.

The Abstract Syntax Tree
▶ lab

The representation every later phase is written against: `let x = 1 + 2;` stops being ten tokens and becomes a declaration holding an addition holding two literals. The punctuation is gone; the containment is everything.

Q · What is an AST actually, and what does it know that the token stream did not?
Designing AST Nodes
▶ lab

Tagged union or class hierarchy, parent pointers or not, pointers or arena indices, forty node kinds or four hundred, and whether `a += 1` is its own node or sugar the parser desugars on the spot. Five decisions, each of which shapes every pass written afterwards.

Q · How should I actually represent AST nodes — classes, tagged unions, or indices into an array?
Walking the Tree
▶ lab

Every frontend pass is a depth-first search over a tree, and which analyses are correct depends on *when* the node is processed: scopes open on the way down, types are computed on the way up, and getting that backwards produces a compiler that is confidently wrong.

Q · How does a compiler pass actually visit every node, and does the order matter?
The Visitor as the Shape of a Pass
▶ lab

A pass is an object with one method per node kind — `visitBinaryExpression`, `visitFunctionDeclaration`, `visitCallExpression` — and the tree calls it. It is the standard shape of a compiler pass because it makes new passes free, and it is the standard complaint about compiler frontends because it makes new node kinds expensive.

Q · Why is every compiler pass written as a visitor, and what does that shape cost me?
Changing the Tree
▶ lab

Two things a pass can do to an AST: annotate it, or rewrite it. Annotation is cheap and reversible; rewriting has a legality condition and destroys what was there. Whether the rewrite happens in place or produces a new tree decides whether the frontend can ever serve an editor.

Q · When a pass changes the AST, does it mutate the tree or build a new one — and why does anyone care?
One Tree, Six Consumers
▶ lab

The compiler is no longer the only thing that parses your code. The formatter, the linter, the language server, the refactoring engine and the documentation generator all need the same tree — which is why a modern frontend is built as a library and why "just parse it again" is the wrong answer six times over.

Q · Why do modern compilers ship their frontend as a library instead of just a binary?