Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use early error to avoid ASI for +,-,/, and /= #18

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
201 changes: 184 additions & 17 deletions spec.emu
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,12 @@ contributors: Ron Buckton, Ecma International
`delete` UnaryExpression
`void` UnaryExpression
`typeof` UnaryExpression
<ins>`throw` UnaryExpression</ins>
`+` UnaryExpression
`-` UnaryExpression
`~` UnaryExpression
`!` UnaryExpression
AwaitExpression
<ins>ThrowExpression</ins>

ExponentiationExpression :
UpdateExpression `**` ExponentiationExpression
Expand Down Expand Up @@ -253,12 +253,12 @@ contributors: Ron Buckton, Ecma International
`delete` UnaryExpression
`void` UnaryExpression
`typeof` UnaryExpression
<ins>`throw` UnaryExpression</ins>
`+` UnaryExpression
`-` UnaryExpression
`~` UnaryExpression
`!` UnaryExpression
AwaitExpression
<ins>ThrowExpression</ins>

ExponentiationExpression :
UpdateExpression `**` ExponentiationExpression
Expand Down Expand Up @@ -328,6 +328,45 @@ contributors: Ron Buckton, Ecma International
1. Return ~invalid~.
</emu-alg>
</emu-clause>

<ins class="block">
<emu-clause id="sec-static-semantics-containsthrow" type="sdo">
<h1>Static Semantics: ContainsThrowOnRight ( ): a Boolean</h1>
<dl class="header">
</dl>
<emu-grammar>ThrowExpression : `throw` UnaryExpression</emu-grammar>
<emu-alg>
1. Return *true*.
</emu-alg>
<emu-grammar>
UpdateExpression :
LeftHandSideExpression
LeftHandSideExpression `++`
LeftHandSideExpression `--`
</emu-grammar>
<emu-alg>
1. Return *false*.
</emu-alg>
<emu-grammar>
ExponentiationExpression :
UpdateExpression `**` ExponentiationExpression

MultiplicativeExpression :
MultiplicativeExpression MultiplicativeOperator ExponentiationExpression
</emu-grammar>
<emu-alg>
1. Return ContainsThrowOnRight of |ExponentiationExpression|.
</emu-alg>
<emu-grammar>
AdditiveExpression :
AdditiveExpression `+` MultiplicativeExpression
AdditiveExpression `-` MultiplicativeExpression
</emu-grammar>
<emu-alg>
1. Return ContainsThrowOnRight of |MultiplicativeExpression|.
</emu-alg>
</emu-clause>
</ins>
</emu-clause>
</emu-clause>

Expand All @@ -343,30 +382,158 @@ contributors: Ron Buckton, Ecma International
`delete` UnaryExpression[?Yield, ?Await]
`void` UnaryExpression[?Yield, ?Await]
`typeof` UnaryExpression[?Yield, ?Await]
<ins>`throw` UnaryExpression[?Yield, ?Await] [lookahead ∉ ThrowExpressionInvalidPunctuator]</ins>
`+` UnaryExpression[?Yield, ?Await]
`-` UnaryExpression[?Yield, ?Await]
`~` UnaryExpression[?Yield, ?Await]
`!` UnaryExpression[?Yield, ?Await]
[+Await] AwaitExpression[?Yield]

<ins class="block">
ThrowExpressionInvalidPunctuator : one of `,` `&lt;` `>` `&lt;=` `>=` `==` `!=` `===` `!==` `+` `-` `*` `/` `%` `**` `&lt;&lt;` `>>` `>>>` `&` `|` `^` `&&` `||` `??` `=` `+=` `-=` `*=` `/=` `%=` `**=` `&lt;&lt;=` `>>=` `>>>=` `&=` `|=` `^=` `&&=` `||=` `??=` `?`
</ins>
<ins>ThrowExpression[?Yield, ?Await]</ins>
</emu-grammar>

<ins class="block">
<emu-clause id="sec-throw-operator">
<h1><ins>The `throw` Operator</ins></h1>
<h2>Syntax</h2>
<emu-grammar type="definition">
ThrowExpression[Yield, Await] :
`throw` UnaryExpression[?Yield, ?Await] [lookahead ∉ ThrowExpressionInvalidPunctuator]

ThrowExpressionInvalidPunctuator : one of `,` `&lt;` `>` `&lt;=` `>=` `==` `!=` `===` `!==` `*` `%` `**` `&lt;&lt;` `>>` `>>>` `&` `|` `^` `&&` `||` `??` `?`
</emu-grammar>

<emu-clause id="sec-throw-operator-runtime-semantics-evaluation">
<h1>Runtime Semantics: Evaluation</h1>
<emu-grammar>ThrowExpression : `throw` UnaryExpression</emu-grammar>
<emu-alg>
1. Let _exprRef_ be ? Evaluation of |UnaryExpression|.
1. Let _exprValue_ be ? GetValue(_exprRef_).
1. Return ThrowCompletion(_exprValue_).
</emu-alg>
</emu-clause>
</emu-clause>
</ins>
</emu-clause>

