iterator.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. /**
  2. * Builds an iterator that outputs the items from the inputted object
  3. * @constructor
  4. * @param {*} obj must support iter protocol (has __iter__ and next methods), if sentinel defined:
  5. * obj must be callable
  6. * @param {*=} sentinel optional if defined returns an object that makes a call to obj until
  7. * sentinel is reached
  8. * @extends Sk.builtin.object
  9. *
  10. * @description
  11. * Constructor for Python iterator.
  12. *
  13. */
  14. Sk.builtin.iterator = function (obj, sentinel) {
  15. var objit;
  16. if (obj instanceof Sk.builtin.generator) {
  17. return obj;
  18. }
  19. objit = Sk.abstr.lookupSpecial(obj, "__iter__");
  20. if (objit) {
  21. return Sk.misceval.callsim(objit, obj);
  22. }
  23. this.sentinel = sentinel;
  24. this.flag = false;
  25. this.idx = 0;
  26. this.obj = obj;
  27. if (sentinel === undefined) {
  28. this.getitem = Sk.abstr.lookupSpecial(obj, "__getitem__");
  29. this.$r = function () {
  30. return new Sk.builtin.str("<iterator object>");
  31. };
  32. } else {
  33. this.call = Sk.abstr.lookupSpecial(obj, "__call__");
  34. this.$r = function () {
  35. return new Sk.builtin.str("<callable-iterator object>");
  36. };
  37. }
  38. return this;
  39. };
  40. Sk.abstr.setUpInheritance("iterator", Sk.builtin.iterator, Sk.builtin.object);
  41. Sk.builtin.iterator.prototype.__class__ = Sk.builtin.iterator;
  42. Sk.builtin.iterator.prototype.__iter__ = new Sk.builtin.func(function (self) {
  43. return self.tp$iter();
  44. });
  45. Sk.builtin.iterator.prototype.tp$iter = function () {
  46. return this;
  47. };
  48. Sk.builtin.iterator.prototype.tp$iternext = function (canSuspend) {
  49. var r;
  50. var self = this;
  51. if (this.flag === true) {
  52. // Iterator has already completed
  53. return undefined;
  54. }
  55. if (this.getitem) {
  56. r = Sk.misceval.tryCatch(function() {
  57. return Sk.misceval.callsimOrSuspend(self.getitem, self.obj, Sk.ffi.remapToPy(self.idx++));
  58. }, function(e) {
  59. if (e instanceof Sk.builtin.StopIteration || e instanceof Sk.builtin.IndexError) {
  60. return undefined;
  61. } else {
  62. throw e;
  63. }
  64. });
  65. return canSuspend ? r : Sk.misceval.retryOptionalSuspensionOrThrow(r);
  66. }
  67. var checkSentinel = function (ret) {
  68. // Iteration is complete if ret value is the sentinel
  69. if (Sk.misceval.richCompareBool(ret, self.sentinel, "Eq")) {
  70. self.flag = true;
  71. return undefined;
  72. }
  73. return ret;
  74. };
  75. if (this.call) {
  76. r = Sk.misceval.chain(Sk.misceval.callsimOrSuspend(this.call, this.obj), checkSentinel);
  77. } else {
  78. var obj = /** @type {Object} */ (this.obj);
  79. r = Sk.misceval.chain(Sk.misceval.callsimOrSuspend(obj), checkSentinel);
  80. }
  81. return canSuspend ? r : Sk.misceval.retryOptionalSuspensionOrThrow(r);
  82. };
  83. Sk.builtin.iterator.prototype["next"] = new Sk.builtin.func(function (self) {
  84. var ret = self.tp$iternext();
  85. if (!ret) {
  86. throw new Sk.builtin.StopIteration();
  87. }
  88. return ret;
  89. });
  90. goog.exportSymbol("Sk.builtin.iterator", Sk.builtin.iterator);