Arrow function followed by divide or syntax error?
Peter van der Zee
ecma at qfox.nl
Wed May 24 08:32:50 UTC 2017
> Unlike an ordinary function expression, which is a PrimaryExpression, an arrow function is merely an AssigmentExpression, so has much lower precedence than any arithmetic operator.
I'm curious how this should be parsed so let's break this down.
Given the following "Script" (I don't think the actual goal matters much here):
```
x=x=>{}/alert(1)/+alert(2)//
```
Script :
ScriptBody opt
ScriptBody :
StatementList
StatementList [Yield, Return] :
StatementListItem [?Yield, ?Return]
StatementList [?Yield, ?Return] StatementListItem [?Yield, ?Return]
StatementListItem [Yield, Return] :
Statement [?Yield, ?Return]
Declaration [?Yield]
Statement [Yield, Return] :
BlockStatement [?Yield, ?Return]
VariableStatement [?Yield]
EmptyStatement
ExpressionStatement [?Yield]
... (trunced)
ExpressionStatement [Yield] :
[lookahead ∉ { { , function , class , let [ }] Expression [In, ?Yield] ;
Expression [In, Yield] :
AssignmentExpression [?In, ?Yield]
Expression [?In, ?Yield] , AssignmentExpression [?In, ?Yield]
AssignmentExpression [In, Yield] :
ConditionalExpression [?In, ?Yield]
[+Yield]
YieldExpression [?In]
ArrowFunction [?In, ?Yield]LeftHandSideExpression [?Yield] =
AssignmentExpression [?In, ?Yield]
LeftHandSideExpression [?Yield] AssignmentOperator
AssignmentExpression [?In, ?Yield]
I hope we can agree that the leading `x=` is consumed by
"LeftHandSideExpression [?Yield] AssignmentOperator" in the very last
rule above. Proceeding with "AssignmentExpression" from the arrow arg.
Note that there is no other rule that applies up to this point.
ArrowFunction [In, Yield] :
ArrowParameters [?Yield] [no LineTerminator here] => ConciseBody [?In]
ArrowParameters [Yield] :
BindingIdentifier [?Yield]
CoverParenthesizedExpressionAndArrowParameterList [?Yield]
Here "CoverParenthesizedExpressionAndArrowParameterList" will consume
the second `x` and then the only rule in "ArrowFunction" will consume
the arrow (`=>`). Continueing to parse the remainder
`{}/alert(1)/+alert(2)//` starting at "ConciseBody".
ConciseBody [In] :
[lookahead ≠ {] AssignmentExpression [?In]
{ FunctionBody }
Obviously only the second rule applies so we parse the function body
and the curlies. We parse greedy but the function body is empty so
only the next two chars are consumed (`{}`). Parser has
`/alert(1)/+alert(2)//` left to parse and the "Statement" rule has
depleted it's options. So we go back to "StatementList" and parse
another statement. This should result in a regular expression, a plus
operator, a call expression, and a single line comment.
I don't think there's a rule here that allows parsing operators after
an explicit arrow function body as being part of the arrow function.
In fact, I remember that this was explicitly designed this way to
prevent this ambiguity. Beyond that I agree that it parses similar to
function expressions.
If this was wrong I'd love to know the right way to parse this.
- peter
On Wed, May 24, 2017 at 9:18 AM, Andreas Rossberg <rossberg at google.com> wrote:
> On 24 May 2017 at 08:57, Gareth Heyes <gareth.heyes at portswigger.net> wrote:
>>
>>
>>>
>>> you'll get a SyntaxError in all browsers but Edge, which interprets it as
>>> `(x => {}) * alert(1)`.
>>>
>>> Given how confusing that expression is, I think that the SyntaxError is
>>> the right choice.
>>
>>
>> Well it is a function expression. So IMO Edge is right. It's equivalent
>> to:
>> x=function(){} * alert(1)
>
>
> Edge is wrong. Unlike an ordinary function expression, which is a
> PrimaryExpression, an arrow function is merely an AssigmentExpression, so
> has much lower precedence than any arithmetic operator. The rationale is
> that its body doesn't necessarily have braces, so `x => x * 1` would be
> ambiguous.
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
More information about the es-discuss
mailing list