Why is the MemberExpression Arguments production located in section 14.7 Async Arrow Function Definitions? Does Cover mean that the rule covers both CallExpression and AsyncArrowHead, and they just decided to put it in 14.7 instead of 12.3?
This is because async
isn't a keyword. That means that in a parser
async ()
is just a function call to a function called async
. This means that in the context of a snippet like
async () =>
until the =>
is found, the parser cannot know what type of syntax it is actually parsing. This concept of something being a known set of tokens, with multiple possible output AST structures, is handled in the spec via what are called cover grammars.
What that essentially means in the general case in the spec is that CoverCallExpressionAndAsyncArrowHead
defines essentially the union of the possible structures that you could find in an arrow function head, or in a function call. When the parser sees the =>
, it says "Okay, the CoverCallExpressionAndAsyncArrowHead
that I parsed is the head of an arrow function, and if it finds anything other than =>
then it knows that it was actually a function call.
According to the above productions, the below would be valid, thus breaking with the SO post linked above. Am I missing something? Why divide it in NewExpression and CallExpression, if NewExpression can contain CallExpression?
I'm also finding the wording in that other answer is a bit hard to follow, though I do think it is accurate. The short answer is that then are split up into NewExpression
and CallExpression
because CallExpression
require parens, and NewExpression
requires there not to be parens. For example, in the general sense new
is a keyword that constructs whatever is on the right-hand side. If you do new Foo
, it will construct Foo
. If you do new obj.Foo
it will read obj.Foo
and then construct an object from it. This means that syntactically you can almost think of these as equivalent:
// 1
var _tmp = Foo;
new _tmp;
// 2
var _tmp = obj.Foo;
new _tmp;
but that's not true, because these are different:
// 3
var _tmp = Foo();
new _tmp;
// 4
new Foo();
The new
keyword has optional parentheses, and it is this behavior that necessitates the division in the grammar. If we look at
NewExpression:
MemberExpression
new NewExpression
it always jumps straight to MemberExpression
meaning that new obj()
will treat the ()
as Arguments
in new MemberExpression Arguments
. Since CallExpression
always handles the ()
for function calls, the NewExpression
grammar is only applicable to the ()
that are optional for construction, whereas
CallExpression:
CoverCallExpressionAndAsyncArrowHead
SuperCall
CallExpression Arguments
CallExpression [Expression]
CallExpression .IdentifierName
CallExpression TemplateLiteral
handles all of the ()
cases that involve function calls that don't have new
.