Stage 1 Draft / January 26, 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] : 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
  • It is a Syntax Error if ContainsUndefinedBreakTarget of Block with argument « » is true.
  • It is a Syntax Error if ContainsUndefinedContinueTarget of Block with arguments « » and « » is true.
  • It is a Syntax Error if EndsInIterationOrDeclaration of Block with arguments « » and true is true.
Editor's Note

The first two Syntax Errors are present for all statement lists which are not immediately contained in other statement lists, i.e. for function bodies, scripts, modules, and now do expressions.

1.3 Static Semantics: EndsInIterationOrDeclaration

With parameters labelSet and isLast.

StatementList : StatementList StatementListItem
  1. If IsEmpty of StatementListItem with argument « » is true, return EndsInIterationOrDeclaration of StatementList with arguments labelSet and isLast.
  2. If IsBreak of StatementListItem with argument labelSet is true, return EndsInIterationOrDeclaration of StatementList with arguments labelSet and true.
  3. If EndsInIterationOrDeclaration of StatementList with arguments labelSet and false is true, return true.
  4. Return EndsInIterationOrDeclaration of StatementListItem with arguments labelSet and isLast.
StatementListItem : Declaration Statement : VariableStatement LabelledItem : FunctionDeclaration BreakableStatement : IterationStatement
  1. Return isLast.
Statement : EmptyStatement ExpressionStatement ContinueStatement BreakStatement ReturnStatement ThrowStatement DebuggerStatement Block : { }
  1. Return false.
IfStatement : if ( Expression ) Statement else Statement
  1. Let first be EndsInIterationOrDeclaration of the first Statement with arguments labelSet and isLast.
  2. If first is true, return true.
  3. Return EndsInIterationOrDeclaration of the second Statement with arguments labelSet and isLast.
IfStatement : if ( Expression ) Statement WithStatement : with ( Expression ) Statement
  1. Return EndsInIterationOrDeclaration 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 EndsInIterationOrDeclaration of LabelledItem with arguments newLabelSet and true.
  2. Return EndsInIterationOrDeclaration of LabelledItem with arguments labelSet and isLast.
SwitchStatement : switch ( Expression ) CaseBlock
  1. Return EndsInIterationOrDeclaration 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 EndsInIterationOrDeclaration 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 EndsInIterationOrDeclaration 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 EndsInIterationOrDeclaration of StatementList with arguments labelSet and isLast.
TryStatement : try Block Catch try Block Catch Finally
  1. If EndsInIterationOrDeclaration of Block with arguments labelSet and isLast is true, return true.
  2. Return EndsInIterationOrDeclaration of Catch with arguments labelSet and isLast.
TryStatement : try Block Finally
  1. Return EndsInIterationOrDeclaration of Block with arguments labelSet and isLast.
Catch : catch ( CatchParameter ) Block
  1. Return EndsInIterationOrDeclaration 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.

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 VarDeclaredNames through the entire expression grammar and update existing uses (IfStatement etc) to use it.

TODO: probably 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.

Early Errors

2.1 Static Semantics: Early Errors

ContinueStatement : continue ; continue LabelIdentifier ;

2.1.1 Static Semantics: Early Errors

BreakStatement : break ;

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.