Expand description
Error recovery: where to resume, and what keeps one error from becoming twenty.
Design: spec/06-lexer-and-parser.md section 6.8.
The goal is many useful errors from one run without cascades, and the strategy is per
construct rather than global. A statement that will not parse skips to the next ; or }
at the current bracket depth. A declaration skips past its ;, or past the } of the
function body it turned out to be. An expression skips nothing at all and puts an error node
in the tree where the operand should have been, because expressions are short and skipping
one costs the rest of the statement.
§Why counting errors is not the mechanism
Every recovery leaves a poisoned node behind, and a diagnostic about a poisoned node is not reported. That is what actually stops the cascade. A flag saying “something already went wrong here” is close enough to work on small inputs and wrong on real ones, because it either suppresses errors in code that was fine or fails to suppress the third message about the same broken subexpression.
The sink that holds the diagnostics is Errors, in rucc-diag, because
semantic analysis reports through the same one and the limit is a number for the compiler
rather than one per pass. What is here is the half of it that needs a tree: which nodes are
poisoned, and therefore which messages are held back.
§What is not here yet
The unclosed brace heuristic. Section 6.8 asks for the opening location plus a guess at the intended closing point taken from the indentation, which is how a compiler avoids five hundred errors at end of file. It needs the source map rather than the token stream, so it lands with the diagnostic rendering rather than here.
Traits§
- Poison
- A node that recovery may have poisoned.
Functions§
- push_
about - Records a diagnostic unless
aboutis a node the parser already poisoned. - skip_
past_ declaration - Skips past the declaration the parser gave up on.
- skip_
to_ statement_ end - Skips to the end of the statement the parser gave up on.