Why isn't FunctionExpression a PrimaryExpression?

# Allen Wirfs-Brock (14 years ago)

ES3 (and ES5) defines these grammar productions:

MemberExpression :

PrimaryExpression FunctionExpression MemberExpression [ Expression ] MemberExpression . IdentifierName new MemberExpression Arguments

PrimaryExpression :

this Identifier Literal ArrayLiteral ObjectLiteral ( Expression )

FunctionExpression :

function Identifieropt ( FormalParameterList ) { FunctionBody }

Does anybody know or see a good reason why FunctionExpression shouldn't be move as a RHS of PrimaryExpression? MemberExpression is the only occurrence of either PrimaryExpression or FunctionExpression on the RHS of a grammar rule.

Function expressions were added in ES3. Were they just added at the wrong place in the grammar?

# Allen Wirfs-Brock (14 years ago)

ES3 (and ES5) defines these grammar productions:

MemberExpression :

PrimaryExpression FunctionExpression MemberExpression [ Expression ] MemberExpression . IdentifierName new MemberExpression Arguments

PrimaryExpression :

this Identifier Literal ArrayLiteral ObjectLiteral ( Expression )

FunctionExpression :

function

Identifieropt ( FormalParameterList ) { FunctionBody } Does anybody know or see a good reason why FunctionExpression shouldn't be move as a RHS of PrimaryExpression? MemberExpression is the only occurrence of either PrimaryExpression or FunctionExpression on the RHS of a grammar rule.

Function expressions were added in ES3. Were they just added at the wrong place in the grammar?

# Allen Wirfs-Brock (14 years ago)

(sorry about any duplicates like this that show up. I seem to have had posting delays yesterday that resulted in duplicate postings)

# Brendan Eich (14 years ago)

On Oct 19, 2011, at 8:16 AM, Allen Wirfs-Brock wrote:

ES3 (and ES5) defines these grammar productions:

MemberExpression :

PrimaryExpression FunctionExpression MemberExpression [ Expression ] MemberExpression . IdentifierName new MemberExpression Arguments

PrimaryExpression :

this Identifier Literal ArrayLiteral ObjectLiteral ( Expression )

FunctionExpression :

function

Identifieropt ( FormalParameterList ) { FunctionBody }

Does anybody know or see a good reason why FunctionExpression shouldn't be move as a RHS of PrimaryExpression? MemberExpression is the only occurrence of either PrimaryExpression or FunctionExpression on the RHS of a grammar rule.

Function expressions were added in ES3. Were they just added at the wrong place in the grammar?

Thanks for raising this, I keep forgetting to.

Oddly enough, SpiderMonkey always had them (prior to ES3 even being drafted) as PrimaryExpressions. No one can observe the difference, as you note. Either way, one can write

var fun_member = function () {}.member;

On aesthetic grounds, I would prefer the grammar to make function expressions primary.

# Allen Wirfs-Brock (14 years ago)

On Oct 19, 2011, at 2:53 PM, Brendan Eich wrote:

On Oct 19, 2011, at 8:16 AM, Allen Wirfs-Brock wrote:

Function expressions were added in ES3. Were they just added at the wrong place in the grammar?

Thanks for raising this, I keep forgetting to.

Oddly enough, SpiderMonkey always had them (prior to ES3 even being drafted) as PrimaryExpressions. No one can observe the difference, as you note. Either way, one can write

var fun_member = function () {}.member;

On aesthetic grounds, I would prefer the grammar to make function expressions primary.

Good, I want to make that change because for semantic specification purposes FunctionExpression works better as PrimaryExpression.

I just wanted to make sure, before I make the change, that there wasn't some grammatical subtlety I was overlooking

# Brendan Eich (14 years ago)

On Oct 19, 2011, at 3:29 PM, Allen Wirfs-Brock wrote:

On Oct 19, 2011, at 2:53 PM, Brendan Eich wrote:

On Oct 19, 2011, at 8:16 AM, Allen Wirfs-Brock wrote:

Function expressions were added in ES3. Were they just added at the wrong place in the grammar?

Thanks for raising this, I keep forgetting to.

Oddly enough, SpiderMonkey always had them (prior to ES3 even being drafted) as PrimaryExpressions. No one can observe the difference, as you note. Either way, one can write

var fun_member = function () {}.member;

On aesthetic grounds, I would prefer the grammar to make function expressions primary.

Good, I want to make that change because for semantic specification purposes FunctionExpression works better as PrimaryExpression.

I just wanted to make sure, before I make the change, that there wasn't some grammatical subtlety I was overlooking

Toy grammar (| is meta, other punctuators after the : are concrete):

E: ME ME: PE | FE | ME [ E ] | ME . ID | ... PE: ( E ) | ...

