@soundscript/soundscript 0.1.16 → 0.1.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/json.js +1 -1
  2. package/numerics.js +4 -4
  3. package/package.json +6 -6
  4. package/project-transform/src/checker/rules/flow.js +16 -3
  5. package/project-transform/src/checker/rules/flow.ts +20 -3
  6. package/project-transform/src/checker/rules/unsound_syntax.js +0 -3
  7. package/project-transform/src/checker/rules/unsound_syntax.ts +0 -4
  8. package/project-transform/src/cli.js +1 -1
  9. package/project-transform/src/cli.ts +1 -1
  10. package/project-transform/src/compiler/compile_project.js +75 -9
  11. package/project-transform/src/compiler/compile_project.ts +121 -7
  12. package/project-transform/src/compiler/ir.ts +19 -1
  13. package/project-transform/src/compiler/lower.js +10335 -1477
  14. package/project-transform/src/compiler/lower.ts +16826 -4074
  15. package/project-transform/src/compiler/toolchain.js +36 -4
  16. package/project-transform/src/compiler/toolchain.ts +36 -4
  17. package/project-transform/src/compiler/wasm_js_host_runtime.js +134 -0
  18. package/project-transform/src/compiler/wasm_js_host_runtime.ts +146 -0
  19. package/project-transform/src/compiler/wat_arrays.js +4 -1
  20. package/project-transform/src/compiler/wat_arrays.ts +5 -1
  21. package/project-transform/src/compiler/wat_emitter.js +1497 -311
  22. package/project-transform/src/compiler/wat_emitter.ts +2971 -1017
  23. package/project-transform/src/compiler/wat_tagged.js +5 -0
  24. package/project-transform/src/compiler/wat_tagged.ts +5 -0
  25. package/project-transform/src/compiler_generator_runner.js +2139 -19
  26. package/project-transform/src/compiler_generator_runner.ts +2143 -20
  27. package/project-transform/src/compiler_promise_runner.js +4615 -636
  28. package/project-transform/src/compiler_promise_runner.ts +4703 -659
  29. package/project-transform/src/compiler_test_helpers.js +0 -579
  30. package/project-transform/src/compiler_test_helpers.ts +0 -648
  31. package/project-transform/src/frontend/macro_expander.js +4 -6
  32. package/project-transform/src/frontend/macro_expander.ts +4 -6
  33. package/project-transform/src/frontend/macro_operand_semantics.js +124 -1
  34. package/project-transform/src/frontend/macro_operand_semantics.ts +230 -6
  35. package/project-transform/src/frontend/macro_resolver.js +2 -2
  36. package/project-transform/src/frontend/macro_resolver.ts +2 -1
  37. package/project-transform/src/frontend/project_macro_support.js +29 -5
  38. package/project-transform/src/frontend/project_macro_support.ts +46 -10
@@ -7,11 +7,27 @@ async function runGeneratorCompilerCase(testCase) {
7
7
  assertEquals(result.exitCode, 0, testCase.name);
8
8
  assertEquals(result.diagnostics, [], testCase.name);
9
9
  const instance = await instantiateCompiledModuleInJs(tempDirectory);
10
- const exportName = await resolveQualifiedExportName(tempDirectory, 'main');
10
+ const exportName = await resolveQualifiedExportName(tempDirectory, testCase.exportName ?? 'main');
11
11
  const exported = instance.exports[exportName];
12
+ if (testCase.run) {
13
+ await testCase.run(exported, instance, tempDirectory);
14
+ return;
15
+ }
12
16
  if (typeof exported !== 'function') {
13
17
  throw new Error(`Expected exported function "${exportName}" for ${testCase.name}.`);
14
18
  }
19
+ if ('expectedThrow' in testCase) {
20
+ let threw = false;
21
+ try {
22
+ exported();
23
+ }
24
+ catch (error) {
25
+ threw = true;
26
+ assertEquals(error, testCase.expectedThrow, testCase.name);
27
+ }
28
+ assertEquals(threw, true, `${testCase.name} should throw.`);
29
+ return;
30
+ }
15
31
  assertEquals(exported(), testCase.expected, testCase.name);
16
32
  }
