Skip to content

Commit

Permalink
Modify RewriteAsyncFunctions to generate less boilerplate code while …
Browse files Browse the repository at this point in the history
…transpiling async functions.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=188322314
  • Loading branch information
SergejSalnikov authored and lauraharker committed Mar 9, 2018
1 parent 813feba commit bf3d108
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 117 deletions.
46 changes: 19 additions & 27 deletions src/com/google/javascript/jscomp/RewriteAsyncFunctions.java
Expand Up @@ -41,20 +41,19 @@
* let $jscomp$async$this = this;
* let $jscomp$async$arguments = arguments;
* let $jscomp$async$super$get$x = () => super.x;
* function* $jscomp$async$generator() {
* // original body of foo() with:
* // - await (x) replaced with yield (x)
* // - arguments replaced with $jscomp$async$arguments
* // - this replaced with $jscomp$async$this
* // - super.x replaced with $jscomp$async$super$get$x()
* // - super.x(5) replaced with $jscomp$async$super$get$x().call($jscomp$async$this, 5)
* }
* return $jscomp.executeAsyncGenerator($jscomp$async$generator());
* return $jscomp.asyncExecutePromiseGeneratorFunction(
* function* () {
* // original body of foo() with:
* // - await (x) replaced with yield (x)
* // - arguments replaced with $jscomp$async$arguments
* // - this replaced with $jscomp$async$this
* // - super.x replaced with $jscomp$async$super$get$x()
* // - super.x(5) replaced with $jscomp$async$super$get$x().call($jscomp$async$this, 5)
* });
* }}</pre>
*/
public final class RewriteAsyncFunctions implements NodeTraversal.Callback, HotSwapCompilerPass {

private static final String ASYNC_GENERATOR_NAME = "$jscomp$async$generator";
private static final String ASYNC_ARGUMENTS = "$jscomp$async$arguments";
private static final String ASYNC_THIS = "$jscomp$async$this";
private static final String ASYNC_SUPER_PROP_GETTER_PREFIX = "$jscomp$async$super$get$";
Expand Down Expand Up @@ -231,7 +230,7 @@ private void convertAsyncFunction(LexicalContext functionContext) {
Node originalFunction = checkNotNull(functionContext.function);
originalFunction.setIsAsyncFunction(false);
Node originalBody = originalFunction.getLastChild();
Node newBody = IR.block().useSourceInfoIfMissingFrom(originalBody);
Node newBody = IR.block();
originalFunction.replaceChild(originalBody, newBody);

if (functionContext.mustAddAsyncThisVariable) {
Expand All @@ -254,26 +253,19 @@ private void convertAsyncFunction(LexicalContext functionContext) {

// Normalize arrow function short body to block body
if (!originalBody.isNormalBlock()) {
originalBody = IR.block(IR.returnNode(originalBody)).useSourceInfoFromForTree(originalBody);
originalBody = IR.block(IR.returnNode(originalBody).useSourceInfoFrom(originalBody))
.useSourceInfoFrom(originalBody);
}
// NOTE: visit() will already have made appropriate replacements in originalBody so it may
// be used as the generator function body.
Node newFunctionName = IR.name(ASYNC_GENERATOR_NAME);
Node originalName = originalFunction.getFirstChild();
// Use the source info from the function name. Without this line, we would use the source info
// from originalBody for the name node near the end of this method.
newFunctionName.useSourceInfoIfMissingFromForTree(originalName);
Node generatorFunction = IR.function(newFunctionName, IR.paramList(), originalBody);
compiler.reportChangeToChangeScope(generatorFunction);
Node generatorFunction = IR.function(IR.name(""), IR.paramList(), originalBody);
generatorFunction.setIsGeneratorFunction(true);
// function* $jscomp$async$generator() { ... }
newBody.addChildToBack(generatorFunction);

// return $jscomp.executeAsyncGenerator($jscomp$async$generator());
Node executeAsyncGenerator = IR.getprop(IR.name("$jscomp"), IR.string("executeAsyncGenerator"));
newBody.addChildToBack(
IR.returnNode(
IR.call(executeAsyncGenerator, NodeUtil.newCallNode(IR.name(ASYNC_GENERATOR_NAME)))));
compiler.reportChangeToChangeScope(generatorFunction);

// return $jscomp.asyncExecutePromiseGeneratorFunction(function* () { ... });
newBody.addChildToBack(IR.returnNode(IR.call(
IR.getprop(IR.name("$jscomp"), IR.string("asyncExecutePromiseGeneratorFunction")),
generatorFunction)));

newBody.useSourceInfoIfMissingFromForTree(originalBody);
compiler.reportChangeToEnclosingScope(newBody);
Expand Down
40 changes: 20 additions & 20 deletions test/com/google/javascript/jscomp/IntegrationTest.java
Expand Up @@ -5166,26 +5166,26 @@ public void testMethodDestructuringInTranspiledAsyncFunction() {
" alert(i);",
"};",
"function foo() {",
" function $jscomp$async$generator() {",
" var JSCompiler_temp_const;",
" var JSCompiler_temp_const$jscomp$1;",
" return $jscomp.generator.createGenerator(",
" $jscomp$async$generator,",
" function ($jscomp$generator$context) {",
" do switch ($jscomp$generator$context.nextAddress) {",
" case 1:",
" JSCompiler_temp_const = A;",
" JSCompiler_temp_const$jscomp$1 = A$doSomething;",
" return $jscomp$generator$context.yield(3, 2);",
" case 2:",
" JSCompiler_temp_const$jscomp$1.call(",
" JSCompiler_temp_const,",
" $jscomp$generator$context.yieldResult);",
" $jscomp$generator$context.jumpToEnd();",
" } while (0);",
" });",
" }",
" return $jscomp.executeAsyncGenerator($jscomp$async$generator())",
" return $jscomp.asyncExecutePromiseGeneratorFunction(",
" function $jscomp$generator$function() {",
" var JSCompiler_temp_const;",
" var JSCompiler_temp_const$jscomp$1;",
" return $jscomp.generator.createGenerator(",
" $jscomp$generator$function,",
" function ($jscomp$generator$context) {",
" do switch ($jscomp$generator$context.nextAddress) {",
" case 1:",
" JSCompiler_temp_const = A;",
" JSCompiler_temp_const$jscomp$1 = A$doSomething;",
" return $jscomp$generator$context.yield(3, 2);",
" case 2:",
" JSCompiler_temp_const$jscomp$1.call(",
" JSCompiler_temp_const,",
" $jscomp$generator$context.yieldResult);",
" $jscomp$generator$context.jumpToEnd();",
" } while (0);",
" });",
" })",
"}",
"foo();"));
}
Expand Down
140 changes: 70 additions & 70 deletions test/com/google/javascript/jscomp/RewriteAsyncFunctionsTest.java
Expand Up @@ -60,12 +60,12 @@ public void testInnerArrowFunctionUsingThis() {
"class X {",
" m() {",
" const $jscomp$async$this = this;",
" function* $jscomp$async$generator() {",
" return new Promise((resolve, reject) => {",
" return $jscomp$async$this",
" });",
" }",
" return $jscomp.executeAsyncGenerator($jscomp$async$generator())",
" return $jscomp.asyncExecutePromiseGeneratorFunction(",
" function* () {",
" return new Promise((resolve, reject) => {",
" return $jscomp$async$this;",
" });",
" });",
" }",
"}"));
}
Expand Down Expand Up @@ -93,10 +93,10 @@ public void testInnerSuperCall() {
" m() {",
" const $jscomp$async$this = this;",
" const $jscomp$async$super$get$m = () => super.m;",
" function* $jscomp$async$generator() {",
" return $jscomp$async$super$get$m().call($jscomp$async$this);",
" }",
" return $jscomp.executeAsyncGenerator($jscomp$async$generator())",
" return $jscomp.asyncExecutePromiseGeneratorFunction(",
" function* () {",
" return $jscomp$async$super$get$m().call($jscomp$async$this);",
" });",
" }",
"}"));
}
Expand Down Expand Up @@ -124,11 +124,11 @@ public void testInnerSuperReference() {
"class X extends A {",
" m() {",
" const $jscomp$async$super$get$m = () => super.m;",
" function* $jscomp$async$generator() {",
" const tmp = $jscomp$async$super$get$m();",
" return tmp.call(null);",
" }",
" return $jscomp.executeAsyncGenerator($jscomp$async$generator())",
" return $jscomp.asyncExecutePromiseGeneratorFunction(",
" function* () {",
" const tmp = $jscomp$async$super$get$m();",
" return tmp.call(null);",
" });",
" }",
"}"));
}
Expand All @@ -146,10 +146,10 @@ public void testNestedArrowFunctionUsingThis() {
" m() {",
" return () => {",
" const $jscomp$async$this = this;",
" function* $jscomp$async$generator() {",
" return () => $jscomp$async$this;",
" }",
" return $jscomp.executeAsyncGenerator($jscomp$async$generator())",
" return $jscomp.asyncExecutePromiseGeneratorFunction(",
" function* () {",
" return () => $jscomp$async$this;",
" })",
" }",
" }",
"}"));
Expand All @@ -169,12 +169,12 @@ public void testInnerArrowFunctionUsingArguments() {
"class X {",
" m() {",
" const $jscomp$async$arguments = arguments;",
" function* $jscomp$async$generator() {",
" return new Promise((resolve,reject) => {",
" return $jscomp$async$arguments",
" });",
" }",
" return $jscomp.executeAsyncGenerator($jscomp$async$generator())",
" return $jscomp.asyncExecutePromiseGeneratorFunction(",
" function* () {",
" return new Promise((resolve, reject) => {",
" return $jscomp$async$arguments",
" });",
" });",
" }",
"}"));
}
Expand All @@ -184,10 +184,10 @@ public void testRequiredCodeInjected() {
"async function foo() { return 1; }",
lines(
"function foo() {",
" function* $jscomp$async$generator() {",
" return 1;",
" }",
" return $jscomp.executeAsyncGenerator($jscomp$async$generator());",
" return $jscomp.asyncExecutePromiseGeneratorFunction(",
" function* () {",
" return 1;",
" });",
"}"));
assertThat(getLastCompiler().injected).containsExactly("es6/execute_async_generator");
}
Expand All @@ -197,10 +197,10 @@ public void testAwaitReplacement() {
"async function foo(promise) { return await promise; }",
lines(
"function foo(promise) {",
" function* $jscomp$async$generator() {",
" return yield promise;",
" }",
" return $jscomp.executeAsyncGenerator($jscomp$async$generator());",
" return $jscomp.asyncExecutePromiseGeneratorFunction(",
" function* () {",
" return yield promise;",
" });",
"}"));
}

