Found in the post-#933 survey. Every row below was executed, with node v24.4.1 as the oracle, against a Debug build of main (f2bafeb). node accepts each program; zig-js rejects it before parsing starts.
The lexer tokenizes the whole source first and decides "regex or division" for each / from the previous token. Three of those decisions are wrong, and all three can be decided exactly from tokens alone:
| # | program | node | zig-js |
|---|---|---|---|
postfix ++/-- | var i = 1; var z = i++ / 2; z | 0.5 | UnterminatedString |
var t = 4; var z = t--/2; z (minified) | 2 | UnterminatedString | |
var x = 10, y = 2; var z = x++ /y/ 1; z | 5 | UnexpectedToken | |
var n = 3; var z = n-- / 3; var s = "a/b"; z + s | 1a/b | UnterminatedString | |
| keyword as a property name | var o = { default: 8 }; o.default / 2 | 4 | UnterminatedString |
s.delete / s.total, s.in / 3, r.return / 2 | numbers | UnterminatedString | |
m?.default / 5 | 2 | UnterminatedString | |
) of an if/while/for head | if (1) /"/.test("\"") && (r = 1) | 1 | UnexpectedCharacter |
if (1) /}/.test("}") && (r = 1) | 1 | UnterminatedString | |
while (i++ < 1) /}/.test("}") && (r = 1) | 1 | UnterminatedString | |
for (var i = 0; i < 1; i++) /"/.test("\"") && (r = 1) | 1 | UnexpectedCharacter | |
function f(a){if(a)/"/.test(a)&&(a=1);return a} (minified) | 1 | UnexpectedCharacter |
Causes (src/lexer.zig, regexAllowed):
- after
++/--a regex is always allowed, but a postfix update ends an expression. Postfix is decidable: an expression ended right before the++on the same line (UpdateExpression has[no LineTerminator here]). The prefix form must stay a regex;++/a/g.lastIndexruns correctly today. - after an identifier, the operand-keyword list (
return,in,default,delete, …) is consulted even when the name follows./?., where it is an IdentifierName, not the keyword. - after
)a regex is never allowed, but a statement follows the)of anif/while/for/with/for awaithead (a do-while's)gets a semicolon inserted, so a statement follows it too).
One parser bug on the same path: yield /a/.source (in a generator) fails with UnexpectedToken even though its regex has no quotes. The / after yield is lexed as division; parseYield re-reads it as a regex but takes only that primary, so .source is left over. await has the same shortcut.
Out of scope here, filed separately: cases that need the parser's context rather than the previous token. Examples are a regex containing a quote or brace after yield/await, a label's block }, a class body's }, and template substitutions (${ n++ / 2 } is scanned by a separate byte heuristic).
Done: each program above returns node's value, and the prefix ++/re/ and return /re/ controls still lex as regex. Pinned as focused frontend cases. Debug before/after --diag over the affected test262 subtrees shows 0 failures on both sides.