Stage 2 Draft / August 5, 2022

ECMAScript Explicit Resource Management

Introduction

This proposal introduces syntax and semantics around explicit resource management.

See the proposal repository for background material and discussion.

1 Notational Conventions

1.1 Algorithm Conventions

1.1.1 Runtime Semantics

1.1.1.1 DisposeIfAbrupt

Algorithm steps that say or are otherwise equivalent to:

  1. DisposeIfAbrupt(argument, disposable).

mean the same thing as:

  1. Assert: disposable is an object with a [[DisposableResourceStack]] internal slot or undefined.
  2. If argument is an abrupt completion, set argument to DisposeResources(disposable, argument).

Algorithm steps that say or are otherwise equivalent to:

  1. DisposeIfAbrupt(argument, disposable, errors).

mean the same thing as:

  1. Assert: disposable is an object with a [[DisposableResourceStack]] internal slot or undefined.
  2. Assert: errors is a List.
  3. If argument is an abrupt completion, set argument to DisposeResources(disposable, argument, errors).

Algorithm steps that say or are otherwise equivalent to:

  1. DisposeIfAbrupt(AbstractOperation(), disposable).

mean the same thing as:

  1. Assert: disposable is an object with a [[DisposableResourceStack]] internal slot or undefined.
  2. Let hygienicTemp be AbstractOperation().
  3. If hygienicTemp is an abrupt completion, set hygienicTemp to DisposeResources(disposable, hygienicTemp).

Where hygienicTemp is ephemeral and visible only in the steps pertaining to DisposeIfAbrupt.

Algorithm steps that say or are otherwise equivalent to:

  1. DisposeIfAbrupt(AbstractOperation(), disposable, errors).

mean the same thing as:

  1. Assert: disposable is an object with a [[DisposableResourceStack]] internal slot or undefined.
  2. Assert: errors is a List.
  3. Let hygienicTemp be AbstractOperation().
  4. If hygienicTemp is an abrupt completion, set hygienicTemp to DisposeResources(disposable, hygienicTemp, errors).

Where hygienicTemp is ephemeral and visible only in the steps pertaining to DisposeIfAbrupt.

Algorithm steps that say or are otherwise equivalent to:

  1. Let result be AbstractOperation(DisposeIfAbrupt(argument, disposable)).

mean the same thing as:

  1. Assert: disposable is an object with a [[DisposableResourceStack]] internal slot or undefined.
  2. If argument is an abrupt completion, set argument to DisposeResources(disposable, argument).
  3. Let result be AbstractOperation(argument).

Algorithm steps that say or are otherwise equivalent to:

  1. Let result be AbstractOperation(DisposeIfAbrupt(argument, disposable, errors)).

mean the same thing as:

  1. Assert: disposable is an object with a [[DisposableResourceStack]] internal slot or undefined.
  2. Assert: errors is a List.
  3. If argument is an abrupt completion, set argument to DisposeResources(disposable, argument, errors).
  4. Let result be AbstractOperation(argument).
Note

DisposeIfAbrupt can be combined with the ? and ! prefixes, so that for example

  1. Let result be ? DisposeIfAbrupt(value, disposable).

means the same thing as:

  1. Let result be DisposeIfAbrupt(value, disposable).
  2. ReturnIfAbrupt(result).

2 ECMAScript Data Types and Values

2.1 ECMAScript Language Types

2.1.1 The Symbol Type

2.1.1.1 Well-Known Symbols

Table 1: Well-known Symbols
Specification Name [[Description]] Value and Purpose
@@asyncDispose "Symbol.asyncDispose" A method that performs explicit resource cleanup on an object. Called by the semantics of the using await declaration while in an async function, async generator, or the top level of a Module.
@@dispose "Symbol.dispose" A method that performs explicit resource cleanup on an object. Called by the semantics of the using declaration.

2.2 ECMAScript Specification Types

2.2.1 The Reference Record Specification Type

2.2.1.1 InitializeReferencedBinding ( V, W )

The abstract operation InitializeReferencedBinding takes arguments V and W and returns either a normal completion containing unused or an abrupt completion. It performs the following steps when called:

  1. ReturnIfAbrupt(V).
  2. ReturnIfAbrupt(W).
  3. Assert: V is a Reference Record.
  4. Assert: IsUnresolvableReference(V) is false.
  5. Assert: hint is normal, sync-dispose, or async-dispose.
  6. Let base be V.[[Base]].
  7. Assert: base is an Environment Record.
  8. Return ? base.InitializeBinding(V.[[ReferencedName]], W, hint).

3 Abstract Operations

3.1 Operations on Disposable Objects

See Common Resource Management Interfaces (9.2.1).

3.1.1 DisposableResource Records

A DisposableResource Record is a Record value used to encapsulate a disposable object along with the method used to dispose the object. DisposableResource Records are produced by the CreateDisposableResource abstract operation.

DisposableResource Records have the fields listed in Table 2:

Table 2: DisposableResource Record Fields
Field Name Value Meaning
[[ResourceValue]] An Object or undefined. The value to be disposed.
[[Hint]] sync-dispose or async-dispose. Indicates whether the resources was added by a using declaration (sync-dispose) or a using await declaration (async-dispose).
[[DisposeMethod]] A function object. A function object that will be called with [[ResourceValue]] as its this value when the resource disposed.

3.1.2 AddDisposableResource ( disposable, V, hint [ , method ] )

The abstract operation AddDisposableResource takes arguments disposable (an object with a [[DisposableResourceStack]] internal slot), V (an ECMAScript language value), and hint (either sync-dispose or async-dispose) and optional argument method (a function object). It performs the following steps when called:

  1. If method is not present then,
    1. If V is null or undefined, return NormalCompletion(empty).
    2. If Type(V) is not Object, throw a TypeError exception.
    3. Let resource be ? CreateDisposableResource(V, hint).
  2. Else,
    1. If V is null or undefined, then
      1. Let resource be ? CreateDisposableResource(undefined, hint, method).
    2. Else,
      1. If Type(V) is not Object, throw a TypeError exception.
      2. Let resource be ? CreateDisposableResource(V, hint, method).
  3. Append resource to disposable.[[DisposableResourceStack]].
  4. Return NormalCompletion(empty).

3.1.3 CreateDisposableResource ( V, hint [ , method ] )

The abstract operation CreateDisposableResource takes arguments V (an Object or undefined) and hint (either sync-dispose or async-dispose) and optional argument method (a function object). It performs the following steps when called:

  1. If method is not present, then
    1. If V is undefined, throw a TypeError exception.
    2. Set method to ? GetDisposeMethod(V, hint).
    3. If method is undefined, throw a TypeError exception.
  2. Else,
    1. If IsCallable(method) is false, throw a TypeError exception.
  3. Return the DisposableResource Record { [[ResourceValue]]: V, [[Hint]]: hint, [[DisposeMethod]]: method }.

3.1.4 GetDisposeMethod ( V, hint )

The abstract operation GetDisposeMethod takes arguments V (an Object) and hint (either sync-dispose or async-dispose). It performs the following steps when called:

  1. If hint is async-dispose, then
    1. Let method be ? GetMethod(V, @@asyncDispose).
    2. If method is undefined, then
      1. Set method to ? GetMethod(V, @@dispose).
  2. Else,
    1. Let method be ? GetMethod(V, @@dispose).
  3. Return method.

3.1.5 Dispose ( V, hint, method )

The abstract operation Dispose takes arguments V (an Object or undefined), hint (either sync-dispose or async-dispose), and method (a function object). It performs the following steps when called:

  1. Let result be ? Call(method, V).
  2. If hint is async-dispose and result is not undefined, then
    1. Perform ? Await(result).
  3. Return undefined.

3.1.6 DisposeResources ( disposable, completion [ , errors ] )

The abstract operation DisposeResources takes arguments disposable (an object with a [[DisposableResourceStack]] internal slot or undefined) and completion (a Completion Record) and optional argument errors (a List) and returns a Completion Record. It performs the following steps when called:

  1. If errors is not present, let errors be a new empty List.
  2. If disposable is not undefined, then
    1. For each resource of disposable.[[DisposableResourceStack]], in reverse list order, do
      1. Let result be Dispose(resource.[[ResourceValue]], resource.[[Hint]], resource.[[DisposeMethod]]).
        1. If result.[[Type]] is throw, then
          1. Append result.[[Value]] to errors.
  3. Let errorsLength be the number of elements in errors.
  4. If errorsLength > 0, then
    1. Let error be a newly created AggregateError object.
    2. Perform ! DefinePropertyOrThrow(error, "errors", PropertyDescriptor { [[Configurable]]: true, [[Enumerable]]: false, [[Writable]]: true, [[Value]]: ! CreateArrayFromList(errors) }).
    3. If completion.[[Type]] is throw, then
      1. Perform ! CreateNonEnumerableDataPropertyOrThrow(error, "cause", completion.[[Value]]).
    4. Return ThrowCompletion(error).
  5. Return completion.
Note
Draft Note: This algorithm uses CreateNonEnumerableDataPropertyOrThrow from the Stage 3 Error Cause proposal.

4 Syntax-Directed Operations

4.1 Scope Analysis

4.1.1 Static Semantics: BoundNames

The syntax-directed operation BoundNames takes no arguments and returns a List of Strings.

Note

"*default*" is used within this specification as a synthetic name for a module's default export when it does not have another name. An entry in the module's [[Environment]] is created with that name and holds the corresponding value, and resolving the export named "default" by calling ResolveExport ( exportName [ , resolveSet ] ) for the module will return a ResolvedBinding Record whose [[BindingName]] is "*default*", which will then resolve in the module's [[Environment]] to the above-mentioned value. This is done only for ease of specification, so that anonymous default exports can be resolved like any other export. The string "*default*" is never accessible to user code or to the module linking algorithm.

It is defined piecewise over the following productions:

BindingIdentifier : Identifier
  1. Return a List whose sole element is the StringValue of Identifier.
BindingIdentifier : yield
  1. Return « "yield" ».
BindingIdentifier : await
  1. Return « "await" ».
LexicalDeclaration : LetOrConst BindingList ;
  1. Return the BoundNames of BindingList.
UsingDeclaration : using BindingList ; using await BindingList ;
  1. Return the BoundNames of BindingList.
BindingList : BindingList , LexicalBinding
  1. Let names1 be the BoundNames of BindingList.
  2. Let names2 be the BoundNames of LexicalBinding.
  3. Return the list-concatenation of names1 and names2.
LexicalBinding : BindingIdentifier Initializeropt
  1. Return the BoundNames of BindingIdentifier.
LexicalBinding : BindingPattern Initializer
  1. Return the BoundNames of BindingPattern.
LexicalBinding : void Initializer
  1. Return a new empty List.
VariableDeclarationList : VariableDeclarationList , VariableDeclaration
  1. Let names1 be BoundNames of VariableDeclarationList.
  2. Let names2 be BoundNames of VariableDeclaration.
  3. Return the list-concatenation of names1 and names2.
VariableDeclaration : BindingIdentifier Initializeropt
  1. Return the BoundNames of BindingIdentifier.
VariableDeclaration : BindingPattern Initializer
  1. Return the BoundNames of BindingPattern.
ObjectBindingPattern : { }
  1. Return a new empty List.
ObjectBindingPattern : { BindingPropertyList , BindingRestProperty }
  1. Let names1 be BoundNames of BindingPropertyList.
  2. Let names2 be BoundNames of BindingRestProperty.
  3. Return the list-concatenation of names1 and names2.
ArrayBindingPattern : [ Elisionopt ]
  1. Return a new empty List.
ArrayBindingPattern : [ Elisionopt BindingRestElement ]
  1. Return the BoundNames of BindingRestElement.
