Implementing JavaScript-to-Java calls in JSBody

This commit is contained in:
Alexey Andreev 2015-09-25 17:31:10 +03:00
parent 7012e9b4d9
commit ffbd68cf69
3 changed files with 68 additions and 4 deletions

View File

@ -71,6 +71,9 @@ import org.mozilla.javascript.ast.VariableDeclaration;
import org.mozilla.javascript.ast.VariableInitializer;
import org.mozilla.javascript.ast.WhileLoop;
import org.teavm.codegen.SourceWriter;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.model.CallLocation;
import org.teavm.model.MethodReference;
/**
*
@ -94,11 +97,13 @@ public class AstWriter {
private static final int PRECEDENCE_COND = 16;
private static final int PRECEDENCE_ASSIGN = 17;
private static final int PRECEDENCE_COMMA = 18;
private Diagnostics diagnostics;
private SourceWriter writer;
private Map<String, NameEmitter> nameMap = new HashMap<>();
private Set<String> aliases = new HashSet<>();
public AstWriter(SourceWriter writer) {
public AstWriter(Diagnostics diagnostics, SourceWriter writer) {
this.diagnostics = diagnostics;
this.writer = writer;
}
@ -501,6 +506,14 @@ public class AstWriter {
}
private void print(FunctionCall node, int precedence) throws IOException {
if (node.getTarget() instanceof PropertyGet) {
PropertyGet propertyGet = (PropertyGet) node.getTarget();
MethodReference methodRef = getJavaMethodSelector(propertyGet.getTarget());
if (methodRef != null && propertyGet.getProperty().getIdentifier().equals("invoke")) {
return;
}
}
if (precedence < PRECEDENCE_FUNCTION) {
writer.append('(');
}
@ -524,6 +537,57 @@ public class AstWriter {
}
}
private MethodReference getJavaMethodSelector(AstNode node) {
if (!(node instanceof FunctionCall)) {
return null;
}
FunctionCall call = (FunctionCall) node;
if (!isJavaMethodRepository(call.getTarget())) {
return null;
}
if (call.getArguments().size() != 1) {
diagnostics.warning(new CallLocation(null), "JavaMethods.get method should take exactly one argument");
return null;
}
StringBuilder nameBuilder = new StringBuilder();
if (!extractMethodName(call.getArguments().get(0), nameBuilder)) {
diagnostics.warning(new CallLocation(null), "JavaMethods.get method should take string constant");
return null;
}
return MethodReference.parse(nameBuilder.toString());
}
private boolean isJavaMethodRepository(AstNode node) {
if (!(node instanceof PropertyGet)) {
return false;
}
PropertyGet propertyGet = (PropertyGet) node;
if (propertyGet.getLeft() instanceof Name) {
return false;
}
if (!((Name) propertyGet.getTarget()).getIdentifier().equals("JavaMethods")) {
return false;
}
if (!propertyGet.getProperty().getIdentifier().equals("get")) {
return false;
}
return true;
}
private boolean extractMethodName(AstNode node, StringBuilder sb) {
if (node.getType() == Token.ADD) {
InfixExpression infix = (InfixExpression) node;
return extractMethodName(infix.getLeft(), sb) && extractMethodName(infix.getRight(), sb);
} else if (node.getType() == Token.STRING) {
sb.append(((StringLiteral) node).getValue());
return true;
} else {
return false;
}
}
private void print(ConditionalExpression node, int precedence) throws IOException {
if (precedence < PRECEDENCE_COND) {
writer.append('(');

View File

@ -39,7 +39,7 @@ class JSBodyAstEmitter implements JSBodyEmitter {
@Override
public void emit(InjectorContext context) throws IOException {
AstWriter astWriter = new AstWriter(context.getWriter());
AstWriter astWriter = new AstWriter(null, context.getWriter());
int paramIndex = 0;
if (!isStatic) {
int index = paramIndex++;
@ -55,7 +55,7 @@ class JSBodyAstEmitter implements JSBodyEmitter {
@Override
public void emit(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
AstWriter astWriter = new AstWriter(writer);
AstWriter astWriter = new AstWriter(context.getDiagnostics(), writer);
int paramIndex = 1;
if (!isStatic) {
int index = paramIndex++;

View File

@ -39,7 +39,7 @@ public class AstWriterTest {
SourceWriterBuilder builder = new SourceWriterBuilder(null);
builder.setMinified(true);
sourceWriter = builder.build(sb);
writer = new AstWriter(sourceWriter);
writer = new AstWriter(null, sourceWriter);
}
@Test