IteratorClose.js 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. 'use strict';
  2. var $TypeError = require('es-errors/type');
  3. var Call = require('./Call');
  4. var CompletionRecord = require('./CompletionRecord');
  5. var GetMethod = require('./GetMethod');
  6. var IsCallable = require('./IsCallable');
  7. var Type = require('./Type');
  8. var isIteratorRecord = require('../helpers/records/iterator-record');
  9. // https://262.ecma-international.org/14.0/#sec-iteratorclose
  10. module.exports = function IteratorClose(iteratorRecord, completion) {
  11. if (!isIteratorRecord(iteratorRecord)) {
  12. throw new $TypeError('Assertion failed: `iteratorRecord` must be an Iterator Record'); // step 1
  13. }
  14. if (Type(iteratorRecord['[[Iterator]]']) !== 'Object') {
  15. throw new $TypeError('Assertion failed: iteratorRecord.[[Iterator]] must be an Object'); // step 1
  16. }
  17. if (!IsCallable(completion) && !(completion instanceof CompletionRecord)) { // step 2
  18. throw new $TypeError('Assertion failed: completion is not a thunk representing a Completion Record, nor a Completion Record instance');
  19. }
  20. var completionThunk = completion instanceof CompletionRecord ? function () { return completion['?'](); } : completion;
  21. var iterator = iteratorRecord['[[Iterator]]']; // step 3
  22. var iteratorReturn;
  23. try {
  24. iteratorReturn = GetMethod(iterator, 'return'); // step 4
  25. } catch (e) {
  26. completionThunk(); // throws if `completion` is a throw completion // step 6
  27. completionThunk = null; // ensure it's not called twice.
  28. throw e; // step 7
  29. }
  30. if (typeof iteratorReturn === 'undefined') {
  31. return completionThunk(); // step 5.a - 5.b
  32. }
  33. var innerResult;
  34. try {
  35. innerResult = Call(iteratorReturn, iterator, []);
  36. } catch (e) {
  37. // if we hit here, then "e" is the innerResult completion that needs re-throwing
  38. completionThunk(); // throws if `completion` is a throw completion // step 6
  39. completionThunk = null; // ensure it's not called twice.
  40. // if not, then return the innerResult completion
  41. throw e; // step 7
  42. }
  43. var completionRecord = completionThunk(); // if innerResult worked, then throw if the completion does
  44. completionThunk = null; // ensure it's not called twice.
  45. if (Type(innerResult) !== 'Object') {
  46. throw new $TypeError('iterator .return must return an object');
  47. }
  48. return completionRecord;
  49. };