/*
* Copyright 2014 The Closure Compiler Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import static com.google.common.truth.Truth.assertThat;
import com.google.javascript.jscomp.CompilerOptions.LanguageMode;
/** Unit tests for {@link Es6RewriteGenerators}. */
// TODO(tbreisacher): Rewrite direct calls to test() to use rewriteGeneratorBody
// or rewriteGeneratorBodyWithVars.
public final class Es6RewriteGeneratorsTest extends CompilerTestCase {
@Override
public void setUp() {
setAcceptedLanguage(LanguageMode.ECMASCRIPT_2015);
runTypeCheckAfterProcessing = true;
compareJsDoc = true;
}
@Override
protected CompilerOptions getOptions() {
CompilerOptions options = super.getOptions();
options.setLanguageOut(LanguageMode.ECMASCRIPT3);
return options;
}
@Override
protected CompilerPass getProcessor(final Compiler compiler) {
return new Es6RewriteGenerators(compiler);
}
public void rewriteGeneratorBody(String beforeBody, String afterBody) {
rewriteGeneratorBodyWithVars(beforeBody, "", afterBody);
}
public void rewriteGeneratorBodyWithVars(
String beforeBody, String varDecls, String afterBody) {
test(
"function *f() {" + beforeBody + "}",
LINE_JOINER.join(
"/** @suppress {uselessCode} */",
"function f() {",
" var $jscomp$generator$state = 0;",
varDecls,
" function $jscomp$generator$impl($jscomp$generator$next$arg,",
" $jscomp$generator$throw$arg) {",
" while (1) switch ($jscomp$generator$state) {",
afterBody,
" default:",
" return {value: undefined, done: true};",
" }",
" }",
" var iterator = /** @type {!Generator<?>} */ ({",
" next: function(arg) { return $jscomp$generator$impl(arg, undefined); },",
" throw: function(arg){ return $jscomp$generator$impl(undefined, arg); },",
" return: function(arg) { throw Error('Not yet implemented'); },",
" });",
" $jscomp.initSymbolIterator();",
" /** @this {!Generator<?>} */",
" iterator[Symbol.iterator] = function() { return this; };",
" return iterator;",
"}"));
}
public void testSimpleGenerator() {
rewriteGeneratorBody(
"",
LINE_JOINER.join(
"case 0:",
" $jscomp$generator$state = -1;"));
assertThat(getLastCompiler().injected).containsExactly("es6/symbol");
rewriteGeneratorBody(
"yield 1;",
LINE_JOINER.join(
"case 0:",
" $jscomp$generator$state = 1;",
" return {value: 1, done: false};",
"case 1:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 2; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 2:",
" $jscomp$generator$state = -1;"));
test(
"/** @param {*} a */ function *f(a, b) {}",
LINE_JOINER.join(
"/** @param {*} a @suppress {uselessCode} */",
"function f(a, b) {",
" var $jscomp$generator$state = 0;",
" function $jscomp$generator$impl($jscomp$generator$next$arg,",
" $jscomp$generator$throw$arg) {",
" while (1) switch ($jscomp$generator$state) {",
" case 0:",
" $jscomp$generator$state = -1;",
" default:",
" return {value: undefined, done: true}",
" }",
" }",
" var iterator = /** @type {!Generator<?>} */ ({",
" next: function(arg){ return $jscomp$generator$impl(arg, undefined); },",
" throw: function(arg){ return $jscomp$generator$impl(undefined, arg); },",
" return: function(arg) { throw Error('Not yet implemented'); },",
" });",
" $jscomp.initSymbolIterator();",
" /** @this {!Generator<?>} */",
" iterator[Symbol.iterator] = function() { return this; };",
" return iterator;",
"}"));
rewriteGeneratorBodyWithVars(
"var i = 0, j = 2",
"var j; var i;",
LINE_JOINER.join(
"case 0:",
" i = 0;",
" j = 2;",
" $jscomp$generator$state = -1;"));
rewriteGeneratorBodyWithVars(
"var i = 0; yield i; i = 1; yield i; i = i + 1; yield i;",
"var i;",
LINE_JOINER.join(
"case 0:",
" i = 0;",
" $jscomp$generator$state = 1;",
" return {value: i, done: false};",
"case 1:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 2; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 2:",
" i = 1;",
" $jscomp$generator$state = 3;",
" return {value: i, done: false};",
"case 3:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 4; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 4:",
" i = i + 1;",
" $jscomp$generator$state = 5;",
" return {value: i, done: false};",
"case 5:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 6; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 6:",
" $jscomp$generator$state = -1;"));
}
public void testReturnGenerator() {
test(
"function f() { return function *g() {yield 1;} }",
LINE_JOINER.join(
"function f() {",
" return /** @suppress {uselessCode} */ function g() {",
" var $jscomp$generator$state = 0;",
" function $jscomp$generator$impl($jscomp$generator$next$arg,",
" $jscomp$generator$throw$arg) {",
" while (1) switch ($jscomp$generator$state) {",
" case 0:",
" $jscomp$generator$state = 1;",
" return {value: 1, done: false};",
" case 1:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 2; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
" case 2:",
" $jscomp$generator$state = -1;",
" default:",
" return {value: undefined, done: true}",
" }",
" }",
" var iterator = /** @type {!Generator<?>} */ ({",
" next: function(arg){ return $jscomp$generator$impl(arg, undefined); },",
" throw: function(arg){ return $jscomp$generator$impl(undefined, arg); },",
" return: function(arg) { throw Error('Not yet implemented'); },",
" });",
" $jscomp.initSymbolIterator();",
" /** @this {!Generator<?>} */",
" iterator[Symbol.iterator] = function() { return this; };",
" return iterator;",
" }",
"}"));
}
public void testNestedGenerator() {
test(
"function *f() { function *g() {yield 2;} yield 1; }",
LINE_JOINER.join(
"/** @suppress {uselessCode} */",
"function f() {",
" var $jscomp$generator$state = 0;",
" /** @suppress {uselessCode} */",
" function g() {",
" var $jscomp$generator$state = 0;",
" function $jscomp$generator$impl($jscomp$generator$next$arg,",
" $jscomp$generator$throw$arg) {",
" while (1) switch ($jscomp$generator$state) {",
" case 0:",
" $jscomp$generator$state = 1;",
" return {value: 2, done: false};",
" case 1:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 2; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
" case 2:",
" $jscomp$generator$state = -1;",
" default:",
" return {value: undefined, done: true}",
" }",
" }",
" var iterator = /** @type {!Generator<?>} */ ({",
" next: function(arg){ return $jscomp$generator$impl(arg, undefined); },",
" throw: function(arg){ return $jscomp$generator$impl(undefined, arg); },",
" return: function(arg) { throw Error('Not yet implemented'); },",
" })",
" $jscomp.initSymbolIterator();",
" /** @this {!Generator<?>} */",
" iterator[Symbol.iterator] = function() { return this; };",
" return iterator;",
" }",
" function $jscomp$generator$impl($jscomp$generator$next$arg,",
" $jscomp$generator$throw$arg) {",
" while (1) switch ($jscomp$generator$state) {",
" case 0:",
" $jscomp$generator$state = 1;",
" return {value: 1, done: false};",
" case 1:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 2; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
" case 2:",
" $jscomp$generator$state = -1;",
" default:",
" return {value: undefined, done: true}",
" }",
" }",
" var iterator = /** @type {!Generator<?>} */ ({",
" next: function(arg){ return $jscomp$generator$impl(arg, undefined); },",
" throw: function(arg){ return $jscomp$generator$impl(undefined, arg); },",
" return: function(arg) { throw Error('Not yet implemented'); },",
" });",
" $jscomp.initSymbolIterator();",
" /** @this {!Generator<?>} */",
" iterator[Symbol.iterator] = function() { return this; };",
" return iterator;",
"}"));
}
public void testForLoopsGenerator() {
rewriteGeneratorBodyWithVars(
"var i = 0; for (var j = 0; j < 10; j++) { i += j; } yield i;",
"var i;",
LINE_JOINER.join(
"case 0:",
" i = 0;",
" for (var j = 0; j < 10; j++) { i += j; }",
" $jscomp$generator$state = 1;",
" return {value: i, done: false};",
"case 1:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 2; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 2:",
" $jscomp$generator$state = -1;"));
rewriteGeneratorBodyWithVars(
"for (var j = 0; j < 10; j++) { yield j; }",
"var j;",
LINE_JOINER.join(
"case 0:",
" j = 0;",
"case 1:",
" if (!(j < 10)) { $jscomp$generator$state = 3; break; }",
" $jscomp$generator$state = 4;",
" return {value: j, done: false};",
"case 4:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 5; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 5:",
"case 2:",
" j++",
" $jscomp$generator$state = 1;",
" break",
"case 3:",
" $jscomp$generator$state = -1;"));
rewriteGeneratorBodyWithVars(
"var i = 0; for (var j = 0; j < 10; j++) { i += j; throw 5; } yield i;",
"var j; var i;",
LINE_JOINER.join(
"case 0:",
" i = 0;",
" j = 0;",
"case 1:",
" if (!(j < 10)) {",
" $jscomp$generator$state = 3;",
" break;",
" }",
" i += j;",
" $jscomp$generator$state = -1;",
" throw 5;",
"case 2:",
" j++;",
" $jscomp$generator$state = 1;",
" break;",
"case 3:",
" $jscomp$generator$state = 4;",
" return {value: i, done: false};",
"case 4:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 5; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 5:",
" $jscomp$generator$state = -1;"));
}
public void testWhileLoopsGenerator() {
rewriteGeneratorBodyWithVars(
"var i = 0; while (i < 10) { i++; i++; i++; } yield i;",
" var i;",
LINE_JOINER.join(
"case 0:",
" i = 0;",
" while (i < 10) { i ++; i++; i++; }",
" $jscomp$generator$state = 1;",
" return {value: i, done: false};",
"case 1:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 2; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 2:",
" $jscomp$generator$state = -1;"));
rewriteGeneratorBodyWithVars(
"var j = 0; while (j < 10) { yield j; j++; }",
"var j;",
LINE_JOINER.join(
"case 0:",
" j = 0;",
"case 1:",
" if (!(j < 10)) { $jscomp$generator$state = 2; break; }",
" $jscomp$generator$state = 3;",
" return {value: j, done: false};",
"case 3:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 4; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 4:",
" j++",
" $jscomp$generator$state = 1;",
" break",
"case 2:",
" $jscomp$generator$state = -1;"));
}
public void testUndecomposableExpression() {
testError("function *f() { obj.bar(yield 5); }",
Es6ToEs3Converter.CANNOT_CONVERT);
}
public void testGeneratorCannotConvertYet() {
testError("function *f() {switch (i) {default: case 1: yield 1;}}",
Es6ToEs3Converter.CANNOT_CONVERT_YET);
testError("function *f() { l: if (true) { var x = 5; break l; x++; yield x; }; }",
Es6ToEs3Converter.CANNOT_CONVERT_YET);
testError("function *f(b, i) {switch (i) { case (b || (yield 1)): yield 2; }}",
Es6ToEs3Converter.CANNOT_CONVERT_YET);
}
public void testThrowGenerator() {
rewriteGeneratorBody(
"throw 1;",
LINE_JOINER.join(
"case 0:",
" $jscomp$generator$state = -1;",
" throw 1;",
" $jscomp$generator$state = -1;"));
}
public void testLabelsGenerator() {
rewriteGeneratorBody(
"l: if (true) { break l; }",
LINE_JOINER.join(
"case 0:",
" l: if (true) { break l; }",
" $jscomp$generator$state = -1;"));
rewriteGeneratorBody(
"l: for (;;) { yield i; continue l; }",
LINE_JOINER.join(
"case 0:",
"case 1:",
" if (!true) { $jscomp$generator$state = 2; break; }",
" $jscomp$generator$state = 3;",
" return {value: i, done: false};",
"case 3:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 4; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 4:",
" $jscomp$generator$state = 1;",
" break;",
" $jscomp$generator$state = 1;",
" break;",
"case 2:",
" $jscomp$generator$state = -1;"));
}
public void testIfGenerator() {
rewriteGeneratorBodyWithVars(
"var j = 0; if (j < 1) { yield j; }",
"var j;",
LINE_JOINER.join(
"case 0:",
" j = 0;",
" if (!(j < 1)) { $jscomp$generator$state = 1; break; }",
" $jscomp$generator$state = 2;",
" return {value: j, done: false};",
"case 2:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 3; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 3:",
"case 1:",
" $jscomp$generator$state = -1;"));
test(
"function *f(i) { if (i < 1) { yield i; } else { yield 1; } }",
LINE_JOINER.join(
"/** @suppress {uselessCode} */",
"function f(i) {",
" var $jscomp$generator$state = 0;",
" function $jscomp$generator$impl($jscomp$generator$next$arg,",
" $jscomp$generator$throw$arg) {",
" while (1) switch ($jscomp$generator$state) {",
" case 0:",
" if (!(i < 1)) { $jscomp$generator$state = 1; break; }",
" $jscomp$generator$state = 3;",
" return {value: i, done: false};",
" case 3:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 4; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
" case 4:",
" $jscomp$generator$state = 2;",
" break;",
" case 1:",
" $jscomp$generator$state = 5;",
" return {value: 1, done: false};",
" case 5:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 6; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
" case 6:",
" case 2:",
" $jscomp$generator$state = -1;",
" default:",
" return {value: undefined, done: true}",
" }",
" }",
" var iterator = /** @type {!Generator<?>} */ ({",
" next: function(arg){ return $jscomp$generator$impl(arg, undefined); },",
" throw: function(arg){ return $jscomp$generator$impl(undefined, arg); },",
" return: function(arg) { throw Error('Not yet implemented'); },",
" });",
" $jscomp.initSymbolIterator();",
" /** @this {!Generator<?>} */",
" iterator[Symbol.iterator] = function() { return this; };",
" return iterator;",
"}"));
}
public void testGeneratorReturn() {
rewriteGeneratorBody(
"return 1;",
LINE_JOINER.join(
"case 0:",
" $jscomp$generator$state = -1;",
" return {value: 1, done: true};",
" $jscomp$generator$state = -1;"));
}
public void testGeneratorBreakContinue() {
rewriteGeneratorBodyWithVars(
"var j = 0; while (j < 10) { yield j; break; }",
"var j;",
LINE_JOINER.join(
"case 0:",
" j = 0;",
"case 1:",
" if (!(j < 10)) { $jscomp$generator$state = 2; break; }",
" $jscomp$generator$state = 3;",
" return {value: j, done: false};",
"case 3:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 4; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 4:",
" $jscomp$generator$state = 2;",
" break;",
" $jscomp$generator$state = 1;",
" break",
"case 2:",
" $jscomp$generator$state = -1;"));
rewriteGeneratorBodyWithVars(
"var j = 0; while (j < 10) { yield j; continue; }",
"var j;",
LINE_JOINER.join(
"case 0:",
" j = 0;",
"case 1:",
" if (!(j < 10)) { $jscomp$generator$state = 2; break; }",
" $jscomp$generator$state = 3;",
" return {value: j, done: false};",
"case 3:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 4; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 4:",
" $jscomp$generator$state = 1;",
" break;",
" $jscomp$generator$state = 1;",
" break",
"case 2:",
" $jscomp$generator$state = -1;"));
rewriteGeneratorBodyWithVars(
"for (var j = 0; j < 10; j++) { yield j; break; }",
"var j;",
LINE_JOINER.join(
"case 0:",
" j = 0;",
"case 1:",
" if (!(j < 10)) { $jscomp$generator$state = 3; break; }",
" $jscomp$generator$state = 4;",
" return {value: j, done: false};",
"case 4:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 5; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 5:",
" $jscomp$generator$state = 3;",
" break;",
"case 2:",
" j++;",
" $jscomp$generator$state = 1;",
" break",
"case 3:",
" $jscomp$generator$state = -1;"));
rewriteGeneratorBodyWithVars(
"for (var j = 0; j < 10; j++) { yield j; continue; }",
"var j;",
LINE_JOINER.join(
"case 0:",
" j = 0;",
"case 1:",
" if (!(j < 10)) { $jscomp$generator$state = 3; break; }",
" $jscomp$generator$state = 4;",
" return {value: j, done: false};",
"case 4:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 5; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 5:",
" $jscomp$generator$state = 2;",
" break;",
"case 2:",
" j++;",
" $jscomp$generator$state = 1;",
" break",
"case 3:",
" $jscomp$generator$state = -1;"));
}
public void testDoWhileLoopsGenerator() {
rewriteGeneratorBodyWithVars(
"do { yield j; } while (j < 10);",
"var $jscomp$generator$first$do;",
LINE_JOINER.join(
"case 0:",
" $jscomp$generator$first$do = true;",
"case 1:",
" if (!($jscomp$generator$first$do || j < 10)) {",
" $jscomp$generator$state = 3; break; }",
" $jscomp$generator$state = 4;",
" return {value: j, done: false};",
"case 4:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 5; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 5:",
"case 2:",
" $jscomp$generator$first$do = false;",
" $jscomp$generator$state = 1;",
" break",
"case 3:",
" $jscomp$generator$state = -1;"));
}
public void testYieldNoValue() {
rewriteGeneratorBody(
"yield;",
LINE_JOINER.join(
"case 0:",
" $jscomp$generator$state = 1;",
" return {value: undefined, done: false};",
"case 1:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 2; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 2:",
" $jscomp$generator$state = -1;"));
}
public void testReturnNoValue() {
rewriteGeneratorBody(
"return;",
LINE_JOINER.join(
"case 0:",
" $jscomp$generator$state = -1;",
" return {value: undefined, done: true};",
" $jscomp$generator$state = -1;"));
}
public void testYieldExpression() {
rewriteGeneratorBodyWithVars(
"return (yield 1);",
"var $jscomp$generator$next$arg0;",
LINE_JOINER.join(
"case 0:",
" $jscomp$generator$state = 1;",
" return {value: 1, done: false};",
"case 1:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 2; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 2:",
" $jscomp$generator$next$arg0 = $jscomp$generator$next$arg;",
" $jscomp$generator$state = -1;",
" return {value: $jscomp$generator$next$arg0, done: true};",
" $jscomp$generator$state = -1;"));
}
public void testFunctionInGenerator() {
test(
"function *f() { function g() {} }",
LINE_JOINER.join(
"/** @suppress {uselessCode} */",
"function f() {",
" var $jscomp$generator$state = 0;",
" function g() {}",
" function $jscomp$generator$impl($jscomp$generator$next$arg,",
" $jscomp$generator$throw$arg) {",
" while (1) switch ($jscomp$generator$state) {",
" case 0:",
" $jscomp$generator$state = -1;",
" default:",
" return {value: undefined, done: true}",
" }",
" }",
" var iterator = /** @type {!Generator<?>} */ ({",
" next: function(arg){ return $jscomp$generator$impl(arg, undefined); },",
" throw: function(arg){ return $jscomp$generator$impl(undefined, arg); },",
" return: function(arg) { throw Error('Not yet implemented'); },",
" });",
" $jscomp.initSymbolIterator();",
" /** @this {!Generator<?>} */",
" iterator[Symbol.iterator] = function() { return this; };",
" return iterator;",
"}"));
}
public void testYieldAll() {
rewriteGeneratorBodyWithVars(
"yield * n;",
"var $jscomp$generator$yield$entry; var $jscomp$generator$yield$all;",
LINE_JOINER.join(
"case 0:",
" $jscomp$generator$yield$all = $jscomp.makeIterator(n);",
"case 1:",
" if (!!($jscomp$generator$yield$entry =",
" $jscomp$generator$yield$all.next($jscomp$generator$next$arg)).done) {",
" $jscomp$generator$state = 2;",
" break;",
" }",
" $jscomp$generator$state = 3;",
" return {value: $jscomp$generator$yield$entry.value, done: false};",
"case 3:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 4; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 4:",
" $jscomp$generator$state = 1;",
" break;",
"case 2:",
" $jscomp$generator$state = -1;"));
assertThat(getLastCompiler().injected)
.containsExactly("es6/symbol", "es6/util/makeiterator");
rewriteGeneratorBodyWithVars(
"var i = yield * n;",
"var i;" + "var $jscomp$generator$yield$entry;" + "var $jscomp$generator$yield$all;",
LINE_JOINER.join(
"case 0:",
" $jscomp$generator$yield$all = $jscomp.makeIterator(n);",
"case 1:",
" if (!!($jscomp$generator$yield$entry =",
" $jscomp$generator$yield$all.next($jscomp$generator$next$arg)).done) {",
" $jscomp$generator$state = 2;",
" break;",
" }",
" $jscomp$generator$state = 3;",
" return {value: $jscomp$generator$yield$entry.value, done: false};",
"case 3:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 4; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 4:",
" $jscomp$generator$state = 1;",
" break;",
"case 2:",
" i = $jscomp$generator$yield$entry.value;",
" $jscomp$generator$state = -1;"));
}
public void testYieldArguments() {
rewriteGeneratorBodyWithVars(
"yield arguments[0];",
"var $jscomp$generator$arguments = arguments;",
LINE_JOINER.join(
"case 0:",
" $jscomp$generator$state = 1;",
" return {value: $jscomp$generator$arguments[0], done: false};",
"case 1:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 2; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 2:",
" $jscomp$generator$state = -1;"));
}
public void testYieldThis() {
rewriteGeneratorBodyWithVars(
"yield this;",
"var $jscomp$generator$this = this;",
LINE_JOINER.join(
"case 0:",
" $jscomp$generator$state = 1;",
" return {value: $jscomp$generator$this, done: false};",
"case 1:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 2; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 2:",
" $jscomp$generator$state = -1;"));
}
public void testGeneratorShortCircuit() {
rewriteGeneratorBody(
"0 || (yield 1);",
LINE_JOINER.join(
"case 0:",
" if (!0) {",
" $jscomp$generator$state = 1;",
" break;",
" }",
" $jscomp$generator$state = 2;",
" break;",
"case 1:",
" $jscomp$generator$state = 3;",
" return{value:1, done:false};",
"case 3:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 4;",
" break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 4:",
"case 2:",
" $jscomp$generator$state = -1;"));
rewriteGeneratorBody(
"0 && (yield 1);",
LINE_JOINER.join(
"case 0:",
" if (!0) {",
" $jscomp$generator$state = 1;",
" break;",
" }",
" $jscomp$generator$state = 2;",
" return{value:1, done:false};",
"case 2:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 3;",
" break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 3:",
"case 1:",
" $jscomp$generator$state = -1;"));
rewriteGeneratorBody(
"0 ? 1 : (yield 1);",
LINE_JOINER.join(
"case 0:",
" if (!0) {",
" $jscomp$generator$state = 1;",
" break;",
" }",
" 1;",
" $jscomp$generator$state = 2;",
" break;",
"case 1:",
" $jscomp$generator$state = 3;",
" return{value:1, done:false};",
"case 3:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 4;",
" break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 4:",
"case 2:",
" $jscomp$generator$state = -1;"));
}
public void testYieldSwitch() {
rewriteGeneratorBodyWithVars(
LINE_JOINER.join(
"while (1) {",
" switch (i) {",
" case 1:",
" yield 2;",
" break;",
" case 2:",
" yield 3;",
" continue;",
" case 3:",
" yield 4;",
" default:",
" yield 5;",
" }",
"}"),
"var $jscomp$generator$switch$val1; var $jscomp$generator$switch$entered0;",
LINE_JOINER.join(
"case 0:",
"case 1:",
" if (!1) {",
" $jscomp$generator$state = 2;",
" break;",
" }",
" $jscomp$generator$switch$entered0 = false;",
" $jscomp$generator$switch$val1 = i;",
" if (!($jscomp$generator$switch$entered0",
" || $jscomp$generator$switch$val1 === 1)) {",
" $jscomp$generator$state = 4;",
" break;",
" }",
" $jscomp$generator$switch$entered0 = true;",
" $jscomp$generator$state = 5;",
" return {value: 2, done: false};",
"case 5:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 6; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 6:",
" $jscomp$generator$state = 3;",
" break;",
"case 4:",
" if (!($jscomp$generator$switch$entered0",
" || $jscomp$generator$switch$val1 === 2)) {",
" $jscomp$generator$state = 7;",
" break;",
" }",
" $jscomp$generator$switch$entered0 = true;",
" $jscomp$generator$state = 8;",
" return {value: 3, done: false};",
"case 8:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 9; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 9:",
" $jscomp$generator$state = 1;",
" break;",
"case 7:",
" if (!($jscomp$generator$switch$entered0",
" || $jscomp$generator$switch$val1 === 3)) {",
" $jscomp$generator$state = 10;",
" break;",
" }",
" $jscomp$generator$switch$entered0 = true;",
" $jscomp$generator$state = 11;",
" return{value: 4, done: false};",
"case 11:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 12; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 12:",
"case 10:",
" $jscomp$generator$switch$entered0 = true;",
" $jscomp$generator$state = 13;",
" return {value: 5, done: false};",
"case 13:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 14; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 14:",
"case 3:",
" $jscomp$generator$state = 1;",
" break;",
"case 2:",
" $jscomp$generator$state = -1;"));
}
public void testGeneratorNoTranslate() {
rewriteGeneratorBody(
"if (1) { try {} catch (e) {} throw 1; }",
LINE_JOINER.join(
"case 0:",
" if (!1) {",
" $jscomp$generator$state = 1;",
" break;",
" }",
" try {} catch (e) {}",
" $jscomp$generator$state = -1;",
" throw 1;",
"case 1:",
" $jscomp$generator$state = -1;"));
}
public void testGeneratorForIn() {
rewriteGeneratorBodyWithVars(
"for (var i in j) { yield 1; }",
LINE_JOINER.join(
"var i;",
"var $jscomp$generator$forin$iter0;",
"var $jscomp$generator$forin$var0;",
"var $jscomp$generator$forin$array0;"),
LINE_JOINER.join(
"case 0:",
" $jscomp$generator$forin$array0 = [];",
" $jscomp$generator$forin$iter0 = j;",
" for (i in $jscomp$generator$forin$iter0) {",
" $jscomp$generator$forin$array0.push(i);",
" }",
" $jscomp$generator$forin$var0 = 0;",
"case 1:",
" if (!($jscomp$generator$forin$var0",
" < $jscomp$generator$forin$array0.length)) {",
" $jscomp$generator$state = 3;",
" break;",
" }",
" i = $jscomp$generator$forin$array0[$jscomp$generator$forin$var0];",
" if (!(!(i in $jscomp$generator$forin$iter0))) {",
" $jscomp$generator$state = 4;",
" break;",
" }",
" $jscomp$generator$state = 2;",
" break;",
"case 4:",
" $jscomp$generator$state = 5;",
" return{value:1, done:false};",
"case 5:",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 6; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
"case 6:",
"case 2:",
" $jscomp$generator$forin$var0++;",
" $jscomp$generator$state = 1;",
" break;",
"case 3:",
" $jscomp$generator$state = -1;"));
}
public void testGeneratorTryCatch() {
rewriteGeneratorBodyWithVars(
"try {yield 1;} catch (e) {}",
"var e; var $jscomp$generator$global$error;",
LINE_JOINER.join(
"case 0:",
" try {",
" $jscomp$generator$state = 3;",
" return {value: 1, done: false};",
" } catch ($jscomp$generator$e) {",
" $jscomp$generator$global$error = $jscomp$generator$e;",
" $jscomp$generator$state = 1;",
" break;",
" }",
"case 3:",
" try {",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 4; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
" } catch ($jscomp$generator$e) {",
" $jscomp$generator$global$error = $jscomp$generator$e;",
" $jscomp$generator$state = 1;",
" break;",
" }",
"case 4:",
" try {",
" $jscomp$generator$state = 2;",
" break;",
" } catch ($jscomp$generator$e) {",
" $jscomp$generator$global$error = $jscomp$generator$e;",
" $jscomp$generator$state = 1;",
" break;",
" }",
"case 1:",
" e = $jscomp$generator$global$error;",
"case 2:",
" $jscomp$generator$state = -1;"));
}
public void testGeneratorFinally() {
rewriteGeneratorBodyWithVars(
"try {yield 1;} catch (e) {} finally {b();}",
"var e; var $jscomp$generator$finally0; var $jscomp$generator$global$error;",
LINE_JOINER.join(
"case 0:",
" try {",
" $jscomp$generator$state = 4;",
" return {value: 1, done: false};",
" } catch ($jscomp$generator$e) {",
" $jscomp$generator$global$error = $jscomp$generator$e;",
" $jscomp$generator$state = 1;",
" break;",
" }",
"case 4:",
" try {",
" if (!($jscomp$generator$throw$arg !== undefined)) {",
" $jscomp$generator$state = 5; break;",
" }",
" $jscomp$generator$state = -1;",
" throw $jscomp$generator$throw$arg;",
" } catch ($jscomp$generator$e) {",
" $jscomp$generator$global$error = $jscomp$generator$e;",
" $jscomp$generator$state = 1;",
" break;",
" }",
"case 5:",
" try {",
" $jscomp$generator$finally0 = 3;",
" $jscomp$generator$state = 2;",
" break;",
" } catch ($jscomp$generator$e) {",
" $jscomp$generator$global$error = $jscomp$generator$e;",
" $jscomp$generator$state = 1;",
" break;",
" }",
"case 1:",
" e = $jscomp$generator$global$error;",
" $jscomp$generator$finally0 = 3;",
"case 2:",
" b();",
" $jscomp$generator$state = $jscomp$generator$finally0;",
" break;",
"case 3:",
" $jscomp$generator$state = -1;"));
}
@Override
protected Compiler createCompiler() {
return new NoninjectingCompiler();
}
@Override
NoninjectingCompiler getLastCompiler() {
return (NoninjectingCompiler) super.getLastCompiler();
}
}