Expand All @@ -218,10 +218,10 @@ public void testArgumentsReplacement_asyncFunction() {
lines(
"function f(a, b, ...rest) {",
" const $jscomp$async$arguments = arguments;",
" function* $jscomp$async$generator() {",
" return $jscomp$async$arguments.length;", // arguments replaced
" }",
" return $jscomp.executeAsyncGenerator($jscomp$async$generator());",
" return $jscomp.asyncExecutePromiseGeneratorFunction(",
" function* () {",
" return $jscomp$async$arguments.length;", // arguments replaced
" });",
"}"));
}

Expand All @@ -236,10 +236,10 @@ public void testArgumentsReplacement_asyncClosure() {
"function outer() {",
" function f() {",
" const $jscomp$async$arguments = arguments;",
" function* $jscomp$async$generator() {",
" return $jscomp$async$arguments.length;", // arguments replaced
" }",
" return $jscomp.executeAsyncGenerator($jscomp$async$generator());",
" return $jscomp.asyncExecutePromiseGeneratorFunction(",
" function* () {",
" return $jscomp$async$arguments.length;", // arguments replaced
" });",
" }",
" return f(arguments)", // unchanged
"}"));
Expand All @@ -257,13 +257,13 @@ public void testArgumentsReplacement_normalClosureInAsync() {
lines(
"function a() {",
" const $jscomp$async$arguments = arguments;",
" function* $jscomp$async$generator() {",
" function inner() {",
" return arguments.length;", // unchanged
" }",
" return inner.apply(undefined, $jscomp$async$arguments);", // arguments replaced
" }",
" return $jscomp.executeAsyncGenerator($jscomp$async$generator());",
" return $jscomp.asyncExecutePromiseGeneratorFunction(",
" function* () {",
" function inner() {",
" return arguments.length;", // unchanged
" }",
" return inner.apply(undefined, $jscomp$async$arguments);",
" });",
"}"));
}

