mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Wrap function by an object if returning value of native method is
a JSFunctor interface. See #280
This commit is contained in:
parent
45ba247265
commit
2992c6e406
|
@ -405,4 +405,8 @@ final class JS {
|
|||
@GeneratedBy(JSNativeGenerator.class)
|
||||
@PluggableDependency(JSNativeGenerator.class)
|
||||
public static native JSObject function(JSObject instance, JSObject property);
|
||||
|
||||
@GeneratedBy(JSNativeGenerator.class)
|
||||
@PluggableDependency(JSNativeGenerator.class)
|
||||
public static native JSObject functionAsObject(JSObject instance, JSObject property);
|
||||
}
|
||||
|
|
|
@ -66,7 +66,6 @@ import org.teavm.model.instructions.AssignInstruction;
|
|||
import org.teavm.model.instructions.ExitInstruction;
|
||||
import org.teavm.model.instructions.InvocationType;
|
||||
import org.teavm.model.instructions.InvokeInstruction;
|
||||
import org.teavm.model.instructions.StringConstantInstruction;
|
||||
import org.teavm.model.util.InstructionVariableMapper;
|
||||
import org.teavm.model.util.ModelUtils;
|
||||
import org.teavm.model.util.ProgramUtils;
|
||||
|
@ -114,7 +113,7 @@ class JSClassProcessor {
|
|||
|
||||
private void getFunctorMethods(String className, Map<MethodDescriptor, MethodReference> methods) {
|
||||
classSource.getAncestors(className).forEach(cls -> {
|
||||
if (cls.getAnnotations().get(JSFunctor.class.getName()) != null && isProperFunctor(cls)) {
|
||||
if (cls.getAnnotations().get(JSFunctor.class.getName()) != null && marshaller.isProperFunctor(cls)) {
|
||||
MethodReference method = cls.getMethods().iterator().next().getReference();
|
||||
if (!methods.containsKey(method.getDescriptor())) {
|
||||
methods.put(method.getDescriptor(), method);
|
||||
|
@ -241,7 +240,7 @@ class JSClassProcessor {
|
|||
|
||||
private void setCurrentProgram(Program program) {
|
||||
this.program = program;
|
||||
marshaller = new JSValueMarshaller(diagnostics, typeHelper, program, replacement);
|
||||
marshaller = new JSValueMarshaller(diagnostics, typeHelper, classSource, program, replacement);
|
||||
}
|
||||
|
||||
void processProgram(MethodHolder methodToProcess) {
|
||||
|
@ -333,18 +332,18 @@ class JSClassProcessor {
|
|||
newInvoke.setReceiver(result);
|
||||
newInvoke.setLocation(invoke.getLocation());
|
||||
if (invoke.getInstance() != null) {
|
||||
Variable arg = wrapArgument(callLocation, invoke.getInstance(),
|
||||
Variable arg = marshaller.wrapArgument(callLocation, invoke.getInstance(),
|
||||
ValueType.object(method.getOwnerName()), false);
|
||||
newInvoke.getArguments().add(arg);
|
||||
}
|
||||
for (int i = 0; i < invoke.getArguments().size(); ++i) {
|
||||
Variable arg = wrapArgument(callLocation, invoke.getArguments().get(i),
|
||||
Variable arg = marshaller.wrapArgument(callLocation, invoke.getArguments().get(i),
|
||||
method.parameterType(i), byRefParams[i]);
|
||||
newInvoke.getArguments().add(arg);
|
||||
}
|
||||
replacement.add(newInvoke);
|
||||
if (result != null) {
|
||||
result = marshaller.unwrap(callLocation, result, method.getResultType());
|
||||
result = marshaller.unwrapReturnValue(callLocation, result, method.getResultType());
|
||||
copyVar(result, invoke.getReceiver(), invoke.getLocation());
|
||||
}
|
||||
|
||||
|
@ -365,7 +364,7 @@ class JSClassProcessor {
|
|||
Variable result = invoke.getReceiver() != null ? program.createVariable() : null;
|
||||
addPropertyGet(propertyName, invoke.getInstance(), result, invoke.getLocation());
|
||||
if (result != null) {
|
||||
result = marshaller.unwrap(callLocation, result, method.getResultType());
|
||||
result = marshaller.unwrapReturnValue(callLocation, result, method.getResultType());
|
||||
copyVar(result, invoke.getReceiver(), invoke.getLocation());
|
||||
}
|
||||
return true;
|
||||
|
@ -375,7 +374,7 @@ class JSClassProcessor {
|
|||
if (propertyName == null) {
|
||||
propertyName = cutPrefix(method.getName(), 3);
|
||||
}
|
||||
Variable wrapped = wrapArgument(callLocation, invoke.getArguments().get(0),
|
||||
Variable wrapped = marshaller.wrapArgument(callLocation, invoke.getArguments().get(0),
|
||||
method.parameterType(0), false);
|
||||
addPropertySet(propertyName, invoke.getInstance(), wrapped, invoke.getLocation());
|
||||
return true;
|
||||
|
@ -394,19 +393,19 @@ class JSClassProcessor {
|
|||
private boolean processIndexer(MethodReader method, CallLocation callLocation, InvokeInstruction invoke) {
|
||||
if (isProperGetIndexer(method.getDescriptor())) {
|
||||
Variable result = invoke.getReceiver() != null ? program.createVariable() : null;
|
||||
addIndexerGet(invoke.getInstance(), marshaller.wrap(invoke.getArguments().get(0),
|
||||
method.parameterType(0), invoke.getLocation(), false), result, invoke.getLocation());
|
||||
addIndexerGet(invoke.getInstance(), marshaller.wrapArgument(callLocation, invoke.getArguments().get(0),
|
||||
method.parameterType(0), false), result, invoke.getLocation());
|
||||
if (result != null) {
|
||||
result = marshaller.unwrap(callLocation, result, method.getResultType());
|
||||
result = marshaller.unwrapReturnValue(callLocation, result, method.getResultType());
|
||||
copyVar(result, invoke.getReceiver(), invoke.getLocation());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (isProperSetIndexer(method.getDescriptor())) {
|
||||
Variable index = marshaller.wrap(invoke.getArguments().get(0), method.parameterType(0),
|
||||
invoke.getLocation(), false);
|
||||
Variable value = marshaller.wrap(invoke.getArguments().get(1), method.parameterType(1),
|
||||
invoke.getLocation(), false);
|
||||
Variable index = marshaller.wrapArgument(callLocation, invoke.getArguments().get(0),
|
||||
method.parameterType(0), false);
|
||||
Variable value = marshaller.wrapArgument(callLocation, invoke.getArguments().get(1),
|
||||
method.parameterType(1), false);
|
||||
addIndexerSet(invoke.getInstance(), index, value, invoke.getLocation());
|
||||
return true;
|
||||
}
|
||||
|
@ -469,17 +468,17 @@ class JSClassProcessor {
|
|||
newInvoke.setType(InvocationType.SPECIAL);
|
||||
newInvoke.setReceiver(result);
|
||||
newInvoke.getArguments().add(invoke.getInstance());
|
||||
newInvoke.getArguments().add(addStringWrap(addString(name, invoke.getLocation()),
|
||||
newInvoke.getArguments().add(marshaller.addStringWrap(marshaller.addString(name, invoke.getLocation()),
|
||||
invoke.getLocation()));
|
||||
newInvoke.setLocation(invoke.getLocation());
|
||||
for (int i = 0; i < invoke.getArguments().size(); ++i) {
|
||||
Variable arg = wrapArgument(callLocation, invoke.getArguments().get(i),
|
||||
Variable arg = marshaller.wrapArgument(callLocation, invoke.getArguments().get(i),
|
||||
method.parameterType(i), byRefParams[i]);
|
||||
newInvoke.getArguments().add(arg);
|
||||
}
|
||||
replacement.add(newInvoke);
|
||||
if (result != null) {
|
||||
result = marshaller.unwrap(callLocation, result, method.getResultType());
|
||||
result = marshaller.unwrapReturnValue(callLocation, result, method.getResultType());
|
||||
copyVar(result, invoke.getReceiver(), invoke.getLocation());
|
||||
}
|
||||
|
||||
|
@ -627,11 +626,11 @@ class JSClassProcessor {
|
|||
insn.setMethod(calleeRef);
|
||||
replacement.clear();
|
||||
if (!callee.hasModifier(ElementModifier.STATIC)) {
|
||||
insn.setInstance(marshaller.unwrap(location, program.variableAt(paramIndex++),
|
||||
insn.setInstance(marshaller.unwrapReturnValue(location, program.variableAt(paramIndex++),
|
||||
ValueType.object(calleeRef.getClassName())));
|
||||
}
|
||||
for (int i = 0; i < callee.parameterCount(); ++i) {
|
||||
insn.getArguments().add(marshaller.unwrap(location, program.variableAt(paramIndex++),
|
||||
insn.getArguments().add(marshaller.unwrapReturnValue(location, program.variableAt(paramIndex++),
|
||||
callee.parameterType(i)));
|
||||
}
|
||||
if (callee.getResultType() != ValueType.VOID) {
|
||||
|
@ -655,7 +654,7 @@ class JSClassProcessor {
|
|||
|
||||
private void addPropertyGet(String propertyName, Variable instance, Variable receiver,
|
||||
TextLocation location) {
|
||||
Variable nameVar = addStringWrap(addString(propertyName, location), location);
|
||||
Variable nameVar = marshaller.addStringWrap(marshaller.addString(propertyName, location), location);
|
||||
InvokeInstruction insn = new InvokeInstruction();
|
||||
insn.setType(InvocationType.SPECIAL);
|
||||
insn.setMethod(new MethodReference(JS.class, "get", JSObject.class, JSObject.class, JSObject.class));
|
||||
|
@ -667,7 +666,7 @@ class JSClassProcessor {
|
|||
}
|
||||
|
||||
private void addPropertySet(String propertyName, Variable instance, Variable value, TextLocation location) {
|
||||
Variable nameVar = addStringWrap(addString(propertyName, location), location);
|
||||
Variable nameVar = marshaller.addStringWrap(marshaller.addString(propertyName, location), location);
|
||||
InvokeInstruction insn = new InvokeInstruction();
|
||||
insn.setType(InvocationType.SPECIAL);
|
||||
insn.setMethod(new MethodReference(JS.class, "set", JSObject.class, JSObject.class,
|
||||
|
@ -710,61 +709,6 @@ class JSClassProcessor {
|
|||
replacement.add(insn);
|
||||
}
|
||||
|
||||
private Variable addStringWrap(Variable var, TextLocation location) {
|
||||
return marshaller.wrap(var, ValueType.object("java.lang.String"), location, false);
|
||||
}
|
||||
|
||||
private Variable addString(String str, TextLocation location) {
|
||||
Variable var = program.createVariable();
|
||||
StringConstantInstruction nameInsn = new StringConstantInstruction();
|
||||
nameInsn.setReceiver(var);
|
||||
nameInsn.setConstant(str);
|
||||
nameInsn.setLocation(location);
|
||||
replacement.add(nameInsn);
|
||||
return var;
|
||||
}
|
||||
|
||||
private Variable wrapArgument(CallLocation location, Variable var, ValueType type, boolean byRef) {
|
||||
if (type instanceof ValueType.Object) {
|
||||
String className = ((ValueType.Object) type).getClassName();
|
||||
ClassReader cls = classSource.get(className);
|
||||
if (cls.getAnnotations().get(JSFunctor.class.getName()) != null) {
|
||||
return wrapFunctor(location, var, cls);
|
||||
}
|
||||
}
|
||||
return marshaller.wrap(var, type, location.getSourceLocation(), byRef);
|
||||
}
|
||||
|
||||
private boolean isProperFunctor(ClassReader type) {
|
||||
if (!type.hasModifier(ElementModifier.INTERFACE)) {
|
||||
return false;
|
||||
}
|
||||
return type.getMethods().stream()
|
||||
.filter(method -> method.hasModifier(ElementModifier.ABSTRACT))
|
||||
.count() == 1;
|
||||
}
|
||||
|
||||
private Variable wrapFunctor(CallLocation location, Variable var, ClassReader type) {
|
||||
if (!isProperFunctor(type)) {
|
||||
diagnostics.error(location, "Wrong functor: {{c0}}", type.getName());
|
||||
return var;
|
||||
}
|
||||
String name = type.getMethods().stream()
|
||||
.filter(method -> method.hasModifier(ElementModifier.ABSTRACT))
|
||||
.findFirst().get().getName();
|
||||
Variable functor = program.createVariable();
|
||||
Variable nameVar = addStringWrap(addString(name, location.getSourceLocation()), location.getSourceLocation());
|
||||
InvokeInstruction insn = new InvokeInstruction();
|
||||
insn.setType(InvocationType.SPECIAL);
|
||||
insn.setMethod(new MethodReference(JS.class, "function", JSObject.class, JSObject.class, JSObject.class));
|
||||
insn.setReceiver(functor);
|
||||
insn.getArguments().add(var);
|
||||
insn.getArguments().add(nameVar);
|
||||
insn.setLocation(location.getSourceLocation());
|
||||
replacement.add(insn);
|
||||
return functor;
|
||||
}
|
||||
|
||||
private MethodReader getMethod(MethodReference ref) {
|
||||
ClassReader cls = classSource.get(ref.getClassName());
|
||||
if (cls == null) {
|
||||
|
|
|
@ -44,6 +44,9 @@ public class JSNativeGenerator implements Injector, DependencyPlugin, Generator
|
|||
case "function":
|
||||
writeFunction(context, writer);
|
||||
break;
|
||||
case "functionAsObject":
|
||||
writeFunctionAsObject(context, writer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,6 +72,16 @@ public class JSNativeGenerator implements Injector, DependencyPlugin, Generator
|
|||
writer.append("return ").append(thisName).append("[name]();").softNewLine();
|
||||
}
|
||||
|
||||
private void writeFunctionAsObject(GeneratorContext context, SourceWriter writer) throws IOException {
|
||||
String thisName = context.getParameterName(1);
|
||||
String methodName = context.getParameterName(2);
|
||||
|
||||
writer.append("var result").ws().append("=").ws().append("{};").softNewLine();
|
||||
writer.append("result[").append(methodName).append("]").ws().append("=").ws().append(thisName)
|
||||
.append(";").softNewLine();
|
||||
writer.append("return result;").softNewLine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
|
||||
SourceWriter writer = context.getWriter();
|
||||
|
@ -143,9 +156,6 @@ public class JSNativeGenerator implements Injector, DependencyPlugin, Generator
|
|||
context.writeExpr(context.getArgument(0), context.getPrecedence());
|
||||
}
|
||||
break;
|
||||
case "function":
|
||||
generateFunction(context);
|
||||
break;
|
||||
case "unwrapString":
|
||||
writer.append("$rt_str(");
|
||||
context.writeExpr(context.getArgument(0), Precedence.min());
|
||||
|
@ -200,17 +210,6 @@ public class JSNativeGenerator implements Injector, DependencyPlugin, Generator
|
|||
}
|
||||
}
|
||||
|
||||
private void generateFunction(InjectorContext context) throws IOException {
|
||||
SourceWriter writer = context.getWriter();
|
||||
writer.append("(function($instance,").ws().append("$property)").ws().append("{").ws()
|
||||
.append("return function()").ws().append("{").indent().softNewLine();
|
||||
writer.append("return $instance[$property].apply($instance,").ws().append("arguments);").softNewLine();
|
||||
writer.outdent().append("};})(");
|
||||
context.writeExpr(context.getArgument(0));
|
||||
writer.append(",").ws();
|
||||
context.writeExpr(context.getArgument(1));
|
||||
writer.append(")");
|
||||
}
|
||||
|
||||
private void renderProperty(Expr property, InjectorContext context) throws IOException {
|
||||
SourceWriter writer = context.getWriter();
|
||||
|
|
|
@ -120,7 +120,7 @@ class JSObjectClassTransformer implements ClassHolderTransformer {
|
|||
|
||||
BasicBlock basicBlock = program.createBasicBlock();
|
||||
List<Instruction> marshallInstructions = new ArrayList<>();
|
||||
JSValueMarshaller marshaller = new JSValueMarshaller(diagnostics, typeHelper, program,
|
||||
JSValueMarshaller marshaller = new JSValueMarshaller(diagnostics, typeHelper, innerSource, program,
|
||||
marshallInstructions);
|
||||
|
||||
List<Variable> variablesToPass = new ArrayList<>();
|
||||
|
@ -129,7 +129,8 @@ class JSObjectClassTransformer implements ClassHolderTransformer {
|
|||
}
|
||||
|
||||
for (int i = 0; i < method.parameterCount(); ++i) {
|
||||
Variable var = marshaller.unwrap(callLocation, variablesToPass.get(i), method.parameterType(i));
|
||||
Variable var = marshaller.unwrapReturnValue(callLocation, variablesToPass.get(i),
|
||||
method.parameterType(i));
|
||||
variablesToPass.set(i, var);
|
||||
}
|
||||
|
||||
|
@ -146,8 +147,8 @@ class JSObjectClassTransformer implements ClassHolderTransformer {
|
|||
ExitInstruction exit = new ExitInstruction();
|
||||
if (method.getResultType() != ValueType.VOID) {
|
||||
invocation.setReceiver(program.createVariable());
|
||||
exit.setValueToReturn(marshaller.wrap(invocation.getReceiver(), method.getResultType(),
|
||||
null, false));
|
||||
exit.setValueToReturn(marshaller.wrapArgument(callLocation, invocation.getReceiver(),
|
||||
method.getResultType(), false));
|
||||
basicBlock.addAll(marshallInstructions);
|
||||
marshallInstructions.clear();
|
||||
}
|
||||
|
|
|
@ -18,10 +18,14 @@ package org.teavm.jso.impl;
|
|||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import org.teavm.diagnostics.Diagnostics;
|
||||
import org.teavm.jso.JSFunctor;
|
||||
import org.teavm.jso.JSObject;
|
||||
import org.teavm.jso.core.JSArray;
|
||||
import org.teavm.jso.core.JSArrayReader;
|
||||
import org.teavm.model.CallLocation;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.Instruction;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.Program;
|
||||
|
@ -32,22 +36,66 @@ import org.teavm.model.instructions.CastInstruction;
|
|||
import org.teavm.model.instructions.ClassConstantInstruction;
|
||||
import org.teavm.model.instructions.InvocationType;
|
||||
import org.teavm.model.instructions.InvokeInstruction;
|
||||
import org.teavm.model.instructions.StringConstantInstruction;
|
||||
|
||||
class JSValueMarshaller {
|
||||
private Diagnostics diagnostics;
|
||||
private JSTypeHelper typeHelper;
|
||||
private ClassReaderSource classSource;
|
||||
private Program program;
|
||||
private List<Instruction> replacement;
|
||||
|
||||
JSValueMarshaller(Diagnostics diagnostics, JSTypeHelper typeHelper, Program program,
|
||||
List<Instruction> replacement) {
|
||||
JSValueMarshaller(Diagnostics diagnostics, JSTypeHelper typeHelper, ClassReaderSource classSource,
|
||||
Program program, List<Instruction> replacement) {
|
||||
this.diagnostics = diagnostics;
|
||||
this.typeHelper = typeHelper;
|
||||
this.classSource = classSource;
|
||||
this.program = program;
|
||||
this.replacement = replacement;
|
||||
}
|
||||
|
||||
public Variable wrap(Variable var, ValueType type, TextLocation location, boolean byRef) {
|
||||
Variable wrapArgument(CallLocation location, Variable var, ValueType type, boolean byRef) {
|
||||
if (type instanceof ValueType.Object) {
|
||||
String className = ((ValueType.Object) type).getClassName();
|
||||
ClassReader cls = classSource.get(className);
|
||||
if (cls.getAnnotations().get(JSFunctor.class.getName()) != null) {
|
||||
return wrapFunctor(location, var, cls);
|
||||
}
|
||||
}
|
||||
return wrap(var, type, location.getSourceLocation(), byRef);
|
||||
}
|
||||
|
||||
boolean isProperFunctor(ClassReader type) {
|
||||
if (!type.hasModifier(ElementModifier.INTERFACE)) {
|
||||
return false;
|
||||
}
|
||||
return type.getMethods().stream()
|
||||
.filter(method -> method.hasModifier(ElementModifier.ABSTRACT))
|
||||
.count() == 1;
|
||||
}
|
||||
|
||||
private Variable wrapFunctor(CallLocation location, Variable var, ClassReader type) {
|
||||
if (!isProperFunctor(type)) {
|
||||
diagnostics.error(location, "Wrong functor: {{c0}}", type.getName());
|
||||
return var;
|
||||
}
|
||||
String name = type.getMethods().stream()
|
||||
.filter(method -> method.hasModifier(ElementModifier.ABSTRACT))
|
||||
.findFirst().get().getName();
|
||||
Variable functor = program.createVariable();
|
||||
Variable nameVar = addStringWrap(addString(name, location.getSourceLocation()), location.getSourceLocation());
|
||||
InvokeInstruction insn = new InvokeInstruction();
|
||||
insn.setType(InvocationType.SPECIAL);
|
||||
insn.setMethod(new MethodReference(JS.class, "function", JSObject.class, JSObject.class, JSObject.class));
|
||||
insn.setReceiver(functor);
|
||||
insn.getArguments().add(var);
|
||||
insn.getArguments().add(nameVar);
|
||||
insn.setLocation(location.getSourceLocation());
|
||||
replacement.add(insn);
|
||||
return functor;
|
||||
}
|
||||
|
||||
Variable wrap(Variable var, ValueType type, TextLocation location, boolean byRef) {
|
||||
if (byRef) {
|
||||
InvokeInstruction insn = new InvokeInstruction();
|
||||
insn.setMethod(new MethodReference(JS.class, "arrayData", Object.class, JSObject.class));
|
||||
|
@ -169,6 +217,17 @@ class JSValueMarshaller {
|
|||
return new MethodReference(JS.class, "arrayWrapper", Function.class);
|
||||
}
|
||||
|
||||
Variable unwrapReturnValue(CallLocation location, Variable var, ValueType type) {
|
||||
if (type instanceof ValueType.Object) {
|
||||
String className = ((ValueType.Object) type).getClassName();
|
||||
ClassReader cls = classSource.get(className);
|
||||
if (cls.getAnnotations().get(JSFunctor.class.getName()) != null) {
|
||||
return unwrapFunctor(location, var, cls);
|
||||
}
|
||||
}
|
||||
return unwrap(location, var, type);
|
||||
}
|
||||
|
||||
Variable unwrap(CallLocation location, Variable var, ValueType type) {
|
||||
if (type instanceof ValueType.Primitive) {
|
||||
switch (((ValueType.Primitive) type).getKind()) {
|
||||
|
@ -402,4 +461,40 @@ class JSValueMarshaller {
|
|||
replacement.add(insn);
|
||||
return result;
|
||||
}
|
||||
|
||||
private Variable unwrapFunctor(CallLocation location, Variable var, ClassReader type) {
|
||||
if (!isProperFunctor(type)) {
|
||||
diagnostics.error(location, "Wrong functor: {{c0}}", type.getName());
|
||||
return var;
|
||||
}
|
||||
String name = type.getMethods().stream()
|
||||
.filter(method -> method.hasModifier(ElementModifier.ABSTRACT))
|
||||
.findFirst().get().getName();
|
||||
Variable functor = program.createVariable();
|
||||
Variable nameVar = addStringWrap(addString(name, location.getSourceLocation()), location.getSourceLocation());
|
||||
InvokeInstruction insn = new InvokeInstruction();
|
||||
insn.setType(InvocationType.SPECIAL);
|
||||
insn.setMethod(new MethodReference(JS.class, "functionAsObject", JSObject.class, JSObject.class,
|
||||
JSObject.class));
|
||||
insn.setReceiver(functor);
|
||||
insn.getArguments().add(var);
|
||||
insn.getArguments().add(nameVar);
|
||||
insn.setLocation(location.getSourceLocation());
|
||||
replacement.add(insn);
|
||||
return functor;
|
||||
}
|
||||
|
||||
Variable addStringWrap(Variable var, TextLocation location) {
|
||||
return wrap(var, ValueType.object("java.lang.String"), location, false);
|
||||
}
|
||||
|
||||
Variable addString(String str, TextLocation location) {
|
||||
Variable var = program.createVariable();
|
||||
StringConstantInstruction nameInsn = new StringConstantInstruction();
|
||||
nameInsn.setReceiver(var);
|
||||
nameInsn.setConstant(str);
|
||||
nameInsn.setLocation(location);
|
||||
replacement.add(nameInsn);
|
||||
return var;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
*/
|
||||
package org.teavm.jso.test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.teavm.jso.JSBody;
|
||||
|
@ -33,6 +34,11 @@ public class FunctorTest {
|
|||
assertEquals("(5)", testMethod((a, b) -> a + b, 2, 3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void functorParamsMarshaled() {
|
||||
assertEquals("(q,w)", testMethod((a, b) -> a + "," + b, "q", "w"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void functorIdentityPreserved() {
|
||||
JSBiFunction javaFunction = (a, b) -> a + b;
|
||||
|
@ -65,9 +71,36 @@ public class FunctorTest {
|
|||
assertEquals("baz_ok", wp.propbaz());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void functorPassedBack() {
|
||||
JSBiFunction function = getBiFunction();
|
||||
assertEquals(23042, function.foo(23, 42));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void functorParamsMarshaledBack() {
|
||||
JSStringBiFunction function = getStringBiFunction();
|
||||
assertEquals("q,w", function.foo("q", "w"));
|
||||
}
|
||||
|
||||
@JSBody(params = { "f", "a", "b" }, script = "return '(' + f(a, b) + ')';")
|
||||
private static native String testMethod(JSBiFunction f, int a, int b);
|
||||
|
||||
@JSBody(params = { "f", "a", "b" }, script = "return '(' + f(a, b) + ')';")
|
||||
private static native String testMethod(JSStringBiFunction f, String a, String b);
|
||||
|
||||
@JSBody(script = ""
|
||||
+ "return function(a, b) {"
|
||||
+ "return a * 1000 + b;"
|
||||
+ "};")
|
||||
private static native JSBiFunction getBiFunction();
|
||||
|
||||
@JSBody(script = ""
|
||||
+ "return function(a, b) {"
|
||||
+ "return a + ',' + b;"
|
||||
+ "};")
|
||||
private static native JSStringBiFunction getStringBiFunction();
|
||||
|
||||
@JSBody(params = "f", script = "return f;")
|
||||
private static native JSObject getFunction(JSBiFunction f);
|
||||
|
||||
|
@ -79,6 +112,11 @@ public class FunctorTest {
|
|||
int foo(int a, int b);
|
||||
}
|
||||
|
||||
@JSFunctor
|
||||
interface JSStringBiFunction extends JSObject {
|
||||
String foo(String a, String b);
|
||||
}
|
||||
|
||||
@JSFunctor
|
||||
interface JSFunctionWithDefaultMethod extends JSObject {
|
||||
int foo(int a);
|
||||
|
|
Loading…
Reference in New Issue
Block a user