#138 : async / await support in JSweet!

This commit is contained in:
Louis Grignon 2018-05-10 01:23:43 +02:00
parent 3dc9aeeab3
commit f627c76e0c
6 changed files with 104 additions and 31 deletions

View File

@ -1,5 +1,7 @@
package def.js;
import java.util.function.BiConsumer;
/**
* Represents the completion of an asynchronous operation
*/
@ -26,13 +28,7 @@ public class Promise<T> extends def.js.Object {
* A reference to the prototype.
*/
public static Promise<?> prototype;
/**
* Creates a new Promise.
* @param executor A callback used to initialize the promise. This callback is passed two arguments:
* a resolve callback used resolve the promise with a value or the result of another promise,
* and a reject callback used to reject the promise with a provided reason or error.
*/
public Promise(ExecutorBiConsumer<java.util.function.Consumer<T>,java.util.function.Consumer<java.lang.Object>> executor){}
/**
* Creates a Promise that is resolved with an array of results when all of the provided Promises
* resolve, or rejected when any Promise is rejected.
@ -126,6 +122,15 @@ public class Promise<T> extends def.js.Object {
* and a reject callback used to reject the promise with a provided reason or error.
*/
public Promise(ExecutorPromiseLikeBiConsumer<java.util.function.Consumer<PromiseLike<T>>,java.util.function.Consumer<java.lang.Object>> executor){}
/**
* Creates a new Promise.
* @param executor A callback used to initialize the promise. This callback is passed two arguments:
* a resolve callback used resolve the promise with a value or the result of another promise,
* and a reject callback used to reject the promise with a provided reason or error.
*/
public Promise(BiConsumer<java.util.function.Consumer<T>,java.util.function.Consumer<java.lang.Object>> executor){}
/**
* Creates a Promise that is resolved with an array of results when all of the provided Promises
* resolve, or rejected when any Promise is rejected.
@ -161,12 +166,7 @@ public class Promise<T> extends def.js.Object {
public interface ExecutorPromiseLikeBiConsumer<T1,T2> {
public void $apply(T1 p1, T2 p2);
}
/** This functional interface should be used for disambiguating lambdas in function parameters (by casting to this interface).<p>It was automatically generated for functions (taking lambdas) that lead to the same erased signature. */
@java.lang.FunctionalInterface()
@jsweet.lang.Erased
public interface ExecutorBiConsumer<T1,T2> {
public void $apply(T1 p1, T2 p2);
}
/** This class was automatically generated for disambiguating erased method signatures. */
@jsweet.lang.Erased
public static class IterableT<T> extends def.js.Object {

View File

@ -0,0 +1,34 @@
/*
* JSweet - http://www.jsweet.org
* Copyright (C) 2015 CINCHEO SAS <renaud.pawlak@cincheo.fr>
*
* 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 jsweet.lang;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* This annotation type is used on async methods.
*
* @author Louis Grignon
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
@Documented
public @interface Async {
}

View File

@ -23,6 +23,7 @@ import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import def.js.Promise;
import jsweet.util.function.Consumer4;
import jsweet.util.function.Consumer5;
import jsweet.util.function.Consumer6;
@ -704,4 +705,9 @@ public final class Lang {
*/
public static native <T> T $insert(String typescriptString);
public static native <R> R await(Promise<R> promise);
public static native <R> def.js.Function async(def.js.Function function);
public static native <T> Promise<T> asyncReturn(T result);
}

View File

@ -253,6 +253,10 @@ public abstract class JSweetConfig {
* Fully-qualified name for the JSweet <code>@Erased</code> annotation (see JSweet core API).
*/
public static final String ANNOTATION_ERASED = JSweetConfig.LANG_PACKAGE + ".Erased";
/**
* Fully-qualified name for the JSweet <code>@Async</code> annotation (see JSweet core API).
*/
public static final String ANNOTATION_ASYNC = JSweetConfig.LANG_PACKAGE + ".Async";
/**
* Fully-qualified name for the JSweet <code>@SyntacticIterable</code> annotation (see JSweet core API).
*/

View File

@ -161,13 +161,12 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
*/
public static final String PARENT_CLASS_FIELD_NAME = "__parent";
/**
* The name of the field where the implemented interface names are stored in
* the generated TypeScript code (for <code>instanceof</code> operator).
* The name of the field where the implemented interface names are stored in the
* generated TypeScript code (for <code>instanceof</code> operator).
*/
public static final String INTERFACES_FIELD_NAME = "__interfaces";
/**
* The suffix added to static field initialization methods (for Java
* semantics).
* The suffix added to static field initialization methods (for Java semantics).
*/
public static final String STATIC_INITIALIZATION_SUFFIX = "_$LI$";
/**
@ -220,8 +219,8 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
*/
public static final Pattern METHOD_NAME_MARKER = Pattern.compile("\\{\\{\\s*methodName\\s*\\}\\}");
/**
* A regular expression for matching class name markers in
* <code>@Replace</code> expression.
* A regular expression for matching class name markers in <code>@Replace</code>
* expression.
*/
public static final Pattern CLASS_NAME_MARKER = Pattern.compile("\\{\\{\\s*className\\s*\\}\\}");
/**
@ -235,8 +234,8 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
protected static Logger logger = Logger.getLogger(Java2TypeScriptTranslator.class);
/**
* A state flag indicating the comparison mode to be used by this printer
* for printing comparison operators.
* A state flag indicating the comparison mode to be used by this printer for
* printing comparison operators.
*
* @author Renaud Pawlak
*/
@ -248,8 +247,8 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
FORCE_STRICT,
/**
* Uses the strict comparison operators (===, >==, <==), except for null
* literals, where loose operators are used to match better the Java
* semantics. This is the default behavior.
* literals, where loose operators are used to match better the Java semantics.
* This is the default behavior.
*/
STRICT,
/**
@ -1961,6 +1960,7 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
// erased elements are ignored
return;
}
JCClassDecl parent = (JCClassDecl) getParent();
if (parent != null && methodDecl.pos == parent.pos && !getScope().enumWrapperClassScope) {
@ -2127,6 +2127,11 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
if (!(inOverload && !inCoreWrongOverload)) {
printDocComment(methodDecl);
}
if (context.hasAnnotationType(methodDecl.sym, JSweetConfig.ANNOTATION_ASYNC)) {
print(" async ");
}
if (parent == null) {
print("function ");
} else if (globals) {
@ -3036,10 +3041,10 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
if (varDecl.init != null && !isDefinitionScope) {
print("if(" + prefix).print(name).print(" == null) ").print(prefix).print(name).print(" = ");
/*
* if (getScope().enumWrapperClassScope) { JCNewClass
* newClass = (JCNewClass) varDecl.init; print("new "
* ).print(clazz.getSimpleName().toString()).print("(")
* .printArgList(null, newClass.args).print(")"); } else {
* if (getScope().enumWrapperClassScope) { JCNewClass newClass = (JCNewClass)
* varDecl.init; print("new "
* ).print(clazz.getSimpleName().toString()).print("(") .printArgList(null,
* newClass.args).print(")"); } else {
*/
if (!substituteAssignedExpression(varDecl.type, varDecl.init)) {
print(varDecl.init);
@ -4518,7 +4523,8 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
: null;
} else if (expr instanceof JCFieldAccess) {
return context.lazyInitializedStatics.contains(((JCFieldAccess) expr).sym)
? (VarSymbol) ((JCFieldAccess) expr).sym : null;
? (VarSymbol) ((JCFieldAccess) expr).sym
: null;
} else {
return null;
}
@ -4815,7 +4821,7 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
if (context.types.isSameType(context.symtab.charType, caseStatement.pat.type)) {
JCLiteral caseLiteral;
if (caseStatement.pat instanceof JCTypeCast) {
caseLiteral = (JCLiteral) ((JCTypeCast)caseStatement.pat).expr;
caseLiteral = (JCLiteral) ((JCTypeCast) caseStatement.pat).expr;
} else {
caseLiteral = (JCLiteral) caseStatement.pat;
}

View File

@ -492,6 +492,21 @@ public class Java2TypeScriptAdapter extends PrinterAdapter {
print(")");
return true;
case "async":
print(" async ");
print(invocationElement.getArgument(0));
return true;
case "await":
print(" await ");
printCastMethodInvocation(invocationElement);
return true;
case "asyncReturn":
print(" ");
printCastMethodInvocation(invocationElement);
return true;
case "union":
getPrinter().typeChecker.checkUnionTypeAssignment(context.types, getPrinter().getParent(),
((MethodInvocationElementSupport) invocationElement).getTree());
@ -1267,11 +1282,19 @@ public class Java2TypeScriptAdapter extends PrinterAdapter {
}
protected final void printCastMethodInvocation(InvocationElement invocation) {
if (getPrinter().getParent() instanceof JCMethodInvocation) {
boolean needsParens =getPrinter().getParent() instanceof JCMethodInvocation;
if (needsParens) {
// async needs no parens to work
JCMethodInvocation parentInvocation = (JCMethodInvocation)getPrinter().getParent();
if (parentInvocation.meth instanceof JCIdent) {
needsParens = !((JCIdent)parentInvocation.meth).getName().toString().equals("async");
}
}
if (needsParens) {
print("(");
}
print(invocation.getArgument(0));
if (getPrinter().getParent() instanceof JCMethodInvocation) {
if (needsParens) {
print(")");
}
}