Skip to content

Instantly share code, notes, and snippets.

@rbuckton
Last active January 25, 2024 18:35
Show Gist options
  • Save rbuckton/d26f0e04bd693324a87c3da3835d87f2 to your computer and use it in GitHub Desktop.
Save rbuckton/d26f0e04bd693324a87c3da3835d87f2 to your computer and use it in GitHub Desktop.

Syntactic Restrictions Without Trailing Lookahead

CoverParenthesizedExpressionAndArrowParameterList[Yield, Await] :
  `(` Expression[+In, ?Yield, ?Await, +Throw] `)`
  `(` Expression[+In, ?Yield, ?Await, ~Throw] `,` `)`
  `(` `)`
  `(` `...` BindingIdentifier[?Yield, ?Await] `)`
  `(` `...` BindingPattern[?Yield, ?Await] `)`
  `(` Expression[+In, ?Yield, ?Await, ~Throw] `,` `...` BindingIdentifier[?Yield, ?Await] `)`
  `(` Expression[+In, ?Yield, ?Await, ~Throw] `,` `...` BindingPattern[?Yield, ?Await] `)`

ParenthesizedExpression[Yield, Await] :
  `(` Expression[+In, ?Yield, ?Await, +Throw] `)`
 
UpdateExpression[Yield, Await, Throw] :
  LeftHandSideExpression[?Yield, ?Await]
  LeftHandSideExpression[?Yield, ?Await] [no LineTerminator here] `++`
  LeftHandSideExpression[?Yield, ?Await] [no LineTerminator here] `--`
  `++` UnaryExpression[?Yield, ?Await, ?Throw]
  `--` UnaryExpression[?Yield, ?Await, ?Throw]

UnaryExpression[Yield, Await, Throw] :
  UpdateExpression[?Yield, ?Await, ?Throw]
  `delete` UnaryExpression[?Yield, ?Await, ?Throw]
  `void` UnaryExpression[?Yield, ?Await, ?Throw]
  `typeof` UnaryExpression[?Yield, ?Await, ?Throw]
  `+` UnaryExpression[?Yield, ?Await, ?Throw]
  `-` UnaryExpression[?Yield, ?Await, ?Throw]
  `~` UnaryExpression[?Yield, ?Await, ?Throw]
  `!` UnaryExpression[?Yield, ?Await, ?Throw]
  [+Await] AwaitExpression[?Yield, ?Throw]
  [+Throw] ThrowExpression[?Yield, ?Await]

ExponentiationExpression[Yield, Await, Throw] :
  UnaryExpression[?Yield, ?Await, ?Throw]
  UpdateExpression[?Yield, ?Await, ~Throw] `**` ExponentiationExpression[?Yield, ?Await, ?Throw]

MultiplicativeExpression[Yield, Await, Throw] :
  ExponentiationExpression[?Yield, ?Await, ?Throw]
  MultiplicativeExpression[?Yield, ?Await, ?Throw] MultiplicativeOperator ExponentiationExpression[?Yield, ?Await, ?Throw]
  # SS:
  #   MultiplicativeExpression :
  #     MultiplicativeExpression MultiplicativeOperator ExponentiationExpression[?Yield, ?Await, ?Throw]
  #   - Syntax error if ContainsThrowOnRight of |MultiplicativeExpression| is `true`.
  #   NOTE: Prevents ASI from kicking in for `a ?? throw b\n /c/d`

AdditiveExpression[Yield, Await, Throw] :
  MultiplicativeExpression[?Yield, ?Await, ?Throw]
  AdditiveExpression[?Yield, ?Await, ?Throw] `+` MultiplicativeExpression[?Yield, ?Await, ?Throw]
  AdditiveExpression[?Yield, ?Await, ?Throw] `-` MultiplicativeExpression[?Yield, ?Await, ?Throw]
  # SS:
  #   AdditiveExpression :
  #     AdditiveExpression `+` MultiplicativeExpression
  #     AdditiveExpression `-` MultiplicativeExpression
  #   - Syntax error if ContainsThrowOnRight of |AdditiveExpression| is `true`.
  #   NOTE: Prevents ASI from kicking in for `a ?? throw b\n + c`