Expand All @@ -274,10 +274,10 @@ public void testClassMethod() {
"class A {",
" f() {",
" const $jscomp$async$this = this;",
" function* $jscomp$async$generator() {",
" return $jscomp$async$this.x;", // this replaced
" }",
" return $jscomp.executeAsyncGenerator($jscomp$async$generator());",
" return $jscomp.asyncExecutePromiseGeneratorFunction(",
" function *() {",
" return $jscomp$async$this.x;", // this replaced
" });",
" }",
"}"));
}
Expand All @@ -296,16 +296,16 @@ public void testAsyncClassMethodWithAsyncArrow() {
" f() {",
" const $jscomp$async$this = this;",
" const $jscomp$async$arguments = arguments;",
" function *$jscomp$async$generator() {",
" let g = () => {",
" function *$jscomp$async$generator() {",
" console.log($jscomp$async$this, $jscomp$async$arguments);",
" }",
" return $jscomp.executeAsyncGenerator($jscomp$async$generator());",
" };",
" g();",
" }",
" return $jscomp.executeAsyncGenerator($jscomp$async$generator());",
" return $jscomp.asyncExecutePromiseGeneratorFunction(",
" function *() {",
" let g = () => {",
" return $jscomp.asyncExecutePromiseGeneratorFunction(",
" function *() {",
" console.log($jscomp$async$this, $jscomp$async$arguments);",
" });",
" };",
" g();",
" });",
" }",
"}"));
}
Expand All @@ -325,10 +325,10 @@ public void testNonAsyncClassMethodWithAsyncArrow() {
" let g = () => {",
" const $jscomp$async$this = this;",
" const $jscomp$async$arguments = arguments;",
" function *$jscomp$async$generator() {",
" console.log($jscomp$async$this, $jscomp$async$arguments);",
" }",
" return $jscomp.executeAsyncGenerator($jscomp$async$generator());",
" return $jscomp.asyncExecutePromiseGeneratorFunction(",
" function *() {",
" console.log($jscomp$async$this, $jscomp$async$arguments);",
" });",
" };",
" g();",
" }",
Expand All @@ -340,10 +340,10 @@ public void testArrowFunctionExpressionBody() {
"let f = async () => 1;",
lines(
"let f = () => {",
" function* $jscomp$async$generator() {",
" return 1;",
" }",
" return $jscomp.executeAsyncGenerator($jscomp$async$generator());",
" return $jscomp.asyncExecutePromiseGeneratorFunction(",
" function* () {",
" return 1;",
" });",
"}"));
}
}

0 comments on commit bf3d108

Please sign in to comment.