ArrayBindingPattern : [ BindingElementList , Elisionopt ]
  1. Return the BoundNames of BindingElementList.
ArrayBindingPattern : [ BindingElementList , Elisionopt BindingRestElement ]
  1. Let names1 be BoundNames of BindingElementList.
  2. Let names2 be BoundNames of BindingRestElement.
  3. Return the list-concatenation of names1 and names2.
BindingPropertyList : BindingPropertyList , BindingProperty
  1. Let names1 be BoundNames of BindingPropertyList.
  2. Let names2 be BoundNames of BindingProperty.
  3. Return the list-concatenation of names1 and names2.
BindingElementList : BindingElementList , BindingElisionElement
  1. Let names1 be BoundNames of BindingElementList.
  2. Let names2 be BoundNames of BindingElisionElement.
  3. Return the list-concatenation of names1 and names2.
BindingElisionElement : Elisionopt BindingElement
  1. Return BoundNames of BindingElement.
BindingProperty : PropertyName : BindingElement
  1. Return the BoundNames of BindingElement.
SingleNameBinding : BindingIdentifier Initializeropt
  1. Return the BoundNames of BindingIdentifier.
BindingElement : BindingPattern Initializeropt
  1. Return the BoundNames of BindingPattern.
ForDeclaration : LetOrConst ForBinding
  1. Return the BoundNames of ForBinding.
FunctionDeclaration : function BindingIdentifier ( FormalParameters ) { FunctionBody }
  1. Return the BoundNames of BindingIdentifier.
FunctionDeclaration : function ( FormalParameters ) { FunctionBody }
  1. Return « "*default*" ».
FormalParameters : [empty]
  1. Return a new empty List.
FormalParameters : FormalParameterList , FunctionRestParameter
  1. Let names1 be BoundNames of FormalParameterList.
  2. Let names2 be BoundNames of FunctionRestParameter.
  3. Return the list-concatenation of names1 and names2.
FormalParameterList : FormalParameterList , FormalParameter
  1. Let names1 be BoundNames of FormalParameterList.
  2. Let names2 be BoundNames of FormalParameter.
  3. Return the list-concatenation of names1 and names2.
ArrowParameters : CoverParenthesizedExpressionAndArrowParameterList
  1. Let formals be the ArrowFormalParameters that is covered by CoverParenthesizedExpressionAndArrowParameterList.
  2. Return the BoundNames of formals.
GeneratorDeclaration : function * BindingIdentifier ( FormalParameters ) { GeneratorBody }
  1. Return the BoundNames of BindingIdentifier.
GeneratorDeclaration : function * ( FormalParameters ) { GeneratorBody }
  1. Return « "*default*" ».
AsyncGeneratorDeclaration : async function * BindingIdentifier ( FormalParameters ) { AsyncGeneratorBody }
  1. Return the BoundNames of BindingIdentifier.
AsyncGeneratorDeclaration : async function * ( FormalParameters ) { AsyncGeneratorBody }
  1. Return « "*default*" ».
ClassDeclaration : class BindingIdentifier ClassTail
  1. Return the BoundNames of BindingIdentifier.
ClassDeclaration : class ClassTail
  1. Return « "*default*" ».
AsyncFunctionDeclaration : async function BindingIdentifier ( FormalParameters ) { AsyncFunctionBody }
  1. Return the BoundNames of BindingIdentifier.
AsyncFunctionDeclaration : async function ( FormalParameters ) { AsyncFunctionBody }
  1. Return « "*default*" ».
CoverCallExpressionAndAsyncArrowHead : MemberExpression Arguments
  1. Let head be the AsyncArrowHead that is covered by CoverCallExpressionAndAsyncArrowHead.
  2. Return the BoundNames of head.
ImportDeclaration : import ImportClause FromClause ;
  1. Return the BoundNames of ImportClause.
ImportDeclaration : import ModuleSpecifier ;
  1. Return a new empty List.
ImportClause : ImportedDefaultBinding , NameSpaceImport
  1. Let names1 be the BoundNames of ImportedDefaultBinding.
  2. Let names2 be the BoundNames of NameSpaceImport.
  3. Return the list-concatenation of names1 and names2.
ImportClause : ImportedDefaultBinding , NamedImports
  1. Let names1 be the BoundNames of ImportedDefaultBinding.
  2. Let names2 be the BoundNames of NamedImports.
  3. Return the list-concatenation of names1 and names2.
NamedImports : { }
  1. Return a new empty List.
ImportsList : ImportsList , ImportSpecifier
  1. Let names1 be the BoundNames of ImportsList.
  2. Let names2 be the BoundNames of ImportSpecifier.
  3. Return the list-concatenation of names1 and names2.
ImportSpecifier : ModuleExportName as ImportedBinding
  1. Return the BoundNames of ImportedBinding.
ExportDeclaration : export ExportFromClause FromClause ; export NamedExports ;
  1. Return a new empty List.
ExportDeclaration : export VariableStatement
  1. Return the BoundNames of VariableStatement.
ExportDeclaration : export Declaration
  1. Return the BoundNames of Declaration.
ExportDeclaration : export default HoistableDeclaration
  1. Let declarationNames be the BoundNames of HoistableDeclaration.
  2. If declarationNames does not include the element "*default*", append "*default*" to declarationNames.
  3. Return declarationNames.
ExportDeclaration : export default ClassDeclaration
  1. Let declarationNames be the BoundNames of ClassDeclaration.
  2. If declarationNames does not include the element "*default*", append "*default*" to declarationNames.
  3. Return declarationNames.
ExportDeclaration : export default AssignmentExpression ;
  1. Return « "*default*" ».

4.1.2 Static Semantics: IsConstantDeclaration

The syntax-directed operation IsConstantDeclaration takes no arguments and returns a Boolean. It is defined piecewise over the following productions:

LexicalDeclaration : LetOrConst BindingList ;
  1. Return IsConstantDeclaration of LetOrConst.
LexicalDeclaration : UsingDeclaration
  1. Return true.
LetOrConst : let
  1. Return false.
LetOrConst : const
  1. Return true.
FunctionDeclaration : function BindingIdentifier ( FormalParameters ) { FunctionBody } function ( FormalParameters ) { FunctionBody } GeneratorDeclaration : function * BindingIdentifier ( FormalParameters ) { GeneratorBody } function * ( FormalParameters ) { GeneratorBody } AsyncGeneratorDeclaration : async function * BindingIdentifier ( FormalParameters ) { AsyncGeneratorBody } async function * ( FormalParameters ) { AsyncGeneratorBody } AsyncFunctionDeclaration : async function BindingIdentifier ( FormalParameters ) { AsyncFunctionBody } async function ( FormalParameters ) { AsyncFunctionBody }
  1. Return false.
ClassDeclaration : class BindingIdentifier ClassTail class ClassTail
  1. Return false.
ExportDeclaration : export ExportFromClause FromClause ; export NamedExports ; export default AssignmentExpression ;
  1. Return false.
Note

It is not necessary to treat export default AssignmentExpression as a constant declaration because there is no syntax that permits assignment to the internal bound name used to reference a module's default object.

4.2 Miscellaneous

4.2.1 Runtime Semantics: IteratorBindingInitialization

The syntax-directed operation IteratorBindingInitialization takes arguments iteratorRecord and environment and returns either a normal completion containing unused or an abrupt completion.

Note

When undefined is passed for environment it indicates that a PutValue operation should be used to assign the initialization value. This is the case for formal parameter lists of non-strict functions. In that case the formal parameter bindings are preinitialized in order to deal with the possibility of multiple parameters with the same name.

It is defined piecewise over the following productions:

ArrayBindingPattern : [ ]
  1. Return unused.
ArrayBindingPattern : [ Elision ]
  1. Return ? IteratorDestructuringAssignmentEvaluation of Elision with argument iteratorRecord.
ArrayBindingPattern : [ Elisionopt BindingRestElement ]
  1. If Elision is present, then
    1. Perform ? IteratorDestructuringAssignmentEvaluation of Elision with argument iteratorRecord.
  2. Return ? IteratorBindingInitialization of BindingRestElement with arguments iteratorRecord and environment.
ArrayBindingPattern : [ BindingElementList , Elision ]
  1. Perform ? IteratorBindingInitialization of BindingElementList with arguments iteratorRecord and environment.
  2. Return ? IteratorDestructuringAssignmentEvaluation of Elision with argument iteratorRecord.
ArrayBindingPattern : [ BindingElementList , Elisionopt BindingRestElement ]
  1. Perform ? IteratorBindingInitialization of BindingElementList with arguments iteratorRecord and environment.
  2. If Elision is present, then
    1. Perform ? IteratorDestructuringAssignmentEvaluation of Elision with argument iteratorRecord.
  3. Return ? IteratorBindingInitialization of BindingRestElement with arguments iteratorRecord and environment.
BindingElementList : BindingElementList , BindingElisionElement
  1. Perform ? IteratorBindingInitialization of BindingElementList with arguments iteratorRecord and environment.
  2. Return ? IteratorBindingInitialization of BindingElisionElement with arguments iteratorRecord and environment.
BindingElisionElement : Elision BindingElement
  1. Perform ? IteratorDestructuringAssignmentEvaluation of Elision with argument iteratorRecord.
  2. Return ? IteratorBindingInitialization of BindingElement with arguments iteratorRecord and environment.
SingleNameBinding : BindingIdentifier Initializeropt
  1. Let bindingId be StringValue of BindingIdentifier.
  2. Let lhs be ? ResolveBinding(bindingId, environment).
  3. Let v be undefined.
  4. If iteratorRecord.[[Done]] is false, then
    1. Let next be Completion(IteratorStep(iteratorRecord)).
    2. If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
    3. ReturnIfAbrupt(next).
    4. If next is false, set iteratorRecord.[[Done]] to true.
    5. Else,
      1. Set v to Completion(IteratorValue(next)).
      2. If v is an abrupt completion, set iteratorRecord.[[Done]] to true.
      3. ReturnIfAbrupt(v).
  5. If Initializer is present and v is undefined, then
    1. If IsAnonymousFunctionDefinition(Initializer) is true, then
      1. Set v to ? NamedEvaluation of Initializer with argument bindingId.
    2. Else,
      1. Let defaultValue be the result of evaluating Initializer.
      2. Set v to ? GetValue(defaultValue).
  6. If environment is undefined, return ? PutValue(lhs, v).
  7. Return ? InitializeReferencedBinding(lhs, v, normal).
BindingElement : BindingPattern Initializeropt
  1. Let v be undefined.
  2. If iteratorRecord.[[Done]] is false, then
    1. Let next be Completion(IteratorStep(iteratorRecord)).
    2. If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
    3. ReturnIfAbrupt(next).
    4. If next is false, set iteratorRecord.[[Done]] to true.
    5. Else,
      1. Set v to Completion(IteratorValue(next)).
      2. If v is an abrupt completion, set iteratorRecord.[[Done]] to true.
      3. ReturnIfAbrupt(v).
  3. If Initializer is present and v is undefined, then
    1. Let defaultValue be the result of evaluating Initializer.
    2. Set v to ? GetValue(defaultValue).
  4. Return ? BindingInitialization of BindingPattern with arguments v and environment.
BindingRestElement : ... BindingIdentifier
  1. Let lhs be ? ResolveBinding(StringValue of BindingIdentifier, environment).
  2. Let A be ! ArrayCreate(0).
  3. Let n be 0.
  4. Repeat,
    1. If iteratorRecord.[[Done]] is false, then
      1. Let next be Completion(IteratorStep(iteratorRecord)).
      2. If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
      3. ReturnIfAbrupt(next).
      4. If next is false, set iteratorRecord.[[Done]] to true.
    2. If iteratorRecord.[[Done]] is true, then
      1. If environment is undefined, return ? PutValue(lhs, A).
      2. Return ? InitializeReferencedBinding(lhs, A, normal).
    3. Let nextValue be Completion(IteratorValue(next)).
    4. If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to true.
    5. ReturnIfAbrupt(nextValue).
    6. Perform ! CreateDataPropertyOrThrow(A, ! ToString(𝔽(n)), nextValue).
    7. Set n to n + 1.
