You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix JS line-terminator conformance across all four lexers (CR / LS / PS)
The lexers counted only LF as a line terminator, but ECMAScript also defines CR
(U+000D), LS (U+2028), and PS (U+2029) — the set that drives ASI and the
"no LineTerminator here" restrictions. So `return\r1` was parsed `return 1`
where a conforming JS parser applies ASI (bare `return`, then `1`).
Fixed consistently in all four lexer implementations so they stay in lockstep:
- gen-lexer.ts (interpreter, the oracle): LF/CR in the ASCII path, LS/PS via the
\s-run regex, and the comment-span check.
- emit-lexer.ts (emitted SoA/JS lexer): the same, in its codegen.
- target-ts.ts (portable, UTF-16): LF/CR/LS/PS.
- target-go.ts / target-rust.ts (portable, byte-based): LF/CR (LS/PS are multi-byte
and fall under the documented non-ASCII offset boundary).
CRLF is unchanged (the LF already set newline-before), so the existing corpus is
unaffected — the change only reaches lone-CR and LS/PS inputs. This supersedes the
earlier direction (which had made the portable lexers match the LF-only interpreter);
now the interpreter is conforming and all four agree on the full set.
sljs gate extended: `return\r1;` / `return\r\n1;` / `return /*\r*/ 1;` reject,
`return\t1;` accepts (tab is whitespace, not a terminator) — checked across ts/go/rust.
emit-parser-verify byte-identical, portable-targets 16 grammars ×3, full suite 42/42.
\t\tif c == 10 { pendingNl = true; pos++; continue } // only LF (10) is newline-before (matches the interpreter); CR is plain whitespace
160
-
\t\tif c == 13 || c == 32 || c == 9 || c == 11 || c == 12 || c == 160 || c == 5760 || (c >= 8192 && c <= 8202) || c == 8239 || c == 8287 || c == 12288 || c == 65279 { pos++; continue }
159
+
\t\tif c == 10 || c == 13 { pendingNl = true; pos++; continue } // JS line terminators LF/CR (matches the interpreter; LS/PS are multi-byte: non-ASCII boundary)
160
+
\t\tif c == 32 || c == 9 || c == 11 || c == 12 || c == 160 || c == 5760 || (c >= 8192 && c <= 8202) || c == 8239 || c == 8287 || c == 12288 || c == 65279 { pos++; continue }
if (c === 13 || c === 8232 || c === 8233 || c === 32 || c === 9 || c === 11 || c === 12 || c === 160 || c === 5760 || (c >= 8192 && c <= 8202) || c === 8239 || c === 8287 || c === 12288 || c === 65279) { pos++; continue; }
150
+
// JS line terminators LF/CR/LS/PS set newline-before, matching the interpreter (gen-lexer.ts).
151
+
if (c === 10 || c === 13 || c === 8232 || c === 8233) { pendingNl = true; pos++; continue; }
152
+
if (c === 32 || c === 9 || c === 11 || c === 12 || c === 160 || c === 5760 || (c >= 8192 && c <= 8202) || c === 8239 || c === 8287 || c === 12288 || c === 65279) { pos++; continue; }
154
153
${tplDispatch}${toks}
155
154
${puncts}
156
155
throw new Error('lex error at ' + pos + ': ' + JSON.stringify(src[pos]));
0 commit comments