Diagnostics & Error Recovery
A compiler that stops at the first error is a bad tool. Spans, recovery, synchronization, and diagnostics that name what was expected instead of saying "syntax error".
File, line, column, offset — four numbers that sound trivial and are not. Byte offsets versus (line, column), and the UTF-16 code unit that LSP counts by and your compiler almost certainly does not.
A span is two offsets, half-open, threaded through every stage of the compiler. This is the lesson where the discipline of carrying them finally pays: underlines, secondary labels, jump-to-definition, rename, quick fixes and source maps are all one data structure.
Detect, report, synchronize, continue. A compiler that stops at the first error costs a round trip per typo — and one that recovers badly turns a single missing brace into forty messages, which is worse.
The judgement call inside error recovery: which token to resume at. Too eager and a whole function is skipped in silence; too timid and one missing brace produces forty messages that are all the same mistake.
`syntax error` versus `Expected ')' after function arguments. Found '{' instead.` The difference is not politeness — it is a span, a named expectation, and a note about the thing that caused it, each of which the compiler had to be built to keep.
A diagnostic that carries an edit an editor can apply, and the discipline that keeps it honest: "did you mean" by edit distance, a confidence label on every suggestion, and a budget past which no suggestion is better than a confident wrong one.