ECMAScript | Определения Функций Генератора (Generator Function Definitions)

ECMAScript | Определения Функций Генератора (Generator Function Definitions)

Синтаксис Определения Функций Генератора

GeneratorMethod [Yield, Await] :

* ClassElementName [?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]

 

 

Примечание 1

Синтаксический контекст сразу после yield требует использования лексической цели InputElementRegExpOrTemplateTail.

 

Примечание 2

YieldExpression нельзя использовать в FormalParameters функции генератора, поскольку любые выражения, являющиеся частью FormalParameters, оцениваются до того, как результирующий объект генератора перейдет в возобновляемое состояние.

 

Примечание 3

Абстрактные операции, относящиеся к объектам-генераторам, определены в разделе 27.5.3.

 

Статическая семантика: Ранние Ошибки — Early Errors

GeneratorMethod : * ClassElementName ( UniqueFormalParameters ) { GeneratorBody }

GeneratorDeclaration :

function * BindingIdentifier ( FormalParameters ) { GeneratorBody }

function * ( FormalParameters ) { GeneratorBody }

GeneratorExpression :

function * BindingIdentifier opt ( FormalParameters ) { GeneratorBody }

 

Семантика среды выполнения: Оценить Тело Генератора — EvaluateGeneratorBody

С параметрами functionObject и argumentsList (Список).

GeneratorBody : FunctionBody

1. Выполнить ? FunctionDeclarationInstantiation(functionObject, argumentsList).
2. Пусть G будет ? OrdinaryCreateFromConstructor(functionObject, "%GeneratorFunction.prototype.prototype%", «[[GeneratorState]], [[GeneratorContext]], [[GeneratorBrand]]»).
3. Установите G.[[GeneratorBrand]] в пустое значение empty.
4. Выполните GeneratorStart(G, FunctionBody).
5. Вернуть завершение Completion { [[Type]]: return, [[Value]]: G, [[Target]]: empty }.

 

Семантика времени выполнения: Создание Экземпляра Функционального Объекта Генератора — InstantiateGeneratorFunctionObject

С параметрами scope и privateScope.

GeneratorDeclaration : function * BindingIdentifier ( FormalParameters ) { GeneratorBody }

1. Пусть имя name будет строковым значением StringValue для BindingIdentifier.
2. Пусть sourceText будет исходным текстом, совпадающим с GeneratorDeclaration.
3. Пусть F будет OrdinaryFunctionCreate(%GeneratorFunction.prototype%, sourceText, FormalParameters, GeneratorBody, non-lexical-this, scope, privateScope).
4. Выполните SetFunctionName(F, name).
5. Пусть прототип prototype будет ! OrdinaryObjectCreate(%GeneratorFunction.prototype.prototype%).
6. Выполните DefinePropertyOrThrow(F, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
7. Вернуть F.

GeneratorDeclaration : function * ( FormalParameters ) { GeneratorBody }

1. Пусть sourceText будет исходным текстом, совпадающим с GeneratorDeclaration.
2. Пусть F будет OrdinaryFunctionCreate(%GeneratorFunction.prototype%, sourceText, FormalParameters, GeneratorBody, non-lexical-this, scope, privateScope).
3. Выполнить SetFunctionName(F, "default").
4. Пусть прототип prototype будет ! OrdinaryObjectCreate(%GeneratorFunction.prototype.prototype%).
5. Выполнить DefinePropertyOrThrow(F, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
6. Вернуть F.
Примечание

Анонимное объявление GeneratorDeclaration может возникать только как часть объявления экспорта по умолчанию — export default, поэтому его функциональный код всегда является кодом строгого режима.

 

Семантика среды выполнения: Создание экземпляра выражения функции генератора —  InstantiateGeneratorFunctionExpression

С необязательным параметром name.

GeneratorExpression : function * ( FormalParameters ) { GeneratorBody }

1. Если имя name не указано, установите для имени name значение "".
2. Пусть область видимости scope будет LexicalEnvironment текущего контекста выполнения.
3. Пусть privateScope будет PrivateEnvironment текущего контекста выполнения.
4. Пусть sourceText будет исходным текстом, совпадающим с GeneratorExpression.
5. Пусть замыкание closure будет OrdinaryFunctionCreate(%GeneratorFunction.prototype%, sourceText, FormalParameters, GeneratorBody, non-lexical-this, scope, privateScope).
6. Выполните SetFunctionName(closure, name).
7. Пусть прототип prototype будет ! OrdinaryObjectCreate(%GeneratorFunction.prototype.prototype%).
8. Выполните DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
9. Вернуть closure.

GeneratorExpression : function * BindingIdentifier ( FormalParameters ) { GeneratorBody }

1. Утверждено: имя name не представлено.
2. Задайте для имя name строковое значение StringValue для BindingIdentifier.
3. Пусть область действия scope будет LexicalEnvironment текущего контекста выполнения.
4. Пусть funcEnv будет NewDeclarativeEnvironment(scope).
5. Выполните funcEnv.CreateImmutableBinding(name, false).
6. Пусть privateScope будет PrivateEnvironment текущего контекста выполнения.
7. Пусть sourceText будет исходным текстом, совпадающим с GeneratorExpression.
8. Пусть замыкание closure будет OrdinaryFunctionCreate(%GeneratorFunction.prototype%, sourceText, FormalParameters, GeneratorBody, non-lexical-this, funcEnv, privateScope).
9. Выполнить SetFunctionName(closure, name).
10. Пусть прототип prototype будет ! OrdinaryObjectCreate(%GeneratorFunction.prototype.prototype%).
11. Выполните DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
12. Выполните funcEnv.InitializeBinding(name, closure).
13. Вернуть closure.
Примечание

На BindingIdentifier в GeneratorExpression можно ссылаться изнутри GeneratorExpression FunctionBody, чтобы код генератора мог вызывать себя рекурсивно. Однако, в отличие от GeneratorDeclaration, на BindingIdentifier в GeneratorExpression нельзя ссылаться, и это не влияет на область, содержащую GeneratorExpression.

 

Семантика времени выполнения: Оценка — Evaluation

GeneratorExpression : function * BindingIdentifier opt ( FormalParameters ) { GeneratorBody }

1. Вернуть InstantiateGeneratorFunctionExpression из GeneratorExpression.

YieldExpression : yield

1. Вернуть ? Yield(undefined).

YieldExpression : yield AssignmentExpression

1. Пусть exprRef будет результатом вычисления AssignmentExpression.
2. Пусть value будет ? GetValue(exprRef).
3. Вернуть ? Yield(value).

YieldExpression : yield * AssignmentExpression

1. Пусть generatorKind будет ! GetGeneratorKind().
2. Пусть exprRef будет результатом вычисления AssignmentExpression.
3. Пусть value будет ? GetValue(exprRef).
4. Пусть iteratorRecord будет ? GetIterator(value, generatorKind).
5. Пусть итератор iterator будет iteratorRecord.[[Iterator]].
6. Пусть получено received будет NormalCompletion(undefined).
7. Повторите,
  а. Если received.[[Type]] является normal (нормально), то
    i. Пусть innerResult будет ? Вызов Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]], «received.[[Value]]»).
    ii. Если generatorKind является async (асинхронным), установите для innerResult значение ? ожидайте Await(innerResult).
    iii. Если Type(innerResult) не является Object, вызовите исключение TypeError.
    iv. Пусть done будет ? IteratorComplete(innerResult).
    v. Если сделано done является true (верно), то
      1. Вернуть ? IteratorValue(innerResult).
    vi. Если generatorKind является async (асинхронным), установите полученный AsyncGeneratorYield(? IteratorValue(innerResult)).
    vii. В противном случае установите received значение GeneratorYield(innerResult).
  b. Иначе, если received.[[Type]] является throw (выбросить), тогда
    i. Пусть throw будет? GetMethod(iterator, "throw").
    ii. Если throw не является undefined (неопределенным), тогда
      1. Пусть innerResult будет ? Вызов Call(throw, iterator, «received.[[Value]]»).
      2. Если generatorKind является async (асинхронным), установите для innerResult значение ? Ожидайте Await(innerResult).
      3. ПРИМЕЧАНИЕ. Исключения из метода throw внутреннего итератора распространяются. Нормальные завершения из внутреннего метода throw обрабатываются аналогично внутреннему next.
      4. Если Type(innerResult) не является Object, выбросить исключение TypeError.
      5. Пусть done будет ? IteratorComplete(innerResult).
      6. Если done является true (истина), то
        а. Вернуть ? IteratorValue(innerResult).
      7. Если generatorKind является async (асинхронным), установите значение received на AsyncGeneratorYield(? IteratorValue(innerResult)).
      8. В противном случае установите полученное значение received на GeneratorYield(innerResult).
    iii. Иначе,
      1. ПРИМЕЧАНИЕ. Если итератор iterator не имеет метода throw, этот throw завершит цикл yield*. Но сначала нам нужно дать итератору iterator возможность очиститься.
      2. Пусть closeCompletion будет Completion { [[Type]]: normal, [[Value]]: empty, [[Target]]: empty }.
      3. Если generatorKind является async (асинхронным), выполнить ? AsyncIteratorClose(iteratorRecord, closeCompletion).
      4. Иначе выполнить ? IteratorClose(iteratorRecord, closeCompletion).
      5. ПРИМЕЧАНИЕ. На следующем шаге возникает ошибка TypeError, указывающая на нарушение протокола yield* : итератор iterator не имеет метода throw.
      6. Вызвать исключение TypeError.
  c. Иначе,
    i. Утверждено: received.[[Type]] является return.
    ii. Пусть return будет ? GetMethod(iterator, "return").
    iii. Если return является undefined (не определен), тогда
      1. Если generatorKind является async (асинхронным), установите значение received.[[Value]] на ? Ждать Await(received.[[Value]]).
      2. Вернуть Completion(received).
    iv. Пусть innerReturnResult будет ? Вызов Call(return, iterator, «received.[[Value]]»).
    v. Если generatorKind является async (асинхронным), установите для innerReturnResult значение ? Ожидание Await(innerReturnResult).
    vi. Если Type(innerReturnResult) не является Object, вызовите исключение TypeError.
    vii. Пусть done будет ? IteratorComplete(innerReturnResult).
    viii. Если done является true (истиной), то
      1. Пусть value будет ? IteratorValue(innerReturnResult).
      2. Вернуть завершение Completion { [[Type]]: return, [[Value]]: value, [[Target]]: empty }.
    ix. Если generatorKind является async (асинхронным), установите значение AsyncGeneratorYield(? IteratorValue(innerReturnResult)).
    x. В противном случае установите значение received на GeneratorYield(innerReturnResult).

 

Информационные ссылки

Стандарт ECMAScript — Раздел «15.5 Generator Function Definitions» — https://tc39.es/ecma262/#sec-generator-function-definitions