BindingRestElement : ... BindingPattern
  1. Let A be ! ArrayCreate(0).
  2. Let n be 0.
  3. Repeat,
    1. If iteratorRecord.[[Done]] is false, then
      1. Let next be Completion(IteratorStep(iteratorRecord)).
      2. If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
      3. ReturnIfAbrupt(next).
      4. If next is false, set iteratorRecord.[[Done]] to true.
    2. If iteratorRecord.[[Done]] is true, then
      1. Return ? BindingInitialization of BindingPattern with arguments A and environment.
    3. Let nextValue be Completion(IteratorValue(next)).
    4. If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to true.
    5. ReturnIfAbrupt(nextValue).
    6. Perform ! CreateDataPropertyOrThrow(A, ! ToString(𝔽(n)), nextValue).
    7. Set n to n + 1.
FormalParameters : [empty]
  1. Return unused.
FormalParameters : FormalParameterList , FunctionRestParameter
  1. Perform ? IteratorBindingInitialization of FormalParameterList with arguments iteratorRecord and environment.
  2. Return ? IteratorBindingInitialization of FunctionRestParameter with arguments iteratorRecord and environment.
FormalParameterList : FormalParameterList , FormalParameter
  1. Perform ? IteratorBindingInitialization of FormalParameterList with arguments iteratorRecord and environment.
  2. Return ? IteratorBindingInitialization of FormalParameter with arguments iteratorRecord and environment.
ArrowParameters : BindingIdentifier
  1. Let v be undefined.
  2. Assert: iteratorRecord.[[Done]] is false.
  3. Let next be Completion(IteratorStep(iteratorRecord)).
  4. If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
  5. ReturnIfAbrupt(next).
  6. If next is false, set iteratorRecord.[[Done]] to true.
  7. Else,
    1. Set v to Completion(IteratorValue(next)).
    2. If v is an abrupt completion, set iteratorRecord.[[Done]] to true.
    3. ReturnIfAbrupt(v).
  8. Return ? BindingInitialization of BindingIdentifier with arguments v and environment.
ArrowParameters : CoverParenthesizedExpressionAndArrowParameterList
  1. Let formals be the ArrowFormalParameters that is covered by CoverParenthesizedExpressionAndArrowParameterList.
  2. Return ? IteratorBindingInitialization of formals with arguments iteratorRecord and environment.
AsyncArrowBindingIdentifier : BindingIdentifier
  1. Let v be undefined.
  2. Assert: iteratorRecord.[[Done]] is false.
  3. Let next be Completion(IteratorStep(iteratorRecord)).
  4. If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
  5. ReturnIfAbrupt(next).
  6. If next is false, set iteratorRecord.[[Done]] to true.
  7. Else,
    1. Set v to Completion(IteratorValue(next)).
    2. If v is an abrupt completion, set iteratorRecord.[[Done]] to true.
    3. ReturnIfAbrupt(v).
  8. Return ? BindingInitialization of BindingIdentifier with arguments v and environment.

5 Executable Code and Execution Contexts

5.1 Environment Records

Environment Record is a specification type used to define the association of Identifiers to specific variables and functions, based upon the lexical nesting structure of ECMAScript code. Usually an Environment Record is associated with some specific syntactic structure of ECMAScript code such as a FunctionDeclaration, a BlockStatement, or a Catch clause of a TryStatement. Each time such code is evaluated, a new Environment Record is created to record the identifier bindings that are created by that code.

Every Environment Record has an [[OuterEnv]] field, which is either null or a reference to an outer Environment Record. This is used to model the logical nesting of Environment Record values. The outer reference of an (inner) Environment Record is a reference to the Environment Record that logically surrounds the inner Environment Record. An outer Environment Record may, of course, have its own outer Environment Record. An Environment Record may serve as the outer environment for multiple inner Environment Records. For example, if a FunctionDeclaration contains two nested FunctionDeclarations then the Environment Records of each of the nested functions will have as their outer Environment Record the Environment Record of the current evaluation of the surrounding function.

Environment Records are purely specification mechanisms and need not correspond to any specific artefact of an ECMAScript implementation. It is impossible for an ECMAScript program to directly access or manipulate such values.

5.1.1 The Environment Record Type Hierarchy

The Environment Record abstract class includes the abstract specification methods defined in Table 3. These abstract methods have distinct concrete algorithms for each of the concrete subclasses.

Table 3: Abstract Methods of Environment Records
Method Purpose
HasBinding(N) Determine if an Environment Record has a binding for the String value N. Return true if it does and false if it does not.
CreateMutableBinding(N, D) Create a new but uninitialized mutable binding in an Environment Record. The String value N is the text of the bound name. If the Boolean argument D is true the binding may be subsequently deleted.
CreateImmutableBinding(N, S) Create a new but uninitialized immutable binding in an Environment Record. The String value N is the text of the bound name. If S is true then attempts to set it after it has been initialized will always throw an exception, regardless of the strict mode setting of operations that reference that binding.
InitializeBinding(N, V, hint) Set the value of an already existing but uninitialized binding in an Environment Record. The String value N is the text of the bound name. V is the value for the binding and is a value of any ECMAScript language type. hint indicates whether the binding came from a using declaration (sync-dispose), a using await declaration (async-dispose), or a regular variable declaration (normal).
SetMutableBinding(N, V, S) Set the value of an already existing mutable binding in an Environment Record. The String value N is the text of the bound name. V is the value for the binding and may be a value of any ECMAScript language type. S is a Boolean flag. If S is true and the binding cannot be set throw a TypeError exception.
GetBindingValue(N, S) Returns the value of an already existing binding from an Environment Record. The String value N is the text of the bound name. S is used to identify references originating in strict mode code or that otherwise require strict mode reference semantics. If S is true and the binding does not exist throw a ReferenceError exception. If the binding exists but is uninitialized a ReferenceError is thrown, regardless of the value of S.
DeleteBinding(N) Delete a binding from an Environment Record. The String value N is the text of the bound name. If a binding for N exists, remove the binding and return true. If the binding exists but cannot be removed return false. If the binding does not exist return true.
HasThisBinding() Determine if an Environment Record establishes a this binding. Return true if it does and false if it does not.
HasSuperBinding() Determine if an Environment Record establishes a super method binding. Return true if it does and false if it does not.
WithBaseObject() If this Environment Record is associated with a with statement, return the with object. Otherwise, return undefined.

5.1.1.1 Declarative Environment Records

Each declarative Environment Record is associated with an ECMAScript program scope containing variable, constant, let, class, module, import, and/or function declarations. A declarative Environment Record binds the set of identifiers defined by the declarations contained within its scope.

Every declarative Environment Record also has a [[DisposableResourceStack]] field, which is a List of DisposableResource Records. This list is a stack of resources tracked by the using and using await declarations that must be disposed when the Evaluation step that constructed the Environment Record has completed.

The behaviour of the concrete specification methods for declarative Environment Records is defined by the following algorithms.

5.1.1.1.1 InitializeBinding ( N, V, hint )

The InitializeBinding concrete method of a declarative Environment Record envRec takes arguments N (a String), V (an ECMAScript language value), and hint (either normal, sync-dispose, or async-dispose) and returns a normal completion containing unused. It is used to set the bound value of the current binding of the identifier whose name is the value of the argument N to the value of argument V. An uninitialized binding for N must already exist. It performs the following steps when called:

  1. Assert: envRec must have an uninitialized binding for N.
  2. If hint is not normal, perform ? AddDisposableResource(envRec, V, hint).
  3. Set the bound value for N in envRec to V.
  4. Record that the binding for N in envRec has been initialized.
  5. Return unused.

5.1.1.2 Object Environment Records

5.1.1.2.1 InitializeBinding ( N, V, hint )

The InitializeBinding concrete method of an object Environment Record envRec takes arguments N (a String), V (an ECMAScript language value), and hint (either normal, sync-dispose, or async-dispose) and returns either a normal completion containing unused or a throw completion. It is used to set the bound value of the current binding of the identifier whose name is the value of the argument N to the value of argument V. It performs the following steps when called:

  1. Assert: hint is normal.
  2. Perform ? envRec.SetMutableBinding(N, V, false).
  3. Return unused.
Note

In this specification, all uses of CreateMutableBinding for object Environment Records are immediately followed by a call to InitializeBinding for the same name. Hence, this specification does not explicitly track the initialization state of bindings in object Environment Records.

5.1.1.3 Global Environment Records

5.1.1.3.1 InitializeBinding ( N, V, hint )

The InitializeBinding concrete method of a global Environment Record envRec takes arguments N (a String), V (an ECMAScript language value), and hint (either normal, sync-dispose, or async-dispose) and returns either a normal completion containing unused or a throw completion. It is used to set the bound value of the current binding of the identifier whose name is the value of the argument N to the value of argument V. An uninitialized binding for N must already exist. It performs the following steps when called:

  1. Let DclRec be envRec.[[DeclarativeRecord]].
  2. If ! DclRec.HasBinding(N) is true, then
    1. Return ! DclRec.InitializeBinding(N, V, hint).
  3. Assert: If the binding exists, it must be in the object Environment Record.
  4. Assert: hint is normal.
  5. Let ObjRec be envRec.[[ObjectRecord]].
  6. Return ? ObjRec.InitializeBinding(N, V).

6 ECMAScript Language: Statements and Declarations

6.1 Block

6.1.1 Runtime Semantics: Evaluation

Block : { StatementList }
  1. Let oldEnv be the running execution context's LexicalEnvironment.
  2. Let blockEnv be NewDeclarativeEnvironment(oldEnv).
  3. Perform BlockDeclarationInstantiation(StatementList, blockEnv).
  4. Set the running execution context's LexicalEnvironment to blockEnv.
  5. Let blockValue be the result of evaluating StatementList.
  6. Set blockValue to DisposeResources(blockEnv, blockValue).
  7. Set the running execution context's LexicalEnvironment to oldEnv.
  8. Return blockValue.
Note

No matter how control leaves the Block the LexicalEnvironment is always restored to its former state.

6.2 Declarations and the Variable Statement

6.2.1 Let and Const, Const, and Using Declarations

Syntax

LexicalDeclaration[In, Yield, Await] : LetOrConst BindingList[?In, ?Yield, ?Await, ~Using] ; UsingDeclaration[?In, ?Yield, ?Await] LetOrConst : let const UsingDeclaration[In, Yield, Await] : using [no LineTerminator here] BindingList[?In, ?Yield, ?Await, +Using] ; [+Await] using [no LineTerminator here] await BindingList[?In, ?Yield, +Await, +Using] ; BindingList[In, Yield, Await, Using] : LexicalBinding[?In, ?Yield, ?Await, ?Using] BindingList[?In, ?Yield, ?Await, ?Using] , LexicalBinding[?In, ?Yield, ?Await, ?Using] LexicalBinding[In, Yield, Await, Using] : BindingIdentifier[?Yield, ?Await] Initializer[?In, ?Yield, ?Await]opt BindingPattern[?Yield, ?Await] Initializer[?In, ?Yield, ?Await] [~Using] BindingPattern[?Yield, ?Await] Initializer[?In, ?Yield, ?Await] [+Using] void Initializer[?In, ?Yield, ?Await]

