Problem Statement

Both arrow function syntax and block lambda revival want, for different reasons, blocks and object literals to be usable in the same context: as an expression-like body of an arrow function, as the zero-argument form of a block-lambda.

Independent interest in statements as expressions comes up on es-discuss from time to time, e.g. here.

let expressions proposed new syntax allowing explicit wrapping of statements to make them expressions, but this strawman was deferred.

Blocks-as-expressions and object literals must have different evaluation semantics (blocks are quoted, their evaluation is deferred until “invocation”; object literals evaluate eagerly). The purpose of this strawman is to refactor the grammar to eliminate grammatical conflicts that prevent treating blocks as expressions in JS today.

Grammar Changes

Block:
    { UnlabeledStatementFirstList? }
    { WellLabeledStatement StatementList? }

UnlabeledStatementFirstList:
    UnlabeledStatement
    UnlabeledStatementFirstList Statement

Statement:
    UnlabeledStatement
    LabeledStatement

UnlabeledStatement:
    VariableStatement
    EmptyStatement
    ExpressionStatement
    ContinueStatement
    ReturnStatement
    LabelUsingStatement
    DebuggerStatement

LabelUsingStatement:
    Block
    IfStatement
    IterationStatement
    BreakStatement
    WithStatement
    SwitchStatement
    ThrowStatement
    TryStatement

A LabelUsingStatement is a statement that might possibly use a label in ES3-5 but not in any ES extended to support blocks-as-expressions or block-lambdas. For maximum backward compatibility, LabeledStatement (spelled LabelledStatement in ECMA-262) remains the same, and WellLabeledStatement restricts the statement after one or more labels to be a LabelUsingStatement.

LabeledStatement:
    Identifier : Statement

WellLabeledStatement:
    Identifier : LabelUsingStatement
    Identifier : WellLabeledStatement

We retain the [lookahead ∉ {{, function}] restriction in ExpressionStatement. At the start of a statement, { can be the start of a block only, never an object literal.

PrimaryExpression:
    ...
    BlockExpression

BlockExpression:
    { UnlabeledStatementFirstList }
    { WellLabeledStatement StatementList? }

PropertyAssignment:
   IdentifierName : AssignmentExpression
   StringLiteral : AssignmentExpression
   NumericLiteral : AssignmentExpression
   get PropertyName ( ) { FunctionBody }
   set PropertyName ( PropertySetParameterList ) { FunctionBody }

PropertyName:
   IdentifierName
   StringLiteral
   NumericLiteral

Thus non-empty blocks may be used as expressions without ambiguity. An empty pair of braces {} other than at start of Statement is an ObjectLiteral. PropertyAssignment must inline-expand PropertyName to avoid an LR(1) shift-reduce conflict with WellLabeledStatement.

Semantics

The refactored Block semantics are straightforward and backward-compatible. The semantics for PrimaryExpression : BlockExpression depend on block lambda revival: a non-empty block used as an expression is equivalent to a zero-parameter block-lambda.

Compatibility

This proposal is mostly backward-compatible. In particular, the “stray label” problem whereby

javascript:foo()

migrates from URL contexts (links, src attribute values, the browser’s address toolbar) into script content, but not at the start of a block, continues to work. Note that such a “label” is not used by the statement or expression to which it is affixed.

Useless labels are thus allowed other than at the start of a block (immediately after the { that starts the block).

A block in JS today, or a block-lambda if that extension is supported, may be prefixed by a label and actually use that label, e.g. via a break targeting that label. The grammar changes above support such a label-using block(-lambda).

Brendan Eich 2011/07/01 16:19

 
strawman/block_vs_object_literal.txt · Last modified: 2011/07/06 04:47 by brendan
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki