Stage 1 Draft / March 3, 2021

do expressions

Introduction

do expressions are a syntactic construct which allows putting (some) statements in expression position without needing an immediately-invoked function expression.

1 Do Expressions

Syntax

DoExpression[Yield, Await, Return] : do Block[?Yield, ?Await, ?Return]

1.1 Runtime Semantics: Evaluation

DoExpression : do Block
  1. Let completion be the result of evaluating Block.
  2. Return Completion(UpdateEmpty(completion, undefined)).

1.2 Static Semantics: Early Errors

DoExpression : do Block
  • TODO: a syntax error for this is contained in a loop head and contains a break or continue which would break or continue the loop.
  • It is a Syntax Error if EndsInIterationOrBareIfOrDeclaration of Block with arguments « » and true is true.

1.3 Static Semantics: EndsInIterationOrBareIfOrDeclaration

With parameters labelSet and isLast.

StatementList : StatementList StatementListItem
  1. If IsEmpty of StatementListItem with argument « » is true, return EndsInIterationOrBareIfOrDeclaration of StatementList with arguments labelSet and isLast.
  2. If IsBreak of StatementListItem with argument labelSet is true, return EndsInIterationOrBareIfOrDeclaration of StatementList with arguments labelSet and true.
  3. If EndsInIterationOrBareIfOrDeclaration of StatementList with arguments labelSet and false is true, return true.
  4. Return EndsInIterationOrBareIfOrDeclaration of StatementListItem with arguments labelSet and isLast.
StatementListItem : Declaration Statement : VariableStatement LabelledItem : FunctionDeclaration
  1. Return isLast.
DoWhileStatement : do Statement while ( Expression ) ; WhileStatement : while ( Expression ) Statement ForStatement : for ( Expressionopt ; Expressionopt ; Expressionopt ) Statement for ( var VariableDeclarationList ; Expressionopt ; Expressionopt ) Statement for ( LexicalDeclaration Expressionopt ; Expressionopt ) Statement ForInOfStatement : for ( LeftHandSideExpression in Expression ) Statement for ( var ForBinding in Expression ) Statement for ( ForDeclaration in Expression ) Statement for ( LeftHandSideExpression of AssignmentExpression ) Statement for ( var ForBinding of AssignmentExpression ) Statement for ( ForDeclaration of AssignmentExpression ) Statement for await ( LeftHandSideExpression of AssignmentExpression ) Statement for await ( var ForBinding of AssignmentExpression ) Statement for await ( ForDeclaration of AssignmentExpression ) Statement
  1. If isLast is true, return true.
  2. If IsBreak of Statement with argument labelSet is true, return true.
  3. Return EndsInIterationOrBareIfOrDeclaration of Statement with arguments labelSet and isLast.
Statement : EmptyStatement ExpressionStatement ContinueStatement BreakStatement ReturnStatement ThrowStatement DebuggerStatement Block : { }
  1. Return false.
IfStatement : if ( Expression ) Statement else Statement
  1. Let first be EndsInIterationOrBareIfOrDeclaration of the first Statement with arguments labelSet and isLast.
  2. If first is true, return true.
  3. Return EndsInIterationOrBareIfOrDeclaration of the second Statement with arguments labelSet and isLast.
IfStatement : if ( Expression ) Statement
  1. If isLast is true, return true.
  2. Return EndsInIterationOrBareIfOrDeclaration of Statement with arguments labelSet and isLast.
WithStatement : with ( Expression ) Statement
  1. Return EndsInIterationOrBareIfOrDeclaration of Statement with arguments labelSet and isLast.
LabelledStatement : LabelIdentifier : LabelledItem
  1. If isLast is true, then
    1. Let label be the StringValue of LabelIdentifier.
    2. Let newLabelSet be a copy of labelSet with label appended.
    3. Return EndsInIterationOrBareIfOrDeclaration of LabelledItem with arguments newLabelSet and true.
  2. Return EndsInIterationOrBareIfOrDeclaration of LabelledItem with arguments labelSet and isLast.
SwitchStatement : switch ( Expression ) CaseBlock
  1. Return EndsInIterationOrBareIfOrDeclaration of CaseBlock with arguments labelSet and isLast.
CaseBlock : { CaseClauses }
  1. If isLast is true, then
    1. Let newLabelSet be a copy of labelSet with empty appended.
  2. Else,
    1. Let newLabelSet be a copy of labelSet with any occurences of empty removed.
  3. Let clauses be the List of CaseClause items in CaseClauses, in source text order.
  4. For each element clause of clauses, in reverse List order, do
    1. If IsEmpty of clause with argument « » is false, then
      1. If EndsInIterationOrBareIfOrDeclaration of clause with arguments newLabelSet and isLast is true, return true.
      2. If IsBreak of clause with argument newLabelSet is true, then
        1. Set isLast to true.
      3. Else,
        1. Set isLast to false.
  5. Return false.
CaseBlock : { CaseClausesopt DefaultClause CaseClausesopt }
  1. If isLast is true, then
    1. Let newLabelSet be a copy of labelSet with empty appended.
  2. Else,
    1. Let newLabelSet be a copy of labelSet with any occurences of empty removed.
  3. If the first CaseClauses is present, then
    1. Let A be the List of CaseClause items in the first CaseClauses, in source text order.
  4. Else,
    1. Let A be « ».
  5. If the second CaseClauses is present, then
    1. Let B be the List of CaseClause items in the second CaseClauses, in source text order.
  6. Else,
    1. Let B be « ».
  7. Let clauses be a List whose elements are the elements of A, followed by DefaultClause, followed by the elements of B.
  8. For each element clause of clauses, in reverse List order, do
    1. If IsEmpty of clause with argument « » is false, then
      1. If EndsInIterationOrBareIfOrDeclaration of clause with arguments newLabelSet and isLast is true, return true.
      2. If IsBreak of clause with argument newLabelSet is true, then
        1. Set isLast to true.
      3. Else,
        1. Set isLast to false.
  9. Return false.
CaseClause : case Expression : StatementListopt DefaultClause : default : StatementListopt
  1. If StatementList is not present, return false.
  2. Return EndsInIterationOrBareIfOrDeclaration of StatementList with arguments labelSet and isLast.
TryStatement : try Block Catch try Block Catch Finally
  1. If EndsInIterationOrBareIfOrDeclaration of Block with arguments labelSet and isLast is true, return true.
  2. Return EndsInIterationOrBareIfOrDeclaration of Catch with arguments labelSet and isLast.
TryStatement : try Block Finally
  1. Return EndsInIterationOrBareIfOrDeclaration of Block with arguments labelSet and isLast.
Catch : catch ( CatchParameter ) Block
  1. Return EndsInIterationOrBareIfOrDeclaration of Block with arguments labelSet and isLast.

1.4 Static Semantics: IsEmpty

With parameter labelSet.

Note

Here "empty" means "consisting solely of EmptyStatements, DebuggerStatements, LabelledItems which immediately unconditionally break themselves, or BlockStatements which are themselves empty".

labelSet is always empty when this SDO is invoked by other operations. It is used to track internally the labels which, if broken, would cause the statements being examined to be empty, as in label: { break label; }.

StatementList : StatementList StatementListItem
  1. If IsBreak of StatementList with argument labelSet is true, return true.
  2. If IsEmpty of StatementListItem with argument labelSet is false, return false.
  3. Return IsEmpty of StatementList with argument labelSet.
Statement : EmptyStatement DebuggerStatement Block : { }
  1. Return true.
StatementListItem : Declaration Statement : VariableStatement ExpressionStatement IfStatement BreakableStatement ContinueStatement ReturnStatement WithStatement ThrowStatement TryStatement LabelledItem : FunctionDeclaration
  1. Return false.
CaseClause : case Expression : StatementListopt DefaultClause : default : StatementListopt
  1. If StatementList is not present, return true.
  2. Return IsEmpty of StatementList with argument labelSet.
BreakStatement : break ;
  1. If empty is an element of labelSet, return true.
  2. Return false.
BreakStatement : break LabelIdentifier ;
  1. Let label be the StringValue of LabelIdentifier.
  2. If label is an element of labelSet, return true.
  3. Return false.
LabelledStatement : LabelIdentifier : LabelledItem
  1. Let label be the StringValue of LabelIdentifier.
  2. Let newLabelSet be a copy of labelSet with label appended.
  3. Return IsEmpty of LabelledItem with argument newLabelSet.

1.5 Static Semantics: IsBreak

With parameter labelSet.

Note

This SDO answers the question "is the first non-empty statement in this Parse Node a BreakStatement for one of the labels in labelSet?". It will recurse into BlockStatements but not other kinds of statement-containing statements.

Editor's Note

TODO: now that we allow break/continue in do expressions, this needs to be updated to check every expression position in every statement to see if it has a DoExpression which contains a break for one of the items in labelSet.

StatementList : StatementList StatementListItem
  1. If IsBreak of StatementList with argument labelSet is true, return true.
  2. If IsEmpty of StatementList with argument « » is false, return false.
  3. Return IsBreak of StatementListItem with argument labelSet.
StatementListItem : Declaration Statement : VariableStatement EmptyStatement ExpressionStatement IfStatement BreakableStatement ContinueStatement ReturnStatement WithStatement LabelledStatement ThrowStatement TryStatement DebuggerStatement LabelledItem : FunctionDeclaration Block : { }
  1. Return false.
CaseClause : case Expression : StatementListopt DefaultClause : default : StatementListopt
  1. If StatementList is not present, return false.
  2. Return IsBreak of StatementList with argument labelSet.
BreakStatement : break ;
  1. If empty is an element of labelSet, return true.
  2. Return false.
BreakStatement : break LabelIdentifier ;
  1. Let label be the StringValue of LabelIdentifier.
  2. If label is an element of labelSet, return true.
  3. Return false.
LabelledStatement : LabelIdentifier : LabelledItem
  1. Return IsBreak of LabelledItem with argument labelSet.

2 Integration

Syntax

PrimaryExpression[Yield, Await] : DoExpression[?Yield, ?Await] ExpressionStatement[Yield, Await] : [lookahead ∉ { {, function, async [no LineTerminator here] function, class, let [, do }] Expression[+In, ?Yield, ?Await] ; Note

Note the additional lookahead for do in ExpressionStatements. This prevents using do expressions in statement position, where they are ambiguous with do statements.

Semantics

TODO: thread the Return grammar parameter through the entire expression grammar. It is allowed in parameter lists and arrow expression bodies, but not class bodies. In other circumstances it's inherited from the containing statement.

TODO: thread ContainsUndefinedBreakTarget and ContainsUndefinedContinueTarget through the entire expression grammar.

TODO: thread VarDeclaredNames through the entire expression grammar and update existing uses (IfStatement etc) to use it.

TODO: thread ContainsDuplicateLabels through the entire expression grammar.

TODO: ban do-exprs which are inside of formal parameter lists and which Contain a VariableStatement. Probably needs a new SDO, sigh. (Or, reconsider banning this, I guess.)

Maybe it is worth abstracting out a single "CollectDoExpressionsFromExpression" SDO that other things can be written in terms of.

A Copyright & Software License

Copyright Notice

© 2021 Dave Herman, Chris Krychom, Kevin Gibbons

Software License

All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT https://ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.