6.2.1.1 Static Semantics: Early Errors

UsingDeclaration : using BindingList ; using await BindingList ; Note
Draft Note: This behavior is currently under discussion in #66. The above boundaries have been chosen for the following reasons:

6.2.1.2 Runtime Semantics: Evaluation

LexicalDeclaration : LetOrConst BindingList ;
  1. Let next be the result of evaluating BindingListBindingEvaluation of BindingList with parameter normal.
  2. ReturnIfAbrupt(next).
  3. Return empty.
UsingDeclaration : using BindingList ;
  1. Let next be BindingEvaluation of BindingList with parameter sync-dispose.
  2. ReturnIfAbrupt(next).
  3. Return empty.
UsingDeclaration : using await BindingList ;
  1. Let next be BindingEvaluation of BindingList with parameter async-dispose.
  2. ReturnIfAbrupt(next).
  3. Return empty.
BindingList : BindingList , LexicalBinding
  1. Let next be the result of evaluating BindingList.
  2. ReturnIfAbrupt(next).
  3. Return the result of evaluating LexicalBinding.
LexicalBinding : BindingIdentifier
  1. Let lhs be ResolveBinding(StringValue of BindingIdentifier).
  2. Perform ? InitializeReferencedBinding(lhs, undefined).
  3. Return empty.
Note

A static semantics rule ensures that this form of LexicalBinding never occurs in a const declaration.

LexicalBinding : BindingIdentifier Initializer
  1. Let bindingId be StringValue of BindingIdentifier.
  2. Let lhs be Completion(ResolveBinding(bindingId)).
  3. If IsAnonymousFunctionDefinition(Initializer) is true, then
    1. Let value be ? NamedEvaluation of Initializer with argument bindingId.
  4. Else,
    1. Let rhs be the result of evaluating Initializer.
    2. Let value be ? GetValue(rhs).
  5. Perform ? InitializeReferencedBinding(lhs, value).
  6. Return empty.
LexicalBinding : BindingPattern Initializer
  1. Let rhs be the result of evaluating Initializer.
  2. Let value be ? GetValue(rhs).
  3. Let env be the running execution context's LexicalEnvironment.
  4. Return ? BindingInitialization for BindingPattern using value and env as the arguments.

6.2.1.3 Runtime Semantics: BindingEvaluation

The syntax-directed operation BindingEvaluation takes argument hint (either normal, sync-dispose, or async-dispose) and returns either a normal completion containing unused or an abrupt completion. It is defined piecewise over the following productions:

BindingList : BindingList , LexicalBinding
  1. Perform ? BindingEvaluation of BindingList with parameter hint.
  2. Perform ? BindingEvaluation of LexicalBinding with parameter hint.
  3. Return unused.
LexicalBinding : BindingIdentifier
  1. Assert: hint is normal.
  2. Let lhs be ? ResolveBinding(StringValue of BindingIdentifier).
  3. Return ? InitializeReferencedBinding(lhs, undefined, normal).
Note

A static semantics rule ensures that this form of LexicalBinding never occurs in a const declaration.

LexicalBinding : BindingIdentifier Initializer
  1. Let bindingId be StringValue of BindingIdentifier.
  2. Let lhs be ? ResolveBinding(bindingId).
  3. If IsAnonymousFunctionDefinition(Initializer) is true, then
    1. Let value be NamedEvaluation of Initializer with argument bindingId.
  4. Else,
    1. Let rhs be the result of evaluating Initializer.
    2. Let value be ? GetValue(rhs).
  5. Return ? InitializeReferencedBinding(lhs, value, hint).
LexicalBinding : BindingPattern Initializer
  1. Assert: hint is normal.
  2. Let rhs be the result of evaluating Initializer.
  3. Let value be ? GetValue(rhs).
  4. Let env be the running execution context's LexicalEnvironment.
  5. Return ? BindingInitialization of BindingPattern with arguments value and env.
LexicalBinding : void Initializer
  1. Assert: hint is sync-dispose or async-dispose.
  2. Let expr be the result of evaluating Initializer.
  3. Let value be ? GetValue(expr).
  4. Let env be the running execution context's LexicalEnvironment.
  5. Return ? AddDisposableResource(env, value, hint).

6.2.2 Destructuring Binding Patterns

6.2.2.1 Runtime Semantics: RestBindingInitialization

The syntax-directed operation RestBindingInitialization takes arguments value, environment, and excludedNames and returns either a normal completion containing unused or an abrupt completion. It is defined piecewise over the following productions:

BindingRestProperty : ... BindingIdentifier
  1. Let lhs be ? ResolveBinding(StringValue of BindingIdentifier, environment).
  2. Let restObj be OrdinaryObjectCreate(%Object.prototype%).
  3. Perform ? CopyDataProperties(restObj, value, excludedNames).
  4. If environment is undefined, return PutValue(lhs, restObj).
  5. Return ? InitializeReferencedBinding(lhs, restObj, normal).

6.2.2.2 Runtime Semantics: KeyedBindingInitialization

The syntax-directed operation KeyedBindingInitialization takes arguments value, environment, and propertyName and returns either a normal completion containing unused or an abrupt completion.

Note

When undefined is passed for environment it indicates that a PutValue operation should be used to assign the initialization value. This is the case for formal parameter lists of non-strict functions. In that case the formal parameter bindings are preinitialized in order to deal with the possibility of multiple parameters with the same name.

It is defined piecewise over the following productions:

BindingElement : BindingPattern Initializeropt
  1. Let v be ? GetV(value, propertyName).
  2. If Initializer is present and v is undefined, then
    1. Let defaultValue be the result of evaluating Initializer.
    2. Set v to ? GetValue(defaultValue).
  3. Return ? BindingInitialization of BindingPattern with arguments v and environment.
SingleNameBinding : BindingIdentifier Initializeropt
  1. Let bindingId be StringValue of BindingIdentifier.
  2. Let lhs be ? ResolveBinding(bindingId, environment).
  3. Let v be ? GetV(value, propertyName).
  4. If Initializer is present and v is undefined, then
    1. If IsAnonymousFunctionDefinition(Initializer) is true, then
      1. Set v to ? NamedEvaluation for Initializer with argument bindingId.
    2. Else,
      1. Let defaultValue be the result of evaluating Initializer.
      2. Set v to ? GetValue(defaultValue).
  5. If environment is undefined, return ? PutValue(lhs, v).
  6. Return ? InitializeReferencedBinding(lhs, v, normal).

6.3 Iteration Statements

6.3.1 The for Statement

6.3.1.1 Runtime Semantics: ForLoopEvaluation

The syntax-directed operation ForLoopEvaluation takes argument labelSet and returns either a normal completion containing an ECMAScript language value or an abrupt completion. It is defined piecewise over the following productions:

ForStatement : for ( Expressionopt ; Expressionopt ; Expressionopt ) Statement
  1. If the first Expression is present, then
    1. Let exprRef be the result of evaluating the first Expression.
    2. Perform ? GetValue(exprRef).
  2. Return ? ForBodyEvaluation(the second Expression, the third Expression, Statement, « », labelSet).
ForStatement : for ( var VariableDeclarationList ; Expressionopt ; Expressionopt ) Statement
  1. Let varDcl be the result of evaluating VariableDeclarationList.
  2. ReturnIfAbrupt(varDcl).
  3. Return ? ForBodyEvaluation(the first Expression, the second Expression, Statement, « », labelSet).
ForStatement : for ( LexicalDeclaration Expressionopt ; Expressionopt ) Statement
  1. Let oldEnv be the running execution context's LexicalEnvironment.
  2. Let loopEnv be NewDeclarativeEnvironment(oldEnv).
  3. Let isConst be IsConstantDeclaration of LexicalDeclaration.
  4. Let boundNames be the BoundNames of LexicalDeclaration.
  5. For each element dn of boundNames, do
    1. If isConst is true, then
      1. Perform ! loopEnv.CreateImmutableBinding(dn, true).
    2. Else,
      1. Perform ! loopEnv.CreateMutableBinding(dn, false).
  6. Set the running execution context's LexicalEnvironment to loopEnv.
  7. Let forDcl be the result of evaluating LexicalDeclaration.
  8. If forDcl is an abrupt completion, then
    1. Set forDcl to DisposeResources(loopEnv, forDcl).
    2. Set the running execution context's LexicalEnvironment to oldEnv.
    3. Return ? forDcl.
  9. If isConst is false, let perIterationLets be boundNames; otherwise let perIterationLets be a new empty List.
  10. Let bodyResult be Completion(ForBodyEvaluation(the first Expression, the second Expression, Statement, perIterationLets, labelSet)).
  11. Set bodyResult to DisposeResources(loopEnv, bodyResult).
  12. Set the running execution context's LexicalEnvironment to oldEnv.
  13. Return ? bodyResult.

6.3.1.2 ForBodyEvaluation ( test, increment, stmt, perIterationBindings, labelSet )

The abstract operation ForBodyEvaluation takes arguments test, increment, stmt, perIterationBindings, and labelSet and returns either a normal completion containing an ECMAScript language value or an abrupt completion. It performs the following steps when called:

  1. Let V be undefined.
  2. Perform ? CreatePerIterationEnvironment(perIterationBindings).
  3. Let thisIterationEnv be ? CreatePerIterationEnvironment(perIterationBindings).
  4. Repeat,
    1. If test is not [empty], then
      1. Let testRef be the result of evaluating test.
      2. Let testValue be ? GetValue(testRef).
      3. Let testValue be ? DisposeIfAbrupt(GetValue(testRef), thisIterationEnv).
      4. If ToBoolean(testValue) is false, return V.
      5. If ToBoolean(testValue) is false, return DisposeResources(thisIterationEnv, V).
    2. Let result be the result of evaluating stmt.
    3. If LoopContinues(result, labelSet) is false, return ? UpdateEmpty(result, V).
    4. If LoopContinues(result, labelSet) is false, return ? DisposeResources(thisIterationEnv, UpdateEmpty(result, V)).
    5. If result.[[Value]] is not empty, set V to result.[[Value]].
    6. Perform ? CreatePerIterationEnvironment(perIterationBindings).
    7. Perform ? DisposeResources(thisIterationEnv, undefined).
    8. Set thisIterationEnv to ? CreatePerIterationEnvironment(perIterationBindings).
    9. If increment is not [empty], then
      1. Let incRef be the result of evaluating increment.
      2. Perform ? GetValue(incRef).
      3. Perform ? DisposeIfAbrupt(GetValue(incRef), thisIterationEnv).

6.3.1.3 CreatePerIterationEnvironment ( perIterationBindings )

The abstract operation CreatePerIterationEnvironment takes argument perIterationBindings and returns either a normal completion containing either a Declarative Environment Record or unused or a throw completion. It performs the following steps when called:

  1. If perIterationBindings has any elements, then
    1. Let lastIterationEnv be the running execution context's LexicalEnvironment.
    2. Let outer be lastIterationEnv.[[OuterEnv]].
    3. Assert: outer is not null.
    4. Let thisIterationEnv be NewDeclarativeEnvironment(outer).
    5. For each element bn of perIterationBindings, do
      1. Perform ! thisIterationEnv.CreateMutableBinding(bn, false).
      2. Let lastValue be ? lastIterationEnv.GetBindingValue(bn, true).
      3. Perform thisIterationEnv.InitializeBinding(bn, lastValue).
    6. Set the running execution context's LexicalEnvironment to thisIterationEnv.
    7. Return thisIterationEnv.
  2. Return unused.

6.3.2 The for-in, for-of, and for-await-of Statements

Syntax

ForInOfStatement[Yield, Await, Return] : for ( [lookahead ≠ let [] LeftHandSideExpression[?Yield, ?Await] in Expression[+In, ?Yield, ?Await] ) Statement[?Yield, ?Await, ?Return] for ( var ForBinding[?Yield, ?Await, ~Using] in Expression[+In, ?Yield, ?Await] ) Statement[?Yield, ?Await, ?Return] for ( ForDeclaration[?Yield, ?Await, ~Using] in Expression[+In, ?Yield, ?Await] ) Statement[?Yield, ?Await, ?Return] for ( [lookahead ∉ { let, async of }] LeftHandSideExpression[?Yield, ?Await] of AssignmentExpression[+In, ?Yield, ?Await] ) Statement[?Yield, ?Await, ?Return] for ( var ForBinding[?Yield, ?Await, ~Using] of AssignmentExpression[+In, ?Yield, ?Await] ) Statement[?Yield, ?Await, ?Return] for ( ForDeclaration[?Yield, ?Await, +Using] of AssignmentExpression[+In, ?Yield, ?Await] ) Statement[?Yield, ?Await, ?Return] [+Await] for await ( [lookahead ≠ let] LeftHandSideExpression[?Yield, ?Await] of AssignmentExpression[+In, ?Yield, ?Await] ) Statement[?Yield, ?Await, ?Return] [+Await] for await ( var ForBinding[?Yield, ?Await, ~Using] of AssignmentExpression[+In, ?Yield, ?Await] ) Statement[?Yield, ?Await, ?Return] [+Await] for await ( ForDeclaration[?Yield, ?Await, +Using] of AssignmentExpression[+In, ?Yield, ?Await] ) Statement[?Yield, ?Await, ?Return] ForDeclaration[Yield, Await, Using] : LetOrConst ForBinding[?Yield, ?Await, ~Using] [+Using] using [no LineTerminator here] ForBinding[?Yield, ?Await, +Using] [+Using, +Await] using [no LineTerminator here] await ForBinding[?Yield, ?Await, +Using] ForBinding[Yield, Await, Using] : BindingIdentifier[?Yield, ?Await] BindingPattern[?Yield, ?Await] [~Using] BindingPattern[?Yield, ?Await]

6.3.2.1 ForIn/OfHeadEvaluation ( uninitializedBoundNames, expr, iterationKind )

The abstract operation ForIn/OfHeadEvaluation takes arguments uninitializedBoundNames, expr, and iterationKind (enumerate, iterate, or async-iterate) and returns either a normal completion containing an Iterator Record or an abrupt completion. It performs the following steps when called:

  1. Let oldEnv be the running execution context's LexicalEnvironment.
  2. If uninitializedBoundNames is not an empty List, then
    1. Assert: uninitializedBoundNames has no duplicate entries.
    2. Let newEnv be NewDeclarativeEnvironment(oldEnv).
    3. For each String name of uninitializedBoundNames, do
      1. Perform ! newEnv.CreateMutableBinding(name, false).
    4. Set the running execution context's LexicalEnvironment to newEnv.
  3. Else,
    1. Let newEnv be undefined.
  4. Let exprRef be the result of evaluating expr.
  5. Set exprRef to DisposeResources(newEnv, exprRef).
  6. Set the running execution context's LexicalEnvironment to oldEnv.
  7. Let exprValue be ? GetValue(exprRef).
  8. If iterationKind is enumerate, then
    1. If exprValue is undefined or null, then
      1. Return Completion Record { [[Type]]: break, [[Value]]: empty, [[Target]]: empty }.
    2. Let obj be ! ToObject(exprValue).
    3. Let iterator be EnumerateObjectProperties(obj).
    4. Let nextMethod be ! GetV(iterator, "next").
    5. Return the Iterator Record { [[Iterator]]: iterator, [[NextMethod]]: nextMethod, [[Done]]: false }.
  9. Else,
    1. Assert: iterationKind is iterate or async-iterate.
    2. If iterationKind is async-iterate, let iteratorHint be async.
    3. Else, let iteratorHint be sync.
    4. Return ? GetIterator(exprValue, iteratorHint).

6.3.2.2 ForIn/OfBodyEvaluation ( lhs, stmt, iteratorRecord, iterationKind, lhsKind, labelSet [ , iteratorKind ] )

The abstract operation ForIn/OfBodyEvaluation takes arguments lhs, stmt, iteratorRecord, iterationKind, lhsKind (assignment, varBinding, or lexicalBinding), and labelSet and optional argument iteratorKind (sync or async) and returns either a normal completion containing an ECMAScript language value or an abrupt completion. It performs the following steps when called:

  1. If iteratorKind is not present, set iteratorKind to sync.
  2. Let oldEnv be the running execution context's LexicalEnvironment.
  3. Let V be undefined.
  4. Let destructuring be IsDestructuring of lhs.
  5. If destructuring is true and if lhsKind is assignment, then
    1. Assert: lhs is a LeftHandSideExpression.
    2. Let assignmentPattern be the AssignmentPattern that is covered by lhs.
  6. Repeat,
    1. Let nextResult be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]).
    2. If iteratorKind is async, set nextResult to ? Await(nextResult).
    3. If Type(nextResult) is not Object, throw a TypeError exception.
    4. Let done be ? IteratorComplete(nextResult).
    5. If done is true, return V.
    6. Let nextValue be ? IteratorValue(nextResult).
    7. If lhsKind is either assignment or varBinding, then
      1. If destructuring is false, then
        1. Let lhsRef be the result of evaluating lhs. (It may be evaluated repeatedly.)
      2. Let iterationEnv be undefined.
    8. Else,
      1. Assert: lhsKind is lexicalBinding.
      2. Assert: lhs is a ForDeclaration.
      3. Let iterationEnv be NewDeclarativeEnvironment(oldEnv).
      4. Perform ForDeclarationBindingInstantiation of lhs with argument iterationEnv.
      5. Set the running execution context's LexicalEnvironment to iterationEnv.
      6. If destructuring is false, then
        1. Assert: lhs binds a single name.
        2. Let lhsName be the sole element of BoundNames of lhs.
        3. Let lhsRef be ! ResolveBinding(lhsName).
    9. If destructuring is false, then
      1. If lhsRef is an abrupt completion, then
        1. Let status be lhsRef.
      2. Else if lhsKind is lexicalBinding, then
        1. Let status be Completion(InitializeReferencedBinding(lhsRef, nextValue)).
      3. Else,
        1. Let status be Completion(PutValue(lhsRef, nextValue)).
    10. Else,
      1. If lhsKind is assignment, then
        1. Let status be Completion(DestructuringAssignmentEvaluation of assignmentPattern with argument nextValue).
      2. Else if lhsKind is varBinding, then
        1. Assert: lhs is a ForBinding.
        2. Let status be Completion(BindingInitialization of lhs with arguments nextValue and undefined).
      3. Else,
        1. Assert: lhsKind is lexicalBinding.
        2. Assert: lhs is a ForDeclaration.
        3. Let status be Completion(ForDeclarationBindingInitialization of lhs with arguments nextValue and iterationEnv).
    11. If status is an abrupt completion, then
      1. Set status to DisposeResources(iterationEnv, status).
      2. Set the running execution context's LexicalEnvironment to oldEnv.
      3. If iteratorKind is async, return ? AsyncIteratorClose(iteratorRecord, status).
      4. If iterationKind is enumerate, then
        1. Return ? status.
      5. Else,
        1. Assert: iterationKind is iterate.
        2. Return ? IteratorClose(iteratorRecord, status).
    12. Let result be the result of evaluating stmt.
    13. Set result to DisposeResources(iterationEnv, result).
    14. Set the running execution context's LexicalEnvironment to oldEnv.
    15. If LoopContinues(result, labelSet) is false, then
      1. If iterationKind is enumerate, then
        1. Return ? UpdateEmpty(result, V).
      2. Else,
        1. Assert: iterationKind is iterate.
        2. Set status to Completion(UpdateEmpty(result, V)).
        3. If iteratorKind is async, return ? AsyncIteratorClose(iteratorRecord, status).
        4. Return ? IteratorClose(iteratorRecord, status).
    16. If result.[[Value]] is not empty, set V to result.[[Value]].

6.4 The switch Statement

6.4.1 Runtime Semantics: Evaluation

SwitchStatement : switch ( Expression ) CaseBlock
  1. Let exprRef be the result of evaluating Expression.
  2. Let switchValue be ? GetValue(exprRef).
  3. Let oldEnv be the running execution context's LexicalEnvironment.
  4. Let blockEnv be NewDeclarativeEnvironment(oldEnv).
  5. Perform BlockDeclarationInstantiation(CaseBlock, blockEnv).
  6. Set the running execution context's LexicalEnvironment to blockEnv.
  7. Let R be Completion(CaseBlockEvaluation of CaseBlock with argument switchValue).
  8. Let env be blockEnv's LexicalEnvironment.
  9. Set R to DisposeResources(env, R).
  10. Set the running execution context's LexicalEnvironment to oldEnv.
  11. Return R.
Note

No matter how control leaves the SwitchStatement the LexicalEnvironment is always restored to its former state.

7 ECMAScript Language: Functions and Classes

7.1 Function Definitions

7.1.1 Runtime Semantics: EvaluateFunctionBody

The syntax-directed operation EvaluateFunctionBody takes arguments functionObject and argumentsList (a List) and returns either a normal completion containing an ECMAScript language value or an abrupt completion. It is defined piecewise over the following productions:

FunctionBody : FunctionStatementList
  1. Perform ? FunctionDeclarationInstantiation(functionObject, argumentsList).
  2. Return the result of evaluating FunctionStatementList.
  3. Let result be result of evaluating FunctionStatementList.
  4. Let env be the running execution context's LexicalEnvironment.
  5. Return ? DisposeResources(env, result).

7.2 Class Definitions

7.2.1 Runtime Semantics: EvaluateClassStaticBlockBody

The syntax-directed operation EvaluateClassStaticBlockBody takes argument functionObject and returns either a normal completion containing an ECMAScript language value or an abrupt completion. It is defined piecewise over the following productions:

ClassStaticBlockBody : ClassStaticBlockStatementList
  1. Perform ? FunctionDeclarationInstantiation(functionObject, « »).
  2. Return the result of evaluating ClassStaticBlockStatementList.
  3. Let result be result of evaluating ClassStaticBlockStatementList.
  4. Let env be the running execution context's LexicalEnvironment.
  5. Return ? DisposeResources(env, result).

7.3 Tail Position Calls

7.3.1 Static Semantics: HasCallInTailPosition

The syntax-directed operation HasCallInTailPosition takes argument call and returns a Boolean.

Note 1

call is a Parse Node that represents a specific range of source text. When the following algorithms compare call to another Parse Node, it is a test of whether they represent the same source text.

Note 2

A using or using await declaration that precedes a call in the same Block, CaseBlock, ForStatement, ForInOfStatement, FunctionBody, GeneratorBody, AsyncGeneratorBody, AsyncFunctionBody, or ClassStaticBlockBody prevents that call from being a possible tail position call.

7.3.1.1 Statement Rules

StatementList : StatementList StatementListItem
  1. Let has be HasCallInTailPosition of StatementList with argument call.
  2. If has is true, return true.
  3. If HasUnterminatedUsingDeclaration of StatementList is true, return false.
  4. Return HasCallInTailPosition of StatementListItem with argument call.
FunctionStatementList : [empty] StatementListItem : Declaration Statement : VariableStatement EmptyStatement ExpressionStatement ContinueStatement BreakStatement ThrowStatement DebuggerStatement Block : { } ReturnStatement : return ; LabelledItem : FunctionDeclaration ForInOfStatement : for ( LeftHandSideExpression of AssignmentExpression ) Statement for ( var ForBinding of AssignmentExpression ) Statement for ( ForDeclaration of AssignmentExpression ) Statement CaseBlock : { }
  1. Return false.
