Skip to content

Starling JS parser: 'in' operator inside parentheses in a for-loop head is rejected #76

Description

@codymullins

The Starling JS parser rejects the in operator inside a parenthesized expression in a for-loop head with expected ')' to close grouping (got In 'in'). The code is legal: the no-in restriction applies only to the top-level expression of the for head (so the parser can tell for(;;) from for-in), never inside parentheses. x.com's shared~ondemand.XChat~ondemand.ChatDrawer.ba31fdba.js chunk dies on this.

What happens

The parser threads the restriction through _disallowInDepth (src/Starling.Js/Parse/JsParser.cs:21). Binary-operator parsing skips in whenever the depth is non-zero (JsParser.cs:748, 764). The depth is correctly saved and zeroed when entering contexts where the restriction must not apply:

  • arrow concise bodies (JsParser.cs:510-519)
  • call arguments (JsParser.cs:1143-1157)
  • bracket subscripts (JsParser.cs:1437-1473)
  • computed member keys (JsParser.cs:1658-1663)

The parenthesized-expression arm does not. The LParen case of the primary-expression parser (JsParser.cs:1279-1299) calls ParseAssignment() with _disallowInDepth still set, so in is suppressed as a binary operator and the parser then trips over the unconsumed in token.

Per the grammar, CoverParenthesizedExpressionAndArrowParameterList always contains Expression[+In] — parentheses reset the restriction.

Repro

for (var x = ('a' in {a: 1}) ? 1 : 2; x < 3; x++) {}   // legal everywhere, node accepts it

The chunk-level failure was verified on 2026-06-10 against the real x.com chunk with the exact message above. The minimal form follows directly from the cited parse path.

Fix

Real fix: in the LParen arm of the primary-expression parser, save _disallowInDepth, zero it, and restore it in a finally — the same pattern the bracket-subscript and call-argument paths already use. No band-aid applies.

Context

Found during the x.com/nasa boot investigation on 2026-06-10 (branch feat/js-stack-trampoline). Same blast-radius pattern as the sibling parser issues (regex Unicode property escapes, template-substitution comma): one parse error kills every webpack module in the chunk.

Metadata

Metadata

Assignees

No one assigned

    Labels

    browserRelates to the browser subsystembugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions