15.5 Generator Function Definitions

Syntax

GeneratorMethod[Yield, Await] : * PropertyName[?Yield, ?Await] ( UniqueFormalParameters[+Yield, ~Await] ) { GeneratorBody } 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 } 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 object is in a resumable state.

Note 3

Abstract operations relating to generator objects are defined in 27.5.3.

15.5.1 Static Semantics: Early Errors

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

15.5.2 Runtime Semantics: EvaluateGeneratorBody

With parameters functionObject and argumentsList (a List).

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 { [[Type]]: return, [[Value]]: G, [[Target]]: empty }.

15.5.3 Runtime Semantics: InstantiateGeneratorFunctionObject

With parameter scope.

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, scope).
  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, scope).
  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

With optional parameter name.

GeneratorExpression : function * ( FormalParameters ) { GeneratorBody }
  1. If name is not present, set name to "".
  2. Let scope be the LexicalEnvironment of the running execution context.
  3. Let sourceText be the source text matched by GeneratorExpression.
  4. Let closure be OrdinaryFunctionCreate(%GeneratorFunction.prototype%, sourceText, FormalParameters, GeneratorBody, non-lexical-this, scope).
  5. Perform SetFunctionName(closure, name).
  6. Let prototype be ! OrdinaryObjectCreate(%GeneratorFunction.prototype.prototype%).
  7. Perform DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
  8. Return closure.
GeneratorExpression : function * BindingIdentifier ( FormalParameters ) { GeneratorBody }
  1. Assert: name is not present.
  2. Set name to StringValue of BindingIdentifier.
  3. Let scope be the running execution context's LexicalEnvironment.
  4. Let funcEnv be NewDeclarativeEnvironment(scope).
  5. Perform funcEnv.CreateImmutableBinding(name, false).
  6. Let sourceText be the source text matched by GeneratorExpression.
  7. Let closure be OrdinaryFunctionCreate(%GeneratorFunction.prototype%, sourceText, FormalParameters, GeneratorBody, non-lexical-this, funcEnv).
  8. Perform SetFunctionName(closure, name).
  9. Let prototype be ! OrdinaryObjectCreate(%GeneratorFunction.prototype.prototype%).
  10. Perform DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
  11. Perform funcEnv.InitializeBinding(name, closure).
  12. 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 the result of evaluating AssignmentExpression.
  2. Let value be ? GetValue(exprRef).
  3. Return ? Yield(value).
YieldExpression : yield * AssignmentExpression
  1. Let generatorKind be ! GetGeneratorKind().
  2. Let exprRef be the result of evaluating 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.[[Type]] is normal, then
      1. Let innerResult be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]], « received.[[Value]] »).
      2. If generatorKind is async, set innerResult to ? Await(innerResult).
      3. If Type(innerResult) is not 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 AsyncGeneratorYield(? IteratorValue(innerResult)).
      7. Else, set received to GeneratorYield(innerResult).
    2. Else if received.[[Type]] is throw, 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 Type(innerResult) is not 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 AsyncGeneratorYield(? IteratorValue(innerResult)).
        8. Else, set received to 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 { [[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.[[Type]] is return.
      2. Let return be ? GetMethod(iterator, "return").
      3. If return is undefined, then
        1. If generatorKind is async, set received.[[Value]] to ? Await(received.[[Value]]).
        2. Return Completion(received).
      4. Let innerReturnResult be ? Call(return, iterator, « received.[[Value]] »).
      5. If generatorKind is async, set innerReturnResult to ? Await(innerReturnResult).
      6. If Type(innerReturnResult) is not Object, throw a TypeError exception.
      7. Let done be ? IteratorComplete(innerReturnResult).
      8. If done is true, then
        1. Let value be ? IteratorValue(innerReturnResult).
        2. Return Completion { [[Type]]: return, [[Value]]: value, [[Target]]: empty }.
      9. If generatorKind is async, set received to AsyncGeneratorYield(? IteratorValue(innerReturnResult)).
      10. Else, set received to GeneratorYield(innerReturnResult).