IfStatement : if ( Expression ) Statement else Statement
  1. Let has be HasCallInTailPosition of the first Statement with argument call.
  2. If has is true, return true.
  3. Return HasCallInTailPosition of the second Statement with argument call.
IfStatement : if ( Expression ) Statement 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 WithStatement : with ( Expression ) Statement
  1. Return HasCallInTailPosition of Statement with argument call.
LabelledStatement : LabelIdentifier : LabelledItem
  1. Return HasCallInTailPosition of LabelledItem with argument call.
ReturnStatement : return Expression ;
  1. Return HasCallInTailPosition of Expression with argument call.
SwitchStatement : switch ( Expression ) CaseBlock
  1. Return HasCallInTailPosition of CaseBlock with argument call.
CaseBlock : { CaseClausesopt DefaultClause CaseClausesopt }
  1. Let has be false.
  2. If the first CaseClauses is present, let has be HasCallInTailPosition of the first CaseClauses with argument call.then
    1. Let has be HasCallInTailPosition of the first CaseClauses with argument call.
    2. If has is true, return true.
    3. If HasUnterminatedUsingDeclaration of the first CaseClauses is true, return false.
  3. If has is true, return true.
  4. Let has be HasCallInTailPosition of DefaultClause with argument call.
  5. If has is true, return true.
  6. If HasUnterminatedUsingDeclaration of DefaultClause is true, return false.
  7. If the second CaseClauses is present, let has be HasCallInTailPosition of the second CaseClauses with argument call.
  8. Return has.
CaseClauses : CaseClauses CaseClause
  1. Let has be HasCallInTailPosition of CaseClauses with argument call.
  2. If has is true, return true.
  3. If HasUnterminatedUsingDeclaration of CaseClauses is true, return false.
  4. Return HasCallInTailPosition of CaseClause with argument call.
CaseClause : case Expression : StatementListopt DefaultClause : default : StatementListopt
  1. If StatementList is present, return HasCallInTailPosition of StatementList with argument call.
TryStatement : try Block Catch
  1. Return HasCallInTailPosition of Catch with argument call.
TryStatement : try Block Finally try Block Catch Finally
  1. Return HasCallInTailPosition of Finally with argument call.
Catch : catch ( CatchParameter ) Block
  1. Return HasCallInTailPosition of Block with argument call.

7.3.1.2 Expression Rules

Note

A potential tail position call that is immediately followed by return GetValue of the call result is also a possible tail position call. A function call cannot return a Reference Record, so such a GetValue operation will always return the same value as the actual function call result.

AssignmentExpression : YieldExpression ArrowFunction AsyncArrowFunction LeftHandSideExpression = AssignmentExpression LeftHandSideExpression AssignmentOperator AssignmentExpression LeftHandSideExpression &&= AssignmentExpression LeftHandSideExpression ||= AssignmentExpression LeftHandSideExpression ??= AssignmentExpression BitwiseANDExpression : BitwiseANDExpression & EqualityExpression BitwiseXORExpression : BitwiseXORExpression ^ BitwiseANDExpression BitwiseORExpression : BitwiseORExpression | BitwiseXORExpression EqualityExpression : EqualityExpression == RelationalExpression EqualityExpression != RelationalExpression EqualityExpression === RelationalExpression EqualityExpression !== RelationalExpression RelationalExpression : RelationalExpression < ShiftExpression RelationalExpression > ShiftExpression RelationalExpression <= ShiftExpression RelationalExpression >= ShiftExpression RelationalExpression instanceof ShiftExpression RelationalExpression in ShiftExpression PrivateIdentifier in ShiftExpression ShiftExpression : ShiftExpression << AdditiveExpression ShiftExpression >> AdditiveExpression ShiftExpression >>> AdditiveExpression AdditiveExpression : AdditiveExpression + MultiplicativeExpression AdditiveExpression - MultiplicativeExpression MultiplicativeExpression : MultiplicativeExpression MultiplicativeOperator ExponentiationExpression ExponentiationExpression : UpdateExpression ** ExponentiationExpression UpdateExpression : LeftHandSideExpression ++ LeftHandSideExpression -- ++ UnaryExpression -- UnaryExpression UnaryExpression : delete UnaryExpression void UnaryExpression typeof UnaryExpression + UnaryExpression - UnaryExpression ~ UnaryExpression ! UnaryExpression AwaitExpression CallExpression : SuperCall CallExpression [ Expression ] CallExpression . IdentifierName CallExpression . PrivateIdentifier NewExpression : new NewExpression MemberExpression : MemberExpression [ Expression ] MemberExpression . IdentifierName SuperProperty MetaProperty new MemberExpression Arguments MemberExpression . PrivateIdentifier PrimaryExpression : this IdentifierReference Literal ArrayLiteral ObjectLiteral FunctionExpression ClassExpression GeneratorExpression AsyncFunctionExpression AsyncGeneratorExpression RegularExpressionLiteral TemplateLiteral
  1. Return false.
Expression : AssignmentExpression Expression , AssignmentExpression
  1. Return HasCallInTailPosition of AssignmentExpression with argument call.
ConditionalExpression : ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
  1. Let has be HasCallInTailPosition of the first AssignmentExpression with argument call.
  2. If has is true, return true.
  3. Return HasCallInTailPosition of the second AssignmentExpression with argument call.
LogicalANDExpression : LogicalANDExpression && BitwiseORExpression
  1. Return HasCallInTailPosition of BitwiseORExpression with argument call.
LogicalORExpression : LogicalORExpression || LogicalANDExpression
  1. Return HasCallInTailPosition of LogicalANDExpression with argument call.
CoalesceExpression : CoalesceExpressionHead ?? BitwiseORExpression
  1. Return HasCallInTailPosition of BitwiseORExpression with argument call.
CallExpression : CoverCallExpressionAndAsyncArrowHead CallExpression Arguments CallExpression TemplateLiteral
  1. If this CallExpression is call, return true.
  2. Return false.
OptionalExpression : MemberExpression OptionalChain CallExpression OptionalChain OptionalExpression OptionalChain
  1. Return HasCallInTailPosition of OptionalChain with argument call.
OptionalChain : ?. [ Expression ] ?. IdentifierName ?. PrivateIdentifier OptionalChain [ Expression ] OptionalChain . IdentifierName OptionalChain . PrivateIdentifier
  1. Return false.
OptionalChain : ?. Arguments OptionalChain Arguments
  1. If this OptionalChain is call, return true.
  2. Return false.
MemberExpression : MemberExpression TemplateLiteral
  1. If this MemberExpression is call, return true.
  2. Return false.
PrimaryExpression : CoverParenthesizedExpressionAndArrowParameterList
  1. Let expr be the ParenthesizedExpression that is covered by CoverParenthesizedExpressionAndArrowParameterList.
  2. Return HasCallInTailPosition of expr with argument call.
ParenthesizedExpression : ( Expression )
  1. Return HasCallInTailPosition of Expression with argument call.

7.3.2 Static Semantics: HasUnterminatedUsingDeclaration

The syntax-directed operation HasUnterminatedUsingDeclaration takes no arguments and returns a Boolean. It is defined piecewise over the following productions:

StatementList : StatementList StatementListItem
  1. Let has be HasUnterminatedUsingDeclaration of StatementList.
  2. If has is true, return true.
  3. Return HasUnterminatedUsingDeclaration of StatementListItem.
StatementListItem : Statement CaseBlock : { } Declaration : HoistableDeclaration ClassDeclaration LexicalDeclaration : LetOrConst BindingList ;
  1. Return false.
LexicalDeclaration : UsingDeclaration
  1. Return true.
CaseClauses : CaseClauses CaseClause
  1. Let has be HasUnterminatedUsingDeclaration of CaseClauses.
  2. If has is true, return true.
  3. Return HasUnterminatedUsingDeclaration of CaseClause with argument call.
CaseClause : case Expression : StatementListopt DefaultClause : default : StatementListopt
  1. If StatementList is present, return HasUnterminatedUsingDeclaration of StatementList.

8 ECMAScript Language: Scripts and Modules

8.1 Modules

8.1.1 Module Semantics

8.1.1.1 Source Text Module Records

8.1.1.1.1 ExecuteModule ( [ capability ] )

The ExecuteModule concrete method of a Source Text Module Record module takes optional argument capability and returns either a normal completion containing unused or a throw completion. It performs the following steps when called:

  1. Let moduleContext be a new ECMAScript code execution context.
  2. Set the Function of moduleContext to null.
  3. Set the Realm of moduleContext to module.[[Realm]].
  4. Set the ScriptOrModule of moduleContext to module.
  5. Assert: module has been linked and declarations in its module environment have been instantiated.
  6. Set the VariableEnvironment of moduleContext to module.[[Environment]].
  7. Set the LexicalEnvironment of moduleContext to module.[[Environment]].
  8. Suspend the currently running execution context.
  9. If module.[[HasTLA]] is false, then
    1. Assert: capability is not present.
    2. Push moduleContext onto the execution context stack; moduleContext is now the running execution context.
    3. Let result be the result of evaluating module.[[ECMAScriptCode]].
    4. Let env be moduleContext's LexicalEnvironment.
    5. Set result to DisposeResources(env, result).
    6. Suspend moduleContext and remove it from the execution context stack.
    7. Resume the context that is now on the top of the execution context stack as the running execution context.
    8. If result is an abrupt completion, then
      1. Return ? result.
  10. Else,
    1. Assert: capability is a PromiseCapability Record.
    2. Perform AsyncBlockStart(capability, module.[[ECMAScriptCode]], moduleContext).
  11. Return unused.

8.1.1.2 Exports

Syntax

ExportDeclaration : export ExportFromClause FromClause ; export NamedExports ; export VariableStatement[~Yield, +Await] export [lookahead ∉ { using }] Declaration[~Yield, +Await] export default HoistableDeclaration[~Yield, +Await, +Default] export default ClassDeclaration[~Yield, +Await, +Default] export default [lookahead ∉ { function, async [no LineTerminator here] function, class }] AssignmentExpression[+In, ~Yield, +Await] ; ExportFromClause : * * as IdentifierName NamedExports NamedExports : { } { ExportsList } { ExportsList , } ExportsList : ExportSpecifier ExportsList , ExportSpecifier ExportSpecifier : IdentifierName IdentifierName as IdentifierName

9 Control Abstraction Objects

9.1 Iteration

9.1.1 The %IteratorPrototype% Object

9.1.1.1 %IteratorPrototype% [ @@dispose ] ( )

The following steps are taken:

  1. Let O be the this value.
  2. Let return be ? GetMethod(O, "return").
  3. If return is not undefined, then
    1. Perform ? Call(return, O, « »).
  4. Return NormalCompletion(empty).

The value of the "name" property of this function is "[Symbol.dispose]".

9.1.2 The %AsyncIteratorPrototype% Object

9.1.2.1 %AsyncIteratorPrototype% [ @@asyncDispose ] ( )

The following steps are taken:

  1. Let O be the this value.
  2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
  3. Let return be GetMethod(O, "return").
  4. IfAbruptRejectPromise(return, promiseCapability).
  5. If return is undefined, then
    1. Perform ! Call(promiseCapability.[[Resolve]], undefined, « undefined »).
  6. Else,
    1. Let result be Call(return, O, « undefined »).
    2. IfAbruptRejectPromise(result, promiseCapability).
  7. Return promiseCapability.[[Promise]].

The value of the "name" property of this function is "[Symbol.asyncDispose]".

9.2 Resource Management

9.2.1 Common Resource Management Interfaces