ShiftExpression[Yield, Await, Throw] :
  AdditiveExpression[?Yield, ?Await, ?Throw]
  ShiftExpression[?Yield, ?Await, ~Throw] `<<` AdditiveExpression[?Yield, ?Await, ?Throw]
  ShiftExpression[?Yield, ?Await, ~Throw] `>>` AdditiveExpression[?Yield, ?Await, ?Throw]
  ShiftExpression[?Yield, ?Await, ~Throw] `>>>` AdditiveExpression[?Yield, ?Await, ?Throw]

RelationalExpression[In, Yield, Await, Throw] :
  ShiftExpression[?Yield, ?Await, ?Throw]
  RelationalExpression[?In, ?Yield, ?Await, ~Throw] `<` ShiftExpression[?Yield, ?Await, ?Throw]
  RelationalExpression[?In, ?Yield, ?Await, ~Throw] `>` ShiftExpression[?Yield, ?Await, ?Throw]
  RelationalExpression[?In, ?Yield, ?Await, ~Throw] `<=` ShiftExpression[?Yield, ?Await, ?Throw]
  RelationalExpression[?In, ?Yield, ?Await, ~Throw] `>=` ShiftExpression[?Yield, ?Await, ?Throw]
  RelationalExpression[?In, ?Yield, ?Await, ~Throw] `instanceof` ShiftExpression[?Yield, ?Await, ?Throw]
  [+In] RelationalExpression[+In, ?Yield, ?Await, ~Throw] `in` ShiftExpression[?Yield, ?Await, ?Throw]
  [+In] PrivateIdentifier `in` ShiftExpression[?Yield, ?Await, ?Throw]

EqualityExpression[In, Yield, Await, Throw] :
  RelationalExpression[?In, ?Yield, ?Await, ?Throw]
  EqualityExpression[?In, ?Yield, ?Await, ~Throw] `==` RelationalExpression[?In, ?Yield, ?Await, ?Throw]
  EqualityExpression[?In, ?Yield, ?Await, ~Throw] `!=` RelationalExpression[?In, ?Yield, ?Await, ?Throw]
  EqualityExpression[?In, ?Yield, ?Await, ~Throw] `===` RelationalExpression[?In, ?Yield, ?Await, ?Throw]
  EqualityExpression[?In, ?Yield, ?Await, ~Throw] `!==` RelationalExpression[?In, ?Yield, ?Await, ?Throw]

BitwiseANDExpression[In, Yield, Await, Throw] :
  EqualityExpression[?In, ?Yield, ?Await, ?Throw]
  BitwiseANDExpression[?In, ?Yield, ?Await, ~Throw] `&` EqualityExpression[?In, ?Yield, ?Await, ?Throw]

BitwiseXORExpression[In, Yield, Await, Throw] :
  BitwiseANDExpression[?In, ?Yield, ?Await, ?Throw]
  BitwiseXORExpression[?In, ?Yield, ?Await, ~Throw] `^` BitwiseANDExpression[?In, ?Yield, ?Await, ?Throw]

BitwiseORExpression[In, Yield, Await, Throw] :
  BitwiseXORExpression[?In, ?Yield, ?Await, ?Throw]
  BitwiseORExpression[?In, ?Yield, ?Await, ~Throw] `|` BitwiseXORExpression[?In, ?Yield, ?Await, ?Throw]

LogicalANDExpression[In, Yield, Await, Throw] :
  BitwiseORExpression[?In, ?Yield, ?Await, ?Throw]
  LogicalANDExpression[?In, ?Yield, ?Await, ~Throw] `&&` BitwiseORExpression[?In, ?Yield, ?Await, ?Throw]