and there's no way that ME -> FE would be reduced where ME -> PE -> FE was not possible, and there are no PE occurrences on the RHS of a production whose LHS is not ME, then FE can move "down" one precedence level from being the sole RHS part of ME, to being the sole RHS of PE.

(Lotta abbreviation there, sorry.)

Trivial search shows PrimaryExpression occurs in only one RHS, as the sole RHS part produced from MemberExpression.

# Andreas Rossberg (14 years ago)

One concern might be that we probably cannot make arrow notation (if we introduce it) a primary expression, and it might be confusing if they have different precedence.

I also think it is easier to parse for the human reader when he sees

(function f() { ... })()

instead of

function f() { ... }()

especially when this occurs as a statement. (Mh, actually, could we even distinguish between function declerations and expression statements starting with a function expr in LALR(1), without heavy grammar transformation?)

# Brendan Eich (14 years ago)

On Oct 20, 2011, at 12:31 AM, Andreas Rossberg wrote:

One concern might be that we probably cannot make arrow notation (if we introduce it) a primary expression, and it might be confusing if they have different precedence.

We absolutely cannot and the strawman specifies the grammar fully:

strawman:arrow_function_syntax

AssignmentExpression : ArrowFunctionExpression ...

ArrowFunctionExpression : ArrowFormalParameters_opt Arrow AssignmentExpression ArrowFormalParameters_opt Arrow ArrowBodyBlock_opt

ArrowFormalParameters : ( FormalParameterList_opt ) ( this Initialiser_opt ) ( this Initialiser_opt , FormalParameterList )

Arrow : one of -> or =>

Arrow function expressions must be low precedence, unparenthesized on the right of assignment operators.

I also think it is easier to parse for the human reader when he sees

(function f() { ... })()

instead of

function f() { ... }()

especially when this occurs as a statement. (Mh, actually, could we even distinguish between function declerations and expression statements starting with a function expr in LALR(1), without heavy grammar transformation?)

The grammar currently uses a lookahead restriction to disambiguate in favor of function declaration:

12.4 Expression Statement

Syntax

ExpressionStatement : [lookahead ∉ {{, function}] Expression ;

NOTE An ExpressionStatement cannot start with an opening curly brace because that might make it ambiguous with a Block. Also, an ExpressionStatement cannot start with the function keyword because that might make it ambiguous with a FunctionDeclaration.

# Brendan Eich (14 years ago)

On Oct 20, 2011, at 12:31 AM, Andreas Rossberg wrote:

(Mh, actually, could we even distinguish between function declerations and expression statements starting with a function expr in LALR(1), without heavy grammar transformation?)

To answer this question, there's no way to disambiguate without a lookahead restriction or massive duplication of the expression sub-grammar. You'd need

ExpressionStatement: ExpressionNoFunctionNoLeftCurlyAtFront

and ExpressionNoFunctionNoLeftCurlyAtFront would produce any expression except those starting with 'function' or '{'. No win in duplicating so much grammar. We'd rather use lookahead restrictions as the spec does currently, or parametric productions as an alternative (would be nice to unduplicate the -NoIn productions).

BTW there's still a de-facto standard lurking about on the web that expects eval("function(){...}") to parse. I'm not sure where different engines stand on this.

# Jeff Walden (14 years ago)

On 10/20/2011 09:44 AM, Brendan Eich wrote:

BTW there's still a de-facto standard lurking about on the web that expects eval("function(){...}") to parse. I'm not sure where different engines stand on this.

No engine supports. Gecko temporarily regressed to support it again at one point (after having deliberately disabled it), but that bug's been fixed. I haven't heard any complaints about sites breaking (not surprising if everyone but us, and only for some releases, had correct behavior).

# Brendan Eich (14 years ago)

On Nov 1, 2011, at 11:37 AM, Jeff Walden wrote:

On 10/20/2011 09:44 AM, Brendan Eich wrote:

BTW there's still a de-facto standard lurking about on the web that expects eval("function(){...}") to parse. I'm not sure where different engines stand on this.

No engine supports. Gecko temporarily regressed to support it again at one point (after having deliberately disabled it), but that bug's been fixed. I haven't heard any complaints about sites breaking (not surprising if everyone but us, and only for some releases, had correct behavior).

Ok, great news. Thanks,

# Waldemar Horwat (14 years ago)

On 10/19/2011 08:16 AM, Allen Wirfs-Brock wrote:

Does anybody know or see a good reason why FunctionExpressionshouldn't be move as a RHS of PrimaryExpression? MemberExpressionis the only occurrence of either PrimaryExpressionor FunctionExpressionon the RHS of a grammar rule.

As you note, the two grammars are equivalent, so this is a purely aesthetic choice. I agree that putting FunctionExpression inside PrimaryExpression is more pleasing.

 Waldemar