An interface is a set of property keys whose associated values match a specific specification. Any object that provides all the properties as described by an interface's specification conforms to that interface. An interface is not represented by a distinct object. There may be many separately implemented objects that conform to any interface. An individual object may conform to multiple interfaces.

9.2.1.1 The Disposable Interface

The Disposable interface includes the property described in Table 4:

Table 4: Disposable Interface Required Properties
Property Value Requirements
@@dispose A function.

Invoking this method notifies the Disposable object that the caller does not intend to continue to use this object. This method should perform any necessary logic to perform explicit clean-up of the resource including, but not limited to, file system handles, streams, host objects, etc. When an exception is thrown from this method, it typically means that the resource could not be explicitly freed.

If called more than once on the same object, the function should not throw an exception. However, this requirement is not enforced.

When using a Disposable object, it is good practice to create the instance with a using declaration, as the resource will be automatically disposed when the Block or Module immediately containing the declaration has been evaluated.

9.2.1.2 The AsyncDisposable Interface

The AsyncDisposable interface includes the property described in Table 5:

Table 5: AsyncDisposable Interface Required Properties
Property Value Requirements
@@asyncDispose A function that returns a promise.

Invoking this method notifies the AsyncDisposable object that the caller does not intend to continue to use this object. This method should perform any necessary logic to perform explicit clean-up of the resource including, but not limited to, file system handles, streams, host objects, etc. When an exception is thrown from this method, it typically means that the resource could not be explicitly freed. An AsyncDisposable object is not considered "disposed" until the resulting Promise has been fulfilled.

If called more than once on the same object, the function should not throw an exception. However, this requirement is not enforced.

When using an AsyncDisposable object, it is good practice to create the instance with a using await declaration, as the resource will be automatically disposed when the Block or Module containing the declaration has been evaluated.

9.3 DisposableStack Objects

A DisposableStack is an object that can be used to contain one or more resources that should be disposed together.

Any DisposableStack object is in one of two mutually exclusive states: disposed or pending:

  • A disposable stack d is pending if d[Symbol.dispose]() has yet to be invoked for d.
  • A disposable stack d is disposed if d[Symbol.dispose]() has already been invoked once for d.

9.3.1 The DisposableStack Constructor

The DisposableStack constructor:

  • is %DisposableStack%.
  • is the initial value of the "DisposableStack" property of the global object.
  • creates and initializes a new DisposableStack when called as a constructor.
  • is not intended to be called as a function and will throw an exception when called in that manner.
  • may be used as the value in an extends clause of a class definition. Subclass constructors that intend to inherit the specified DisposableStack behaviour must include a super call to the DisposableStack constructor to create and initialize the subclass instance with the internal state necessary to support the DisposableStack and DisposableStack.prototype built-in methods.

9.3.1.1 DisposableStack ( )

When the DisposableStack function is called, the following steps are taken:

  1. If NewTarget is undefined, throw a TypeError exception.
  2. Let disposableStack be ? OrdinaryCreateFromConstructor(NewTarget, "%DisposableStack.prototype%", « [[DisposableState]], [[DisposableResourceStack]], [[BoundDispose]] »).
  3. Set disposableStack.[[DisposableState]] to pending.
  4. Set disposableStack.[[DisposableResourceStack]] to a new empty List.
  5. Set disposableStack.[[BoundDispose]] to undefined.
  6. Return disposableStack.

9.3.2 Properties of the DisposableStack Constructor

The DisposableStack constructor:

9.3.2.1 get DisposableStack [ @@species ]

DisposableStack[@@species] is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:

  1. Return the this value.

The value of the "name" property of this function is "get [Symbol.species]".

9.3.3 Properties of the DisposableStack Prototype Object

The DisposableStack prototype object:

  • is %DisposableStack.prototype%.
  • has a [[Prototype]] internal slot whose value is %Object.prototype%.
  • is an ordinary object.
  • does not have a [[DisposableState]] internal slot or any of the other internal slots of DisposableStack instances.

9.3.3.1 get DisposableStack.prototype.dispose

DisposableStack.prototype.dispose is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:

  1. Let disposableStack be the this value.
  2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
  3. If disposableStack.[[BoundDispose]] is undefined, then
    1. Let dispose be GetMethod(disposableStack, @@dispose).
    2. If dispose is undefined, throw a TypeError exception.
    3. Let F be a new built-in function object as defined in 9.3.3.1.1.
    4. Set F.[[DisposableStack]] to disposableStack.
    5. Set F.[[DisposeMethod]] to dispose.
    6. Set disposableStack.[[BoundDispose]] to F.
  4. Return disposableStack.[[BoundDispose]].

9.3.3.1.1 DisposableStack Dispose Functions

A DisposableStack dispose function is an anonymous built-in function object that has [[DisposableStack]] and [[DisposeMethod]] internal slots.

When a DisposableStack dispose function is called, the following steps are taken:

  1. Let F be the active function object.
  2. Let disposableStack be F.[[DisposableStack]].
  3. Let dispose be F.[[DisposeMethod]].
  4. Assert: Type(disposableStack) is Object and disposableStack has a [[DisposableState]] internal slot.
  5. Assert: IsCallable(dispose) is true.
  6. Return Call(dispose, disposableStack, « »).

9.3.3.2 DisposableStack.prototype.use( value [, onDispose ] )

When the use function is called with one or two arguments, the following steps are taken:

Note

The onDispose argument is optional. If it is not provided, undefined is used.

  1. Let disposableStack be the this value.
  2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
  3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
  4. If onDispose is not undefined, then
    1. If IsCallable(onDispose) is false, throw a TypeError exception.
    2. Let F be a new built-in function object as defined in 9.3.3.2.1.
    3. Set F.[[Argument]] to value.
    4. Set F.[[OnDisposeCallback]] to onDispose.
    5. Perform ? AddDisposableResource(disposableStack, undefined, sync-dispose, F).
  5. Else, if value is neither null nor undefined, then
    1. If Type(value) is not Object, throw a TypeError exception.
    2. Let method be GetDisposeMethod(value, sync-dispose).
    3. If method is undefined, then
      1. If IsCallable(value) is true, then
        1. Perform ? AddDisposableResource(disposableStack, undefined, sync-dispose, value).
      2. Else,
        1. Throw a TypeError exception.
    4. Else,
      1. Perform ? AddDisposableResource(disposableStack, value, sync-dispose, method).
  6. Return value.

9.3.3.2.1 DisposableStack Callback Functions

A DisposableStack callback function is an anonymous built-in function object that has [[Argument]] and [[OnDisposeCallback]] internal slots.

When a DisposableStack callback function is called, the following steps are taken:

  1. Let F be the active function object.
  2. Assert: IsCallable(F.[[OnDisposeCallback]]) is true.
  3. Return Call(F.[[OnDisposeCallback]], undefined, « F.[[Argument]] »).

9.3.3.3 DisposableStack.prototype.move()

When the move function is called, the following steps are taken:

  1. Let disposableStack be the this value.
  2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
  3. If disposableStack.[[DisposableState]] is disposed, throw a ReferenceError exception.
  4. Let C be ? SpeciesConstructor(disposableStack, %DisposableStack%).
  5. Assert: IsConstructor(C) is true.
  6. Let newDisposableStack be ? Construct(C, « »).
  7. Perform ? RequireInternalSlot(newDisposableStack, [[DisposableState]]).
  8. If newDisposableStack.[[DisposableState]] is not pending, throw a TypeError exception.
  9. Append each element of disposableStack.[[DisposableResourceStack]] to newDisposableStack.[[DisposableResourceStack]].
  10. Set disposableStack.[[DisposableResourceStack]] to a new empty List.
  11. Return newDisposableStack.

9.3.3.4 DisposableStack.prototype [ @@dispose ] ()

When the @@dispose method is called, the following steps are taken:

  1. Let disposableStack be the this value.
  2. Perform ? RequireInternalSlot(disposableStack, [[DisposableState]]).
  3. If disposableStack.[[DisposableState]] is disposed, return undefined.
  4. Set disposableStack.[[DisposableState]] to disposed.
  5. Return DisposeResources(disposableStack, NormalCompletion(undefined)).

The value of the "name" property of this function is "[Symbol.dispose]".

