Parent: #899
Problem
Nineteen parser early-error sites across checkParamBodyConflict, checkCatchClause, validateStrictParams, and parseFunctionDecl still return bare UnexpectedToken. They cover four related binding invariants but lose both the conflicting name and the grammar reason before the JS boundary renders the exception.
Executed on current main (8ba110f), a 20-case eval differential renders UnexpectedToken at ... for every zig-js rejection. Raw JavaScriptCore 625.1.22 distinguishes the cases:
| source family | JavaScriptCore message |
|---|---|
parameter a + body let a | Cannot declare a let variable twice: 'a'. |
parameter a + body const a | Cannot declare a const variable twice: 'a'. |
parameter a + body class a | Cannot declare a class twice: 'a'. |
| duplicate catch binding | Unexpected identifier 'e'. Cannot declare a lexical variable twice: 'e'. |
catch binding + body let / const / class | declaration-kind-specific duplicate prose |
| catch binding + body function | Cannot declare a function that shadows a let/const/class/function variable 'e'. |
strict eval/arguments or duplicate parameters | Invalid parameters or function name in strict mode. |
| anonymous FunctionDeclaration | Function statements must have a name. |
| keyword FunctionDeclaration name | Cannot use the keyword 'if' as a function name. |
| non-simple parameters + own strict directive | 'use strict' directive not allowed inside a function with a non-simple parameter list. |
strict function name eval / arguments | name-specific strict-mode prose |
The same run exposed one oracle difference that must not change acceptance: JavaScriptCore accepts function f(interface) { "use strict"; } and a labeled function shadowing a catch binding, while Node rejects both and test262 defines the strict-reserved-word/catch conflicts as early errors. JavaScriptCore remains the prose oracle only where it implements the required rejection.
Implementation
- Add structured reasons for parameter/body conflicts, catch binding conflicts, strict parameter lists, and FunctionDeclaration name/strictness failures.
- Carry the already-parsed conflicting name and a declaration-kind discriminator to the renderer; do not rescan source text.
- Preserve
ParseError.UnexpectedTokenand existing acceptance semantics. - Keep name lookup and formatting on failure paths; do not widen hot runtime values or add per-source side maps solely for diagnostics.
- Convert all 19 bare returns in the four named functions.
Verification
- Pin reason, message, and a stable grammar-site location for each shape in parser tests.
- Add a production frontend boundary case for eval-visible
.messagevalues. - Compare supported messages with raw JavaScriptCore and rejected grammar with Node/test262 where the oracles differ.
- Compare affected test262 function/catch subtrees against an exact-parent binary and report denominators plus gains/regressions.