17
33
  async function main() {
@@ -21,7 +37,9 @@ async function main() {
21
37
  }
22
38
  const caseFilter = Deno.env.get('SOUNDSCRIPT_GENERATOR_CASE');
23
39
  const caseFiltersValue = Deno.env.get('SOUNDSCRIPT_GENERATOR_CASES');
24
- const caseFilters = caseFiltersValue ? new Set(JSON.parse(caseFiltersValue)) : undefined;
40
+ const caseFilters = caseFiltersValue
41
+ ? new Set(JSON.parse(caseFiltersValue))
42
+ : undefined;
25
43
  const selectedCases = cases.filter((testCase) => caseFilter ? testCase.name === caseFilter : caseFilters ? caseFilters.has(testCase.name) : true);
26
44
  for (const testCase of selectedCases) {
27
45
  await runGeneratorCompilerCase(testCase);
@@ -46,8 +64,8 @@ const cases = [
46
64
  ' const firstValue = first.done ? 0 : first.value;',
47
65
  ' const secondValue = second.done ? 0 : second.value;',
48
66
  ' const thirdValue = third.done ? third.value : 0;',
49
- ' return (first.done ? 1000000 : 0) + (firstValue * 10000) + (second.done ? 1000 : 0)'
50
- + ' + (secondValue * 100) + (third.done ? 10 : 0) + thirdValue;',
67
+ ' return (first.done ? 1000000 : 0) + (firstValue * 10000) + (second.done ? 1000 : 0)' +
68
+ ' + (secondValue * 100) + (third.done ? 10 : 0) + thirdValue;',
51
69
  '}',
52
70
  '',
53
71
  ].join('\n'),
@@ -68,14 +86,534 @@ const cases = [
68
86
  ' const third = iterator.next();',
69
87
  ' const firstValue = first.done ? 0 : first.value;',
70
88
  ' const secondValue = second.done ? second.value : 0;',
71
- ' return (firstValue * 10000)'
72
- + ' + (first.done ? 1000 : 0)'
73
- + ' + (secondValue * 100)'
74
- + ' + (second.done ? 10 : 0)'
75
- + ' + (third.done ? 1 : 0);',
89
+ ' return (firstValue * 10000)' +
90
+ ' + (first.done ? 1000 : 0)' +
91
+ ' + (secondValue * 100)' +
92
+ ' + (second.done ? 10 : 0)' +
93
+ ' + (third.done ? 1 : 0);',
94
+ '}',
95
+ '',
96
+ ].join('\n'),
97
+ },
98
+ {
99
+ name: 'compileProject exports sync generator functions as host iterators',
100
+ exportName: 'iterate',
101
+ source: [
102
+ 'export function* iterate(): Generator<number, number, unknown> {',
103
+ ' yield 3;',
104
+ ' yield 5;',
105
+ ' return 7;',
106
+ '}',
107
+ '',
108
+ ].join('\n'),
109
+ run: (exported) => {
110
+ if (typeof exported !== 'function') {
111
+ throw new Error('Expected exported sync generator function.');
112
+ }
113
+ const iterator = exported();
114
+ if ((typeof iterator !== 'object' && typeof iterator !== 'function') || iterator === null) {
115
+ throw new Error('Expected exported sync generator to return an iterator object.');
116
+ }
117
+ const next = iterator.next;
118
+ if (typeof next !== 'function') {
119
+ throw new Error('Expected exported sync generator iterator to expose next().');
120
+ }
121
+ const first = iterator.next();
122
+ const second = iterator.next();
123
+ const third = iterator.next();
124
+ assertEquals(first, { value: 3, done: false });
125
+ assertEquals(second, { value: 5, done: false });
126
+ assertEquals(third, { value: 7, done: true });
127
+ },
128
+ },
129
+ {
130
+ name: 'compileProject exports sync generator yielded Promises as host Promises',
131
+ exportName: 'iterate',
132
+ source: [
133
+ 'export function* iterate(): Generator<Promise<number>, void, unknown> {',
134
+ ' yield Promise.resolve(3);',
135
+ '}',
136
+ '',
137
+ ].join('\n'),
138
+ run: async (exported) => {
139
+ if (typeof exported !== 'function') {
140
+ throw new Error('Expected exported sync generator function.');
141
+ }
142
+ const iterator = exported();
143
+ if ((typeof iterator !== 'object' && typeof iterator !== 'function') || iterator === null) {
144
+ throw new Error('Expected exported sync generator to return an iterator object.');
145
+ }
146
+ const first = iterator.next();
147
+ if (!(first.value instanceof Promise)) {
148
+ throw new Error('Expected yielded sync generator Promise to bridge to a host Promise.');
149
+ }
150
+ const second = iterator.next();
151
+ assertEquals(await first.value, 3);
152
+ assertEquals(first.done, false);
153
+ assertEquals(second, { value: undefined, done: true });
154
+ },
155
+ },
156
+ {
157
+ name: 'compileProject exports sync generator return calls as host iterators',
158
+ exportName: 'iterate',
159
+ source: [
160
+ 'export function* iterate(): Generator<number, number, unknown> {',
161
+ ' yield 3;',
162
+ ' yield 5;',
163
+ ' return 7;',
164
+ '}',
165
+ '',
166
+ ].join('\n'),
167
+ run: (exported) => {
168
+ if (typeof exported !== 'function') {
169
+ throw new Error('Expected exported sync generator function.');
170
+ }
171
+ const iterator = exported();
172
+ if ((typeof iterator !== 'object' && typeof iterator !== 'function') || iterator === null) {
173
+ throw new Error('Expected exported sync generator to return an iterator object.');
174
+ }
175
+ const first = iterator.next();
176
+ const second = iterator.return?.(20);
177
+ const third = iterator.next();
178
+ assertEquals(first, { value: 3, done: false });
179
+ assertEquals(second, { value: 20, done: true });
180
+ assertEquals(third, { value: undefined, done: true });
181
+ },
182
+ },
183
+ {
184
+ name: 'compileProject exports sync generator throw calls as host iterators',
185
+ exportName: 'iterate',
186
+ source: [
187
+ 'export function* iterate(): Generator<number, number, number> {',
188
+ ' try {',
189
+ ' yield 3;',
190
+ ' return 8;',
191
+ ' } catch {',
192
+ ' yield 7;',
193
+ ' return 9;',
194
+ ' }',
195
+ '}',
196
+ '',
197
+ ].join('\n'),
198
+ run: (exported) => {
199
+ if (typeof exported !== 'function') {
200
+ throw new Error('Expected exported sync generator function.');
201
+ }
202
+ const iterator = exported();
203
+ if ((typeof iterator !== 'object' && typeof iterator !== 'function') || iterator === null) {
204
+ throw new Error('Expected exported sync generator to return an iterator object.');
205
+ }
206
+ const first = iterator.next();
207
+ const second = iterator.throw?.(5);
208
+ const third = iterator.next();
209
+ assertEquals(first, { value: 3, done: false });
210
+ assertEquals(second, { value: 7, done: false });
211
+ assertEquals(third, { value: 9, done: true });
212
+ },
213
+ },
214
+ {
215
+ name: 'compileProject exports sync generator yield star over local arrays as host iterators',
216
+ exportName: 'iterate',
217
+ source: [
218
+ 'export function* iterate(): Generator<number, number, unknown> {',
219
+ ' const values = [3, 5, 7];',
220
+ ' yield* values;',
221
+ ' return 9;',
222
+ '}',
223
+ '',
224
+ ].join('\n'),
225
+ run: (exported) => {
226
+ if (typeof exported !== 'function') {
227
+ throw new Error('Expected exported sync generator function.');
228
+ }
229
+ const iterator = exported();
230
+ if ((typeof iterator !== 'object' && typeof iterator !== 'function') || iterator === null) {
231
+ throw new Error('Expected exported sync generator to return an iterator object.');
232
+ }
233
+ const first = iterator.next();
234
+ const second = iterator.next();
235
+ const third = iterator.next();
236
+ const fourth = iterator.next();
237
+ assertEquals(first, { value: 3, done: false });
238
+ assertEquals(second, { value: 5, done: false });
239
+ assertEquals(third, { value: 7, done: false });
240
+ assertEquals(fourth, { value: 9, done: true });
241
+ },
242
+ },
243
+ {
244
+ name: 'compileProject exports sync generator yield star over local Promise arrays as host iterators',
245
+ exportName: 'iterate',
246
+ source: [
247
+ 'export function* iterate(): Generator<Promise<number>, number, unknown> {',
248
+ ' const values = [Promise.resolve(3), Promise.resolve(5), Promise.resolve(7)];',
249
+ ' yield* values;',
250
+ ' return 9;',
251
+ '}',
252
+ '',
253
+ ].join('\n'),
254
+ run: async (exported) => {
255
+ if (typeof exported !== 'function') {
256
+ throw new Error('Expected exported sync generator function.');
257
+ }
258
+ const iterator = exported();
259
+ if ((typeof iterator !== 'object' && typeof iterator !== 'function') || iterator === null) {
260
+ throw new Error('Expected exported sync generator to return an iterator object.');
261
+ }
262
+ const first = iterator.next();
263
+ const second = iterator.next();
264
+ const third = iterator.next();
265
+ const fourth = iterator.next();
266
+ if (!(first.value instanceof Promise) || !(second.value instanceof Promise) ||
267
+ !(third.value instanceof Promise)) {
268
+ throw new Error('Expected yielded Promise-array values to bridge to host Promises.');
269
+ }
270
+ assertEquals(await first.value, 3);
271
+ assertEquals(await second.value, 5);
272
+ assertEquals(await third.value, 7);
273
+ assertEquals(fourth, { value: 9, done: true });
274
+ },
275
+ },
276
+ {
277
+ name: 'compileProject exports sync generator throw through array yield star as host iterators',
278
+ exportName: 'iterate',
279
+ source: [
280
+ 'export function* iterate(): Generator<number, number, unknown> {',
281
+ ' yield* [3, 5, 7];',
282
+ ' return 9;',
283
+ '}',
284
+ '',
285
+ ].join('\n'),
286
+ run: (exported) => {
287
+ if (typeof exported !== 'function') {
288
+ throw new Error('Expected exported sync generator function.');
289
+ }
290
+ const iterator = exported();
291
+ if ((typeof iterator !== 'object' && typeof iterator !== 'function') || iterator === null) {
292
+ throw new Error('Expected exported sync generator to return an iterator object.');
293
+ }
294
+ const first = iterator.next();
295
+ assertEquals(first, { value: 3, done: false });
296
+ let threw = false;
297
+ try {
298
+ iterator.throw?.(5);
299
+ }
300
+ catch (error) {
301
+ threw = true;
302
+ assertEquals(error, {
303
+ name: 'TypeError',
304
+ message: 'yield* delegate does not support throw',
305
+ });
306
+ }
307
+ assertEquals(threw, true, 'Expected exported array yield* throw to rethrow to host.');
308
+ },
309
+ },
310
+ {
311
+ name: 'compileProject exports sync generator yield star over iterator-valued locals as host iterators',
312
+ exportName: 'iterate',
313
+ source: [
314
+ 'export function* iterate(): Generator<number, number, unknown> {',
315
+ ' const values = new Map([["a", 3], ["b", 5], ["c", 7]]).values();',
316
+ ' yield* values;',
317
+ ' return 9;',
318
+ '}',
319
+ '',
320
+ ].join('\n'),
321
+ run: (exported) => {
322
+ if (typeof exported !== 'function') {
323
+ throw new Error('Expected exported sync generator function.');
324
+ }
325
+ const iterator = exported();
326
+ if ((typeof iterator !== 'object' && typeof iterator !== 'function') || iterator === null) {
327
+ throw new Error('Expected exported sync generator to return an iterator object.');
328
+ }
329
+ const first = iterator.next();
330
+ const second = iterator.next();
331
+ const third = iterator.next();
332
+ const fourth = iterator.next();
333
+ assertEquals(first, { value: 3, done: false });
334
+ assertEquals(second, { value: 5, done: false });
335
+ assertEquals(third, { value: 7, done: false });
336
+ assertEquals(fourth, { value: 9, done: true });
337
+ },
338
+ },
339
+ {
340
+ name: 'compileProject exports sync generator yield star through sync generator delegates as host iterators',
341
+ exportName: 'outer',
342
+ source: [
343
+ 'function* inner(): Generator<number, number, number> {',
344
+ ' const received = yield 10;',
345
+ ' yield received + 1;',
346
+ ' return received + 2;',
347
+ '}',
348
+ '',
349
+ 'export function* outer(): Generator<number, number, number> {',
350
+ ' const delegated = yield* inner();',
351
+ ' yield delegated + 3;',
352
+ ' return delegated + 4;',
353
+ '}',
354
+ '',
355
+ ].join('\n'),
356
+ run: (exported) => {
357
+ if (typeof exported !== 'function') {
358
+ throw new Error('Expected exported sync generator function.');
359
+ }
360
+ const iterator = exported();
361
+ if ((typeof iterator !== 'object' && typeof iterator !== 'function') || iterator === null) {
362
+ throw new Error('Expected exported sync generator to return an iterator object.');
363
+ }
364
+ const first = iterator.next();
365
+ const second = iterator.next(7);
366
+ const third = iterator.next();
367
+ const fourth = iterator.next();
368
+ assertEquals(first, { value: 10, done: false });
369
+ assertEquals(second, { value: 8, done: false });
370
+ assertEquals(third, { value: 12, done: false });
371
+ assertEquals(fourth, { value: 13, done: true });
372
+ },
373
+ },
374
+ {
375
+ name: 'compileProject exports sync generator throw delegation through yield star as host iterators',
376
+ exportName: 'outer',
377
+ source: [
378
+ 'function* inner(): Generator<number, number, number> {',
379
+ ' try {',
380
+ ' yield 3;',
381
+ ' return 8;',
382
+ ' } catch {',
383
+ ' yield 7;',
384
+ ' return 9;',
385
+ ' }',
386
+ '}',
387
+ '',
388
+ 'export function* outer(): Generator<number, number, number> {',
389
+ ' const delegated = yield* inner();',
390
+ ' yield delegated + 1;',
391
+ ' return delegated + 2;',
392
+ '}',
393
+ '',
394
+ ].join('\n'),
395
+ run: (exported) => {
396
+ if (typeof exported !== 'function') {
397
+ throw new Error('Expected exported sync generator function.');
398
+ }
399
+ const iterator = exported();
400
+ if ((typeof iterator !== 'object' && typeof iterator !== 'function') || iterator === null) {
401
+ throw new Error('Expected exported sync generator to return an iterator object.');
402
+ }
403
+ const first = iterator.next();
404
+ const second = iterator.throw?.(5);
405
+ const third = iterator.next();
406
+ const fourth = iterator.next();
407
+ assertEquals(first, { value: 3, done: false });
408
+ assertEquals(second, { value: 7, done: false });
409
+ assertEquals(third, { value: 10, done: false });
410
+ assertEquals(fourth, { value: 11, done: true });
411
+ },
412
+ },
413
+ {
414
+ name: 'compileProject exports sync generator return delegation through yield star as host iterators',
415
+ exportName: 'outer',
416
+ source: [
417
+ 'function* inner(): Generator<number, number, number> {',
418
+ ' try {',
419
+ ' yield 3;',
420
+ ' yield 5;',
421
+ ' return 7;',
422
+ ' } finally {',
423
+ ' yield 9;',
424
+ ' }',
425
+ '}',
426
+ '',
427
+ 'export function* outer(): Generator<number, number, number> {',
428
+ ' const delegated = yield* inner();',
429
+ ' return delegated + 1;',
430
+ '}',
431
+ '',
432
+ ].join('\n'),
433
+ run: (exported) => {
434
+ if (typeof exported !== 'function') {
435
+ throw new Error('Expected exported sync generator function.');
436
+ }
437
+ const iterator = exported();
438
+ if ((typeof iterator !== 'object' && typeof iterator !== 'function') || iterator === null) {
439
+ throw new Error('Expected exported sync generator to return an iterator object.');
440
+ }
441
+ const first = iterator.next();
442
+ const second = iterator.return?.(4);
443
+ const third = iterator.next();
444
+ const fourth = iterator.next();
445
+ assertEquals(first, { value: 3, done: false });
446
+ assertEquals(second, { value: 9, done: false });
447
+ assertEquals(third, { value: 5, done: true });
448
+ assertEquals(fourth, { value: undefined, done: true });
449
+ },
450
+ },
451
+ {
452
+ name: 'compileProject exports sync generator yielded delegated Promises as host Promises',
453
+ exportName: 'outer',
454
+ source: [
455
+ 'function* inner(): Generator<Promise<number>, number, unknown> {',
456
+ ' const values = [Promise.resolve(3), Promise.resolve(5)];',
457
+ ' yield* values;',
458
+ ' return 7;',
459
+ '}',
460
+ '',
461
+ 'export function* outer(): Generator<Promise<number>, number, unknown> {',
462
+ ' const delegated = yield* inner();',
463
+ ' return delegated + 1;',
464
+ '}',
465
+ '',
466
+ ].join('\n'),
467
+ run: async (exported) => {
468
+ if (typeof exported !== 'function') {
469
+ throw new Error('Expected exported sync generator function.');
470
+ }
471
+ const iterator = exported();
472
+ if ((typeof iterator !== 'object' && typeof iterator !== 'function') || iterator === null) {
473
+ throw new Error('Expected exported sync generator to return an iterator object.');
474
+ }
475
+ const first = iterator.next();
476
+ const second = iterator.next();
477
+ const third = iterator.next();
478
+ if (!(first.value instanceof Promise) || !(second.value instanceof Promise)) {
479
+ throw new Error('Expected delegated yielded Promise values to bridge to host Promises.');
480
+ }
481
+ assertEquals(await first.value, 3);
482
+ assertEquals(await second.value, 5);
483
+ assertEquals(third, { value: 8, done: true });
484
+ },
485
+ },
486
+ {
487
+ name: 'compileProject exports sync generator class methods as host iterators',
488
+ exportName: 'iterateFromCounter',
489
+ source: [
490
+ 'class Counter {',
491
+ ' base = 4;',
492
+ '',
493
+ ' *iterate(): Generator<number, number, unknown> {',
494
+ ' yield this.base;',
495
+ ' yield this.base + 1;',
496
+ ' return this.base + 2;',
497
+ ' }',
498
+ '}',
499
+ '',
500
+ 'export function iterateFromCounter(): Generator<number, number, unknown> {',
501
+ ' return new Counter().iterate();',
502
+ '}',
503
+ '',
504
+ ].join('\n'),
505
+ run: (exported) => {
506
+ if (typeof exported !== 'function') {
507
+ throw new Error('Expected exported generator wrapper function.');
508
+ }
509
+ const iterator = exported();
510
+ const first = iterator.next();
511
+ const second = iterator.next();
512
+ const third = iterator.next();
513
+ assertEquals(first, { value: 4, done: false });
514
+ assertEquals(second, { value: 5, done: false });
515
+ assertEquals(third, { value: 6, done: true });
516
+ },
517
+ },
518
+ {
519
+ name: 'compileProject exports sync generator class methods with super calls as host iterators',
520
+ exportName: 'iterateFromCounter',
521
+ source: [
522
+ 'class Base {',
523
+ ' bump(value: number): number {',
524
+ ' return value + 1;',
525
+ ' }',
526
+ '}',
527
+ '',
528
+ 'class Counter extends Base {',
529
+ ' base = 4;',
530
+ '',
531
+ ' *iterate(): Generator<number, number, unknown> {',
532
+ ' yield super.bump(this.base);',
533
+ ' yield super.bump(this.base + 1);',
534
+ ' return super.bump(this.base + 2);',
535
+ ' }',
536
+ '}',
537
+ '',
538
+ 'export function iterateFromCounter(): Generator<number, number, unknown> {',
539
+ ' return new Counter().iterate();',
540
+ '}',
541
+ '',
542
+ ].join('\n'),
543
+ run: (exported) => {
544
+ if (typeof exported !== 'function') {
545
+ throw new Error('Expected exported generator wrapper function.');
546
+ }
547
+ const iterator = exported();
548
+ const first = iterator.next();
549
+ const second = iterator.next();
550
+ const third = iterator.next();
551
+ assertEquals(first, { value: 5, done: false });
552
+ assertEquals(second, { value: 6, done: false });
553
+ assertEquals(third, { value: 7, done: true });
554
+ },
555
+ },
556
+ {
557
+ name: 'compileProject exports uncaught sync generator builtin Error throws to host iterators',
558
+ exportName: 'iterate',
559
+ source: [
560
+ 'export function* iterate(): Generator<number, number, unknown> {',
561
+ ' yield 3;',
562
+ ' throw new Error("boom");',
563
+ '}',
564
+ '',
565
+ ].join('\n'),
566
+ run: (exported) => {
567
+ if (typeof exported !== 'function') {
568
+ throw new Error('Expected exported sync generator function.');
569
+ }
570
+ const iterator = exported();
571
+ if ((typeof iterator !== 'object' && typeof iterator !== 'function') || iterator === null) {
572
+ throw new Error('Expected exported sync generator to return an iterator object.');
573
+ }
574
+ const first = iterator.next();
575
+ assertEquals(first, { value: 3, done: false });
576
+ let threw = false;
577
+ try {
578
+ iterator.next();
579
+ }
580
+ catch (error) {
581
+ threw = true;
582
+ assertEquals(error, { name: 'Error', message: 'boom' });
583
+ }
584
+ assertEquals(threw, true, 'Expected exported sync generator next() to rethrow Error.');
585
+ },
586
+ },
587
+ {
588
+ name: 'compileProject exports uncaught sync generator throw Error calls to host iterators',
589
+ exportName: 'iterate',
590
+ source: [
591
+ 'export function* iterate(): Generator<number, number, number> {',
592
+ ' yield 3;',
593
+ ' return 8;',
76
594
  '}',
77
595
  '',
78
596
  ].join('\n'),
597
+ run: (exported) => {
598
+ if (typeof exported !== 'function') {
599
+ throw new Error('Expected exported sync generator function.');
600
+ }
601
+ const iterator = exported();
602
+ if ((typeof iterator !== 'object' && typeof iterator !== 'function') || iterator === null) {
603
+ throw new Error('Expected exported sync generator to return an iterator object.');
604
+ }
605
+ const first = iterator.next();
606
+ assertEquals(first, { value: 3, done: false });
607
+ let threw = false;
608
+ try {
609
+ iterator.throw?.(new Error('boom'));
610
+ }
611
+ catch (error) {
612
+ threw = true;
613
+ assertEquals(error, { name: 'Error', message: 'boom' });
614
+ }
615
+ assertEquals(threw, true, 'Expected exported sync generator throw(Error) to rethrow.');
616
+ },
79
617
  },
80
618
  {
81
619
  name: 'compileProject lowers for-of over sync generator results',
@@ -116,21 +654,210 @@ const cases = [
116
654
  ' const second = iterator.next();',
117
655
  ' const third = iterator.next();',
118
656
  ' const fourth = iterator.next();',
119
- ' return (first.done ? 100000 : 0) + ((first.done ? 0 : first.value) * 10000)'
120
- + ' + (second.done ? 1000 : 0) + ((second.done ? 0 : second.value) * 100)'
121
- + ' + ((third.done ? 0 : third.value) * 10) + (fourth.done ? fourth.value : 0);',
657
+ ' return (first.done ? 100000 : 0) + ((first.done ? 0 : first.value) * 10000)' +
658
+ ' + (second.done ? 1000 : 0) + ((second.done ? 0 : second.value) * 100)' +
659
+ ' + ((third.done ? 0 : third.value) * 10) + (fourth.done ? fourth.value : 0);',
122
660
  '}',
123
661
  '',
124
662
  ].join('\n'),
125
663
  },
126
664
  {
127
- name: 'compileProject lowers sync generator for bodies',
128
- expected: 4568,
665
+ name: 'compileProject lowers sync generator do while bodies',
666
+ expected: 456,
129
667
  source: [
130
668
  'function* iterate(): Generator<number, number, unknown> {',
131
669
  ' let index = 0;',
132
- ' for (; index < 3; index = index + 1) {',
670
+ ' do {',
133
671
  ' yield index + 4;',
672
+ ' index = index + 1;',
673
+ ' } while (index < 2);',
674
+ ' return index + 4;',
675
+ '}',
676
+ '',
677
+ 'export function main(): number {',
678
+ ' const iterator = iterate();',
679
+ ' const first = iterator.next();',
680
+ ' const second = iterator.next();',
681
+ ' const third = iterator.next();',
682
+ ' return ((first.done ? 0 : first.value) * 100)' +
683
+ ' + ((second.done ? 0 : second.value) * 10)' +
684
+ ' + (third.done ? third.value : 0);',
685
+ '}',
686
+ '',
687
+ ].join('\n'),
688
+ },
689
+ {
690
+ name: 'compileProject preserves outer locals across sync generator block scoped yields',
691
+ expected: 122,
692
+ source: [
693
+ 'function* iterate(): Generator<number, number, number> {',
694
+ ' let total = 20;',
695
+ ' {',
696
+ ' let total = 0;',
697
+ ' total = yield 1;',
698
+ ' }',
699
+ ' return total + 2;',
700
+ '}',
701
+ '',
702
+ 'export function main(): number {',
703
+ ' const iterator = iterate();',
704
+ ' const first = iterator.next();',
705
+ ' const second = iterator.next(5);',
706
+ ' return ((first.done ? 0 : first.value) * 100) + (second.done ? second.value : 0);',
707
+ '}',
708
+ '',
709
+ ].join('\n'),
710
+ },
711
+ {
712
+ name: 'compileProject preserves sync generator do while continue and break through finally',
713
+ expected: 357621,
714
+ source: [
715
+ 'function* iterate(): Generator<number, number, unknown> {',
716
+ ' let index = 0;',
717
+ ' let total = 0;',
718
+ ' do {',
719
+ ' try {',
720
+ ' index = index + 1;',
721
+ ' if (index === 1) {',
722
+ ' yield 3;',
723
+ ' continue;',
724
+ ' }',
725
+ ' yield 7;',
726
+ ' break;',
727
+ ' } finally {',
728
+ ' total = total + 5;',
729
+ ' yield 5;',
730
+ ' }',
731
+ ' } while (index < 3);',
732
+ ' return total + index;',
733
+ '}',
734
+ '',
735
+ 'export function main(): number {',
736
+ ' const iterator = iterate();',
737
+ ' const first = iterator.next();',
738
+ ' const second = iterator.next();',
739
+ ' const third = iterator.next();',
740
+ ' const fourth = iterator.next();',
741
+ ' const fifth = iterator.next();',
742
+ ' return ((first.done ? 0 : first.value) * 100000)' +
743
+ ' + ((second.done ? 0 : second.value) * 10000)' +
744
+ ' + ((third.done ? 0 : third.value) * 1000)' +
745
+ ' + ((fourth.done ? 0 : fourth.value) * 100)' +
746
+ ' + ((fifth.done ? fifth.value : 0) * 10)' +
747
+ ' + (fifth.done ? 1 : 0);',
748
+ '}',
749
+ '',
750
+ ].join('\n'),
751
+ },
752
+ {
753
+ name: 'compileProject lowers sync generator for of loops over Sets',
754
+ expected: 359,
755
+ source: [
756
+ 'function* iterate(): Generator<number, number, unknown> {',
757
+ ' for (const value of new Set([2, 4])) {',
758
+ ' yield value + 1;',
759
+ ' }',
760
+ ' return 9;',
761
+ '}',
762
+ '',
763
+ 'export function main(): number {',
764
+ ' const iterator = iterate();',
765
+ ' const first = iterator.next();',
766
+ ' const second = iterator.next();',
767
+ ' const third = iterator.next();',
768
+ ' return ((first.done ? 0 : first.value) * 100)' +
769
+ ' + ((second.done ? 0 : second.value) * 10)' +
770
+ ' + (third.done ? third.value : 0);',
771
+ '}',
772
+ '',
773
+ ].join('\n'),
774
+ },
775
+ {
776
+ name: 'compileProject lowers sync generator for of loops over sync generator results',
777
+ expected: 358,
778
+ source: [
779
+ 'function* values(): Generator<number, number, unknown> {',
780
+ ' yield 2;',
781
+ ' yield 4;',
782
+ ' return 9;',
783
+ '}',
784
+ '',
785
+ 'function* iterate(): Generator<number, number, unknown> {',
786
+ ' for (const value of values()) {',
787
+ ' yield value + 1;',
788
+ ' }',
789
+ ' return 8;',
790
+ '}',
791
+ '',
792
+ 'export function main(): number {',
793
+ ' const iterator = iterate();',
794
+ ' const first = iterator.next();',
795
+ ' const second = iterator.next();',
796
+ ' const third = iterator.next();',
797
+ ' return ((first.done ? 0 : first.value) * 100)' +
798
+ ' + ((second.done ? 0 : second.value) * 10)' +
799
+ ' + (third.done ? third.value : 0);',
800
+ '}',
801
+ '',
802
+ ].join('\n'),
803
+ },
804
+ {
805
+ name: 'compileProject lowers sync generator for of loops over Map values iterators',
806
+ expected: 358,
807
+ source: [
808
+ 'function* iterate(): Generator<number, number, unknown> {',
809
+ " for (const value of new Map<string, number>([['a', 2], ['b', 4]]).values()) {",
810
+ ' yield value + 1;',
811
+ ' }',
812
+ ' return 8;',
813
+ '}',
814
+ '',
815
+ 'export function main(): number {',
816
+ ' const iterator = iterate();',
817
+ ' const first = iterator.next();',
818
+ ' const second = iterator.next();',
819
+ ' const third = iterator.next();',
820
+ ' return ((first.done ? 0 : first.value) * 100)' +
821
+ ' + ((second.done ? 0 : second.value) * 10)' +
822
+ ' + (third.done ? third.value : 0);',
823
+ '}',
824
+ '',
825
+ ].join('\n'),
826
+ },
827
+ {
828
+ name: 'compileProject lowers sync generator for of loops over iterator-valued locals',
829
+ expected: 1238,
830
+ source: [
831
+ 'function* iterate(): Generator<number, number, unknown> {',
832
+ ' const values = new Map([["a", 1], ["b", 2], ["c", 3]]).values();',
833
+ ' for (const value of values) {',
834
+ ' yield value;',
835
+ ' }',
836
+ ' return 8;',
837
+ '}',
838
+ '',
839
+ 'export function main(): number {',
840
+ ' const iterator = iterate();',
841
+ ' const first = iterator.next();',
842
+ ' const second = iterator.next();',
843
+ ' const third = iterator.next();',
844
+ ' const fourth = iterator.next();',
845
+ ' return ((first.done ? 0 : first.value) * 1000)' +
846
+ ' + ((second.done ? 0 : second.value) * 100)' +
847
+ ' + ((third.done ? 0 : third.value) * 10)' +
848
+ ' + (fourth.done ? fourth.value : 0);',
849
+ '}',
850
+ '',
851
+ ].join('\n'),
852
+ },
853
+ {
854
+ name: 'compileProject lowers sync generator for of loops over owned number array locals',
855
+ expected: 2468,
856
+ source: [
857
+ 'function* iterate(): Generator<number, number, unknown> {',
858
+ ' const values = [2, 4, 6];',
859
+ ' for (const value of values) {',
860
+ ' yield value;',
134
861
  ' }',
135
862
  ' return 8;',
136
863
  '}',
@@ -141,10 +868,1403 @@ const cases = [
141
868
  ' const second = iterator.next();',
142
869
  ' const third = iterator.next();',
143
870
  ' const fourth = iterator.next();',
144
- ' return ((first.done ? 0 : first.value) * 1000)'
145
- + ' + ((second.done ? 0 : second.value) * 100)'
146
- + ' + ((third.done ? 0 : third.value) * 10)'
147
- + ' + (fourth.done ? fourth.value : 0);',
871
+ ' return ((first.done ? 0 : first.value) * 1000)' +
872
+ ' + ((second.done ? 0 : second.value) * 100)' +
873
+ ' + ((third.done ? 0 : third.value) * 10)' +
874
+ ' + (fourth.done ? fourth.value : 0);',
875
+ '}',
876
+ '',
877
+ ].join('\n'),
878
+ },
879
+ {
880
+ name: 'compileProject lowers sync generator for of loops over owned string array locals',
881
+ expected: 128,
882
+ source: [
883
+ 'function* iterate(): Generator<number, number, unknown> {',
884
+ " const values = ['a', 'b'];",
885
+ ' for (const value of values) {',
886
+ " yield value === 'a' ? 1 : 2;",
887
+ ' }',
888
+ ' return 8;',
889
+ '}',
890
+ '',
891
+ 'export function main(): number {',
892
+ ' const iterator = iterate();',
893
+ ' const first = iterator.next();',
894
+ ' const second = iterator.next();',
895
+ ' const third = iterator.next();',
896
+ ' return ((first.done ? 0 : first.value) * 100)' +
897
+ ' + ((second.done ? 0 : second.value) * 10)' +
898
+ ' + (third.done ? third.value : 0);',
899
+ '}',
900
+ '',
901
+ ].join('\n'),
902
+ },
903
+ {
904
+ name: 'compileProject lowers sync generator for of loops over owned boolean array locals',
905
+ expected: 1018,
906
+ source: [
907
+ 'function* iterate(): Generator<number, number, unknown> {',
908
+ ' const values = [true, false, true];',
909
+ ' for (const value of values) {',
910
+ ' yield value ? 1 : 0;',
911
+ ' }',
912
+ ' return 8;',
913
+ '}',
914
+ '',
915
+ 'export function main(): number {',
916
+ ' const iterator = iterate();',
917
+ ' const first = iterator.next();',
918
+ ' const second = iterator.next();',
919
+ ' const third = iterator.next();',
920
+ ' const fourth = iterator.next();',
921
+ ' return ((first.done ? 0 : first.value) * 1000)' +
922
+ ' + ((second.done ? 0 : second.value) * 100)' +
923
+ ' + ((third.done ? 0 : third.value) * 10)' +
924
+ ' + (fourth.done ? fourth.value : 0);',
925
+ '}',
926
+ '',
927
+ ].join('\n'),
928
+ },
929
+ {
930
+ name: 'compileProject lowers sync generator for of loops over owned tagged array locals',
931
+ expected: 2948,
932
+ source: [
933
+ 'function* iterate(): Generator<number, number, unknown> {',
934
+ " const values: Array<number | string> = [2, 'a', 4];",
935
+ ' for (const value of values) {',
936
+ " yield typeof value === 'number' ? value : 9;",
937
+ ' }',
938
+ ' return 8;',
939
+ '}',
940
+ '',
941
+ 'export function main(): number {',
942
+ ' const iterator = iterate();',
943
+ ' const first = iterator.next();',
944
+ ' const second = iterator.next();',
945
+ ' const third = iterator.next();',
946
+ ' const fourth = iterator.next();',
947
+ ' return ((first.done ? 0 : first.value) * 1000)' +
948
+ ' + ((second.done ? 0 : second.value) * 100)' +
949
+ ' + ((third.done ? 0 : third.value) * 10)' +
950
+ ' + (fourth.done ? fourth.value : 0);',
951
+ '}',
952
+ '',
953
+ ].join('\n'),
954
+ },
955
+ {
956
+ name: 'compileProject lowers sync generator for in loops over ordinary objects',
957
+ expected: 12119,
958
+ source: [
959
+ 'function* iterate(): Generator<number, number, unknown> {',
960
+ ' const pair = { left: 1, right: 2, stop: 3 };',
961
+ ' for (const key in pair) {',
962
+ ' try {',
963
+ ' if (key === "left") {',
964
+ ' continue;',
965
+ ' }',
966
+ ' if (key === "stop") {',
967
+ ' break;',
968
+ ' }',
969
+ ' yield key === "right" ? 2 : 9;',
970
+ ' } finally {',
971
+ ' yield 1;',
972
+ ' }',
973
+ ' }',
974
+ ' return 9;',
975
+ '}',
976
+ '',
977
+ 'export function main(): number {',
978
+ ' const iterator = iterate();',
979
+ ' const first = iterator.next();',
980
+ ' const second = iterator.next();',
981
+ ' const third = iterator.next();',
982
+ ' const fourth = iterator.next();',
983
+ ' const fifth = iterator.next();',
984
+ ' return ((first.done ? 0 : first.value) * 10000)' +
985
+ ' + ((second.done ? 0 : second.value) * 1000)' +
986
+ ' + ((third.done ? 0 : third.value) * 100)' +
987
+ ' + ((fourth.done ? 0 : fourth.value) * 10)' +
988
+ ' + (fifth.done ? fifth.value : 0);',
989
+ '}',
990
+ '',
991
+ ].join('\n'),
992
+ },
993
+ {
994
+ name: 'compileProject lowers sync generator for bodies',
995
+ expected: 4568,
996
+ source: [
997
+ 'function* iterate(): Generator<number, number, unknown> {',
998
+ ' let index = 0;',
999
+ ' for (; index < 3; index = index + 1) {',
1000
+ ' yield index + 4;',
1001
+ ' }',
1002
+ ' return 8;',
1003
+ '}',
1004
+ '',
1005
+ 'export function main(): number {',
1006
+ ' const iterator = iterate();',
1007
+ ' const first = iterator.next();',
1008
+ ' const second = iterator.next();',
1009
+ ' const third = iterator.next();',
1010
+ ' const fourth = iterator.next();',
1011
+ ' return ((first.done ? 0 : first.value) * 1000)' +
1012
+ ' + ((second.done ? 0 : second.value) * 100)' +
1013
+ ' + ((third.done ? 0 : third.value) * 10)' +
1014
+ ' + (fourth.done ? fourth.value : 0);',
1015
+ '}',
1016
+ '',
1017
+ ].join('\n'),
1018
+ },
1019
+ {
1020
+ name: 'compileProject lowers sync generator for let bodies and preserves outer locals',
1021
+ expected: 1223,
1022
+ source: [
1023
+ 'function* iterate(): Generator<number, number, unknown> {',
1024
+ ' let current = 20;',
1025
+ ' for (let current = 0; current < 2; current = current + 1) {',
1026
+ ' yield current + 1;',
1027
+ ' }',
1028
+ ' return current + 3;',
1029
+ '}',
1030
+ '',
1031
+ 'export function main(): number {',
1032
+ ' const iterator = iterate();',
1033
+ ' const first = iterator.next();',
1034
+ ' const second = iterator.next();',
1035
+ ' const third = iterator.next();',
1036
+ ' return ((first.done ? 0 : first.value) * 1000)' +
1037
+ ' + ((second.done ? 0 : second.value) * 100)' +
1038
+ ' + (third.done ? third.value : 0);',
1039
+ '}',
1040
+ '',
1041
+ ].join('\n'),
1042
+ },
1043
+ {
1044
+ name: 'compileProject lowers sync generator for let continue statements and preserves outer locals',
1045
+ expected: 1323,
1046
+ source: [
1047
+ 'function* iterate(): Generator<number, number, unknown> {',
1048
+ ' let current = 20;',
1049
+ ' for (let current = 0; current < 3; current = current + 1) {',
1050
+ ' if (current === 1) {',
1051
+ ' continue;',
1052
+ ' }',
1053
+ ' yield current + 1;',
1054
+ ' }',
1055
+ ' return current + 3;',
1056
+ '}',
1057
+ '',
1058
+ 'export function main(): number {',
1059
+ ' const iterator = iterate();',
1060
+ ' const first = iterator.next();',
1061
+ ' const second = iterator.next();',
1062
+ ' const third = iterator.next();',
1063
+ ' return ((first.done ? 0 : first.value) * 1000)' +
1064
+ ' + ((second.done ? 0 : second.value) * 100)' +
1065
+ ' + (third.done ? third.value : 0);',
1066
+ '}',
1067
+ '',
1068
+ ].join('\n'),
1069
+ },
1070
+ {
1071
+ name: 'compileProject lowers sync generator for let continue through finally and preserves outer locals',
1072
+ expected: 15503731,
1073
+ source: [
1074
+ 'function* iterate(): Generator<number, number, unknown> {',
1075
+ ' let current = 20;',
1076
+ ' for (let current = 0; current < 3; current = current + 1) {',
1077
+ ' try {',
1078
+ ' if (current === 1) {',
1079
+ ' continue;',
1080
+ ' }',
1081
+ ' yield current + 1;',
1082
+ ' } finally {',
1083
+ ' yield 5;',
1084
+ ' }',
1085
+ ' }',
1086
+ ' return current + 3;',
1087
+ '}',
1088
+ '',
1089
+ 'export function main(): number {',
1090
+ ' const iterator = iterate();',
1091
+ ' const first = iterator.next();',
1092
+ ' const second = iterator.next();',
1093
+ ' const third = iterator.next();',
1094
+ ' const fourth = iterator.next();',
1095
+ ' const fifth = iterator.next();',
1096
+ ' const sixth = iterator.next();',
1097
+ ' return ((first.done ? 0 : first.value) * 10000000)' +
1098
+ ' + ((second.done ? 0 : second.value) * 1000000)' +
1099
+ ' + ((third.done ? 0 : third.value) * 100000)' +
1100
+ ' + ((fourth.done ? 0 : fourth.value) * 1000)' +
1101
+ ' + ((fifth.done ? 0 : fifth.value) * 100)' +
1102
+ ' + ((sixth.done ? sixth.value : 0) * 10)' +
1103
+ ' + (sixth.done ? 1 : 0);',
1104
+ '}',
1105
+ '',
1106
+ ].join('\n'),
1107
+ },
1108
+ {
1109
+ name: 'compileProject lowers nested sync generator try finally regions',
1110
+ expected: 15,
1111
+ source: [
1112
+ 'function* iterate(): Generator<number, number, unknown> {',
1113
+ ' let total = 0;',
1114
+ ' try {',
1115
+ ' try {',
1116
+ ' yield 1;',
1117
+ ' } finally {',
1118
+ ' total = total + 2;',
1119
+ ' }',
1120
+ ' } finally {',
1121
+ ' total = total + 3;',
1122
+ ' }',
1123
+ ' return total;',
1124
+ '}',
1125
+ '',
1126
+ 'export function main(): number {',
1127
+ ' const iterator = iterate();',
1128
+ ' const first = iterator.next();',
1129
+ ' const second = iterator.next();',
1130
+ ' return ((first.done ? 0 : first.value) * 10) + (second.done ? second.value : 0);',
1131
+ '}',
1132
+ '',
1133
+ ].join('\n'),
1134
+ },
1135
+ {
1136
+ name: 'compileProject hoists local function declarations inside sync generators across yield boundaries',
1137
+ expected: 222,
1138
+ source: [
1139
+ 'function* iterate(): Generator<number, number, number> {',
1140
+ ' function addTwo(value: number): number {',
1141
+ ' return value + 2;',
1142
+ ' }',
1143
+ ' const received = yield 20;',
1144
+ ' return addTwo(received);',
1145
+ '}',
1146
+ '',
1147
+ 'export function main(): number {',
1148
+ ' const iterator = iterate();',
1149
+ ' const first = iterator.next();',
1150
+ ' const second = iterator.next(20);',
1151
+ ' return ((first.done ? 0 : first.value) * 10) + (second.done ? second.value : 0);',
1152
+ '}',
1153
+ '',
1154
+ ].join('\n'),
1155
+ },
1156
+ {
1157
+ name: 'compileProject preserves hoisted local function captures over persisted generator locals',
1158
+ expected: 22,
1159
+ source: [
1160
+ 'function* iterate(): Generator<number, number, number> {',
1161
+ ' let total = 20;',
1162
+ ' function readTotal(offset: number): number {',
1163
+ ' return total + offset;',
1164
+ ' }',
1165
+ ' total = yield 0;',
1166
+ ' return readTotal(1);',
1167
+ '}',
1168
+ '',
1169
+ 'export function main(): number {',
1170
+ ' const iterator = iterate();',
1171
+ ' iterator.next();',
1172
+ ' const result = iterator.next(21);',
1173
+ ' return result.done ? result.value : 0;',
1174
+ '}',
1175
+ '',
1176
+ ].join('\n'),
1177
+ },
1178
+ {
1179
+ name: 'compileProject hoists block-scoped local function declarations inside sync generators across yield boundaries',
1180
+ expected: 24,
1181
+ source: [
1182
+ 'function* iterate(): Generator<number, number, number> {',
1183
+ ' if (true) {',
1184
+ ' let total = 20;',
1185
+ ' function readTotal(offset: number): number {',
1186
+ ' return total + offset;',
1187
+ ' }',
1188
+ ' total = yield 0;',
1189
+ ' return readTotal(3);',
1190
+ ' }',
1191
+ ' return 0;',
1192
+ '}',
1193
+ '',
1194
+ 'export function main(): number {',
1195
+ ' const iterator = iterate();',
1196
+ ' iterator.next();',
1197
+ ' const result = iterator.next(21);',
1198
+ ' return result.done ? result.value : 0;',
1199
+ '}',
1200
+ '',
1201
+ ].join('\n'),
1202
+ },
1203
+ {
1204
+ name: 'compileProject lowers sync generator class methods',
1205
+ expected: 456,
1206
+ source: [
1207
+ 'class Counter {',
1208
+ ' *iterate(): Generator<number, number, unknown> {',
1209
+ ' yield 4;',
1210
+ ' yield 5;',
1211
+ ' return 6;',
1212
+ ' }',
1213
+ '}',
1214
+ '',
1215
+ 'export function main(): number {',
1216
+ ' const iterator = new Counter().iterate();',
1217
+ ' const first = iterator.next();',
1218
+ ' const second = iterator.next();',
1219
+ ' const third = iterator.next();',
1220
+ ' return ((first.done ? 0 : first.value) * 100)' +
1221
+ ' + ((second.done ? 0 : second.value) * 10)' +
1222
+ ' + (third.done ? third.value : 0);',
1223
+ '}',
1224
+ '',
1225
+ ].join('\n'),
1226
+ },
1227
+ {
1228
+ name: 'compileProject lowers sync generator class methods with this field reads',
1229
+ expected: 456,
1230
+ source: [
1231
+ 'class Counter {',
1232
+ ' base = 4;',
1233
+ '',
1234
+ ' *iterate(): Generator<number, number, unknown> {',
1235
+ ' yield this.base;',
1236
+ ' yield this.base + 1;',
1237
+ ' return this.base + 2;',
1238
+ ' }',
1239
+ '}',
1240
+ '',
1241
+ 'export function main(): number {',
1242
+ ' const iterator = new Counter().iterate();',
1243
+ ' const first = iterator.next();',
1244
+ ' const second = iterator.next();',
1245
+ ' const third = iterator.next();',
1246
+ ' return ((first.done ? 0 : first.value) * 100)' +
1247
+ ' + ((second.done ? 0 : second.value) * 10)' +
1248
+ ' + (third.done ? third.value : 0);',
1249
+ '}',
1250
+ '',
1251
+ ].join('\n'),
1252
+ },
1253
+ {
1254
+ name: 'compileProject lowers sync generator class methods with super calls',
1255
+ expected: 567,
1256
+ source: [
1257
+ 'class Base {',
1258
+ ' bump(value: number): number {',
1259
+ ' return value + 1;',
1260
+ ' }',
1261
+ '}',
1262
+ '',
1263
+ 'class Counter extends Base {',
1264
+ ' base = 4;',
1265
+ '',
1266
+ ' *iterate(): Generator<number, number, unknown> {',
1267
+ ' yield super.bump(this.base);',
1268
+ ' yield super.bump(this.base + 1);',
1269
+ ' return super.bump(this.base + 2);',
1270
+ ' }',
1271
+ '}',
1272
+ '',
1273
+ 'export function main(): number {',
1274
+ ' const iterator = new Counter().iterate();',
1275
+ ' const first = iterator.next();',
1276
+ ' const second = iterator.next();',
1277
+ ' const third = iterator.next();',
1278
+ ' return ((first.done ? 0 : first.value) * 100)' +
1279
+ ' + ((second.done ? 0 : second.value) * 10)' +
1280
+ ' + (third.done ? third.value : 0);',
1281
+ '}',
1282
+ '',
1283
+ ].join('\n'),
1284
+ },
1285
+ {
1286
+ name: 'compileProject lowers sync generator static class methods',
1287
+ expected: 456,
1288
+ source: [
1289
+ 'class Counter {',
1290
+ ' static *iterate(): Generator<number, number, unknown> {',
1291
+ ' yield 4;',
1292
+ ' yield 5;',
1293
+ ' return 6;',
1294
+ ' }',
1295
+ '}',
1296
+ '',
1297
+ 'export function main(): number {',
1298
+ ' const iterator = Counter.iterate();',
1299
+ ' const first = iterator.next();',
1300
+ ' const second = iterator.next();',
1301
+ ' const third = iterator.next();',
1302
+ ' return ((first.done ? 0 : first.value) * 100)' +
1303
+ ' + ((second.done ? 0 : second.value) * 10)' +
1304
+ ' + (third.done ? third.value : 0);',
1305
+ '}',
1306
+ '',
1307
+ ].join('\n'),
1308
+ },
1309
+ {
1310
+ name: 'compileProject lowers sync generator static class methods with this field reads',
1311
+ expected: 456,
1312
+ source: [
1313
+ 'class Counter {',
1314
+ ' static base = 4;',
1315
+ '',
1316
+ ' static *iterate(): Generator<number, number, unknown> {',
1317
+ ' yield this.base;',
1318
+ ' yield this.base + 1;',
1319
+ ' return this.base + 2;',
1320
+ ' }',
1321
+ '}',
1322
+ '',
1323
+ 'export function main(): number {',
1324
+ ' const iterator = Counter.iterate();',
1325
+ ' const first = iterator.next();',
1326
+ ' const second = iterator.next();',
1327
+ ' const third = iterator.next();',
1328
+ ' return ((first.done ? 0 : first.value) * 100)' +
1329
+ ' + ((second.done ? 0 : second.value) * 10)' +
1330
+ ' + (third.done ? third.value : 0);',
1331
+ '}',
1332
+ '',
1333
+ ].join('\n'),
1334
+ },
1335
+ {
1336
+ name: 'compileProject lowers local object literal sync generator methods',
1337
+ expected: 456,
1338
+ source: [
1339
+ 'export function main(): number {',
1340
+ ' const counter = {',
1341
+ ' *iterate(): Generator<number, number, unknown> {',
1342
+ ' yield 4;',
1343
+ ' yield 5;',
1344
+ ' return 6;',
1345
+ ' },',
1346
+ ' };',
1347
+ ' const iterator = counter.iterate();',
1348
+ ' const first = iterator.next();',
1349
+ ' const second = iterator.next();',
1350
+ ' const third = iterator.next();',
1351
+ ' return ((first.done ? 0 : first.value) * 100)' +
1352
+ ' + ((second.done ? 0 : second.value) * 10)' +
1353
+ ' + (third.done ? third.value : 0);',
1354
+ '}',
1355
+ '',
1356
+ ].join('\n'),
1357
+ },
1358
+ {
1359
+ name: 'compileProject lowers local object literal sync generator methods with this field reads',
1360
+ expected: 456,
1361
+ source: [
1362
+ 'export function main(): number {',
1363
+ ' const counter = {',
1364
+ ' base: 4,',
1365
+ ' *iterate(): Generator<number, number, unknown> {',
1366
+ ' yield this.base;',
1367
+ ' yield this.base + 1;',
1368
+ ' return this.base + 2;',
1369
+ ' },',
1370
+ ' };',
1371
+ ' const iterator = counter.iterate();',
1372
+ ' const first = iterator.next();',
1373
+ ' const second = iterator.next();',
1374
+ ' const third = iterator.next();',
1375
+ ' return ((first.done ? 0 : first.value) * 100)' +
1376
+ ' + ((second.done ? 0 : second.value) * 10)' +
1377
+ ' + (third.done ? third.value : 0);',
1378
+ '}',
1379
+ '',
1380
+ ].join('\n'),
1381
+ },
1382
+ {
1383
+ name: 'compileProject lowers sync generator yield star delegation',
1384
+ expected: 10081213,
1385
+ source: [
1386
+ 'function* inner(): Generator<number, number, number> {',
1387
+ ' const received = yield 10;',
1388
+ ' yield received + 1;',
1389
+ ' return received + 2;',
1390
+ '}',
1391
+ '',
1392
+ 'function* outer(): Generator<number, number, number> {',
1393
+ ' const delegated = yield* inner();',
1394
+ ' yield delegated + 3;',
1395
+ ' return delegated + 4;',
1396
+ '}',
1397
+ '',
1398
+ 'export function main(): number {',
1399
+ ' const iterator = outer();',
1400
+ ' const first = iterator.next();',
1401
+ ' const second = iterator.next(7);',
1402
+ ' const third = iterator.next();',
1403
+ ' const fourth = iterator.next();',
1404
+ ' return ((first.done ? 0 : first.value) * 1000000)' +
1405
+ ' + ((second.done ? 0 : second.value) * 10000)' +
1406
+ ' + ((third.done ? 0 : third.value) * 100)' +
1407
+ ' + (fourth.done ? fourth.value : 0);',
1408
+ '}',
1409
+ '',
1410
+ ].join('\n'),
1411
+ },
1412
+ {
1413
+ name: 'compileProject lowers sync generator yield star over arrays',
1414
+ expected: 3579,
1415
+ source: [
1416
+ 'function* outer(): Generator<number, number, unknown> {',
1417
+ ' yield* [3, 5, 7];',
1418
+ ' return 9;',
1419
+ '}',
1420
+ '',
1421
+ 'export function main(): number {',
1422
+ ' const iterator = outer();',
1423
+ ' const first = iterator.next();',
1424
+ ' const second = iterator.next();',
1425
+ ' const third = iterator.next();',
1426
+ ' const fourth = iterator.next();',
1427
+ ' return ((first.done ? 0 : first.value) * 1000)' +
1428
+ ' + ((second.done ? 0 : second.value) * 100)' +
1429
+ ' + ((third.done ? 0 : third.value) * 10)' +
1430
+ ' + (fourth.done ? fourth.value : 0);',
1431
+ '}',
1432
+ '',
1433
+ ].join('\n'),
1434
+ },
1435
+ {
1436
+ name: 'compileProject lowers sync generator return during array yield star',
1437
+ expected: 3081,
1438
+ source: [
1439
+ 'function* outer(): Generator<number, number, unknown> {',
1440
+ ' yield* [3, 5, 7];',
1441
+ ' return 9;',
1442
+ '}',
1443
+ '',
1444
+ 'export function main(): number {',
1445
+ ' const iterator = outer();',
1446
+ ' const first = iterator.next();',
1447
+ ' const second = iterator.return(8);',
1448
+ ' const third = iterator.next();',
1449
+ ' return ((first.done ? 0 : first.value) * 1000)' +
1450
+ ' + ((second.done ? second.value : 0) * 10)' +
1451
+ ' + (third.done ? 1 : 0);',
1452
+ '}',
1453
+ '',
1454
+ ].join('\n'),
1455
+ },
1456
+ {
1457
+ name: 'compileProject lowers sync generator yield star over iterator-valued locals',
1458
+ expected: 3579,
1459
+ source: [
1460
+ 'function* outer(): Generator<number, number, unknown> {',
1461
+ ' const values = new Map([["a", 3], ["b", 5], ["c", 7]]).values();',
1462
+ ' yield* values;',
1463
+ ' return 9;',
1464
+ '}',
1465
+ '',
1466
+ 'export function main(): number {',
1467
+ ' const iterator = outer();',
1468
+ ' const first = iterator.next();',
1469
+ ' const second = iterator.next();',
1470
+ ' const third = iterator.next();',
1471
+ ' const fourth = iterator.next();',
1472
+ ' return ((first.done ? 0 : first.value) * 1000)' +
1473
+ ' + ((second.done ? 0 : second.value) * 100)' +
1474
+ ' + ((third.done ? 0 : third.value) * 10)' +
1475
+ ' + (fourth.done ? fourth.value : 0);',
1476
+ '}',
1477
+ '',
1478
+ ].join('\n'),
1479
+ },
1480
+ {
1481
+ name: 'compileProject lowers sync generator yield star over strings',
1482
+ expected: 1359,
1483
+ source: [
1484
+ 'function* outer(): Generator<string, number, unknown> {',
1485
+ ' yield* "ace";',
1486
+ ' return 9;',
1487
+ '}',
1488
+ '',
1489
+ 'export function main(): number {',
1490
+ ' const iterator = outer();',
1491
+ ' const first = iterator.next();',
1492
+ ' const second = iterator.next();',
1493
+ ' const third = iterator.next();',
1494
+ ' const fourth = iterator.next();',
1495
+ ' const firstValue = first.done ? 0 : first.value.charCodeAt(0) - 96;',
1496
+ ' const secondValue = second.done ? 0 : second.value.charCodeAt(0) - 96;',
1497
+ ' const thirdValue = third.done ? 0 : third.value.charCodeAt(0) - 96;',
1498
+ ' return (firstValue * 1000) + (secondValue * 100) + (thirdValue * 10)' +
1499
+ ' + (fourth.done ? fourth.value : 0);',
1500
+ '}',
1501
+ '',
1502
+ ].join('\n'),
1503
+ },
1504
+ {
1505
+ name: 'compileProject lowers sync generator yield star over local string arrays',
1506
+ expected: 1359,
1507
+ source: [
1508
+ 'function* outer(): Generator<string, number, unknown> {',
1509
+ " const values = ['a', 'c', 'e'];",
1510
+ ' yield* values;',
1511
+ ' return 9;',
1512
+ '}',
1513
+ '',
1514
+ 'export function main(): number {',
1515
+ ' const iterator = outer();',
1516
+ ' const first = iterator.next();',
1517
+ ' const second = iterator.next();',
1518
+ ' const third = iterator.next();',
1519
+ ' const fourth = iterator.next();',
1520
+ ' const firstValue = first.done ? 0 : first.value.charCodeAt(0) - 96;',
1521
+ ' const secondValue = second.done ? 0 : second.value.charCodeAt(0) - 96;',
1522
+ ' const thirdValue = third.done ? 0 : third.value.charCodeAt(0) - 96;',
1523
+ ' return (firstValue * 1000) + (secondValue * 100) + (thirdValue * 10)' +
1524
+ ' + (fourth.done ? fourth.value : 0);',
1525
+ '}',
1526
+ '',
1527
+ ].join('\n'),
1528
+ },
1529
+ {
1530
+ name: 'compileProject lowers sync generator yield star over local boolean arrays',
1531
+ expected: 1018,
1532
+ source: [
1533
+ 'function* outer(): Generator<boolean, number, unknown> {',
1534
+ ' const values = [true, false, true];',
1535
+ ' yield* values;',
1536
+ ' return 8;',
1537
+ '}',
1538
+ '',
1539
+ 'export function main(): number {',
1540
+ ' const iterator = outer();',
1541
+ ' const first = iterator.next();',
1542
+ ' const second = iterator.next();',
1543
+ ' const third = iterator.next();',
1544
+ ' const fourth = iterator.next();',
1545
+ ' return ((first.done ? 0 : (first.value ? 1 : 0)) * 1000)' +
1546
+ ' + ((second.done ? 0 : (second.value ? 1 : 0)) * 100)' +
1547
+ ' + ((third.done ? 0 : (third.value ? 1 : 0)) * 10)' +
1548
+ ' + (fourth.done ? fourth.value : 0);',
1549
+ '}',
1550
+ '',
1551
+ ].join('\n'),
1552
+ },
1553
+ {
1554
+ name: 'compileProject lowers sync generator yield star over local tagged arrays',
1555
+ expected: 2948,
1556
+ source: [
1557
+ 'function* outer(): Generator<number | string, number, unknown> {',
1558
+ " const values: Array<number | string> = [2, 'a', 4];",
1559
+ ' yield* values;',
1560
+ ' return 8;',
1561
+ '}',
1562
+ '',
1563
+ 'export function main(): number {',
1564
+ ' const iterator = outer();',
1565
+ ' const first = iterator.next();',
1566
+ ' const second = iterator.next();',
1567
+ ' const third = iterator.next();',
1568
+ ' const fourth = iterator.next();',
1569
+ " const firstValue = first.done ? 0 : (typeof first.value === 'number' ? first.value : 9);",
1570
+ " const secondValue = second.done ? 0 : (typeof second.value === 'number' ? second.value : 9);",
1571
+ " const thirdValue = third.done ? 0 : (typeof third.value === 'number' ? third.value : 9);",
1572
+ ' return (firstValue * 1000) + (secondValue * 100) + (thirdValue * 10)' +
1573
+ ' + (fourth.done ? fourth.value : 0);',
1574
+ '}',
1575
+ '',
1576
+ ].join('\n'),
1577
+ },
1578
+ {
1579
+ name: 'compileProject lowers sync generator yield star over primitive Sets',
1580
+ expected: 3579,
1581
+ source: [
1582
+ 'function* outer(): Generator<number, number, unknown> {',
1583
+ ' yield* new Set([3, 5, 7]);',
1584
+ ' return 9;',
1585
+ '}',
1586
+ '',
1587
+ 'export function main(): number {',
1588
+ ' const iterator = outer();',
1589
+ ' const first = iterator.next();',
1590
+ ' const second = iterator.next();',
1591
+ ' const third = iterator.next();',
1592
+ ' const fourth = iterator.next();',
1593
+ ' return ((first.done ? 0 : first.value) * 1000)' +
1594
+ ' + ((second.done ? 0 : second.value) * 100)' +
1595
+ ' + ((third.done ? 0 : third.value) * 10)' +
1596
+ ' + (fourth.done ? fourth.value : 0);',
1597
+ '}',
1598
+ '',
1599
+ ].join('\n'),
1600
+ },
1601
+ {
1602
+ name: 'compileProject lowers sync generator yield star over Map values iterables',
1603
+ expected: 3579,
1604
+ source: [
1605
+ 'function* outer(): Generator<number, number, unknown> {',
1606
+ ' yield* new Map([["a", 3], ["b", 5], ["c", 7]]).values();',
1607
+ ' return 9;',
1608
+ '}',
1609
+ '',
1610
+ 'export function main(): number {',
1611
+ ' const iterator = outer();',
1612
+ ' const first = iterator.next();',
1613
+ ' const second = iterator.next();',
1614
+ ' const third = iterator.next();',
1615
+ ' const fourth = iterator.next();',
1616
+ ' return ((first.done ? 0 : first.value) * 1000)' +
1617
+ ' + ((second.done ? 0 : second.value) * 100)' +
1618
+ ' + ((third.done ? 0 : third.value) * 10)' +
1619
+ ' + (fourth.done ? fourth.value : 0);',
1620
+ '}',
1621
+ '',
1622
+ ].join('\n'),
1623
+ },
1624
+ {
1625
+ name: 'compileProject lowers sync generator yield star over Map key iterables',
1626
+ expected: 1359,
1627
+ source: [
1628
+ 'function* outer(): Generator<string, number, unknown> {',
1629
+ ' yield* new Map([["a", 3], ["c", 5], ["e", 7]]).keys();',
1630
+ ' return 9;',
1631
+ '}',
1632
+ '',
1633
+ 'export function main(): number {',
1634
+ ' const iterator = outer();',
1635
+ ' const first = iterator.next();',
1636
+ ' const second = iterator.next();',
1637
+ ' const third = iterator.next();',
1638
+ ' const fourth = iterator.next();',
1639
+ ' const firstValue = first.done ? 0 : first.value.charCodeAt(0) - 96;',
1640
+ ' const secondValue = second.done ? 0 : second.value.charCodeAt(0) - 96;',
1641
+ ' const thirdValue = third.done ? 0 : third.value.charCodeAt(0) - 96;',
1642
+ ' return (firstValue * 1000) + (secondValue * 100) + (thirdValue * 10)' +
1643
+ ' + (fourth.done ? fourth.value : 0);',
1644
+ '}',
1645
+ '',
1646
+ ].join('\n'),
1647
+ },
1648
+ {
1649
+ name: 'compileProject lowers sync generator yield star over direct Set iterables',
1650
+ expected: 3579,
1651
+ source: [
1652
+ 'function* outer(): Generator<number, number, unknown> {',
1653
+ ' const values = new Set([3, 5, 7]);',
1654
+ ' yield* values;',
1655
+ ' return 9;',
1656
+ '}',
1657
+ '',
1658
+ 'export function main(): number {',
1659
+ ' const iterator = outer();',
1660
+ ' const first = iterator.next();',
1661
+ ' const second = iterator.next();',
1662
+ ' const third = iterator.next();',
1663
+ ' const fourth = iterator.next();',
1664
+ ' return ((first.done ? 0 : first.value) * 1000)' +
1665
+ ' + ((second.done ? 0 : second.value) * 100)' +
1666
+ ' + ((third.done ? 0 : third.value) * 10)' +
1667
+ ' + (fourth.done ? fourth.value : 0);',
1668
+ '}',
1669
+ '',
1670
+ ].join('\n'),
1671
+ },
1672
+ {
1673
+ name: 'compileProject lowers sync generator yield star over direct Map iterables',
1674
+ expected: 133557,
1675
+ source: [
1676
+ 'function* outer(): Generator<[string, number], number, unknown> {',
1677
+ ' const values = new Map([["a", 3], ["c", 5], ["e", 7]]);',
1678
+ ' yield* values;',
1679
+ ' return 9;',
1680
+ '}',
1681
+ '',
1682
+ 'export function main(): number {',
1683
+ ' const iterator = outer();',
1684
+ ' const first = iterator.next();',
1685
+ ' const second = iterator.next();',
1686
+ ' const third = iterator.next();',
1687
+ ' const fourth = iterator.next();',
1688
+ ' const firstValue = first.done ? 0 : ((first.value[0].charCodeAt(0) - 96) * 10) + first.value[1];',
1689
+ ' const secondValue = second.done ? 0 : ((second.value[0].charCodeAt(0) - 96) * 10) + second.value[1];',
1690
+ ' const thirdValue = third.done ? 0 : ((third.value[0].charCodeAt(0) - 96) * 10) + third.value[1];',
1691
+ ' return (firstValue * 10000) + (secondValue * 100) + (thirdValue) + (fourth.done ? 0 : 0);',
1692
+ '}',
1693
+ '',
1694
+ ].join('\n'),
1695
+ },
1696
+ {
1697
+ name: 'compileProject lowers sync generator yield star over Set entries iterables',
1698
+ expected: 336677,
1699
+ source: [
1700
+ 'function* outer(): Generator<[number, number], number, unknown> {',
1701
+ ' yield* new Set([3, 6, 7]).entries();',
1702
+ ' return 9;',
1703
+ '}',
1704
+ '',
1705
+ 'export function main(): number {',
1706
+ ' const iterator = outer();',
1707
+ ' const first = iterator.next();',
1708
+ ' const second = iterator.next();',
1709
+ ' const third = iterator.next();',
1710
+ ' const fourth = iterator.next();',
1711
+ ' const firstValue = first.done ? 0 : (first.value[0] * 10) + first.value[1];',
1712
+ ' const secondValue = second.done ? 0 : (second.value[0] * 10) + second.value[1];',
1713
+ ' const thirdValue = third.done ? 0 : (third.value[0] * 10) + third.value[1];',
1714
+ ' return (firstValue * 10000) + (secondValue * 100) + thirdValue + (fourth.done ? 0 : 0);',
1715
+ '}',
1716
+ '',
1717
+ ].join('\n'),
1718
+ },
1719
+ {
1720
+ name: 'compileProject lowers sync generator try finally on natural completion',
1721
+ expected: 3591,
1722
+ source: [
1723
+ 'function* iterate(): Generator<number, number, unknown> {',
1724
+ ' try {',
1725
+ ' yield 3;',
1726
+ ' return 9;',
1727
+ ' } finally {',
1728
+ ' yield 5;',
1729
+ ' }',
1730
+ '}',
1731
+ '',
1732
+ 'export function main(): number {',
1733
+ ' const iterator = iterate();',
1734
+ ' const first = iterator.next();',
1735
+ ' const second = iterator.next();',
1736
+ ' const third = iterator.next();',
1737
+ ' return ((first.done ? 0 : first.value) * 1000)' +
1738
+ ' + ((second.done ? 0 : second.value) * 100)' +
1739
+ ' + ((third.done ? third.value : 0) * 10)' +
1740
+ ' + (third.done ? 1 : 0);',
1741
+ '}',
1742
+ '',
1743
+ ].join('\n'),
1744
+ },
1745
+ {
1746
+ name: 'compileProject lowers sync generator return through finally',
1747
+ expected: 3581,
1748
+ source: [
1749
+ 'function* iterate(): Generator<number, number, unknown> {',
1750
+ ' try {',
1751
+ ' yield 3;',
1752
+ ' return 9;',
1753
+ ' } finally {',
1754
+ ' yield 5;',
1755
+ ' }',
1756
+ '}',
1757
+ '',
1758
+ 'export function main(): number {',
1759
+ ' const iterator = iterate();',
1760
+ ' const first = iterator.next();',
1761
+ ' const second = iterator.return(8);',
1762
+ ' const third = iterator.next();',
1763
+ ' return ((first.done ? 0 : first.value) * 1000)' +
1764
+ ' + ((second.done ? 0 : second.value) * 100)' +
1765
+ ' + ((third.done ? third.value : 0) * 10)' +
1766
+ ' + (third.done ? 1 : 0);',
1767
+ '}',
1768
+ '',
1769
+ ].join('\n'),
1770
+ },
1771
+ {
1772
+ name: 'compileProject lowers sync generator external return through finally cleanup yields',
1773
+ expected: 175,
1774
+ source: [
1775
+ 'function* iterate(): Generator<number, number, unknown> {',
1776
+ ' try {',
1777
+ ' yield 1;',
1778
+ ' yield 2;',
1779
+ ' } finally {',
1780
+ ' yield 7;',
1781
+ ' }',
1782
+ ' return 3;',
1783
+ '}',
1784
+ '',
1785
+ 'export function main(): number {',
1786
+ ' const iterator = iterate();',
1787
+ ' const first = iterator.next();',
1788
+ ' const second = iterator.return(5);',
1789
+ ' const third = iterator.next();',
1790
+ ' return ((first.done ? 9 : first.value) * 100)' +
1791
+ ' + ((second.done ? 9 : second.value) * 10)' +
1792
+ ' + (third.done ? third.value : 9);',
1793
+ '}',
1794
+ '',
1795
+ ].join('\n'),
1796
+ },
1797
+ {
1798
+ name: 'compileProject lowers sync generator break through finally',
1799
+ expected: 3591,
1800
+ source: [
1801
+ 'function* iterate(): Generator<number, number, unknown> {',
1802
+ ' let index = 0;',
1803
+ ' while (index < 1) {',
1804
+ ' try {',
1805
+ ' index = index + 1;',
1806
+ ' yield 3;',
1807
+ ' break;',
1808
+ ' } finally {',
1809
+ ' yield 5;',
1810
+ ' }',
1811
+ ' }',
1812
+ ' return 9;',
1813
+ '}',
1814
+ '',
1815
+ 'export function main(): number {',
1816
+ ' const iterator = iterate();',
1817
+ ' const first = iterator.next();',
1818
+ ' const second = iterator.next();',
1819
+ ' const third = iterator.next();',
1820
+ ' return ((first.done ? 0 : first.value) * 1000)' +
1821
+ ' + ((second.done ? 0 : second.value) * 100)' +
1822
+ ' + ((third.done ? third.value : 0) * 10)' +
1823
+ ' + (third.done ? 1 : 0);',
1824
+ '}',
1825
+ '',
1826
+ ].join('\n'),
1827
+ },
1828
+ {
1829
+ name: 'compileProject lowers sync generator continue through finally',
1830
+ expected: 3507591,
1831
+ source: [
1832
+ 'function* iterate(): Generator<number, number, unknown> {',
1833
+ ' let index = 0;',
1834
+ ' while (index < 2) {',
1835
+ ' try {',
1836
+ ' index = index + 1;',
1837
+ ' if (index === 1) {',
1838
+ ' yield 3;',
1839
+ ' continue;',
1840
+ ' }',
1841
+ ' yield 7;',
1842
+ ' } finally {',
1843
+ ' yield 5;',
1844
+ ' }',
1845
+ ' }',
1846
+ ' return 9;',
1847
+ '}',
1848
+ '',
1849
+ 'export function main(): number {',
1850
+ ' const iterator = iterate();',
1851
+ ' const first = iterator.next();',
1852
+ ' const second = iterator.next();',
1853
+ ' const third = iterator.next();',
1854
+ ' const fourth = iterator.next();',
1855
+ ' const fifth = iterator.next();',
1856
+ ' return ((first.done ? 0 : first.value) * 1000000)' +
1857
+ ' + ((second.done ? 0 : second.value) * 100000)' +
1858
+ ' + ((third.done ? 0 : third.value) * 1000)' +
1859
+ ' + ((fourth.done ? 0 : fourth.value) * 100)' +
1860
+ ' + ((fifth.done ? fifth.value : 0) * 10)' +
1861
+ ' + (fifth.done ? 1 : 0);',
1862
+ '}',
1863
+ '',
1864
+ ].join('\n'),
1865
+ },
1866
+ {
1867
+ name: 'compileProject lowers sync generator throw calls caught by try catch',
1868
+ expected: 37091,
1869
+ source: [
1870
+ 'function* iterate(): Generator<number, number, number> {',
1871
+ ' try {',
1872
+ ' yield 3;',
1873
+ ' return 8;',
1874
+ ' } catch {',
1875
+ ' yield 7;',
1876
+ ' return 9;',
1877
+ ' }',
1878
+ '}',
1879
+ '',
1880
+ 'export function main(): number {',
1881
+ ' const iterator = iterate();',
1882
+ ' const first = iterator.next();',
1883
+ ' const second = iterator.throw(5);',
1884
+ ' const third = iterator.next();',
1885
+ ' return ((first.done ? 0 : first.value) * 10000)' +
1886
+ ' + ((second.done ? 0 : second.value) * 1000)' +
1887
+ ' + ((third.done ? third.value : 0) * 10)' +
1888
+ ' + (third.done ? 1 : 0);',
1889
+ '}',
1890
+ '',
1891
+ ].join('\n'),
1892
+ },
1893
+ {
1894
+ name: 'compileProject lowers sync generator throw calls caught by try catch finally',
1895
+ expected: 37591,
1896
+ source: [
1897
+ 'function* iterate(): Generator<number, number, number> {',
1898
+ ' try {',
1899
+ ' yield 3;',
1900
+ ' return 8;',
1901
+ ' } catch {',
1902
+ ' yield 7;',
1903
+ ' return 9;',
1904
+ ' } finally {',
1905
+ ' yield 5;',
1906
+ ' }',
1907
+ '}',
1908
+ '',
1909
+ 'export function main(): number {',
1910
+ ' const iterator = iterate();',
1911
+ ' const first = iterator.next();',
1912
+ ' const second = iterator.throw(5);',
1913
+ ' const third = iterator.next();',
1914
+ ' const fourth = iterator.next();',
1915
+ ' return ((first.done ? 0 : first.value) * 10000)' +
1916
+ ' + ((second.done ? 0 : second.value) * 1000)' +
1917
+ ' + ((third.done ? 0 : third.value) * 100)' +
1918
+ ' + ((fourth.done ? fourth.value : 0) * 10)' +
1919
+ ' + (fourth.done ? 1 : 0);',
1920
+ '}',
1921
+ '',
1922
+ ].join('\n'),
1923
+ },
1924
+ {
1925
+ name: 'compileProject lowers authored sync generator throw caught by try catch',
1926
+ expected: 3791,
1927
+ source: [
1928
+ 'function* iterate(): Generator<number, number, unknown> {',
1929
+ ' try {',
1930
+ ' yield 3;',
1931
+ ' throw new Error("boom");',
1932
+ ' } catch {',
1933
+ ' yield 7;',
1934
+ ' return 9;',
1935
+ ' }',
1936
+ '}',
1937
+ '',
1938
+ 'export function main(): number {',
1939
+ ' const iterator = iterate();',
1940
+ ' const first = iterator.next();',
1941
+ ' const second = iterator.next();',
1942
+ ' const third = iterator.next();',
1943
+ ' return ((first.done ? 0 : first.value) * 1000)' +
1944
+ ' + ((second.done ? 0 : second.value) * 100)' +
1945
+ ' + ((third.done ? third.value : 0) * 10)' +
1946
+ ' + (third.done ? 1 : 0);',
1947
+ '}',
1948
+ '',
1949
+ ].join('\n'),
1950
+ },
1951
+ {
1952
+ name: 'compileProject lowers authored sync generator throw caught by try catch finally',
1953
+ expected: 37591,
1954
+ source: [
1955
+ 'function* iterate(): Generator<number, number, unknown> {',
1956
+ ' try {',
1957
+ ' yield 3;',
1958
+ ' throw new Error("boom");',
1959
+ ' } catch {',
1960
+ ' yield 7;',
1961
+ ' return 9;',
1962
+ ' } finally {',
1963
+ ' yield 5;',
1964
+ ' }',
1965
+ '}',
1966
+ '',
1967
+ 'export function main(): number {',
1968
+ ' const iterator = iterate();',
1969
+ ' const first = iterator.next();',
1970
+ ' const second = iterator.next();',
1971
+ ' const third = iterator.next();',
1972
+ ' const fourth = iterator.next();',
1973
+ ' return ((first.done ? 0 : first.value) * 10000)' +
1974
+ ' + ((second.done ? 0 : second.value) * 1000)' +
1975
+ ' + ((third.done ? 0 : third.value) * 100)' +
1976
+ ' + ((fourth.done ? fourth.value : 0) * 10)' +
1977
+ ' + (fourth.done ? 1 : 0);',
1978
+ '}',
1979
+ '',
1980
+ ].join('\n'),
1981
+ },
1982
+ {
1983
+ name: 'compileProject lowers sync generator throw delegation through yield star',
1984
+ expected: 3071111,
1985
+ source: [
1986
+ 'function* inner(): Generator<number, number, number> {',
1987
+ ' try {',
1988
+ ' yield 3;',
1989
+ ' return 8;',
1990
+ ' } catch {',
1991
+ ' yield 7;',
1992
+ ' return 9;',
1993
+ ' }',
1994
+ '}',
1995
+ '',
1996
+ 'function* outer(): Generator<number, number, number> {',
1997
+ ' const delegated = yield* inner();',
1998
+ ' yield delegated + 1;',
1999
+ ' return delegated + 2;',
2000
+ '}',
2001
+ '',
2002
+ 'export function main(): number {',
2003
+ ' const iterator = outer();',
2004
+ ' const first = iterator.next();',
2005
+ ' const second = iterator.throw(5);',
2006
+ ' const third = iterator.next();',
2007
+ ' const fourth = iterator.next();',
2008
+ ' return ((first.done ? 0 : first.value) * 1000000)' +
2009
+ ' + ((second.done ? 0 : second.value) * 10000)' +
2010
+ ' + ((third.done ? 0 : third.value) * 100)' +
2011
+ ' + ((fourth.done ? fourth.value : 0) * 10)' +
2012
+ ' + (fourth.done ? 1 : 0);',
2013
+ '}',
2014
+ '',
2015
+ ].join('\n'),
2016
+ },
2017
+ {
2018
+ name: 'compileProject rethrows TypeError for sync generator throw through array yield star',
2019
+ expectedThrow: { name: 'TypeError', message: 'yield* delegate does not support throw' },
2020
+ source: [
2021
+ 'function* outer(): Generator<number, number, unknown> {',
2022
+ ' yield* [3, 5, 7];',
2023
+ ' return 9;',
2024
+ '}',
2025
+ '',
2026
+ 'export function main(): number {',
2027
+ ' const iterator = outer();',
2028
+ ' iterator.next();',
2029
+ ' iterator.throw(5);',
2030
+ ' return 0;',
2031
+ '}',
2032
+ '',
2033
+ ].join('\n'),
2034
+ },
2035
+ {
2036
+ name: 'compileProject catches TypeError for sync generator throw through array yield star',
2037
+ expected: 3861,
2038
+ source: [
2039
+ 'function* outer(): Generator<number, number, unknown> {',
2040
+ ' try {',
2041
+ ' yield* [3, 5, 7];',
2042
+ ' return 9;',
2043
+ ' } catch (error) {',
2044
+ ' if (error instanceof TypeError) {',
2045
+ ' yield 8;',
2046
+ ' return 6;',
2047
+ ' }',
2048
+ ' return 0;',
2049
+ ' }',
2050
+ '}',
2051
+ '',
2052
+ 'export function main(): number {',
2053
+ ' const iterator = outer();',
2054
+ ' const first = iterator.next();',
2055
+ ' const second = iterator.throw(5);',
2056
+ ' const third = iterator.next();',
2057
+ ' return ((first.done ? 0 : first.value) * 1000)' +
2058
+ ' + ((second.done ? 0 : second.value) * 100)' +
2059
+ ' + ((third.done ? third.value : 0) * 10)' +
2060
+ ' + (third.done ? 1 : 0);',
2061
+ '}',
2062
+ '',
2063
+ ].join('\n'),
2064
+ },
2065
+ {
2066
+ name: 'compileProject lowers sync generator catch bindings for thrown values',
2067
+ expected: 37091,
2068
+ source: [
2069
+ 'function* iterate(): Generator<number, number, unknown> {',
2070
+ ' try {',
2071
+ ' yield 3;',
2072
+ ' return 8;',
2073
+ ' } catch (error) {',
2074
+ ' if (typeof error === "number") {',
2075
+ ' yield error + 2;',
2076
+ ' return error + 4;',
2077
+ ' }',
2078
+ ' return 0;',
2079
+ ' }',
2080
+ '}',
2081
+ '',
2082
+ 'export function main(): number {',
2083
+ ' const iterator = iterate();',
2084
+ ' const first = iterator.next();',
2085
+ ' const second = iterator.throw(5);',
2086
+ ' const third = iterator.next();',
2087
+ ' return ((first.done ? 0 : first.value) * 10000)' +
2088
+ ' + ((second.done ? 0 : second.value) * 1000)' +
2089
+ ' + ((third.done ? third.value : 0) * 10)' +
2090
+ ' + (third.done ? 1 : 0);',
2091
+ '}',
2092
+ '',
2093
+ ].join('\n'),
2094
+ },
2095
+ {
2096
+ name: 'compileProject rethrows uncaught sync generator throw calls to host',
2097
+ expectedThrow: 5,
2098
+ source: [
2099
+ 'function* iterate(): Generator<number, number, unknown> {',
2100
+ ' yield 3;',
2101
+ ' return 8;',
2102
+ '}',
2103
+ '',
2104
+ 'export function main(): number {',
2105
+ ' const iterator = iterate();',
2106
+ ' iterator.next();',
2107
+ ' iterator.throw(5);',
2108
+ ' return 0;',
2109
+ '}',
2110
+ '',
2111
+ ].join('\n'),
2112
+ },
2113
+ {
2114
+ name: 'compileProject rethrows uncaught authored builtin Error throws from sync generators to host',
2115
+ expectedThrow: { name: 'Error', message: 'boom' },
2116
+ source: [
2117
+ 'function* iterate(): Generator<number, number, unknown> {',
2118
+ ' yield 3;',
2119
+ ' throw new Error("boom");',
2120
+ '}',
2121
+ '',
2122
+ 'export function main(): number {',
2123
+ ' const iterator = iterate();',
2124
+ ' iterator.next();',
2125
+ ' iterator.next();',
2126
+ ' return 0;',
2127
+ '}',
2128
+ '',
2129
+ ].join('\n'),
2130
+ },
2131
+ {
2132
+ name: 'compileProject rethrows uncaught sync generator throw Error calls to host',
2133
+ expectedThrow: { name: 'Error', message: 'boom' },
2134
+ source: [
2135
+ 'function* iterate(): Generator<number, number, unknown> {',
2136
+ ' yield 3;',
2137
+ ' return 8;',
2138
+ '}',
2139
+ '',
2140
+ 'export function main(): number {',
2141
+ ' const iterator = iterate();',
2142
+ ' iterator.next();',
2143
+ ' iterator.throw(new Error("boom"));',
2144
+ ' return 0;',
2145
+ '}',
2146
+ '',
2147
+ ].join('\n'),
2148
+ },
2149
+ {
2150
+ name: 'compileProject lowers sync generator switch statements with fallthrough',
2151
+ expected: 12021844,
2152
+ source: [
2153
+ 'function* iterate(flag: number): Generator<number, number, unknown> {',
2154
+ ' let total = 1;',
2155
+ ' switch (flag) {',
2156
+ ' case 1:',
2157
+ ' yield total + 10;',
2158
+ ' break;',
2159
+ ' case 2:',
2160
+ ' yield total + 20;',
2161
+ ' default:',
2162
+ ' total = total + 3;',
2163
+ ' yield total;',
2164
+ ' break;',
2165
+ ' }',
2166
+ ' return total * 10;',
2167
+ '}',
2168
+ '',
2169
+ 'export function main(): number {',
2170
+ ' const one = iterate(1);',
2171
+ ' const oneFirst = one.next();',
2172
+ ' const oneSecond = one.next();',
2173
+ ' const two = iterate(2);',
2174
+ ' const twoFirst = two.next();',
2175
+ ' const twoSecond = two.next();',
2176
+ ' const twoThird = two.next();',
2177
+ ' const three = iterate(3);',
2178
+ ' const threeFirst = three.next();',
2179
+ ' const threeSecond = three.next();',
2180
+ ' return ((oneFirst.done ? 0 : oneFirst.value) * 1000000)' +
2181
+ ' + ((oneSecond.done ? oneSecond.value : 0) * 100000)' +
2182
+ ' + ((twoFirst.done ? 0 : twoFirst.value) * 1000)' +
2183
+ ' + ((twoSecond.done ? 0 : twoSecond.value) * 100)' +
2184
+ ' + ((twoThird.done ? twoThird.value : 0) * 10)' +
2185
+ ' + (threeFirst.done ? 0 : threeFirst.value)' +
2186
+ ' + (threeSecond.done ? threeSecond.value : 0);',
2187
+ '}',
2188
+ '',
2189
+ ].join('\n'),
2190
+ },
2191
+ {
2192
+ name: 'compileProject lowers sync generator string switch statements with fallthrough',
2193
+ expected: 12021844,
2194
+ source: [
2195
+ 'function* iterate(flag: string): Generator<number, number, unknown> {',
2196
+ ' let total = 1;',
2197
+ ' switch (flag) {',
2198
+ ' case "one":',
2199
+ ' yield total + 10;',
2200
+ ' break;',
2201
+ ' case "two":',
2202
+ ' yield total + 20;',
2203
+ ' default:',
2204
+ ' total = total + 3;',
2205
+ ' yield total;',
2206
+ ' break;',
2207
+ ' }',
2208
+ ' return total * 10;',
2209
+ '}',
2210
+ '',
2211
+ 'export function main(): number {',
2212
+ ' const one = iterate("one");',
2213
+ ' const oneFirst = one.next();',
2214
+ ' const oneSecond = one.next();',
2215
+ ' const two = iterate("two");',
2216
+ ' const twoFirst = two.next();',
2217
+ ' const twoSecond = two.next();',
2218
+ ' const twoThird = two.next();',
2219
+ ' const three = iterate("other");',
2220
+ ' const threeFirst = three.next();',
2221
+ ' const threeSecond = three.next();',
2222
+ ' return ((oneFirst.done ? 0 : oneFirst.value) * 1000000)' +
2223
+ ' + ((oneSecond.done ? oneSecond.value : 0) * 100000)' +
2224
+ ' + ((twoFirst.done ? 0 : twoFirst.value) * 1000)' +
2225
+ ' + ((twoSecond.done ? 0 : twoSecond.value) * 100)' +
2226
+ ' + ((twoThird.done ? twoThird.value : 0) * 10)' +
2227
+ ' + (threeFirst.done ? 0 : threeFirst.value)' +
2228
+ ' + (threeSecond.done ? threeSecond.value : 0);',
2229
+ '}',
2230
+ '',
2231
+ ].join('\n'),
2232
+ },
2233
+ {
2234
+ name: 'compileProject preserves sync generator switch break inside try finally loops',
2235
+ expected: 213223,
2236
+ source: [
2237
+ 'function* iterate(): Generator<number, number, unknown> {',
2238
+ ' let count = 0;',
2239
+ ' let total = 0;',
2240
+ ' while (count < 2) {',
2241
+ ' try {',
2242
+ ' switch (count) {',
2243
+ ' case 0:',
2244
+ ' total = total + 1;',
2245
+ ' break;',
2246
+ ' default:',
2247
+ ' total = total + 2;',
2248
+ ' break;',
2249
+ ' }',
2250
+ ' yield total;',
2251
+ ' total = total + 10;',
2252
+ ' } finally {',
2253
+ ' count = count + 1;',
2254
+ ' total = total + 100;',
2255
+ ' }',
2256
+ ' }',
2257
+ ' return total;',
2258
+ '}',
2259
+ '',
2260
+ 'export function main(): number {',
2261
+ ' const iterator = iterate();',
2262
+ ' const first = iterator.next();',
2263
+ ' const second = iterator.next();',
2264
+ ' const third = iterator.next();',
2265
+ ' return ((first.done ? 0 : first.value) * 100000) +',
2266
+ ' ((second.done ? 0 : second.value) * 1000) +',
2267
+ ' (third.done ? third.value : 0);',
148
2268
  '}',
149
2269
  '',
150
2270
  ].join('\n'),