5

Consider Sec. 11.2 of ECMA-262.

Syntax
MemberExpression :
    PrimaryExpression
    FunctionExpression
    MemberExpression [ Expression ]
    MemberExpression . IdentifierName
    new MemberExpression Arguments
NewExpression :
    MemberExpression
    new NewExpression
CallExpression :
    MemberExpression Arguments
    CallExpression Arguments
    CallExpression [ Expression ]
    CallExpression . IdentifierName
Arguments :
    ( )
    ( ArgumentList )
ArgumentList :
    AssignmentExpression
    ArgumentList , AssignmentExpression
LeftHandSideExpression :
    NewExpression
    CallExpression

The PrimaryExpression is the following

PrimaryExpression :
    this 
    Identifier 
    Literal 
    ArrayLiteral 
    ObjectLiteral 
    ( Expression )

The first question is:

What ( Expression ) does mean in the PrimaryExpression defenition?

The {prop: 'prop'} is ObjectLiteral. Thus {prop: 'prop'}() is CallExpression. I'm trying to check this with JSFIDDLE but I have

[20:16:12.347] SyntaxError: syntax error @ http://fiddle.jshell.net/_display/:21

The second question: Why this error was caused? I think that {prop: 'prop'}() is correct line and I'm excepted that the error will be kind of {prop: 'prop'} is not a function.

UPD: I'm using firefox 25.0.1

St.Antario
  • 26,175
  • 41
  • 130
  • 318
  • 1
    I believe, `{...}()` is grammatically valid. On my chrome, I dont get a syntax error, rather I get "Object is not a function" -- which means its valid. And in your fiddle, just prepend `var x = ` to your line, you will get the same error. – UltraInstinct Dec 19 '13 at 19:07
  • 1
    @Thrustmaster Interesting. Whey would you need to add that assignment? – cstack Dec 19 '13 at 19:13
  • @Thrustmaster Very interesting, thanks for your comment. Can you explain why `var x={prop:'prop'}()` is gramatically valid. Please give a proof/link if it possible. I cant still answer my two questions. – St.Antario Dec 19 '13 at 19:14
  • 1
    @cstack Its because JS Parser looks at it as a code block rather than an object. :) – UltraInstinct Dec 19 '13 at 19:15

2 Answers2

2

First question:

( Expression ) simply means a (, an Expression, and then a ).


Second question:

{prop: 'prop'}()

Is being parsed as:

// a block
{
    // syntax error
    prop: 'prop'
}
// syntax error
()

You could add parens, and then you would get the expected error:

({prop: 'prop'}())

This also works since a block is not valid there:

var obj = {prop: 'prop'}
obj()
tckmn
  • 57,719
  • 27
  • 114
  • 156
1

As for the big question:

What ( Expression ) does mean in the PrimaryExpression defenition?

It's a recursive definition, used for nesting arbitrary things in the grammar.

JavaScript grammar allows for things like

var o = "Hello" +({stuff:"stuff"}); 

Although this is not very meaningful semantically, we need to be able to express an arbitrary expression as a part of an expression in the language.

This recursive property in the grammar is what allows arbitrary nesting.

Let's see this by example.

A much simpler grammar might be grammar describing basic math. We want to describe something basic like 3+5+3/(5+3).

We want to allow operator precedence and arbitrary nesting - the definition here is itself recursive. Let's see this from Wikipedia:

<expression> ::= <term> | <expression> "+" <term>
<term>       ::= <factor> | <term> "*" <factor>
<factor>     ::= <constant> | <variable> | "(" <expression> ")"
<variable>   ::= "x" | "y" | "z" 
<constant>   ::= <digit> | <digit> <constant>
<digit>      ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"

Note how <factor> here allows for an "(" <expression> ")" in it in order to allow the arbitrary nesting we want.

As for why your {} syntax is invalid:

{prop: 'prop'} is not valid, you're starting a block statement here.

Formally - you're not in a left hand side expression at all, so section 11.2 does not apply here.

Rather you're in a 12 - statement:

Syntax

Statement :
    Block
    VariableStatement
    EmptyStatement
    ExpressionStatement
    IfStatement
    IterationStatement
    ContinueStatement
    BreakStatement
    ReturnStatement
    WithStatement
    LabelledStatement
    SwitchStatement
    ThrowStatement
    TryStatement
    DebuggerStatement

When it hits Block here - it sees 12.1 - Block which in turn does:

Block :    
    { StatementListopt }
    StatementList :
    Statement
    StatementList Statement
    Semantics

So as far as the grammar is concerned - we're inside a StatementList inside a Block.

That statement includes prop: prop. Here, the prop: gets parsed as a LabelledStatement which explains the error.

See my answer here for how it's implemented in plates and wrapping it.

Community
  • 1
  • 1
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • Thanks you for your answer! But i have once more question: Can you explain what's a difference between `({prop: 'prop'})()` and `({prop:'prop'}())`? – St.Antario Dec 19 '13 at 19:27
  • @St.Antario syntactically they're different, semantically they are the same (syntax errors). The key difference in the syntax here is that in the first one we're first evaluating the object as an expression and then trying to invoke it where in the second we're trying to invoke it inside the expression. – Benjamin Gruenbaum Dec 19 '13 at 19:30