Stage 2.7 Draft / October 28, 2024

Joint Iteration

1 Iterator.zip ( iterables [ , options ] )

This method performs the following steps when called:

  1. If iterables is not an Object, throw a TypeError exception.
  2. Set options to ? GetOptionsObject(options).
  3. Let mode be ? Get(options, "mode").
  4. If mode is undefined, set mode to "shortest".
  5. If mode is not one of "shortest", "longest", or "strict", throw a TypeError exception.
  6. Let paddingOption be undefined.
  7. If mode is "longest", then
    1. Set paddingOption to ? Get(options, "padding").
    2. If paddingOption is not undefined and paddingOption is not an Object, throw a TypeError exception.
  8. Let iters be a new empty List.
  9. Let padding be a new empty List.
  10. Let inputIter be ? GetIterator(iterables, sync).
  11. Let next be not-started.
  12. Repeat, while next is not done,
    1. Set next to Completion(IteratorStepValue(inputIter)).
    2. IfAbruptCloseIterators(next, iters).
    3. If next is not done, then
      1. Let iter be Completion(GetIteratorFlattenable(next, reject-strings)).
      2. IfAbruptCloseIterators(iter, the list-concatenation of « inputIter » and iters).
      3. Append iter to iters.
  13. Let iterCount be the number of elements in iters.
  14. If mode is "longest", then
    1. If paddingOption is undefined, then
      1. Perform the following steps iterCount times:
        1. Append undefined to padding.
    2. Else,
      1. Let paddingIter be Completion(GetIterator(paddingOption, sync)).
      2. IfAbruptCloseIterators(paddingIter, iters).
      3. Let usingIterator be true.
      4. Perform the following steps iterCount times:
        1. If usingIterator is true, then
          1. Set next to Completion(IteratorStepValue(paddingIter)).
          2. IfAbruptCloseIterators(next, iters).
          3. If next is done, then
            1. Set usingIterator to false.
          4. Else,
            1. Append next to padding.
        2. If usingIterator is false, append undefined to padding.
      5. If usingIterator is true, then
        1. Let completion be Completion(IteratorClose(paddingIter, NormalCompletion(unused))).
        2. IfAbruptCloseIterators(completion, iters).
  15. Let finishResults be a new Abstract Closure with parameters (results) that captures nothing and performs the following steps when called:
    1. Return CreateArrayFromList(results).
  16. Return IteratorZip(iters, mode, padding, finishResults).

2 Iterator.zipKeyed ( iterables [ , options ] )

This method performs the following steps when called:

  1. If iterables is not an Object, throw a TypeError exception.
  2. Set options to ? GetOptionsObject(options).
  3. Let mode be ? Get(options, "mode").
  4. If mode is undefined, set mode to "shortest".
  5. If mode is not one of "shortest", "longest", or "strict", throw a TypeError exception.
  6. Let paddingOption be undefined.
  7. If mode is "longest", then
    1. Set paddingOption to ? Get(options, "padding").
    2. If paddingOption is not undefined and paddingOption is not an Object, throw a TypeError exception.
  8. Let iters be a new empty List.
  9. Let padding be a new empty List.
  10. Let allKeys be ? iterables.[[OwnPropertyKeys]]().
  11. Let keys be a new empty List.
  12. For each element key of allKeys, do
    1. Let desc be Completion(iterables.[[GetOwnProperty]](key)).
    2. IfAbruptCloseIterators(desc, iters).
    3. If desc is not undefined and desc.[[Enumerable]] is true, then
      1. Let value be undefined.
      2. If IsDataDescriptor(desc) is true, then
        1. Set value to desc.[[Value]].
      3. Else,
        1. Assert: IsAccessorDescriptor(desc) is true.
        2. Let getter be desc.[[Get]].
        3. If getter is not undefined, then
          1. Let getterResult be Completion(Call(getter, iterables)).
          2. IfAbruptCloseIterators(getterResult, iters).
          3. Set value to getterResult.
      4. If value is not undefined, then
        1. Append key to keys.
        2. Let iter be Completion(GetIteratorFlattenable(value, reject-strings)).
        3. IfAbruptCloseIterators(iter, iters).
        4. Append iter to iters.
  13. Let iterCount be the number of elements in iters.
  14. If mode is "longest", then
    1. If paddingOption is undefined, then
      1. Perform the following steps iterCount times:
        1. Append undefined to padding.
    2. Else,
      1. For each element key of keys, do
        1. Let value be Completion(Get(paddingOption, key)).
        2. IfAbruptCloseIterators(value, iters).
        3. Append value to padding.
  15. Let finishResults be a new Abstract Closure with parameters (results) that captures keys and iterCount and performs the following steps when called:
    1. Let obj be OrdinaryObjectCreate(null).
    2. For each integer i such that 0 ≤ i < iterCount, in ascending order, do
      1. Perform ! CreateDataPropertyOrThrow(obj, keys[i], results[i]).
    3. Return obj.
  16. Return IteratorZip(iters, mode, padding, finishResults).

3 IteratorZip ( iters, mode, padding, finishResults )

The abstract operation IteratorZip takes arguments iters (a List of Iterator Records), mode (either "shortest", "longest", or "strict"), padding (a List of ECMAScript language values), and finishResults (an Abstract Closure that takes a List of ECMAScript values and returns an ECMAScript value) and returns a Generator. It performs the following steps when called:

  1. Let iterCount be the number of elements in iters.
  2. Let openIters be a copy of iters.
  3. Let closure be a new Abstract Closure with no parameters that captures iters, iterCount, openIters, mode, padding, and finishResults, and performs the following steps when called:
    1. If iterCount = 0, return ReturnCompletion(undefined).
    2. Repeat,
      1. Let results be a new empty List.
      2. Assert: openIters is not empty.
      3. For each integer i such that 0 ≤ i < iterCount, in ascending order, do
        1. Let iter be iters[i].
        2. If iter is null, then
          1. Assert: mode is "longest".
          2. Let result be padding[i].
        3. Else,
          1. Let result be Completion(IteratorStepValue(iter)).
          2. If result is an abrupt completion, then
            1. Remove iter from openIters.
            2. Return ? IteratorCloseAll(openIters, result).
          3. Set result to ! result.
          4. If result is done, then
            1. Remove iter from openIters.
            2. If mode is "shortest", then
              1. Return ? IteratorCloseAll(openIters, ReturnCompletion(undefined)).
            3. Else if mode is "strict", then
              1. If i ≠ 0, then
                1. Return ? IteratorCloseAll(openIters, ThrowCompletion(a newly created TypeError object)).
              2. For each integer k such that 1 ≤ k < iterCount, in ascending order, do
                1. Assert: iters[k] is not null.
                2. Let open be Completion(IteratorStep(iters[k])).
                3. If open is an abrupt completion, then
                  1. Remove iters[k] from openIters.
                  2. Return ? IteratorCloseAll(openIters, open).
                4. Set open to ! open.
                5. If open is done, then
                  1. Remove iters[k] from openIters.
                6. Else,
                  1. Return ? IteratorCloseAll(openIters, ThrowCompletion(a newly created TypeError object)).
              3. Return ReturnCompletion(undefined).
            4. Else,
              1. Assert: mode is "longest".
              2. If openIters is empty, return ReturnCompletion(undefined).
              3. Set iters[i] to null.
              4. Set result to padding[i].
        4. Append result to results.
      4. Set results to finishResults(results).
      5. Let completion be Completion(Yield(results)).
      6. If completion is an abrupt completion, then
        1. Return ? IteratorCloseAll(openIters, completion).
  4. Let gen be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterators]] »).
  5. Set gen.[[UnderlyingIterators]] to openIters.
  6. Return gen.

4 IteratorCloseAll ( iters, completion )

The abstract operation IteratorCloseAll takes arguments iters (a List of Iterator Records) and completion (a Completion Record) and returns a Completion Record. It performs the following steps when called:

  1. For each element iter of iters, in reverse List order, do
    1. Set completion to Completion(IteratorClose(iter, completion)).
  2. Return ? completion.

5 IfAbruptCloseIterators ( value, iteratorRecords )

IfAbruptCloseIterators is a shorthand for a sequence of algorithm steps that use a list of Iterator Records. An algorithm step of the form:

  1. IfAbruptCloseIterators(value, iteratorRecords).

means the same thing as:

  1. Assert: value is a Completion Record.
  2. If value is an abrupt completion, return ? IteratorCloseAll(iteratorRecords, value).
  3. Else, set value to value.[[Value]].

6 %IteratorHelperPrototype%.return ( )

  1. Let O be this value.
  2. Perform ? RequireInternalSlot(O, [[UnderlyingIterator]]).
  3. Perform ? RequireInternalSlot(O, [[UnderlyingIterators]]).
  4. Assert: O has a [[GeneratorState]] slot.
  5. If O.[[GeneratorState]] is suspended-start, then
    1. Set O.[[GeneratorState]] to completed.
    2. NOTE: Once a generator enters the completed state it never leaves it and its associated execution context is never resumed. Any execution state associated with O can be discarded at this point.
    3. Perform ? IteratorClose(O.[[UnderlyingIterator]], ReturnCompletion(undefined)).
    4. Perform ? IteratorCloseAll(O.[[UnderlyingIterators]], ReturnCompletion(undefined)).
    5. Return CreateIteratorResultObject(undefined, true).
  6. Let C be Completion { [[Type]]: return, [[Value]]: undefined, [[Target]]: empty }.
  7. Return ? GeneratorResumeAbrupt(O, C, "Iterator Helper").

7 Infra

Note

These AOs are taken from ecma402 and are listed here because they will need to move to ecma262. This is the first API in ecma262 that will take an options bag.

7.1 GetOptionsObject ( options )

The abstract operation GetOptionsObject takes argument options (an ECMAScript language value) and returns either a normal completion containing an Object or a throw completion. It returns an Object suitable for use with GetOption, either options itself or a default empty Object. It throws a TypeError if options is not undefined and not an Object. It performs the following steps when called:

  1. If options is undefined, then
    1. Return OrdinaryObjectCreate(null).
  2. If options is an Object, then
    1. Return options.
  3. Throw a TypeError exception.