ECMAScript® 2024 Language Specification

Draft ECMA-262 / February 15, 2024

15.5 Generator Function Definitions

Syntax

GeneratorDeclaration[Yield, Await, Default] : function * BindingIdentifier[?Yield, ?Await] ( FormalParameters[+Yield, ~Await] ) { GeneratorBody } [+Default] function * ( FormalParameters[+Yield, ~Await] ) { GeneratorBody } GeneratorExpression : function * BindingIdentifier[+Yield, ~Await]opt ( FormalParameters[+Yield, ~Await] ) { GeneratorBody } GeneratorMethod[Yield, Await] : * ClassElementName[?Yield, ?Await] ( UniqueFormalParameters[+Yield, ~Await] ) { GeneratorBody } GeneratorBody : FunctionBody[+Yield, ~Await] YieldExpression[In, Await] : yield yield [no LineTerminator here] AssignmentExpression[?In, +Yield, ?Await] yield [no LineTerminator here] * AssignmentExpression[?In, +Yield, ?Await] Note 1

The syntactic context immediately following yield requires use of the InputElementRegExpOrTemplateTail lexical goal.

Note 2

YieldExpression cannot be used within the FormalParameters of a generator function because any expressions that are part of FormalParameters are evaluated before the resulting Generator is in a resumable state.

Note 3

Abstract operations relating to Generators are defined in 27.5.3.

15.5.1 Static Semantics: Early Errors

GeneratorMethod : * ClassElementName ( UniqueFormalParameters ) { GeneratorBody } GeneratorDeclaration : function * BindingIdentifier ( FormalParameters ) { GeneratorBody } function * ( FormalParameters ) { GeneratorBody } GeneratorExpression : function * BindingIdentifieropt ( FormalParameters ) { GeneratorBody }

15.5.2 Runtime Semantics: EvaluateGeneratorBody

The syntax-directed operation EvaluateGeneratorBody takes arguments functionObject (an ECMAScript function object) and argumentsList (a List of ECMAScript language values) and returns a throw completion or a return completion. It is defined piecewise over the following productions:

GeneratorBody : FunctionBody
  1. Perform ? FunctionDeclarationInstantiation(functionObject, argumentsList).
  2. Let G be ? OrdinaryCreateFromConstructor(functionObject, "%GeneratorFunction.prototype.prototype%", « [[GeneratorState]], [[GeneratorContext]], [[GeneratorBrand]] »).
  3. Set G.[[GeneratorBrand]] to empty.
  4. Perform GeneratorStart(G, FunctionBody).
  5. Return Completion Record { [[Type]]: return, [[Value]]: G, [[Target]]: empty }.

15.5.3 Runtime Semantics: InstantiateGeneratorFunctionObject

The syntax-directed operation InstantiateGeneratorFunctionObject takes arguments env (an Environment Record) and privateEnv (a PrivateEnvironment Record or null) and returns an ECMAScript function object. It is defined piecewise over the following productions:

GeneratorDeclaration : function * BindingIdentifier ( FormalParameters ) { GeneratorBody }
  1. Let name be StringValue of BindingIdentifier.
  2. Let sourceText be the source text matched by GeneratorDeclaration.
  3. Let F be OrdinaryFunctionCreate(%GeneratorFunction.prototype%, sourceText, FormalParameters, GeneratorBody, non-lexical-this, env, privateEnv).
  4. Perform SetFunctionName(F, name).
  5. Let prototype be OrdinaryObjectCreate(%GeneratorFunction.prototype.prototype%).
  6. Perform ! DefinePropertyOrThrow(F, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
  7. Return F.
GeneratorDeclaration : function * ( FormalParameters ) { GeneratorBody }
  1. Let sourceText be the source text matched by GeneratorDeclaration.
  2. Let F be OrdinaryFunctionCreate(%GeneratorFunction.prototype%, sourceText, FormalParameters, GeneratorBody, non-lexical-this, env, privateEnv).
  3. Perform SetFunctionName(F, "default").
  4. Let prototype be OrdinaryObjectCreate(%GeneratorFunction.prototype.prototype%).
  5. Perform ! DefinePropertyOrThrow(F, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
  6. Return F.
Note

An anonymous GeneratorDeclaration can only occur as part of an export default declaration, and its function code is therefore always strict mode code.

15.5.4 Runtime Semantics: InstantiateGeneratorFunctionExpression

The syntax-directed operation InstantiateGeneratorFunctionExpression takes optional argument name (a property key or a Private Name) and returns an ECMAScript function object. It is defined piecewise over the following productions:

GeneratorExpression : function * ( FormalParameters ) { GeneratorBody }
  1. If name is not present, set name to "".
  2. Let env be the LexicalEnvironment of the running execution context.
  3. Let privateEnv be the running execution context's PrivateEnvironment.
  4. Let sourceText be the source text matched by GeneratorExpression.
  5. Let closure be OrdinaryFunctionCreate(%GeneratorFunction.prototype%, sourceText, FormalParameters, GeneratorBody, non-lexical-this, env, privateEnv).
  6. Perform SetFunctionName(closure, name).
  7. Let prototype be OrdinaryObjectCreate(%GeneratorFunction.prototype.prototype%).
  8. Perform ! DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
  9. Return closure.
GeneratorExpression : function * BindingIdentifier ( FormalParameters ) { GeneratorBody }
  1. Assert: name is not present.
  2. Set name to StringValue of BindingIdentifier.
  3. Let outerEnv be the running execution context's LexicalEnvironment.
  4. Let funcEnv be NewDeclarativeEnvironment(outerEnv).
  5. Perform ! funcEnv.CreateImmutableBinding(name, false).
  6. Let privateEnv be the running execution context's PrivateEnvironment.
  7. Let sourceText be the source text matched by GeneratorExpression.
  8. Let closure be OrdinaryFunctionCreate(%GeneratorFunction.prototype%, sourceText, FormalParameters, GeneratorBody, non-lexical-this, funcEnv, privateEnv).
  9. Perform SetFunctionName(closure, name).
  10. Let prototype be OrdinaryObjectCreate(%GeneratorFunction.prototype.prototype%).
  11. Perform ! DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
  12. Perform ! funcEnv.InitializeBinding(name, closure).
  13. Return closure.
Note

The BindingIdentifier in a GeneratorExpression can be referenced from inside the GeneratorExpression's FunctionBody to allow the generator code to call itself recursively. However, unlike in a GeneratorDeclaration, the BindingIdentifier in a GeneratorExpression cannot be referenced from and does not affect the scope enclosing the GeneratorExpression.

15.5.5 Runtime Semantics: Evaluation

GeneratorExpression : function * BindingIdentifieropt ( FormalParameters ) { GeneratorBody }
  1. Return InstantiateGeneratorFunctionExpression of GeneratorExpression.
YieldExpression : yield
  1. Return ? Yield(undefined).
YieldExpression : yield AssignmentExpression
  1. Let exprRef be ? Evaluation of AssignmentExpression.
  2. Let value be ? GetValue(exprRef).
  3. Return ? Yield(value).
YieldExpression : yield * AssignmentExpression
  1. Let generatorKind be GetGeneratorKind().
  2. Let exprRef be ? Evaluation of AssignmentExpression.
  3. Let value be ? GetValue(exprRef).
  4. Let iteratorRecord be ? GetIterator(value, generatorKind).
  5. Let iterator be iteratorRecord.[[Iterator]].
  6. Let received be NormalCompletion(undefined).
  7. Repeat,
    1. If received is a normal completion, then
      1. Let innerResult be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]], « received.[[Value]] »).
      2. If generatorKind is async, set innerResult to ? Await(innerResult).
      3. If innerResult is not an Object, throw a TypeError exception.
      4. Let done be ? IteratorComplete(innerResult).
      5. If done is true, then
        1. Return ? IteratorValue(innerResult).
      6. If generatorKind is async, set received to Completion(AsyncGeneratorYield(? IteratorValue(innerResult))).
      7. Else, set received to Completion(GeneratorYield(innerResult)).
    2. Else if received is a throw completion, then
      1. Let throw be ? GetMethod(iterator, "throw").
      2. If throw is not undefined, then
        1. Let innerResult be ? Call(throw, iterator, « received.[[Value]] »).
        2. If generatorKind is async, set innerResult to ? Await(innerResult).
        3. NOTE: Exceptions from the inner iterator throw method are propagated. Normal completions from an inner throw method are processed similarly to an inner next.
        4. If innerResult is not an Object, throw a TypeError exception.
        5. Let done be ? IteratorComplete(innerResult).
        6. If done is true, then
          1. Return ? IteratorValue(innerResult).
        7. If generatorKind is async, set received to Completion(AsyncGeneratorYield(? IteratorValue(innerResult))).
        8. Else, set received to Completion(GeneratorYield(innerResult)).
      3. Else,
        1. NOTE: If iterator does not have a throw method, this throw is going to terminate the yield* loop. But first we need to give iterator a chance to clean up.
        2. Let closeCompletion be Completion Record { [[Type]]: normal, [[Value]]: empty, [[Target]]: empty }.
        3. If generatorKind is async, perform ? AsyncIteratorClose(iteratorRecord, closeCompletion).
        4. Else, perform ? IteratorClose(iteratorRecord, closeCompletion).
        5. NOTE: The next step throws a TypeError to indicate that there was a yield* protocol violation: iterator does not have a throw method.
        6. Throw a TypeError exception.
    3. Else,
      1. Assert: received is a return completion.
      2. Let return be ? GetMethod(iterator, "return").
      3. If return is undefined, then
        1. Set value to received.[[Value]].
        2. If generatorKind is async, then
          1. Set value to ? Await(value).
        3. Return Completion Record { [[Type]]: return, [[Value]]: value, [[Target]]: empty }.
      4. Let innerReturnResult be ? Call(return, iterator, « received.[[Value]] »).
      5. If generatorKind is async, set innerReturnResult to ? Await(innerReturnResult).
      6. If innerReturnResult is not an Object, throw a TypeError exception.
      7. Let done be ? IteratorComplete(innerReturnResult).
      8. If done is true, then
        1. Set value to ? IteratorValue(innerReturnResult).
        2. Return Completion Record { [[Type]]: return, [[Value]]: value, [[Target]]: empty }.
      9. If generatorKind is async, set received to Completion(AsyncGeneratorYield(? IteratorValue(innerReturnResult))).
      10. Else, set received to Completion(GeneratorYield(innerReturnResult)).