9.3.3.5 DisposableStack.prototype [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "DisposableStack".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

9.3.4 Properties of DisposableStack Instances

DisposableStack instances are ordinary objects that inherit properties from the DisposableStack prototype object (the intrinsic %DisposableStack.prototype%). DisposableStack instances are initially created with internal slots described in Table 6.

Table 6: Internal Slots of DisposableStack Instances
Internal Slot Description
[[DisposableState]] One of pending or disposed. Governs how a disposable stack will react to incoming calls to its @@dispose method.
[[DisposableResourceStack]] A List of DisposableResource Records.
[[BoundDispose]] Either undefined or a function object that caches the function returned by the DisposableStack.prototype.dispose accessor (9.3.3.1).

9.4 AsyncDisposableStack Objects

An AsyncDisposableStack is an object that can be used to contain one or more resources that should be asynchronously disposed together.

Any AsyncDisposableStack object is in one of two mutually exclusive states: disposed or pending:

  • An async-disposable stack d is pending if d[Symbol.asyncDispose]() has yet to be invoked for d.
  • An async-disposable stack d is disposed if d[Symbol.asyncDispose]() has already been invoked once for d.

9.4.1 The AsyncDisposableStack Constructor

The AsyncDisposableStack constructor:

  • is %AsyncDisposableStack%.
  • is the initial value of the "AsyncDisposableStack" property of the global object.
  • creates and initializes a new AsyncDisposableStack when called as a constructor.
  • is not intended to be called as a function and will throw an exception when called in that manner.
  • may be used as the value in an extends clause of a class definition. Subclass constructors that intend to inherit the specified AsyncDisposableStack behaviour must include a super call to the AsyncDisposableStack constructor to create and initialize the subclass instance with the internal state necessary to support the AsyncDisposableStack and AsyncDisposableStack.prototype built-in methods.

9.4.1.1 AsyncDisposableStack ( )

When the AsyncDisposableStack function is called, the following steps are taken:

  1. If NewTarget is undefined, throw a TypeError exception.
  2. Let asyncDisposableStack be ? OrdinaryCreateFromConstructor(NewTarget, "%AsyncDisposableStack.prototype%", « [[AsyncDisposableState]], [[DisposableResourceStack]], [[BoundDisposeAsync]] »).
  3. Set asyncDisposableStack.[[AsyncDisposableState]] to pending.
  4. Set asyncDisposableStack.[[DisposableResourceStack]] to a new empty List.
  5. Set asyncDisposableStack.[[BoundDisposeAsync]] to undefined.
  6. Return asyncDisposableStack.

9.4.2 Properties of the AsyncDisposableStack Constructor

The AsyncDisposableStack constructor:

9.4.2.1 get AsyncDisposableStack [ @@species ]

AsyncDisposableStack[@@species] is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:

  1. Return the this value.

The value of the "name" property of this function is "get [Symbol.species]".

9.4.3 Properties of the AsyncDisposableStack Prototype Object

The AsyncDisposableStack prototype object:

  • is %AsyncDisposableStack.prototype%.
  • has a [[Prototype]] internal slot whose value is %Object.prototype%.
  • is an ordinary object.
  • does not have an [[AsyncDisposableState]] internal slot or any of the other internal slots of AsyncDisposableStack instances.

9.4.3.1 get AsyncDisposableStack.prototype.disposeAsync

AsyncDisposableStack.prototype.disposeAsync is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:

  1. Let asyncDisposableStack be the this value.
  2. Perform ? RequireInternalSlot(asyncDisposableStack, [[AsyncDisposableState]]).
  3. If asyncDisposableStack.[[BoundDisposeAsync]] is undefined, then
    1. Let disposeAsync be GetMethod(asyncDisposableStack, @@asyncDispose).
    2. If disposeAsync is undefined, throw a TypeError exception.
    3. Let F be a new built-in function object as defined in 9.4.3.1.1.
    4. Set F.[[AsyncDisposableStack]] to asyncDisposableStack.
    5. Set F.[[DisposeAsyncMethod]] to disposeAsync.
    6. Set asyncDisposableStack.[[BoundDisposeAsync]] to F.
  4. Return asyncDisposableStack.[[BoundDisposeAsync]].

9.4.3.1.1 AsyncDisposableStack Dispose Functions

An AsyncDisposableStack dispose function is an anonymous built-in function that has [[AsyncDisposableStack]] and [[DisposeAsyncMethod]] internal slots.

When an AsyncDisposableStack dispose function is called, the following steps are taken:

  1. Let F be the active function object.
  2. Let asyncDisposableStack be F.[[AsyncDisposableStack]].
  3. Let disposeAsync be F.[[DisposeAsyncMethod]].
  4. Assert: Type(asyncDisposableStack) is Object and asyncDisposableStack has an [[AsyncDisposableState]] internal slot.
  5. Assert: IsCallable(disposeAsync) is true.
  6. Return Call(disposeAsync, asyncDisposableStack, « »).

9.4.3.2 AsyncDisposableStack.prototype.use( value [, onDisposeAsync ] )

When the use function is called with one or two arguments, the following steps are taken:

Note

The onDisposeAsync argument is optional. If it is not provided, undefined is used.

  1. Let asyncDisposableStack be the this value.
  2. Perform ? RequireInternalSlot(asyncDisposableStack, [[AsyncDisposableState]]).
  3. If asyncDisposableStack.[[AsyncDisposableState]] is disposed, throw a ReferenceError exception.
  4. If onDisposeAsync is not undefined, then
    1. If IsCallable(onDisposeAsync) is false, throw a TypeError exception.
    2. Let F be a new built-in function object as defined in 9.4.3.2.1.
    3. Set F.[[Argument]] to value.
    4. Set F.[[OnDisposeAsyncCallback]] to onDisposeAsync.
    5. Perform ? AddDisposableResource(asyncDisposableStack, undefined, async-dispose, F).
  5. Else, if value is neither null nor undefined, then
    1. If Type(value) is not Object, throw a TypeError exception.
    2. Let method be GetDisposeMethod(value, async-dispose).
    3. If method is undefined, then
      1. If IsCallable(value) is true, then
        1. Perform ? AddDisposableResource(disposableStack, undefined, async-dispose, value).
      2. Else,
        1. Throw a TypeError exception.
    4. Else,
      1. Perform ? AddDisposableResource(disposableStack, value, async-dispose, method).
  6. Return value.

9.4.3.2.1 AsyncDisposableStack Callback Functions

An AsyncDisposableStack callback function is an anonymous built-in function that has [[Argument]] and [[OnDisposeAsyncCallback]] internal slots.

When an AsyncDisposableStack callback function is called, the following steps are taken:

  1. Let F be the active function object.
  2. Assert: IsCallable(F.[[OnDisposeAsyncCallback]]) is true.
  3. Return Call(F.[[OnDisposeAsyncCallback]], undefined, « F.[[Argument]] »).

9.4.3.3 AsyncDisposableStack.prototype.move()

When the move function is called, the following steps are taken:

  1. Let asyncDisposableStack be the this value.
  2. Perform ? RequireInternalSlot(asyncDisposableStack, [[AsyncDisposableState]]).
  3. If asyncDisposableStack.[[AsyncDisposableState]] is disposed, throw a ReferenceError exception.
  4. Let C be ? SpeciesConstructor(asyncDisposableStack, %AsyncDisposableStack%).
  5. Assert: IsConstructor(C) is true.
  6. Let newAsyncDisposableStack be ? Construct(C, « »).
  7. Perform ? RequireInternalSlot(newAsyncDisposableStack, [[AsyncDisposableState]]).
  8. If newAsyncDisposableStack.[[AsyncDisposableState]] is not pending, throw a TypeError exception.
  9. Append each element of asyncDisposableStack.[[DisposableResourceStack]] to newAsyncDisposableStack.[[DisposableResourceStack]].
  10. Set asyncDisposableStack.[[DisposableResourceStack]] to a new empty List.
  11. Return newAsyncDisposableStack.

9.4.3.4 AsyncDisposableStack.prototype [ @@asyncDispose ] ()

When the @@asyncDispose method is called, the following steps are taken:

  1. Let asyncDisposableStack be the this value.
  2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
  3. If asyncDisposableStack does not have a [[DisposableState]] internal slot, then
    1. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
    2. Return promiseCapability.[[Promise]].
  4. If asyncDisposableStack.[[DisposableState]] is disposed, then
    1. Perform ! Call(promiseCapability.[[Resolve]], undefined, « undefined »).
    2. Return promiseCapability.[[Promise]].
  5. Set asyncDisposableStack.[[DisposableState]] to disposed.
  6. Let result be DisposeResources(asyncDisposableStack, NormalCompletion(undefined)).
  7. IfAbruptRejectPromise(result, promiseCapability).
  8. Perform ! Call(promiseCapability.[[Resolve]], undefined, « result »).
  9. Return promiseCapability.[[Promise]].

The value of the "name" property of this function is "[Symbol.asyncDispose]".

9.4.3.5 AsyncDisposableStack.prototype [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "AsyncDisposableStack".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

9.4.4 Properties of AsyncDisposableStack Instances

AsyncDisposableStack instances are ordinary objects that inherit properties from the AsyncDisposableStack prototype object (the intrinsic %AsyncDisposableStack.prototype%). AsyncDisposableStack instances are initially created with internal slots described in Table 7.

Table 7: Internal Slots of AsyncDisposableStack Instances
Internal Slot Description
[[AsyncDisposableState]] One of pending or disposed. Governs how a disposable stack will react to incoming calls to its @@asyncDispose method.
[[DisposableResourceStack]] A List of DisposableResource records.
[[BoundDisposeAsync]] Either undefined or a function object that caches the function returned by the AsyncDisposableStack.prototype.disposeAsync accessor (9.4.3.1).

9.5 Generator Objects

9.5.1 Generator Abstract Operations

9.5.1.1 GeneratorStart ( generator, generatorBody )

The abstract operation GeneratorStart takes arguments generator and generatorBody (a FunctionBody Parse Node or an Abstract Closure with no parameters) and returns unused. It performs the following steps when called:

  1. Assert: The value of generator.[[GeneratorState]] is undefined.
  2. Let genContext be the running execution context.
  3. Set the Generator component of genContext to generator.
  4. Set the code evaluation state of genContext such that when evaluation is resumed for that execution context the following steps will be performed:
    1. If generatorBody is a Parse Node, then
      1. Let result be the result of evaluating generatorBody.
    2. Else,
      1. Assert: generatorBody is an Abstract Closure with no parameters.
      2. Let result be generatorBody().
    3. Assert: If we return here, the generator either threw an exception or performed either an implicit or explicit return.
    4. Remove genContext from the execution context stack and restore the execution context that is at the top of the execution context stack as the running execution context.
    5. Set generator.[[GeneratorState]] to completed.
    6. Once a generator enters the completed state it never leaves it and its associated execution context is never resumed. Any execution state associated with generator can be discarded at this point.
    7. Let env be genContext's LexicalEnvironment.
    8. Set result to DisposeResources(env, result).
    9. If result.[[Type]] is normal, let resultValue be undefined.
    10. Else if result.[[Type]] is return, let resultValue be result.[[Value]].
    11. Else,
      1. Assert: result.[[Type]] is throw.
      2. Return ? result.
    12. Return CreateIterResultObject(resultValue, true).
  5. Set generator.[[GeneratorContext]] to genContext.
  6. Set generator.[[GeneratorState]] to suspendedStart.
  7. Return unused.

9.6 AsyncGenerator Objects

9.6.1 AsyncGenerator Abstract Operations

9.6.1.1 AsyncGeneratorStart ( generator, generatorBody )

The abstract operation AsyncGeneratorStart takes arguments generator (an AsyncGenerator) and generatorBody (a FunctionBody Parse Node or an Abstract Closure with no parameters) and returns unused. It performs the following steps when called:

  1. Assert: generator.[[AsyncGeneratorState]] is undefined.
  2. Let genContext be the running execution context.
  3. Set the Generator component of genContext to generator.
  4. Set the code evaluation state of genContext such that when evaluation is resumed for that execution context the following steps will be performed:
    1. If generatorBody is a Parse Node, then
      1. Let result be the result of evaluating generatorBody.
    2. Else,
      1. Assert: generatorBody is an Abstract Closure with no parameters.
      2. Let result be Completion(generatorBody()).
    3. Assert: If we return here, the async generator either threw an exception or performed either an implicit or explicit return.
    4. Remove genContext from the execution context stack and restore the execution context that is at the top of the execution context stack as the running execution context.
    5. Set generator.[[AsyncGeneratorState]] to completed.
    6. Let env be genContext's LexicalEnvironment.
    7. Set result to DisposeResources(env, result).
    8. If result.[[Type]] is normal, set result to NormalCompletion(undefined).
    9. If result.[[Type]] is return, set result to NormalCompletion(result.[[Value]]).
    10. Perform AsyncGeneratorCompleteStep(generator, result, true).
    11. Perform AsyncGeneratorDrainQueue(generator).
    12. Return undefined.
  5. Set generator.[[AsyncGeneratorContext]] to genContext.
  6. Set generator.[[AsyncGeneratorState]] to suspendedStart.
  7. Set generator.[[AsyncGeneratorQueue]] to a new empty List.
  8. Return unused.

9.7 AsyncFunction Objects

9.7.1 Async Functions Abstract Operations

9.7.1.1 AsyncBlockStart ( promiseCapability, asyncBody, asyncContext )

The abstract operation AsyncBlockStart takes arguments promiseCapability (a PromiseCapability Record), asyncBody (a Parse Node), and asyncContext (an execution context) and returns unused. It performs the following steps when called:

  1. Assert: promiseCapability is a PromiseCapability Record.
  2. Let runningContext be the running execution context.
  3. Set the code evaluation state of asyncContext such that when evaluation is resumed for that execution context the following steps will be performed:
    1. Let result be the result of evaluating asyncBody.
    2. Assert: If we return here, the async function either threw an exception or performed an implicit or explicit return; all awaiting is done.
    3. Remove asyncContext from the execution context stack and restore the execution context that is at the top of the execution context stack as the running execution context.
    4. Let env be asyncContext's LexicalEnvironment.
    5. Set result to DisposeResources(env, result).
    6. If result.[[Type]] is normal, then
      1. Perform ! Call(promiseCapability.[[Resolve]], undefined, « undefined »).
    7. Else if result.[[Type]] is return, then
      1. Perform ! Call(promiseCapability.[[Resolve]], undefined, « result.[[Value]] »).
    8. Else,
      1. Assert: result.[[Type]] is throw.
      2. Perform ! Call(promiseCapability.[[Reject]], undefined, « result.[[Value]] »).
    9. Return unused.
  4. Push asyncContext onto the execution context stack; asyncContext is now the running execution context.
  5. Resume the suspended evaluation of asyncContext. Let result be the value returned by the resumed computation.
  6. Assert: When we return here, asyncContext has already been removed from the execution context stack and runningContext is the currently running execution context.
  7. Assert: result is a normal completion with a value of unused. The possible sources of this value are Await or, if the async function doesn't await anything, step 3.i above.
  8. Return unused.

A Copyright & Software License

Copyright Notice

© 2022 Ron Buckton, Ecma International

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.