LogicalORExpression[In, Yield, Await, Throw] :
  LogicalANDExpression[?In, ?Yield, ?Await, ?Throw]
  LogicalORExpression[?In, ?Yield, ?Await, ~Throw] `||` LogicalANDExpression[?In, ?Yield, ?Await, ?Throw]

CoalesceExpression[In, Yield, Await, Throw] :
  CoalesceExpressionHead[?In, ?Yield, ?Await, ~Throw] `??` BitwiseORExpression[?In, ?Yield, ?Await, ?Throw]

CoalesceExpressionHead[In, Yield, Await, Throw] :
  CoalesceExpression[?In, ?Yield, ?Await, ?Throw]
  BitwiseORExpression[?In, ?Yield, ?Await, ?Throw]

ShortCircuitExpression[In, Yield, Await, Throw] :
  LogicalORExpression[?In, ?Yield, ?Await, ?Throw]
  CoalesceExpression[?In, ?Yield, ?Await, ?Throw]

ConditionalExpression[In, Yield, Await, Throw] :
  ShortCircuitExpression[?In, ?Yield, ?Await, ?Throw]
  ShortCircuitExpression[?In, ?Yield, ?Await, ~Throw] `?` AssignmentExpression[+In, ?Yield, ?Await, ?Throw] `:` AssignmentExpression[?In, ?Yield, ?Await, ?Throw]

AssignmentExpression[In, Yield, Await, Throw] :
  ConditionalExpression[?In, ?Yield, ?Await, ?Throw]
  [+Yield] YieldExpression[?In, ?Await, ?Throw]
  ArrowFunction[?In, ?Yield, ?Await, ?Throw]
  AsyncArrowFunction[?In, ?Yield, ?Await, ?Throw]
  LeftHandSideExpression[?Yield, ?Await, ~Throw] `=` AssignmentExpression[?In, ?Yield, ?Await, ?Throw]
  LeftHandSideExpression[?Yield, ?Await, ~Throw] AssignmentOperator AssignmentExpression[?In, ?Yield, ?Await, ?Throw]
  LeftHandSideExpression[?Yield, ?Await, ~Throw] `&&=` AssignmentExpression[?In, ?Yield, ?Await, ?Throw]
  LeftHandSideExpression[?Yield, ?Await, ~Throw] `||=` AssignmentExpression[?In, ?Yield, ?Await, ?Throw]
  LeftHandSideExpression[?Yield, ?Await, ~Throw] `??=` AssignmentExpression[?In, ?Yield, ?Await, ?Throw]
  [+Throw] ThrowExpression[?Yield, ?Await] `/=` AssignmentExpression[?In, ?Yield, ?Await, ?Throw]
  # SS:
  #   AssignmentExpression :
  #     ThrowExpression `/=` AssignmentExpression
  #   - Syntax error if any source text matched by this production
  #   NOTE: Prevents ASI from kicking in for `a = throw b\n /=c/d`

Expression[In, Yield, Await, Throw] :
  AssignmentExpression[?In, ?Yield, ?Await, ?Throw]
  Expression[?In, ?Yield, ?Await, ~Throw] `,` AssignmentExpression[?In, ?Yield, ?Await, ?Throw]

ExpressionStatement[Yield, Await] :
  [lookahead ∉ { `{`, `function`, `async` [no LineTerminator here] `function`, `class`, `let [` }] Expression[+In, ?Yield, ?Await, ~Throw] `;`

ArrowFunction[In, Yield, Await, Throw] :
  ArrowParameters[?Yield, ?Await] [no LineTerminator here] => ConciseBody[?In, ?Throw]