<emu-clause id="sec-throw-operator">
<h1><ins>The `throw` Operator</ins></h1>
<emu-clause id="sec-throw-operator-runtime-semantics-evaluation">
<h1>Runtime Semantics: Evaluation</h1>
<emu-grammar>UnaryExpression : `throw` UnaryExpression</emu-grammar>
<emu-alg>
1. Let _exprRef_ be ? Evaluation of |UnaryExpression|.
1. Let _exprValue_ be ? GetValue(_exprRef_).
1. Return ThrowCompletion(_exprValue_).
</emu-alg>
<emu-clause id="sec-multiplicative-operators">
<h1>Multiplicative Operators</h1>
<ins class="block">
<emu-clause id="sec-multiplicative-operators-static-semantics">
<h1>Static Semantics</h1>
<emu-clause id="sec-multiplicative-operators-static-semantics-early-errors">
<h1>Static Semantics: Early Errors</h1>
<emu-grammar>
MultiplicativeExpression :
MultiplicativeExpression MultiplicativeOperator ExponentiationExpression
</emu-grammar>
<ul>
<li>
It is a Syntax Error if the source text matched by |MultiplicativeOperator| is `/` and ContainsThrowOnRight of |MultiplicativeExpression| is *true*.
</li>
</ul>
<emu-note>
<p>This production exists in order to prevent automatic semicolon insertion rules (<emu-xref href="#sec-automatic-semicolon-insertion"></emu-xref>) from being applied to the following code:</p>
<pre><code class="javascript">
a ?? throw b
/c/d
</code></pre>
<p>so that it would be interpreted as two valid statements. The purpose is to maintain consistency with similar code using |ThrowStatement|:</p>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of "maintain consistency" I would say "avoid different valid behaviour", given that we are not consistent with statements because we entirely disallow this case.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly, though I'd like an editor to weigh in as I think "maintain consistency" here and in OptionalChain TemplateExpression refers specifically to ASI handling, since both grammars are intended to produce an error.

<pre><code class="javascript">
throw b
/c/d
</code></pre>
<p>which is a valid statement and where automatic semicolon insertion does not apply.</p>
</emu-note>
</emu-clause>
</emu-clause>
</ins>
</emu-clause>

<emu-clause id="sec-additive-operators">
<h1>Additive Operators</h1>
<ins class="block">
<emu-clause id="sec-additive-operators-static-semantics">
<h1>Static Semantics</h1>
<emu-clause id="sec-additive-operators-static-semantics-early-errors">
<h1>Static Semantics: Early Errors</h1>
<emu-grammar>
AdditiveExpression :
AdditiveExpression `+` MultiplicativeExpression
AdditiveExpression `-` MultiplicativeExpression
</emu-grammar>
<ul>
<li>
It is a Syntax Error if ContainsThrowOnRight of |AdditiveExpression| is *true*.
</li>
</ul>
<emu-note>
<p>This production exists in order to prevent automatic semicolon insertion rules (<emu-xref href="#sec-automatic-semicolon-insertion"></emu-xref>) from being applied to the following code:</p>
<pre><code class="javascript">
a ?? throw b
+ c
</code></pre>
<p>so that it would be interpreted as two valid statements. The purpose is to maintain consistency with similar code using |ThrowStatement|:</p>
<pre><code class="javascript">
throw b
+ c
</code></pre>
<p>which is a valid statement and where automatic semicolon insertion does not apply.</p>
</emu-note>
</emu-clause>
</emu-clause>
</ins>
</emu-clause>

<emu-clause id="sec-assignment-operators">
<h1>Assignment Operators</h1>
<h2>Syntax</h2>
<emu-grammar type="definition">
AssignmentExpression[In, Yield, Await] :
ConditionalExpression[?In, ?Yield, ?Await]
[+Yield] YieldExpression[?In, ?Await]
ArrowFunction[?In, ?Yield, ?Await]
AsyncArrowFunction[?In, ?Yield, ?Await]
LeftHandSideExpression[?Yield, ?Await] `=` AssignmentExpression[?In, ?Yield, ?Await] #assignment
LeftHandSideExpression[?Yield, ?Await] AssignmentOperator AssignmentExpression[?In, ?Yield, ?Await]
LeftHandSideExpression[?Yield, ?Await] `&amp;&amp;=` AssignmentExpression[?In, ?Yield, ?Await]
LeftHandSideExpression[?Yield, ?Await] `||=` AssignmentExpression[?In, ?Yield, ?Await]
LeftHandSideExpression[?Yield, ?Await] `??=` AssignmentExpression[?In, ?Yield, ?Await]
<ins>ThrowExpression[?Yield, ?Await] `/=` AssignmentExpression[?In, ?Yield, ?Await]</ins>

// emu-format ignore
AssignmentOperator : one of
`*=` `/=` `%=` `+=` `-=` `&lt;&lt;=` `&gt;&gt;=` `&gt;&gt;&gt;=` `&amp;=` `^=` `|=` `**=`
</emu-grammar>

<ins class="block">
<emu-clause id="sec-assignment-operators-static-semantics">
<h1>Static Semantics</h1>
<emu-clause id="sec-assignment-operators-static-semantics-early-errors">
<h1>Static Semantics: Early Errors</h1>
<emu-grammar>
AssignmentExpression :
ThrowExpression `/=` AssignmentExpression
</emu-grammar>
<ul>
<li>
It is a Syntax Error if any source text is matched by this production.
</li>
</ul>
<emu-note>
<p>This production exists in order to prevent automatic semicolon insertion rules (<emu-xref href="#sec-automatic-semicolon-insertion"></emu-xref>) from being applied to the following code:</p>
<pre><code class="javascript">
a = throw b
/= c / d
</code></pre>
<p>so that it would be interpreted as two valid statements. The purpose is to maintain consistency with similar code using |ThrowStatement|:</p>
<pre><code class="javascript">
throw b
/= c / d
</code></pre>
<p>which is a valid statement and where automatic semicolon insertion does not apply.</p>
</emu-note>
</emu-clause>
</emu-clause>
</ins>
</emu-clause>
</emu-clause>

Expand Down