UNPKG

57.7 kBJavaScriptView Raw
1/**
2 * Copyright (c) 2014, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * https://raw.github.com/facebook/regenerator/master/LICENSE file. An
7 * additional grant of patent rights can be found in the PATENTS file in
8 * the same directory.
9 */
10
11var assert = require("assert");
12var runningInTranslation = /\.wrap\(/.test(function*(){});
13var iteratorSymbol = typeof Symbol === "function"
14 && Symbol.iterator
15 || "@@iterator";
16
17function check(g, yields, returnValue) {
18 for (var i = 0; i < yields.length; ++i) {
19 var info = g.next(i);
20 assert.deepEqual(info.value, yields[i]);
21 assert.strictEqual(info.done, false);
22 }
23
24 assert.deepEqual(
25 i > 0 ? g.next(i) : g.next(),
26 { value: returnValue, done: true }
27 );
28}
29
30// A version of `throw` whose behavior can't be statically analyzed.
31// Useful for testing dynamic exception dispatching.
32function raise(argument) {
33 throw argument;
34}
35
36function assertAlreadyFinished(generator) {
37 assert.deepEqual(generator.next(), {
38 value: void 0,
39 done: true
40 });
41}
42
43describe("regeneratorRuntime", function() {
44 it("should be defined globally", function() {
45 var global = Function("return this")();
46 assert.ok("regeneratorRuntime" in global);
47 assert.strictEqual(global.regeneratorRuntime, regeneratorRuntime);
48 });
49
50 it("should have a .wrap method", function() {
51 assert.strictEqual(typeof regeneratorRuntime.wrap, "function");
52 });
53
54 it("should have a .mark method", function() {
55 assert.strictEqual(typeof regeneratorRuntime.mark, "function");
56 });
57
58 it("should be the object name returned by util.runtimeProperty", function() {
59 assert.strictEqual(
60 require("../lib/util").runtimeProperty("foo").object.name,
61 "regeneratorRuntime"
62 );
63 });
64});
65
66(runningInTranslation ? describe : xdescribe)("@@iterator", function() {
67 it("is defined on Generator.prototype and returns this", function() {
68 function *gen(){}
69 var iterator = gen();
70 assert.ok(!iterator.hasOwnProperty(iteratorSymbol));
71 assert.ok(!Object.getPrototypeOf(iterator).hasOwnProperty(iteratorSymbol));
72 assert.ok(Object.getPrototypeOf(
73 Object.getPrototypeOf(iterator)
74 ).hasOwnProperty(iteratorSymbol));
75 assert.strictEqual(iterator[iteratorSymbol](), iterator);
76 });
77});
78
79describe("simple argument yielder", function() {
80 it("should yield only its first argument", function() {
81 function *gen(x) {
82 yield x;
83 }
84
85 check(gen("oyez"), ["oyez"]);
86 check(gen("foo", "bar"), ["foo"]);
87 });
88
89 it("should support multiple yields in expression", function() {
90 function *gen() { return (yield 0) + (yield 0); }
91 var itr = gen();
92 itr.next();
93 itr.next(1);
94 assert.equal(itr.next(2).value, 3);
95 });
96});
97
98function *range(n) {
99 for (var i = 0; i < n; ++i) {
100 yield i;
101 }
102}
103
104describe("range generator", function() {
105 it("should yield the empty range", function() {
106 check(range(0), []);
107 })
108
109 it("should yield the range 0..n-1", function() {
110 check(range(5), [0, 1, 2, 3, 4]);
111 });
112});
113
114describe("collatz generator", function() {
115 function *gen(n) {
116 var count = 0;
117
118 yield n;
119
120 while (n !== 1) {
121 count += 1;
122
123 if (n % 2) {
124 yield n = n * 3 + 1;
125 } else {
126 yield n >>= 1;
127 }
128 }
129
130 return count;
131 }
132
133 function collatz(n) {
134 var result = [n];
135
136 while (n !== 1) {
137 if (n % 2) {
138 n *= 3;
139 n += 1;
140 } else {
141 n >>= 1;
142 }
143
144 result.push(n);
145 }
146
147 return result;
148 }
149
150 var seven = collatz(7);
151 var fiftyTwo = seven.slice(seven.indexOf(52));
152 var eightyTwo = collatz(82);
153
154 it("seven", function() {
155 check(gen(7), seven, 16);
156 });
157
158 it("fifty two", function() {
159 check(gen(52), fiftyTwo, 11);
160 });
161
162 it("eighty two", function() {
163 check(gen(82), eightyTwo, 110);
164 });
165});
166
167describe("throw", function() {
168 (runningInTranslation ? it : xit)("should complete generator", function() {
169 function *gen(x) {
170 throw 1;
171 }
172
173 var u = gen();
174
175 try {
176 u.next();
177 } catch (err) {
178 assert.strictEqual(err, 1);
179 }
180
181 assertAlreadyFinished(u);
182 });
183});
184
185describe("try-catch generator", function() {
186 function *usingThrow(x) {
187 yield 0;
188 try {
189 yield 1;
190 if (x % 2 === 0)
191 throw 2;
192 yield x;
193 } catch (x) {
194 yield x;
195 }
196 yield 3;
197 }
198
199 function *usingRaise(x) {
200 yield 0;
201 try {
202 yield 1;
203 if (x % 2 === 0)
204 raise(2);
205 yield x;
206 } catch (x) {
207 yield x;
208 }
209 yield 3;
210 }
211
212 it("should catch static exceptions properly", function() {
213 check(usingThrow(4), [0, 1, 2, 3]);
214 check(usingThrow(5), [0, 1, 5, 3]);
215 });
216
217 it("should catch dynamic exceptions properly", function() {
218 check(usingRaise(4), [0, 1, 2, 3]);
219 check(usingRaise(5), [0, 1, 5, 3]);
220 });
221});
222
223describe("nested generators in try-catch", function() {
224 function *gen() {
225 try {
226 nonExistent;
227 } catch (e) {
228 yield function* () {
229 yield e;
230 }
231 }
232 }
233
234 it('should get a reference to the caught error', function () {
235 var genFun2 = gen().next().value;
236 assert.ok(regeneratorRuntime.isGeneratorFunction(genFun2));
237 var gen2 = genFun2();
238 var res = gen2.next();
239 assert.ok(res.value instanceof ReferenceError);
240 // Note that we don't do strict equality over the message because it varies
241 // across browsers (if we ever want to run tests in browsers).
242 assert.ok(res.value.message.match(/nonExistent/));
243 });
244
245});
246
247describe("try-finally generator", function() {
248 function *usingThrow(condition) {
249 yield 0;
250 try {
251 yield 1;
252 throw 2;
253 yield 3;
254 } finally {
255 if (condition) {
256 yield 4;
257 return 5;
258 }
259 yield 6;
260 return 7;
261 }
262 }
263
264 function *usingRaise(condition) {
265 yield 0;
266 try {
267 yield 1;
268 raise(2);
269 yield 3;
270 } finally {
271 if (condition) {
272 yield 4;
273 return 5;
274 }
275 yield 6;
276 return 7;
277 }
278 }
279
280 function *usingAbrupt(abruptType, finallyAbruptType) {
281 yield 0;
282 for (;;) {
283 try {
284 yield 1;
285 if (abruptType === "return") {
286 return 2;
287 } else if (abruptType === "break") {
288 break;
289 } else if (abruptType === "continue") {
290 abruptType = "return";
291 continue;
292 }
293 }
294 finally {
295 yield 3;
296 if (finallyAbruptType === "return") {
297 return 4;
298 } else if (finallyAbruptType === "break") {
299 break;
300 } else if (finallyAbruptType === "continue") {
301 finallyAbruptType = null;
302 continue;
303 }
304 }
305 }
306 return 5;
307 }
308
309 it("should honor return", function() {
310 check(usingAbrupt("return", null), [0, 1, 3], 2);
311 });
312
313 it("should honor break", function() {
314 check(usingAbrupt("break", null), [0, 1, 3], 5);
315 });
316
317 it("should honor continue", function() {
318 check(usingAbrupt("continue", null), [0, 1, 3, 1, 3], 2);
319 });
320
321 it("should override abrupt with return", function() {
322 check(usingAbrupt("return", "return"), [0, 1, 3], 4);
323 check(usingAbrupt("break", "return"), [0, 1, 3], 4);
324 check(usingAbrupt("continue", "return"), [0, 1, 3], 4);
325 });
326
327 it("should override abrupt with break", function() {
328 check(usingAbrupt("return", "break"), [0, 1, 3], 5);
329 check(usingAbrupt("break", "break"), [0, 1, 3], 5);
330 check(usingAbrupt("continue", "break"), [0, 1, 3], 5);
331 });
332
333 it("should override abrupt with continue", function() {
334 check(usingAbrupt("return", "continue"), [0, 1, 3, 1, 3], 2);
335 check(usingAbrupt("break", "continue"), [0, 1, 3, 1, 3], 5);
336 check(usingAbrupt("continue", "continue"), [0, 1, 3, 1, 3], 2);
337 });
338
339 it("should execute finally blocks statically", function() {
340 check(usingThrow(true), [0, 1, 4], 5);
341 check(usingThrow(false), [0, 1, 6], 7);
342 });
343
344 it("should execute finally blocks dynamically", function() {
345 check(usingRaise(true), [0, 1, 4], 5);
346 check(usingRaise(false), [0, 1, 6], 7);
347 });
348
349 it("should execute finally blocks before throwing", function() {
350 var uncaughtError = new Error("uncaught");
351
352 function *uncaught(condition) {
353 try {
354 yield 0;
355 if (condition) {
356 yield 1;
357 raise(uncaughtError);
358 }
359 yield 2;
360 } finally {
361 yield 3;
362 }
363 yield 4;
364 }
365
366 check(uncaught(false), [0, 2, 3, 4]);
367
368 var u = uncaught(true);
369
370 assert.deepEqual(u.next(), { value: 0, done: false });
371 assert.deepEqual(u.next(), { value: 1, done: false });
372 assert.deepEqual(u.next(), { value: 3, done: false });
373
374 try {
375 u.next();
376 assert.ok(false, "should have thrown an exception");
377 } catch (err) {
378 assert.strictEqual(err, uncaughtError);
379 }
380 });
381
382 it("should throw correct error when finally contains catch", function() {
383 var right = new Error("right");
384 var wrong = new Error("wrong");
385
386 function *gen() {
387 try {
388 yield 0;
389 raise(right);
390 } finally {
391 yield 1;
392 try {
393 raise(wrong);
394 } catch (err) {
395 assert.strictEqual(err, wrong);
396 yield 2;
397 }
398 }
399 }
400
401 var g = gen();
402
403 assert.deepEqual(g.next(), {
404 value: 0,
405 done: false
406 });
407
408 assert.deepEqual(g.next(), {
409 value: 1,
410 done: false
411 });
412
413 assert.deepEqual(g.next(), {
414 value: 2,
415 done: false
416 });
417
418 try {
419 g.next();
420 assert.ok(false, "should have thrown an exception");
421 } catch (err) {
422 assert.strictEqual(err, right);
423 }
424 });
425
426 it("should run finally after break within try", function() {
427 function *gen() {
428 try {
429 yield 0;
430 while (true) {
431 yield 1;
432 break;
433 }
434 } finally {
435 yield 2;
436 }
437 yield 3;
438 }
439
440 check(gen(), [0, 1, 2, 3]);
441 });
442});
443
444describe("try-catch-finally generator", function() {
445 function *usingThrow() {
446 yield 0;
447 try {
448 try {
449 yield 1;
450 throw 2;
451 yield 3;
452 } catch (x) {
453 throw yield x;
454 } finally {
455 yield 5;
456 }
457 } catch (thrown) {
458 yield thrown;
459 }
460 yield 6;
461 }
462
463 function *usingRaise() {
464 yield 0;
465 try {
466 try {
467 yield 1;
468 raise(2);
469 yield 3;
470 } catch (x) {
471 throw yield x;
472 } finally {
473 yield 5;
474 }
475 } catch (thrown) {
476 yield thrown;
477 }
478 yield 6;
479 }
480
481 it("should statically catch and then finalize", function() {
482 check(usingThrow(), [0, 1, 2, 5, 3, 6]);
483 });
484
485 it("should dynamically catch and then finalize", function() {
486 check(usingRaise(), [0, 1, 2, 5, 3, 6]);
487 });
488
489 it("should execute catch and finally blocks at most once", function() {
490 var error = new Error();
491
492 function *gen() {
493 try {
494 switch (1) {
495 case 1:
496 yield "a";
497 break;
498 default:
499 break;
500 }
501 throw error;
502 } catch (e) {
503 assert.strictEqual(e, error);
504 yield "b";
505 do {
506 do {
507 yield "c";
508 break;
509 } while (false);
510 yield "d";
511 break;
512 } while (false);
513 yield "e";
514 } finally {
515 yield "f";
516 }
517 }
518
519 check(gen(), ["a", "b", "c", "d", "e", "f"]);
520 });
521
522 it("should handle backwards jumps in labeled loops", function() {
523 function *gen() {
524 var firstTime = true;
525 outer:
526 while (true) {
527 yield 0;
528 try {
529 while (true) {
530 yield 1;
531 if (firstTime) {
532 firstTime = false;
533 yield 2;
534 continue outer;
535 } else {
536 yield 3;
537 break;
538 }
539 }
540 yield 4;
541 break;
542 } finally {
543 yield 5;
544 }
545 yield 6;
546 }
547 yield 7;
548 }
549
550 check(gen(), [0, 1, 2, 5, 0, 1, 3, 4, 5, 7]);
551 });
552
553 it("should handle loop continue statements properly", function() {
554 var error = new Error("thrown");
555 var markers = [];
556
557 function *gen() {
558 var c = 2;
559 while (c > 0) {
560 try {
561 markers.push("try");
562 yield c;
563 } catch (e) {
564 assert.strictEqual(e, error);
565 markers.push("catch");
566 continue;
567 } finally {
568 markers.push("finally");
569 }
570 markers.push("decrement");
571 --c;
572 }
573 }
574
575 var g = gen();
576
577 assert.deepEqual(g.next(), { value: 2, done: false });
578 assert.deepEqual(g.throw(error), { value: 2, done: false });
579 assert.deepEqual(g.next(), { value: 1, done: false });
580 assert.deepEqual(g.next(), { value: void 0, done: true });
581
582 assert.deepEqual(markers, [
583 "try",
584 "catch",
585 "finally",
586 "try",
587 "finally",
588 "decrement",
589 "try",
590 "finally",
591 "decrement"
592 ]);
593 });
594});
595
596describe("dynamic exception", function() {
597 function *gen(x, fname) {
598 try {
599 return fns[fname](x);
600 } catch (thrown) {
601 yield thrown;
602 }
603 }
604
605 var fns = {
606 f: function(x) {
607 throw x;
608 },
609
610 g: function(x) {
611 return x;
612 }
613 };
614
615 it("should be dispatched correctly", function() {
616 check(gen("asdf", "f"), ["asdf"]);
617 check(gen("asdf", "g"), [], "asdf");
618 });
619});
620
621describe("nested finally blocks", function() {
622 function *usingThrow() {
623 try {
624 try {
625 try {
626 throw "thrown";
627 } finally {
628 yield 1;
629 }
630 } catch (thrown) {
631 yield thrown;
632 } finally {
633 yield 2;
634 }
635 } finally {
636 yield 3;
637 }
638 }
639
640 function *usingRaise() {
641 try {
642 try {
643 try {
644 raise("thrown");
645 } finally {
646 yield 1;
647 }
648 } catch (thrown) {
649 yield thrown;
650 } finally {
651 yield 2;
652 }
653 } finally {
654 yield 3;
655 }
656 }
657
658 it("should statically execute in order", function() {
659 check(usingThrow(), [1, "thrown", 2, 3]);
660 });
661
662 it("should dynamically execute in order", function() {
663 check(usingRaise(), [1, "thrown", 2, 3]);
664 });
665});
666
667describe("for-in loop generator", function() {
668 it("should handle the simple case", function() {
669 function *gen() {
670 var count = 0;
671 var obj = {foo: 1, bar: 2};
672 for (var key in obj) {
673 assert(obj.hasOwnProperty(key), key + " must be own property");
674 yield [key, obj[key]];
675 count += 1;
676 }
677 return count;
678 }
679
680 check(gen(), [["foo", 1], ["bar", 2]], 2);
681 });
682
683 it("should handle break in loop", function() {
684 function *gen(obj) {
685 var count = 0;
686 for (var key in (yield "why not", obj)) {
687 if (obj.hasOwnProperty(key)) {
688 if (key === "skip") {
689 break;
690 }
691 count += 1;
692 yield [key, obj[key]];
693 }
694 }
695 return count;
696 }
697
698 check(
699 gen({ a: 1, b: 2, skip: 3, c: 4 }),
700 ["why not", ["a", 1], ["b", 2]],
701 2
702 );
703 });
704
705 it("should handle property deletion in loop", function() {
706 function *gen() {
707 var count = 0;
708 var obj = {foo: 1, bar: 2};
709 for (var key in obj) {
710 assert(obj.hasOwnProperty(key), key + " must be own property");
711 yield [key, obj[key]];
712 delete obj.bar;
713 count += 1;
714 }
715 return count;
716 }
717
718 check(gen(), [["foo", 1]], 1);
719 });
720
721 it("should loop over inherited properties", function() {
722 function *gen() {
723 var count = 0;
724 function Foo() {
725 this.baz = 1
726 }
727 Foo.prototype.bar = 2;
728
729 var foo = new Foo();
730 for (var key in foo) {
731 yield [key, foo[key]];
732 count += 1;
733 }
734 return count;
735 }
736
737 check(gen(), [["baz", 1], ["bar", 2]], 2);
738 });
739
740 it("should handle risky object expressions", function() {
741 function a(sent) {
742 assert.strictEqual(sent, 1);
743 a.called = true;
744 }
745
746 function b(sent) {
747 assert.strictEqual(sent, 2);
748 b.called = true;
749 return { callee: b };
750 }
751
752 function *gen() {
753 assert.ok(!a.called);
754 assert.ok(!b.called);
755 for (var key in a(yield 0), b(yield 1)) {
756 assert.ok(a.called);
757 assert.ok(b.called);
758 assert.strictEqual(yield key, 3);
759 }
760
761 for (var key in a(1), { foo: "foo", bar: "bar" }) {
762 yield key;
763 }
764 }
765
766 check(gen(), [0, 1, "callee", "foo", "bar"]);
767 });
768
769 it("should allow non-Identifier left-hand expressions", function() {
770 var obj = {};
771 var baz = { a: 1, b: 2, c: 3 };
772 var markers = [];
773
774 function foo() {
775 markers.push("called foo");
776 return obj;
777 }
778
779 function *gen() {
780 for (foo().bar in baz) {
781 markers.push(obj.bar);
782 yield obj.bar;
783 }
784 }
785
786 check(gen(), ["a", "b", "c"]);
787
788 assert.deepEqual(markers, [
789 "called foo",
790 "a",
791 "called foo",
792 "b",
793 "called foo",
794 "c"
795 ]);
796 });
797});
798
799describe("yield chain", function() {
800 function *gen(n) {
801 return yield yield yield yield n;
802 }
803
804 it("should have correct associativity", function() {
805 check(gen(5), [5, 1, 2, 3], 4);
806 check(gen("asdf"), ["asdf", 1, 2, 3], 4);
807 });
808});
809
810describe("object literal generator", function() {
811 function *gen(a, b) {
812 yield {
813 a: a - (yield a),
814 b: yield b
815 };
816 }
817
818 it("should yield the correct object", function() {
819 check(gen(1, 2), [1, 2, { a: 0, b: 2 }]);
820 check(gen(4, 2), [4, 2, { a: 3, b: 2 }]);
821 });
822});
823
824describe("switch statement generator", function() {
825 function *gen(a) {
826 switch (yield a) {
827 case (yield "x") - a:
828 return "first case";
829 case (yield "y") - a:
830 return "second case";
831 }
832 }
833
834 it("should jump to the correct cases", function() {
835 check(gen(1), [1, "x"], "first case");
836 check(gen(2), [2, "x", "y"], "second case");
837 });
838});
839
840describe("infinite sequence generator", function() {
841 function *gen(start, step) {
842 step = step || 1;
843 while (true) {
844 yield start;
845 start += step;
846 }
847 }
848
849 function *limit(g, stop) {
850 while (true) {
851 var info = g.next();
852 if (info.done) {
853 return;
854 } else if (info.value < stop) {
855 yield info.value;
856 } else {
857 return;
858 }
859 }
860 }
861
862 it("should generate a lot of plausible values", function() {
863 var g = gen(10, 2);
864
865 assert.deepEqual(g.next(), { value: 10, done: false });
866 assert.deepEqual(g.next(), { value: 12, done: false });
867 assert.deepEqual(g.next(), { value: 14, done: false });
868 assert.deepEqual(g.next(), { value: 16, done: false });
869
870 var sum = 10 + 12 + 14 + 16;
871
872 for (var n = 0; n < 1000; ++n) {
873 var info = g.next();
874 sum += info.value;
875 assert.strictEqual(info.done, false);
876 }
877
878 assert.strictEqual(sum, 1017052);
879 });
880
881 it("should allow limiting", function() {
882 check(limit(gen(10, 3), 20), [10, 13, 16, 19]);
883 });
884});
885
886describe("generator function expression", function() {
887 it("should behave just like a declared generator", function() {
888 check(function *(x, y) {
889 yield x;
890 yield y;
891 yield x + y;
892 return x * y;
893 }(3, 7), [3, 7, 10], 21);
894 })
895});
896
897describe("generator reentry attempt", function() {
898 function *gen(x) {
899 try {
900 (yield x).next(x);
901 } catch (err) {
902 yield err;
903 }
904 return x + 1;
905 }
906
907 it("should complain with a TypeError", function() {
908 var g = gen(3);
909 assert.deepEqual(g.next(), { value: 3, done: false });
910 var complaint = g.next(g); // Sending the generator to itself.
911 assert.ok(complaint.value instanceof Error);
912 assert.strictEqual(
913 complaint.value.message,
914 "Generator is already running"
915 );
916 assert.deepEqual(g.next(), { value: 4, done: true });
917 });
918});
919
920describe("completed generator", function() {
921 function *gen() {
922 return "ALL DONE";
923 }
924
925 (runningInTranslation ? it : xit)
926 ("should refuse to resume", function() {
927 var g = gen();
928
929 assert.deepEqual(g.next(), {
930 value: "ALL DONE", done: true
931 });
932
933 assertAlreadyFinished(g);
934 });
935});
936
937describe("delegated yield", function() {
938 it("should delegate correctly", function() {
939 function *gen(condition) {
940 yield 0;
941 if (condition) {
942 yield 1;
943 yield* gen(false);
944 yield 2;
945 }
946 yield 3;
947 }
948
949 check(gen(true), [0, 1, 0, 3, 2, 3]);
950 check(gen(false), [0, 3]);
951 });
952
953 it("should cope with empty delegatees", function() {
954 function *gen(condition) {
955 if (condition) {
956 yield 0;
957 yield* gen(false);
958 yield 1;
959 }
960 }
961
962 check(gen(true), [0, 1]);
963 check(gen(false), []);
964 });
965
966 it("should support deeper nesting", function() {
967 function *outer(n) {
968 yield n;
969 yield* middle(n - 1, inner(n + 10));
970 yield n + 1;
971 }
972
973 function *middle(n, plusTen) {
974 yield n;
975 yield* inner(n - 1);
976 yield n + 1;
977 yield* plusTen;
978 }
979
980 function *inner(n) {
981 yield n;
982 }
983
984 check(outer(5), [5, 4, 3, 5, 15, 6]);
985 });
986
987 it("should pass sent values through", function() {
988 function *outer(n) {
989 yield* inner(n << 1);
990 yield "zxcv";
991 }
992
993 function *inner(n) {
994 return yield yield yield n;
995 }
996
997 var g = outer(3);
998 assert.deepEqual(g.next(), { value: 6, done: false });
999 assert.deepEqual(g.next(1), { value: 1, done: false });
1000 assert.deepEqual(g.next(2), { value: 2, done: false });
1001 assert.deepEqual(g.next(4), { value: "zxcv", done: false });
1002 assert.deepEqual(g.next(5), { value: void 0, done: true });
1003 });
1004
1005 it("should be governed by enclosing try statements", function() {
1006 var error = new Error("thrown");
1007
1008 function *outer(n) {
1009 try {
1010 yield 0;
1011 yield* inner(n);
1012 yield 1;
1013 } catch (err) {
1014 yield err.message;
1015 }
1016 yield 4;
1017 }
1018
1019 function *inner(n) {
1020 while (n --> 0) {
1021 try {
1022 if (n === 3) {
1023 raise(error);
1024 }
1025 } finally {
1026 yield n;
1027 }
1028 }
1029 }
1030
1031 check(outer(3), [0, 2, 1, 0, 1, 4]);
1032 check(outer(5), [0, 4, 3, "thrown", 4]);
1033 });
1034
1035 it("should dispatch .thrown exceptions correctly", function() {
1036 var count = 0;
1037
1038 function *gen() {
1039 yield* inner();
1040 try {
1041 yield* inner();
1042 } catch (err) {
1043 // pass
1044 }
1045 return yield* inner();
1046 }
1047
1048 function *inner() {
1049 return yield count++;
1050 }
1051
1052 var g = gen();
1053
1054 assert.deepEqual(g.next(), {
1055 value: 0,
1056 done: false
1057 });
1058
1059 assert.deepEqual(g.next(), {
1060 value: 1,
1061 done: false
1062 });
1063
1064 assert.deepEqual(g.throw(new Error("lol")), {
1065 value: 2,
1066 done: false,
1067 });
1068
1069 assert.deepEqual(g.next("sent"), {
1070 value: "sent",
1071 done: true
1072 });
1073 });
1074
1075 it("should call .return methods of delegate iterators", function() {
1076 var throwee = new Error("argument to gen.throw");
1077 var thrownFromThrow = new Error("thrown from throw method");
1078 var thrownFromReturn = new Error("thrown from return method");
1079
1080 function *gen(delegate) {
1081 try {
1082 return yield* delegate;
1083 } catch (err) {
1084 return err;
1085 }
1086 }
1087
1088 function check(throwMethod, returnMethod) {
1089 var throwCalled = false;
1090 var returnCalled = false;
1091 var count = 0;
1092 var iterator = {
1093 next: function() {
1094 return { value: count++, done: false };
1095 }
1096 };
1097
1098 iterator[iteratorSymbol] = function() {
1099 return this;
1100 };
1101
1102 if (throwMethod) {
1103 iterator["throw"] = function() {
1104 throwCalled = true;
1105 return throwMethod.apply(this, arguments);
1106 };
1107 }
1108
1109 if (returnMethod) {
1110 iterator["return"] = function() {
1111 returnCalled = true;
1112 return returnMethod.apply(this, arguments);
1113 };
1114 }
1115
1116 var g = gen(iterator);
1117
1118 assert.deepEqual(g.next(), { value: 0, done: false });
1119 assert.deepEqual(g.next(), { value: 1, done: false });
1120 assert.deepEqual(g.next(), { value: 2, done: false });
1121 assert.deepEqual(g.next(), { value: 3, done: false });
1122
1123 assert.strictEqual(throwCalled, false);
1124 assert.strictEqual(returnCalled, false);
1125
1126 var result = {};
1127
1128 result.throwResult = g.throw(throwee);
1129 result.throwCalled = throwCalled;
1130 result.returnCalled = returnCalled;
1131
1132 return result;
1133 }
1134
1135 var checkResult = check(undefined, function() {
1136 throw thrownFromReturn;
1137 });
1138 if (runningInTranslation) {
1139 // BUG: Node v0.11 and v0.12 neglect to call .return here.
1140 assert.strictEqual(checkResult.throwResult.value, thrownFromReturn);
1141 } else {
1142 // This is the TypeError that results from trying to call the
1143 // undefined .throw method of the iterator.
1144 assert.ok(checkResult.throwResult.value instanceof TypeError);
1145 }
1146 assert.strictEqual(checkResult.throwResult.done, true);
1147 assert.strictEqual(checkResult.throwCalled, false);
1148 // BUG: Node v0.11 and v0.12 neglect to call .return here.
1149 assert.strictEqual(checkResult.returnCalled, runningInTranslation);
1150
1151 checkResult = check(undefined, function() {
1152 return { value: "from return", done: true };
1153 });
1154 assert.notStrictEqual(checkResult.throwResult.value, throwee);
1155 // This is the TypeError that results from trying to call the
1156 // undefined .throw method of the iterator.
1157 assert.ok(checkResult.throwResult.value instanceof TypeError);
1158 assert.strictEqual(checkResult.throwResult.done, true);
1159 assert.strictEqual(checkResult.throwCalled, false);
1160 // BUG: Node v0.11 and v0.12 neglect to call .return here.
1161 assert.strictEqual(checkResult.returnCalled, runningInTranslation);
1162
1163 var checkResult = check(function(thrown) {
1164 return { value: "from throw", done: true };
1165 }, function() {
1166 throw thrownFromReturn;
1167 });
1168 assert.strictEqual(checkResult.throwResult.value, "from throw");
1169 assert.strictEqual(checkResult.throwResult.done, true);
1170 assert.strictEqual(checkResult.throwCalled, true);
1171 assert.strictEqual(checkResult.returnCalled, false);
1172
1173 var checkResult = check(function(thrown) {
1174 throw thrownFromThrow;
1175 }, function() {
1176 throw thrownFromReturn;
1177 });
1178 assert.strictEqual(checkResult.throwResult.value, thrownFromThrow);
1179 assert.strictEqual(checkResult.throwResult.done, true);
1180 assert.strictEqual(checkResult.throwCalled, true);
1181 assert.strictEqual(checkResult.returnCalled, false);
1182
1183 var checkResult = check(undefined, undefined);
1184 assert.notStrictEqual(checkResult.throwResult.value, throwee);
1185 // This is the TypeError that results from trying to call the
1186 // undefined .throw method of the iterator.
1187 assert.ok(checkResult.throwResult.value instanceof TypeError);
1188 assert.strictEqual(checkResult.throwResult.done, true);
1189 assert.strictEqual(checkResult.throwCalled, false);
1190 assert.strictEqual(checkResult.returnCalled, false);
1191 });
1192
1193 it("should not be required to have a .return method", function() {
1194 function *gen(delegate) {
1195 return yield* delegate;
1196 }
1197
1198 var inner = range(5);
1199 var iterator = { next: inner.next.bind(inner) };
1200 iterator[iteratorSymbol] = function() {
1201 return this;
1202 };
1203
1204 var g = gen(iterator);
1205 assert.deepEqual(g.next(), { value: 0, done: false });
1206 assert.deepEqual(g.next(), { value: 1, done: false });
1207 assert.deepEqual(g.next(), { value: 2, done: false });
1208
1209 if (typeof g.return === "function") {
1210 assert.deepEqual(g.return(-1), { value: -1, done: true });
1211 assert.deepEqual(g.next(), { value: void 0, done: true });
1212 }
1213 });
1214
1215 (runningInTranslation ? it : xit)
1216 ("should support any iterable argument", function() {
1217 function *gen() {
1218 yield 0;
1219 yield* [
1220 yield "one",
1221 yield "two",
1222 yield "three"
1223 ];
1224 yield 5;
1225 }
1226
1227 check(gen(), [0, "one", "two", "three", 2, 3, 4, 5]);
1228
1229 function *string() {
1230 return yield* "asdf";
1231 }
1232
1233 check(string(), ["a", "s", "d", "f"]);
1234 });
1235
1236 it("should evaluate to the return value of the delegate", function() {
1237 function *inner() {
1238 yield 1;
1239 return 2;
1240 }
1241
1242 function *outer(delegate) {
1243 return yield* delegate;
1244 }
1245
1246 check(outer(inner()), [1], 2);
1247
1248 var arrayDelegate = [3, 4];
1249 if (!runningInTranslation) {
1250 // Node v0.11 doesn't know how to turn arrays into iterators over
1251 // their elements without a little help.
1252 arrayDelegate = regeneratorRuntime.values(arrayDelegate);
1253 }
1254 check(outer(arrayDelegate), [3, 4], void 0); // See issue #143.
1255
1256 if (!runningInTranslation) {
1257 return;
1258 }
1259
1260 check(outer({
1261 next: function() {
1262 return { value: "oyez", done: true };
1263 }
1264 }), [], "oyez");
1265 });
1266
1267 it("should work as a subexpression", function() {
1268 function *inner(arg) {
1269 return arg;
1270 }
1271
1272 function *gen(delegate) {
1273 // Unfortunately these parentheses appear to be necessary.
1274 return 1 + (yield* delegate);
1275 }
1276
1277 check(gen(inner(2)), [], 3);
1278 check(gen(inner(3)), [], 4);
1279
1280 if (!runningInTranslation) {
1281 return;
1282 }
1283
1284 check(gen({
1285 next: function() {
1286 return { value: "foo", done: true };
1287 }
1288 }), [], "1foo");
1289 });
1290});
1291
1292describe("function declaration hoisting", function() {
1293 it("should work even if the declarations are out of order", function() {
1294 function *gen(n) {
1295 yield increment(n);
1296
1297 function increment(x) {
1298 return x + 1;
1299 }
1300
1301 if (n % 2) {
1302 yield halve(decrement(n));
1303
1304 function halve(x) {
1305 return x >> 1;
1306 }
1307
1308 function decrement(x) {
1309 return x - 1;
1310 }
1311 } else {
1312 // The behavior of function declarations nested inside conditional
1313 // blocks is notoriously underspecified, and in V8 it appears the
1314 // halve function is still defined when we take this branch, so
1315 // "undefine" it for consistency with regenerator semantics.
1316 halve = void 0;
1317 }
1318
1319 yield typeof halve;
1320
1321 yield increment(increment(n));
1322 }
1323
1324 check(gen(3), [4, 1, "function", 5]);
1325 check(gen(4), [5, "undefined", 6]);
1326 });
1327
1328 it("should work for nested generator function declarations", function() {
1329 function *outer(n) {
1330 yield 0;
1331 assert.ok(regeneratorRuntime.isGeneratorFunction(inner));
1332 return yield* inner(n);
1333
1334 // Note that this function declaration comes after everything else
1335 // in the outer function, but needs to be fully available above.
1336 function *inner(n) {
1337 yield n - 1;
1338 yield n;
1339 return yield n + 1;
1340 }
1341 }
1342
1343 check(outer(2), [0, 1, 2, 3], 4);
1344 });
1345
1346 it("should not interfere with function rebinding", function() {
1347 function rebindTo(value) {
1348 var oldValue = toBeRebound;
1349 toBeRebound = value;
1350 return oldValue;
1351 }
1352
1353 function *toBeRebound() {
1354 var originalValue = toBeRebound;
1355 yield toBeRebound;
1356 assert.strictEqual(rebindTo(42), originalValue);
1357 yield toBeRebound;
1358 assert.strictEqual(rebindTo("asdf"), 42);
1359 yield toBeRebound;
1360 }
1361
1362 var original = toBeRebound;
1363 check(toBeRebound(), [original, 42, "asdf"]);
1364
1365 function attemptToRebind(value) {
1366 var oldValue = safe;
1367 safe = value;
1368 return oldValue;
1369 }
1370
1371 var safe = function *safe() {
1372 var originalValue = safe;
1373 yield safe;
1374 assert.strictEqual(attemptToRebind(42), originalValue);
1375 yield safe;
1376 assert.strictEqual(attemptToRebind("asdf"), 42);
1377 yield safe;
1378 }
1379
1380 original = safe;
1381 check(safe(), [safe, safe, safe]);
1382 });
1383});
1384
1385describe("the arguments object", function() {
1386 it("should work in simple variadic functions", function() {
1387 function *sum() {
1388 var result = 0;
1389
1390 for (var i = 0; i < arguments.length; ++i) {
1391 yield result += arguments[i];
1392 }
1393
1394 return result;
1395 }
1396
1397 check(sum(1, 2, 3), [1, 3, 6], 6);
1398 check(sum(9, -5, 3, 0, 2), [9, 4, 7, 7, 9], 9);
1399 });
1400
1401 it("should alias function parameters", function() {
1402 function *gen(x, y) {
1403 yield x;
1404 ++arguments[0];
1405 yield x;
1406
1407 yield y;
1408 --arguments[1];
1409 yield y;
1410
1411 var temp = y;
1412 y = x;
1413 x = temp;
1414
1415 yield x;
1416 yield y;
1417 }
1418
1419 check(gen(3, 7), [3, 4, 7, 6, 6, 4]);
1420 check(gen(10, -5), [10, 11, -5, -6, -6, 11]);
1421 });
1422
1423 it("should be shadowable by explicit declarations", function() {
1424 function *asParameter(x, arguments) {
1425 arguments = arguments + 1;
1426 yield x + arguments;
1427 }
1428
1429 check(asParameter(4, 5), [10]);
1430 check(asParameter("asdf", "zxcv"), ["asdfzxcv1"]);
1431
1432 function *asVariable(x) {
1433 // TODO References to arguments before the variable declaration
1434 // seem to see the object instead of the undefined value.
1435 var arguments = x + 1;
1436 yield arguments;
1437 }
1438
1439 check(asVariable(4), [5]);
1440 check(asVariable("asdf"), ["asdf1"]);
1441 });
1442
1443 it("should not get confused by properties", function() {
1444 function *gen(args) {
1445 var obj = { arguments: args };
1446 yield obj.arguments;
1447 obj.arguments = "oyez";
1448 yield obj;
1449 }
1450
1451 check(gen(42), [42, { arguments: "oyez" }]);
1452 });
1453
1454 it("supports .callee", function() {
1455 function *gen(doYield) {
1456 yield 1;
1457 if (doYield) {
1458 yield 2;
1459 } else {
1460 yield 3
1461 yield* arguments.callee(true);
1462 yield 4
1463 }
1464 yield 5;
1465 }
1466
1467 check(gen(false), [1, 3, 1, 2, 5, 4, 5]);
1468 });
1469});
1470
1471describe("catch parameter shadowing", function() {
1472 it("should leave outer variables unmodified", function() {
1473 function *gen(x) {
1474 var y = x + 1;
1475 try {
1476 throw x + 2;
1477 } catch (x) {
1478 yield x;
1479 x += 1;
1480 yield x;
1481 }
1482 yield x;
1483 try {
1484 throw x + 3;
1485 } catch (y) {
1486 yield y;
1487 y *= 2;
1488 yield y;
1489 }
1490 yield y;
1491 }
1492
1493 check(gen(1), [3, 4, 1, 4, 8, 2]);
1494 check(gen(2), [4, 5, 2, 5, 10, 3]);
1495 });
1496
1497 it("should not replace variables defined in inner scopes", function() {
1498 function *gen(x) {
1499 try {
1500 throw x;
1501 } catch (x) {
1502 yield x;
1503
1504 yield (function(x) {
1505 return x += 1;
1506 }(x + 1));
1507
1508 yield (function() {
1509 var x = arguments[0];
1510 return x * 2;
1511 }(x + 2));
1512
1513 yield (function() {
1514 function notCalled(x) {
1515 throw x;
1516 }
1517
1518 x >>= 1;
1519 return x;
1520 }());
1521
1522 yield x -= 1;
1523 }
1524
1525 yield x;
1526 }
1527
1528 check(gen(10), [10, 12, 24, 5, 4, 10]);
1529 check(gen(11), [11, 13, 26, 5, 4, 11]);
1530 });
1531
1532 it("should allow nested catch parameters of the same name", function() {
1533 function *gen() {
1534 try {
1535 raise("e1");
1536 } catch (e) {
1537 yield e;
1538 try {
1539 raise("e2");
1540 } catch (e) {
1541 yield e;
1542 }
1543 yield e;
1544 }
1545 }
1546
1547 check(gen(), ["e1", "e2", "e1"]);
1548 });
1549
1550 it("should not interfere with non-referential identifiers", function() {
1551 function *gen() {
1552 try {
1553 yield 1;
1554 raise(new Error("oyez"));
1555 yield 2;
1556 } catch (e) {
1557 yield 3;
1558 e.e = "e.e";
1559 e[e.message] = "e.oyez";
1560 return {
1561 e: e,
1562 identity: function(x) {
1563 var e = x;
1564 return e;
1565 }
1566 };
1567 }
1568 yield 4;
1569 }
1570
1571 var g = gen();
1572 assert.deepEqual(g.next(), { value: 1, done: false });
1573 assert.deepEqual(g.next(), { value: 3, done: false });
1574
1575 var info = g.next();
1576 assert.strictEqual(info.done, true);
1577 assert.strictEqual(info.value.e.message, "oyez");
1578 assert.strictEqual(info.value.e.e, "e.e");
1579 assert.strictEqual(info.value.e.oyez, "e.oyez");
1580 assert.strictEqual(info.value.identity("same"), "same");
1581 });
1582});
1583
1584describe("empty while loops", function() {
1585 it("should be preserved in generated code", function() {
1586 function *gen(x) {
1587 while (x) {
1588 // empty while loop
1589 }
1590
1591 do {
1592 // empty do-while loop
1593 } while (x);
1594
1595 return gen.toString();
1596 }
1597
1598 var info = gen(false).next();
1599 assert.strictEqual(info.done, true);
1600 assert.ok(/empty while loop/.test(info.value));
1601 assert.ok(/empty do-while loop/.test(info.value));
1602 });
1603});
1604
1605describe("object literals with multiple yields", function() {
1606 it("should receive different sent values", function() {
1607 function *gen(fn) {
1608 return {
1609 a: yield "a",
1610 b: yield "b",
1611 c: fn(yield "c", yield "d"),
1612 d: [yield "e", yield "f"]
1613 };
1614 }
1615
1616 check(gen(function sum(x, y) {
1617 return x + y;
1618 }), ["a", "b", "c", "d", "e", "f"], {
1619 a: 1,
1620 b: 2,
1621 c: 3 + 4,
1622 d: [5, 6]
1623 });
1624 });
1625});
1626
1627describe("generator .throw method", function() {
1628 (runningInTranslation ? it : xit)("should complete generator", function() {
1629 function *gen(x) {
1630 yield 2;
1631 throw 1;
1632 }
1633
1634 var u = gen();
1635
1636 u.next();
1637
1638 try {
1639 u.throw(2);
1640 } catch (err) {
1641 assert.strictEqual(err, 2);
1642 }
1643
1644 assertAlreadyFinished(u);
1645 });
1646
1647 it("should work after the final call to .next", function() {
1648 function *gen() {
1649 yield 1;
1650 }
1651
1652 var g = gen();
1653 assert.deepEqual(g.next(), { value: 1, done: false });
1654
1655 var exception = new Error("unhandled exception");
1656 try {
1657 g.throw(exception);
1658 assert.ok(false, "should have thrown an exception");
1659 } catch (err) {
1660 assert.strictEqual(err, exception);
1661 }
1662 });
1663
1664 it("should immediately complete a new-born generator", function() {
1665 var began = false;
1666
1667 function *gen() {
1668 began = true;
1669 yield 1;
1670 }
1671
1672 var g = gen();
1673 var exception = new Error("unhandled exception");
1674 try {
1675 g.throw(exception);
1676 assert.ok(false, "should have thrown an exception");
1677 } catch (err) {
1678 assert.strictEqual(err, exception);
1679 assert.strictEqual(began, false);
1680 }
1681 });
1682
1683 it("should not propagate errors handled inside a delegate", function() {
1684 function *outer() {
1685 try {
1686 yield* inner();
1687 } catch (err) {
1688 return -1;
1689 }
1690 return 1;
1691 }
1692
1693 function *inner() {
1694 try {
1695 yield void 0;
1696 } catch (e) {
1697 return;
1698 }
1699 }
1700
1701 var g = outer();
1702 g.next();
1703 assert.equal(g.throw(new Error('foo')).value, 1);
1704 });
1705
1706 it("should propagate errors unhandled inside a delegate", function() {
1707 function *outer() {
1708 try {
1709 yield* inner();
1710 } catch (err) {
1711 return -1;
1712 }
1713 return 1;
1714 }
1715
1716 function *inner() {
1717 yield void 0;
1718 }
1719
1720 var g = outer();
1721 g.next();
1722 assert.equal(g.throw(new Error('foo')).value, -1);
1723 });
1724});
1725
1726describe("unqualified function calls", function() {
1727 it("should have a global `this` object", function() {
1728 function getThis() {
1729 return this;
1730 }
1731
1732 // This is almost certainly the global object, but there's a chance it
1733 // might be null or undefined (in strict mode).
1734 var unqualifiedThis = getThis();
1735
1736 function *invoke() {
1737 // It seems like a bug in the ES6 spec that we have to yield an
1738 // argument instead of just calling (yield)().
1739 return (yield "dummy")();
1740 }
1741
1742 var g = invoke();
1743 var info = g.next();
1744
1745 assert.deepEqual(info, { value: "dummy", done: false });
1746
1747 info = g.next(getThis);
1748
1749 // Avoid using assert.strictEqual when the arguments might equal the
1750 // global object, since JSON.stringify chokes on circular structures.
1751 assert.ok(info.value === unqualifiedThis);
1752
1753 assert.strictEqual(info.done, true);
1754 });
1755});
1756
1757describe("yield* expression results", function () {
1758 it("have correct values", function () {
1759 function* foo() {
1760 yield 0;
1761 return yield* bar();
1762 }
1763
1764 function* bar() {
1765 yield 1;
1766 return 2;
1767 }
1768
1769 check(foo(), [0, 1], 2);
1770 });
1771
1772 it("can be used in complex expressions", function () {
1773 function pumpNumber(gen) {
1774 var n = 0;
1775
1776 while (true) {
1777 var res = n > 0 ? gen.next(n) : gen.next();
1778 n = res.value;
1779 if (res.done) {
1780 return n;
1781 }
1782 }
1783 }
1784
1785 function* foo() {
1786 return (yield* bar()) + (yield* bar());
1787 }
1788
1789 function* bar() {
1790 return (yield 2) + (yield 3);
1791 }
1792
1793 assert.strictEqual(pumpNumber(bar()), 5);
1794 assert.strictEqual(pumpNumber(foo()), 10);
1795 });
1796});
1797
1798describe("isGeneratorFunction", function() {
1799 it("should work for function declarations", function() {
1800 // Do the assertions up here to make sure the generator function is
1801 // marked at the beginning of the block the function is declared in.
1802 assert.strictEqual(
1803 regeneratorRuntime.isGeneratorFunction(genFun),
1804 true
1805 );
1806
1807 assert.strictEqual(
1808 regeneratorRuntime.isGeneratorFunction(normalFun),
1809 false
1810 );
1811
1812 function normalFun() {
1813 return 0;
1814 }
1815
1816 function *genFun() {
1817 yield 0;
1818 }
1819 });
1820
1821 it("should work for function expressions", function() {
1822 assert.strictEqual(
1823 regeneratorRuntime.isGeneratorFunction(function *genFun() {
1824 yield 0;
1825 }),
1826 true
1827 );
1828
1829 assert.strictEqual(
1830 regeneratorRuntime.isGeneratorFunction(function normalFun() {
1831 return 0;
1832 }),
1833 false
1834 );
1835 });
1836});
1837
1838describe("new expressions", function() {
1839 it("should be able to contain yield sub-expressions", function() {
1840 function A(first, second) {
1841 this.first = first;
1842 this.second = second;
1843 }
1844
1845 function *gen() {
1846 return yield new (yield 0)(yield 1, yield 2);
1847 }
1848
1849 var g = gen();
1850
1851 assert.deepEqual(g.next(), { value: 0, done: false });
1852 assert.deepEqual(g.next(A), { value: 1, done: false });
1853 assert.deepEqual(g.next("asdf"), { value: 2, done: false });
1854
1855 var info = g.next("zxcv");
1856 assert.strictEqual(info.done, false);
1857 assert.ok(info.value instanceof A);
1858 assert.strictEqual(info.value.first, "asdf");
1859 assert.strictEqual(info.value.second, "zxcv");
1860
1861 assert.deepEqual(g.next("qwer"), { value: "qwer", done: true });
1862 });
1863});
1864
1865describe("block binding", function() {
1866 it("should translate block binding correctly", function() {
1867 "use strict";
1868
1869 function *gen() {
1870 var a$0 = 0, a$1 = 1;
1871
1872 let a = 3;
1873
1874 {
1875 let a = 1;
1876 yield a + a$0;
1877 }
1878
1879 {
1880 let a = 2;
1881 yield a - 1 + a$1;
1882 }
1883
1884 yield a;
1885 }
1886
1887 var g = gen();
1888
1889 assert.deepEqual(g.next(), { value: 1, done: false });
1890 assert.deepEqual(g.next(), { value: 2, done: false });
1891 assert.deepEqual(g.next(), { value: 3, done: false });
1892 assert.deepEqual(g.next(), { value: void 0, done: true });
1893 });
1894
1895 it("should translate block binding with iife correctly", function() {
1896 "use strict";
1897
1898 function *gen() {
1899 let arr = [];
1900
1901 for (let x = 0; x < 3; x++) {
1902 let y = x;
1903 arr.push(function() { return y; });
1904 }
1905
1906 {
1907 let x;
1908 while( x = arr.pop() ) {
1909 yield x;
1910 }
1911 }
1912 }
1913
1914 var g = gen();
1915
1916 assert.equal(g.next().value(), 2);
1917 assert.equal(g.next().value(), 1);
1918 assert.equal(g.next().value(), 0);
1919 assert.deepEqual(g.next(), { value: void 0, done: true });
1920 });
1921});
1922
1923describe("newborn generators", function() {
1924 it("should be able to yield* non-newborn generators", function() {
1925 function *inner() {
1926 return [yield 1, yield 2];
1927 }
1928
1929 function *outer(delegate) {
1930 return yield* delegate;
1931 }
1932
1933 var n = inner();
1934
1935 assert.deepEqual(n.next(), {
1936 value: 1,
1937 done: false
1938 });
1939
1940 var g = outer(n);
1941
1942 // I would really like to be able to pass 3 to g.next here, but V8
1943 // ignores values sent to newborn generators, and SpiderMonkey throws
1944 // a TypeError.
1945 assert.deepEqual(g.next(), {
1946 value: 2,
1947 done: false
1948 });
1949
1950 assert.deepEqual(g.next(4), {
1951 value: [void 0, 4],
1952 done: true
1953 });
1954 });
1955
1956 it("should support the ignore-initial-yield wrapper idiom", function() {
1957 var markers = [];
1958
1959 function *inner() {
1960 markers.push(0);
1961 var sent1 = yield 1;
1962 markers.push(2);
1963 var sent2 = yield 2;
1964 markers.push(3);
1965 return [sent1, sent2];
1966 }
1967
1968 function wrapper(delegate) {
1969 var gen = (function*() {
1970 // This yield is the "initial yield" whose argument we ignore.
1971 var sent = yield "ignored", info;
1972
1973 markers.push(1);
1974
1975 while (!(info = delegate.next(sent)).done) {
1976 sent = yield info.value;
1977 }
1978
1979 markers.push(4);
1980
1981 return info.value;
1982 })();
1983
1984 // Ensure that gen is not newborn and that the next invocation of
1985 // gen.next(value) can send value to the initial yield expression.
1986 gen.next();
1987
1988 return gen;
1989 }
1990
1991 var n = inner();
1992
1993 assert.deepEqual(n.next(), {
1994 value: 1,
1995 done: false
1996 });
1997
1998 var g = wrapper(n);
1999
2000 // Unlike in the previous spec, it's fine to pass 3 to g.next here,
2001 // because g is not newborn, because g.next was already called once
2002 // before g was returned from the wrapper function.
2003 assert.deepEqual(g.next(3), {
2004 value: 2,
2005 done: false
2006 });
2007
2008 assert.deepEqual(g.next(4), {
2009 value: [3, 4],
2010 done: true
2011 });
2012
2013 // Ensure we encountered the marker points in the expected order.
2014 assert.deepEqual(markers, [0, 1, 2, 3, 4]);
2015 });
2016
2017 it("should allow chaining newborn and non-newborn generators", function() {
2018 function *range(n) {
2019 for (var i = 0; i < n; ++i) {
2020 yield i;
2021 }
2022 }
2023
2024 function *chain(a, b) {
2025 yield* a;
2026 yield* b;
2027 }
2028
2029 check(chain(range(3), range(5)), [0, 1, 2, 0, 1, 2, 3, 4]);
2030
2031 function *y3(x) {
2032 return yield yield yield x;
2033 }
2034
2035 function *y5(x) {
2036 return yield yield yield yield yield x;
2037 }
2038
2039 check(
2040 chain(y3("foo"), y5("bar")),
2041 ["foo", 1, 2, "bar", 4, 5, 6, 7]
2042 );
2043
2044 var g3 = y3("three");
2045 assert.deepEqual(g3.next(), {
2046 value: "three",
2047 done: false
2048 });
2049
2050 var g5 = y5("five");
2051 assert.deepEqual(g5.next(), {
2052 value: "five",
2053 done: false
2054 });
2055
2056 var undef; // A little easier to read than void 0.
2057 check(chain(g3, g5), [undef, 1, undef, 3, 4, 5]);
2058 });
2059});
2060
2061describe("labeled break and continue statements", function() {
2062 it("should be able to exit multiple try statements", function() {
2063 var e1 = "first";
2064 var e2 = "second";
2065 var e3 = "third";
2066 var e4 = "fourth";
2067
2068 function *gen(n, which) {
2069 try {
2070 yield 0;
2071 raise(e1);
2072
2073 } finally {
2074 yield 1;
2075
2076 loop:
2077 for (var i = 0; i < n; ++i) {
2078 yield i;
2079
2080 try {
2081 raise(e2);
2082 } finally {
2083 yield 2;
2084
2085 try {
2086 raise(e3);
2087 } finally {
2088 yield 3;
2089
2090 try {
2091 raise(e4);
2092 } finally {
2093 yield 4;
2094
2095 if (which === "break") {
2096 yield "breaking";
2097 break loop;
2098 }
2099
2100 if (which === "continue") {
2101 yield "continuing";
2102 continue loop;
2103 }
2104
2105 yield 5;
2106 }
2107 }
2108 }
2109 }
2110
2111 yield 6;
2112 }
2113 }
2114
2115 try {
2116 check(gen(1, "break"), [
2117 0, 1, 0, 2, 3, 4, "breaking", 6
2118 ]);
2119 assert.ok(false, "should have thrown an exception");
2120 } catch (err) {
2121 assert.strictEqual(err, e1);
2122 }
2123
2124 try {
2125 check(gen(3, "continue"), [
2126 0, 1, 0, 2, 3, 4, "continuing",
2127 1, 2, 3, 4, "continuing",
2128 2, 2, 3, 4, "continuing",
2129 6 // Loop finished naturally.
2130 ]);
2131 assert.ok(false, "should have thrown an exception");
2132 } catch (err) {
2133 assert.strictEqual(err, e1);
2134 }
2135
2136 try {
2137 check(gen(3, "neither"), [
2138 0, 1, 0, 2, 3, 4, 5
2139 ]);
2140 assert.ok(false, "should have thrown an exception");
2141 } catch (err) {
2142 assert.strictEqual(err, e4);
2143 }
2144 });
2145
2146 it("should allow breaking from any labeled statement", function() {
2147 function* gen(limit) {
2148 yield 0;
2149
2150 for (var i = 0; i < limit; ++i) {
2151 yield 1;
2152
2153 label1: {
2154 yield 2;
2155 break label1;
2156 yield 3;
2157 }
2158
2159 label2:
2160 if (limit === 3) label3: {
2161 yield 4;
2162 if (i === 0) break label2;
2163 yield 5;
2164 if (i === 1) break label3;
2165 label4: yield 6;
2166 // This should break from the for-loop.
2167 if (i === 2) xxx: break;
2168 yield 7;
2169 }
2170
2171 // This should be a no-op.
2172 xxx: break xxx;
2173
2174 yield 8
2175 }
2176
2177 yield 9;
2178 }
2179
2180 check(gen(0), [0, 9]);
2181 check(gen(1), [0, 1, 2, 8, 9]);
2182 check(gen(2), [0, 1, 2, 8, 1, 2, 8, 9]);
2183 check(gen(3), [0, 1, 2, 4, 8, 1, 2, 4, 5, 8, 1, 2, 4, 5, 6, 9]);
2184 });
2185});
2186
2187describe("for loop with var decl and no update expression", function() {
2188 // https://github.com/facebook/regenerator/issues/103
2189 function *range() {
2190 for (var i = 0; false; ) {
2191 }
2192 }
2193
2194 it("should compile and run", function() {
2195 check(range(), []);
2196 });
2197});
2198
2199describe("generator function prototype", function() {
2200 function getProto(obj) {
2201 return Object.getPrototypeOf
2202 ? Object.getPrototypeOf(obj)
2203 : obj.__proto__;
2204 }
2205
2206 it("should follow the expected object model", function() {
2207 var GeneratorFunctionPrototype = getProto(f);
2208 var GeneratorFunction = GeneratorFunctionPrototype.constructor;
2209
2210 assert.strictEqual(GeneratorFunction.name, 'GeneratorFunction');
2211 assert.strictEqual(GeneratorFunction.prototype,
2212 GeneratorFunctionPrototype);
2213 assert.strictEqual(GeneratorFunctionPrototype.prototype.constructor,
2214 GeneratorFunctionPrototype);
2215 assert.strictEqual(GeneratorFunctionPrototype.prototype,
2216 getProto(f.prototype));
2217 assert.strictEqual(getProto(GeneratorFunctionPrototype),
2218 Function.prototype);
2219
2220 if (typeof process === "undefined" ||
2221 process.version.slice(1, 3) === "0.") {
2222 // Node version strings start with 0.
2223 assert.strictEqual(GeneratorFunctionPrototype.name,
2224 "GeneratorFunctionPrototype");
2225 } else if (process.version.slice(1, 3) === "1.") {
2226 // iojs version strings start with 1., and iojs gets this .name
2227 // property wrong. TODO report this?
2228 assert.strictEqual(GeneratorFunctionPrototype.name, "");
2229 }
2230
2231 assert.strictEqual(typeof f2, "function");
2232 assert.strictEqual(f2.constructor, GeneratorFunction);
2233 assert.ok(f2 instanceof GeneratorFunction);
2234 assert.strictEqual(f2.name, "f2");
2235
2236 var g = f();
2237 assert.ok(g instanceof f);
2238 assert.strictEqual(getProto(g), f.prototype);
2239
2240 assert.deepEqual([], Object.getOwnPropertyNames(f.prototype));
2241 // assert.deepEqual([], Object.getOwnPropertyNames(g));
2242
2243 f.prototype.x = 42;
2244
2245 var g2 = f();
2246 assert.strictEqual(g2.x, 42);
2247
2248 var g3 = new f();
2249 assert.strictEqual(g3.x, 42);
2250
2251 function* f2() {
2252 yield 1;
2253 }
2254
2255 assert.strictEqual(getProto(f), getProto(f2));
2256 assert.strictEqual(f.hasOwnProperty('constructor'), false);
2257 assert.strictEqual(getProto(f).constructor.name, 'GeneratorFunction');
2258
2259 // Intentionally at the end to test hoisting.
2260 function* f() {
2261 yield this;
2262 }
2263
2264 function* f() {
2265 yield 1;
2266 }
2267
2268 var f2 = f;
2269 f = 42;
2270 var g = f2();
2271
2272 assert.deepEqual(g.next(), { value: 1, done: false });
2273 assert.deepEqual(g.next(), { value: void 0, done: true });
2274 assert.ok(g instanceof f2);
2275 });
2276});
2277
2278describe("for-of loops", function() {
2279 (runningInTranslation ? it : xit)
2280 ("should work for Arrays", function() {
2281 var sum = 0;
2282 for (var x of [1, 2].concat(3)) {
2283 sum += x;
2284 }
2285 assert.strictEqual(sum, 6);
2286 });
2287
2288 it("should work for generators", function() {
2289 var value, values = [];
2290 for (value of range(3))
2291 values.push(value);
2292 assert.deepEqual(values, [0, 1, 2]);
2293 });
2294
2295 it("should work inside of generators", function() {
2296 function *yieldPermutations(list) {
2297 if (list.length < 2) {
2298 yield list;
2299 return 1;
2300 }
2301
2302 var count = 0;
2303 var first = list.slice(0, 1);
2304 var genRest = yieldPermutations(list.slice(1));
2305
2306 for (var perm of genRest) {
2307 for (var i = 0; i < list.length; ++i) {
2308 var prefix = perm.slice(0, i);
2309 var suffix = perm.slice(i);
2310 yield prefix.concat(first, suffix);
2311 }
2312
2313 count += i;
2314 }
2315
2316 return count;
2317 }
2318
2319 var count = 0;
2320 for (var perm of yieldPermutations([])) {
2321 assert.deepEqual(perm, []);
2322 ++count;
2323 }
2324 assert.strictEqual(count, 1);
2325
2326 check(yieldPermutations([1]), [[1]], 1);
2327
2328 check(yieldPermutations([2, 1]), [
2329 [2, 1],
2330 [1, 2]
2331 ], 2);
2332
2333 check(yieldPermutations([1,3,2]), [
2334 [1, 3, 2],
2335 [3, 1, 2],
2336 [3, 2, 1],
2337 [1, 2, 3],
2338 [2, 1, 3],
2339 [2, 3, 1]
2340 ], 6);
2341 });
2342});
2343
2344describe("generator return method", function() {
2345 if (!runningInTranslation) {
2346 // The return method has not been specified or implemented natively,
2347 // yet, so these tests need only pass in translation.
2348 return;
2349 }
2350
2351 it("should work with newborn generators", function() {
2352 function *gen() {
2353 yield 0;
2354 }
2355
2356 var g = gen();
2357
2358 assert.deepEqual(g.return("argument"), {
2359 value: "argument",
2360 done: true
2361 });
2362
2363 assertAlreadyFinished(g);
2364 });
2365
2366 it("should behave as if generator actually returned", function() {
2367 var executedFinally = false;
2368
2369 function *gen() {
2370 try {
2371 yield 0;
2372 } catch (err) {
2373 assert.ok(false, "should not have executed the catch handler");
2374 } finally {
2375 executedFinally = true;
2376 }
2377 }
2378
2379 var g = gen();
2380 assert.deepEqual(g.next(), { value: 0, done: false });
2381
2382 assert.deepEqual(g.return("argument"), {
2383 value: "argument",
2384 done: true
2385 });
2386
2387 assert.strictEqual(executedFinally, true);
2388 assertAlreadyFinished(g);
2389 });
2390
2391 it("should return both delegate and delegator", function() {
2392 var checkpoints = [];
2393
2394 function* callee(errorToThrow) {
2395 try {
2396 yield 1;
2397 yield 2;
2398 } finally {
2399 checkpoints.push("callee finally");
2400 if (errorToThrow) {
2401 throw errorToThrow;
2402 }
2403 }
2404 }
2405
2406 function* caller(errorToThrow) {
2407 try {
2408 yield 0;
2409 yield* callee(errorToThrow);
2410 yield 3;
2411 } finally {
2412 checkpoints.push("caller finally");
2413 }
2414 }
2415
2416 var g1 = caller();
2417
2418 assert.deepEqual(g1.next(), { value: 0, done: false });
2419 assert.deepEqual(g1.next(), { value: 1, done: false });
2420 assert.deepEqual(g1.return(-1), { value: -1, done: true });
2421 assert.deepEqual(checkpoints, [
2422 "callee finally",
2423 "caller finally"
2424 ]);
2425
2426 var error = new Error("thrown from callee");
2427 var g2 = caller(error);
2428
2429 assert.deepEqual(g2.next(), { value: 0, done: false });
2430 assert.deepEqual(g2.next(), { value: 1, done: false });
2431
2432 try {
2433 g2.return(-1);
2434 assert.ok(false, "should have thrown an exception");
2435 } catch (thrown) {
2436 assert.strictEqual(thrown, error);
2437 }
2438
2439 assert.deepEqual(checkpoints, [
2440 "callee finally",
2441 "caller finally",
2442 "callee finally",
2443 "caller finally"
2444 ]);
2445 });
2446});
2447
2448describe("expressions containing yield subexpressions", function() {
2449 it("should evaluate all subexpressions before yielding", function() {
2450 function *gen(x) {
2451 return x * (yield (function(y) { x = y }));
2452 }
2453
2454 var g = gen(2);
2455 var result = g.next();
2456 assert.strictEqual(result.done, false);
2457
2458 result.value(5);
2459
2460 assert.deepEqual(g.next(5), {
2461 value: 10,
2462 done: true
2463 });
2464 });
2465
2466 it("should work even with getter member expressions", function() {
2467 function *gen() {
2468 return a.b + (yield "asdf");
2469 }
2470
2471 var a = {};
2472 var b = 0;
2473
2474 Object.defineProperty(a, "b", {
2475 get: function() {
2476 return ++b;
2477 }
2478 });
2479
2480 var g = gen();
2481
2482 assert.strictEqual(a.b, 1);
2483
2484 assert.deepEqual(g.next(), {
2485 value: "asdf",
2486 done: false
2487 });
2488
2489 assert.strictEqual(a.b, 3);
2490
2491 assert.deepEqual(g.next(2), {
2492 value: 4,
2493 done: true
2494 });
2495 });
2496
2497 it("should evaluate all array elements before yielding", function() {
2498 function *gen() {
2499 return [a, yield "asdf", a];
2500 }
2501
2502 var a = 1;
2503 var g = gen();
2504
2505 assert.deepEqual(g.next(), {
2506 value: "asdf",
2507 done: false
2508 });
2509
2510 a = 3;
2511
2512 assert.deepEqual(g.next(2), {
2513 value: [1, 2, 3],
2514 done: true
2515 });
2516 });
2517
2518 it("should handle callee member expressions correctly", function() {
2519 function *gen() {
2520 a = a.slice(0).concat(yield "asdf");
2521 return a;
2522 }
2523
2524 var a = [];
2525 var g = gen();
2526
2527 assert.deepEqual(g.next(), {
2528 value: "asdf",
2529 done: false
2530 });
2531
2532 a.push(1);
2533
2534 assert.deepEqual(g.next(2), {
2535 value: [2],
2536 done: true
2537 });
2538 });
2539
2540 it("should handle implicit stringification correctly", function() {
2541 function *gen() {
2542 return a + (yield "asdf");
2543 }
2544
2545 var a = [1, 2];
2546 var g = gen();
2547
2548 assert.deepEqual(g.next(), {
2549 value: "asdf",
2550 done: false
2551 });
2552
2553 a = [4,5];
2554
2555 assert.deepEqual(g.next(",3"), {
2556 value: "1,2,3",
2557 done: true
2558 });
2559 });
2560});