ConciseBody[In, Throw] :
  [lookahead ≠ {] ExpressionBody[?In, ~Await, ?Throw]
  `{` FunctionBody[~Yield, ~Await] `}`

ExpressionBody[In, Await, Throw] :
  AssignmentExpression[?In, ~Yield, ?Await, ?Throw]

AsyncArrowFunction[In, Yield, Await, Throw] :
  `async` [no LineTerminator here] AsyncArrowBindingIdentifier[?Yield] [no LineTerminator here] `=>` AsyncConciseBody[?In, ?Throw]
  CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await] [no LineTerminator here] `=>` AsyncConciseBody[?In, ?Throw]

AsyncConciseBody[In, Throw] :
  [lookahead ≠ {] ExpressionBody[?In, +Await, ?Throw]
  `{` AsyncFunctionBody `}`

Alternative: [no ASI if lookahead ...]

Alternatively, we could introduce a [no ASI if lookahead ...] constraint to ecmarkup to replace the Static Semantics constraints used to work around ASI, and do something like this instead:

CoverParenthesizedExpressionAndArrowParameterList[Yield, Await] :
  `(` Expression[+In, ?Yield, ?Await, +Throw] `)`
  `(` Expression[+In, ?Yield, ?Await, ~Throw] `,` `)`
  `(` `)`
  `(` `...` BindingIdentifier[?Yield, ?Await] `)`
  `(` `...` BindingPattern[?Yield, ?Await] `)`
  `(` Expression[+In, ?Yield, ?Await, ~Throw] `,` `...` BindingIdentifier[?Yield, ?Await] `)`
  `(` Expression[+In, ?Yield, ?Await, ~Throw] `,` `...` BindingPattern[?Yield, ?Await] `)`

ParenthesizedExpression[Yield, Await] :
  `(` Expression[+In, ?Yield, ?Await, +Throw] `)`
 
UpdateExpression[Yield, Await, Throw] :
  LeftHandSideExpression[?Yield, ?Await]
  LeftHandSideExpression[?Yield, ?Await] [no LineTerminator here] `++`
  LeftHandSideExpression[?Yield, ?Await] [no LineTerminator here] `--`
  `++` UnaryExpression[?Yield, ?Await, ?Throw]
  `--` UnaryExpression[?Yield, ?Await, ?Throw]

ThrowExpression[Yield, Await] :
  `throw` UnaryExpression[?Yield, ?Await, +Throw] [no ASI if lookahead ∈ { `/`, `/=`, `+`, `-` }]

UnaryExpression[Yield, Await, Throw] :
  UpdateExpression[?Yield, ?Await, ?Throw]
  `delete` UnaryExpression[?Yield, ?Await, ?Throw]
  `void` UnaryExpression[?Yield, ?Await, ?Throw]
  `typeof` UnaryExpression[?Yield, ?Await, ?Throw]
  `+` UnaryExpression[?Yield, ?Await, ?Throw]
  `-` UnaryExpression[?Yield, ?Await, ?Throw]
  `~` UnaryExpression[?Yield, ?Await, ?Throw]
  `!` UnaryExpression[?Yield, ?Await, ?Throw]
  [+Await] AwaitExpression[?Yield, ?Throw]
  [+Throw] ThrowExpression[?Yield, ?Await]

ExponentiationExpression[Yield, Await, Throw] :
  UnaryExpression[?Yield, ?Await, ?Throw]
  UpdateExpression[?Yield, ?Await, ~Throw] `**` ExponentiationExpression[?Yield, ?Await, ?Throw]

MultiplicativeExpression[Yield, Await, Throw] :
  ExponentiationExpression[?Yield, ?Await, ?Throw]
  MultiplicativeExpression[?Yield, ?Await, ~Throw] MultiplicativeOperator ExponentiationExpression[?Yield, ?Await, ?Throw]

AdditiveExpression[Yield, Await, Throw] :
  MultiplicativeExpression[?Yield, ?Await, ?Throw]
  AdditiveExpression[?Yield, ?Await, ~Throw] `+` MultiplicativeExpression[?Yield, ?Await, ?Throw]
  AdditiveExpression[?Yield, ?Await, ~Throw] `-` MultiplicativeExpression[?Yield, ?Await, ?Throw]

ShiftExpression[Yield, Await, Throw] :
  AdditiveExpression[?Yield, ?Await, ?Throw]
  ShiftExpression[?Yield, ?Await, ~Throw] `<<` AdditiveExpression[?Yield, ?Await, ?Throw]
  ShiftExpression[?Yield, ?Await, ~Throw] `>>` AdditiveExpression[?Yield, ?Await, ?Throw]
  ShiftExpression[?Yield, ?Await, ~Throw] `>>>` AdditiveExpression[?Yield, ?Await, ?Throw]

RelationalExpression[In, Yield, Await, Throw] :
  ShiftExpression[?Yield, ?Await, ?Throw]
  RelationalExpression[?In, ?Yield, ?Await, ~Throw] `<` ShiftExpression[?Yield, ?Await, ?Throw]
  RelationalExpression[?In, ?Yield, ?Await, ~Throw] `>` ShiftExpression[?Yield, ?Await, ?Throw]
  RelationalExpression[?In, ?Yield, ?Await, ~Throw] `<=` ShiftExpression[?Yield, ?Await, ?Throw]
  RelationalExpression[?In, ?Yield, ?Await, ~Throw] `>=` ShiftExpression[?Yield, ?Await, ?Throw]
  RelationalExpression[?In, ?Yield, ?Await, ~Throw] `instanceof` ShiftExpression[?Yield, ?Await, ?Throw]
  [+In] RelationalExpression[+In, ?Yield, ?Await, ~Throw] `in` ShiftExpression[?Yield, ?Await, ?Throw]
  [+In] PrivateIdentifier `in` ShiftExpression[?Yield, ?Await, ?Throw]

EqualityExpression[In, Yield, Await, Throw] :
  RelationalExpression[?In, ?Yield, ?Await, ?Throw]
  EqualityExpression[?In, ?Yield, ?Await, ~Throw] `==` RelationalExpression[?In, ?Yield, ?Await, ?Throw]
  EqualityExpression[?In, ?Yield, ?Await, ~Throw] `!=` RelationalExpression[?In, ?Yield, ?Await, ?Throw]
  EqualityExpression[?In, ?Yield, ?Await, ~Throw] `===` RelationalExpression[?In, ?Yield, ?Await, ?Throw]
  EqualityExpression[?In, ?Yield, ?Await, ~Throw] `!==` RelationalExpression[?In, ?Yield, ?Await, ?Throw]

BitwiseANDExpression[In, Yield, Await, Throw] :
  EqualityExpression[?In, ?Yield, ?Await, ?Throw]
  BitwiseANDExpression[?In, ?Yield, ?Await, ~Throw] `&` EqualityExpression[?In, ?Yield, ?Await, ?Throw]

BitwiseXORExpression[In, Yield, Await, Throw] :
  BitwiseANDExpression[?In, ?Yield, ?Await, ?Throw]
  BitwiseXORExpression[?In, ?Yield, ?Await, ~Throw] `^` BitwiseANDExpression[?In, ?Yield, ?Await, ?Throw]

BitwiseORExpression[In, Yield, Await, Throw] :
  BitwiseXORExpression[?In, ?Yield, ?Await, ?Throw]
  BitwiseORExpression[?In, ?Yield, ?Await, ~Throw] `|` BitwiseXORExpression[?In, ?Yield, ?Await, ?Throw]

LogicalANDExpression[In, Yield, Await, Throw] :
  BitwiseORExpression[?In, ?Yield, ?Await, ?Throw]
  LogicalANDExpression[?In, ?Yield, ?Await, ~Throw] `&&` BitwiseORExpression[?In, ?Yield, ?Await, ?Throw]

LogicalORExpression[In, Yield, Await, Throw] :
  LogicalANDExpression[?In, ?Yield, ?Await, ?Throw]
  LogicalORExpression[?In, ?Yield, ?Await, ~Throw] `||` LogicalANDExpression[?In, ?Yield, ?Await, ?Throw]

CoalesceExpression[In, Yield, Await, Throw] :
  CoalesceExpressionHead[?In, ?Yield, ?Await, ~Throw] `??` BitwiseORExpression[?In, ?Yield, ?Await, ?Throw]

CoalesceExpressionHead[In, Yield, Await, Throw] :
  CoalesceExpression[?In, ?Yield, ?Await, ?Throw]
  BitwiseORExpression[?In, ?Yield, ?Await, ?Throw]

ShortCircuitExpression[In, Yield, Await, Throw] :
  LogicalORExpression[?In, ?Yield, ?Await, ?Throw]
  CoalesceExpression[?In, ?Yield, ?Await, ?Throw]

ConditionalExpression[In, Yield, Await, Throw] :
  ShortCircuitExpression[?In, ?Yield, ?Await, ?Throw]
  ShortCircuitExpression[?In, ?Yield, ?Await, ~Throw] `?` AssignmentExpression[+In, ?Yield, ?Await, ?Throw] `:` AssignmentExpression[?In, ?Yield, ?Await, ?Throw]

AssignmentExpression[In, Yield, Await, Throw] :
  ConditionalExpression[?In, ?Yield, ?Await, ?Throw]
  [+Yield] YieldExpression[?In, ?Await, ?Throw]
  ArrowFunction[?In, ?Yield, ?Await, ?Throw]
  AsyncArrowFunction[?In, ?Yield, ?Await, ?Throw]
  LeftHandSideExpression[?Yield, ?Await, ~Throw] `=` AssignmentExpression[?In, ?Yield, ?Await, ?Throw]
  LeftHandSideExpression[?Yield, ?Await, ~Throw] AssignmentOperator AssignmentExpression[?In, ?Yield, ?Await, ?Throw]
  LeftHandSideExpression[?Yield, ?Await, ~Throw] `&&=` AssignmentExpression[?In, ?Yield, ?Await, ?Throw]
  LeftHandSideExpression[?Yield, ?Await, ~Throw] `||=` AssignmentExpression[?In, ?Yield, ?Await, ?Throw]
  LeftHandSideExpression[?Yield, ?Await, ~Throw] `??=` AssignmentExpression[?In, ?Yield, ?Await, ?Throw]

Expression[In, Yield, Await, Throw] :
  AssignmentExpression[?In, ?Yield, ?Await, ?Throw]
  Expression[?In, ?Yield, ?Await, ~Throw] `,` AssignmentExpression[?In, ?Yield, ?Await, ?Throw]

ExpressionStatement[Yield, Await] :
  [lookahead ∉ { `{`, `function`, `async` [no LineTerminator here] `function`, `class`, `let [` }] Expression[+In, ?Yield, ?Await, ~Throw] `;`

ArrowFunction[In, Yield, Await, Throw] :
  ArrowParameters[?Yield, ?Await] [no LineTerminator here] => ConciseBody[?In, ?Throw]

ConciseBody[In, Throw] :
  [lookahead ≠ {] ExpressionBody[?In, ~Await, ?Throw]
  `{` FunctionBody[~Yield, ~Await] `}`

ExpressionBody[In, Await, Throw] :
  AssignmentExpression[?In, ~Yield, ?Await, ?Throw]

AsyncArrowFunction[In, Yield, Await, Throw] :
  `async` [no LineTerminator here] AsyncArrowBindingIdentifier[?Yield] [no LineTerminator here] `=>` AsyncConciseBody[?In, ?Throw]
  CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await] [no LineTerminator here] `=>` AsyncConciseBody[?In, ?Throw]

AsyncConciseBody[In, Throw] :
  [lookahead ≠ {] ExpressionBody[?In, +Await, ?Throw]
  `{` AsyncFunctionBody `}`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment