mirror of
https://github.com/konsoletyper/teavm.git
synced 2024-11-27 01:30:35 +08:00
Make JS function out of JS object when casting to JSFunctor interface
This commit is contained in:
parent
5035c58533
commit
6551f3eb68
@ -61,6 +61,7 @@ import org.teavm.model.TextLocation;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.Variable;
|
||||
import org.teavm.model.instructions.AssignInstruction;
|
||||
import org.teavm.model.instructions.CastInstruction;
|
||||
import org.teavm.model.instructions.ExitInstruction;
|
||||
import org.teavm.model.instructions.InvocationType;
|
||||
import org.teavm.model.instructions.InvokeInstruction;
|
||||
@ -252,25 +253,55 @@ class JSClassProcessor {
|
||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||
BasicBlock block = program.basicBlockAt(i);
|
||||
for (Instruction insn : block) {
|
||||
if (!(insn instanceof InvokeInstruction)) {
|
||||
continue;
|
||||
}
|
||||
InvokeInstruction invoke = (InvokeInstruction) insn;
|
||||
if (insn instanceof CastInstruction) {
|
||||
replacement.clear();
|
||||
CallLocation callLocation = new CallLocation(methodToProcess.getReference(), insn.getLocation());
|
||||
if (processCast((CastInstruction) insn, callLocation)) {
|
||||
insn.insertNextAll(replacement);
|
||||
insn.delete();
|
||||
}
|
||||
} else if (insn instanceof InvokeInstruction) {
|
||||
InvokeInstruction invoke = (InvokeInstruction) insn;
|
||||
|
||||
MethodReader method = getMethod(invoke.getMethod());
|
||||
if (method == null) {
|
||||
continue;
|
||||
}
|
||||
CallLocation callLocation = new CallLocation(methodToProcess.getReference(), insn.getLocation());
|
||||
replacement.clear();
|
||||
if (processInvocation(method, callLocation, invoke, methodToProcess)) {
|
||||
insn.insertNextAll(replacement);
|
||||
insn.delete();
|
||||
MethodReader method = getMethod(invoke.getMethod());
|
||||
if (method == null) {
|
||||
continue;
|
||||
}
|
||||
CallLocation callLocation = new CallLocation(methodToProcess.getReference(), insn.getLocation());
|
||||
replacement.clear();
|
||||
if (processInvocation(method, callLocation, invoke, methodToProcess)) {
|
||||
insn.insertNextAll(replacement);
|
||||
insn.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean processCast(CastInstruction cast, CallLocation location) {
|
||||
if (!(cast.getTargetType() instanceof ValueType.Object)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String targetClassName = ((ValueType.Object) cast.getTargetType()).getClassName();
|
||||
if (!typeHelper.isJavaScriptClass(targetClassName)) {
|
||||
return false;
|
||||
}
|
||||
ClassReader targetClass = classSource.get(targetClassName);
|
||||
if (targetClass.getAnnotations().get(JSFunctor.class.getName()) == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Variable result = marshaller.unwrapFunctor(location, cast.getValue(), targetClass);
|
||||
AssignInstruction assign = new AssignInstruction();
|
||||
assign.setLocation(location.getSourceLocation());
|
||||
assign.setAssignee(result);
|
||||
assign.setReceiver(cast.getReceiver());
|
||||
replacement.add(assign);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean processInvocation(MethodReader method, CallLocation callLocation, InvokeInstruction invoke,
|
||||
MethodHolder methodToProcess) {
|
||||
if (method.getAnnotations().get(JSBody.class.getName()) != null) {
|
||||
|
@ -76,8 +76,8 @@ public class JSNativeGenerator implements Injector, DependencyPlugin, Generator
|
||||
String thisName = context.getParameterName(1);
|
||||
String methodName = context.getParameterName(2);
|
||||
|
||||
writer.append("if").ws().append("(").append(thisName).ws().append("===").ws().append("null)").ws()
|
||||
.append("return null;").softNewLine();
|
||||
writer.append("if").ws().append("(typeof ").append(thisName).ws().append("!==").ws().append("\"function\")")
|
||||
.ws().append("return ").append(thisName).append(";").softNewLine();
|
||||
writer.append("var result").ws().append("=").ws().append("{};").softNewLine();
|
||||
writer.append("result[").append(methodName).append("]").ws().append("=").ws().append(thisName)
|
||||
.append(";").softNewLine();
|
||||
|
@ -462,7 +462,7 @@ class JSValueMarshaller {
|
||||
return result;
|
||||
}
|
||||
|
||||
private Variable unwrapFunctor(CallLocation location, Variable var, ClassReader type) {
|
||||
Variable unwrapFunctor(CallLocation location, Variable var, ClassReader type) {
|
||||
if (!isProperFunctor(type)) {
|
||||
diagnostics.error(location, "Wrong functor: {{c0}}", type.getName());
|
||||
return var;
|
||||
|
@ -83,6 +83,12 @@ public class FunctorTest {
|
||||
assertEquals("q,w", function.foo("q", "w"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void castToFunctor() {
|
||||
JSBiFunction f = getBiFunctionAsObject().cast();
|
||||
assertEquals(23042, f.foo(23, 42));
|
||||
}
|
||||
|
||||
@JSBody(params = { "f", "a", "b" }, script = "return '(' + f(a, b) + ')';")
|
||||
private static native String testMethod(JSBiFunction f, int a, int b);
|
||||
|
||||
@ -95,6 +101,12 @@ public class FunctorTest {
|
||||
+ "};")
|
||||
private static native JSBiFunction getBiFunction();
|
||||
|
||||
@JSBody(script = ""
|
||||
+ "return function(a, b) {"
|
||||
+ "return a * 1000 + b;"
|
||||
+ "};")
|
||||
private static native JSObject getBiFunctionAsObject();
|
||||
|
||||
@JSBody(script = ""
|
||||
+ "return function(a, b) {"
|
||||
+ "return a + ',' + b;"
|
||||
|
Loading…
Reference in New Issue
Block a user