Improves value conversion support for JavaScriptBody

This commit is contained in:
konsoletyper 2014-02-18 17:21:26 +04:00
parent ee28309008
commit f27c641d32
5 changed files with 99 additions and 26 deletions

View File

@ -79,6 +79,8 @@ public class JavaScriptBodyDependency implements DependencyListener {
dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.toJsMethod, DependencyStack.ROOT); dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.toJsMethod, DependencyStack.ROOT);
dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.intValueMethod, DependencyStack.ROOT); dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.intValueMethod, DependencyStack.ROOT);
dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.valueOfIntMethod, DependencyStack.ROOT); dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.valueOfIntMethod, DependencyStack.ROOT);
dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.booleanValueMethod, DependencyStack.ROOT);
dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.valueOfBooleanMethod, DependencyStack.ROOT);
} }
@Override @Override

View File

@ -20,6 +20,7 @@ import java.util.List;
import net.java.html.js.JavaScriptBody; import net.java.html.js.JavaScriptBody;
import org.teavm.codegen.NamingStrategy; import org.teavm.codegen.NamingStrategy;
import org.teavm.codegen.SourceWriter; import org.teavm.codegen.SourceWriter;
import org.teavm.javascript.Renderer;
import org.teavm.javascript.ni.Generator; import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext; import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.model.*; import org.teavm.model.*;
@ -53,7 +54,7 @@ public class JavaScriptBodyGenerator implements Generator {
writer.outdent().append("}).call(").append(context.getParameterName(0)); writer.outdent().append("}).call(").append(context.getParameterName(0));
for (int i = 0; i < args.size(); ++i) { for (int i = 0; i < args.size(); ++i) {
writer.append(",").ws(); writer.append(",").ws();
wrapParameter(writer, methodRef.getDescriptor().parameterType(i), context.getParameterName(i + 1)); wrapParameter(writer, context.getParameterName(i + 1));
} }
writer.append(")").softNewLine(); writer.append(")").softNewLine();
writer.append("return "); writer.append("return ");
@ -61,22 +62,15 @@ public class JavaScriptBodyGenerator implements Generator {
writer.append(";").softNewLine(); writer.append(";").softNewLine();
} }
private void wrapParameter(SourceWriter writer, ValueType type, String param) throws IOException { private void wrapParameter(SourceWriter writer, String param) throws IOException {
if (type.isObject("java.lang.Object")) {
writer.appendMethodBody(JavaScriptConvGenerator.toJsMethod); writer.appendMethodBody(JavaScriptConvGenerator.toJsMethod);
writer.append("(").append(param).append(")"); writer.append("(").append(param).append(")");
} else {
writer.append(param);
}
} }
private void unwrapValue(SourceWriter writer, ValueType type, String param) throws IOException { private void unwrapValue(SourceWriter writer, ValueType type, String param) throws IOException {
if (type.isObject("java.lang.Object")) {
writer.appendMethodBody(JavaScriptConvGenerator.fromJsMethod); writer.appendMethodBody(JavaScriptConvGenerator.fromJsMethod);
writer.append("(").append(param).append(")"); writer.append("(").append(param).append(",").ws().append(Renderer.typeToClsString(writer.getNaming(), type))
} else { .append(")");
writer.append(param);
}
} }
private static class GeneratorJsCallback extends JsCallback { private static class GeneratorJsCallback extends JsCallback {

View File

@ -29,5 +29,5 @@ public final class JavaScriptConv {
public static native Object toJavaScript(Object obj); public static native Object toJavaScript(Object obj);
@GeneratedBy(JavaScriptConvGenerator.class) @GeneratedBy(JavaScriptConvGenerator.class)
public static native Object fromJavaScript(Object obj); public static native Object fromJavaScript(Object obj, Object cls);
} }

View File

@ -29,13 +29,17 @@ public class JavaScriptConvGenerator implements Generator {
private static final String convCls = JavaScriptConv.class.getName(); private static final String convCls = JavaScriptConv.class.getName();
static final MethodReference intValueMethod = new MethodReference("java.lang.Integer", static final MethodReference intValueMethod = new MethodReference("java.lang.Integer",
new MethodDescriptor("intValue", ValueType.INTEGER)); new MethodDescriptor("intValue", ValueType.INTEGER));
static final MethodReference booleanValueMethod = new MethodReference("java.lang.Boolean",
new MethodDescriptor("booleanValue", ValueType.BOOLEAN));
static final MethodReference valueOfIntMethod = new MethodReference("java.lang.Integer", static final MethodReference valueOfIntMethod = new MethodReference("java.lang.Integer",
new MethodDescriptor("valueOf", ValueType.INTEGER, ValueType.object("java.lang.Integer"))); new MethodDescriptor("valueOf", ValueType.INTEGER, ValueType.object("java.lang.Integer")));
static final MethodReference valueOfBooleanMethod = new MethodReference("java.lang.Boolean",
new MethodDescriptor("valueOf", ValueType.BOOLEAN, ValueType.object("java.lang.Boolean")));
private static final ValueType objType = ValueType.object("java.lang.Object"); private static final ValueType objType = ValueType.object("java.lang.Object");
static final MethodReference toJsMethod = new MethodReference(convCls, new MethodDescriptor( static final MethodReference toJsMethod = new MethodReference(convCls, new MethodDescriptor(
"toJavaScript", objType, objType)); "toJavaScript", objType, objType));
static final MethodReference fromJsMethod = new MethodReference(convCls, new MethodDescriptor( static final MethodReference fromJsMethod = new MethodReference(convCls, new MethodDescriptor(
"fromJavaScript", objType, objType)); "fromJavaScript", objType, objType, objType));
@Override @Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException { public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
@ -53,43 +57,67 @@ public class JavaScriptConvGenerator implements Generator {
String obj = context.getParameterName(1); String obj = context.getParameterName(1);
writer.append("if (" + obj + " === null) {").softNewLine().indent(); writer.append("if (" + obj + " === null) {").softNewLine().indent();
writer.append("return null;").softNewLine(); writer.append("return null;").softNewLine();
writer.outdent().append("} else if (typeof " + obj + " === 'number') {").indent().softNewLine();
writer.append("return " + obj + ";").softNewLine();
writer.outdent().append("} else if (" + obj + ".constructor.$meta.item) {").indent().softNewLine(); writer.outdent().append("} else if (" + obj + ".constructor.$meta.item) {").indent().softNewLine();
writer.append("var arr = new Array(" + obj + ".data.length);").softNewLine(); writer.append("var arr = new Array(" + obj + ".data.length);").softNewLine();
writer.append("for (var i = 0; i < arr.length; ++i) {").indent().softNewLine(); writer.append("for (var i = 0; i < arr.length; ++i) {").indent().softNewLine();
writer.append("arr[i] = ").appendMethodBody(toJsMethod).append("(" + obj + ".data[i]);").softNewLine(); writer.append("arr[i] = ").appendMethodBody(toJsMethod).append("(" + obj + ".data[i]);").softNewLine();
writer.outdent().append("}").softNewLine(); writer.outdent().append("}").softNewLine();
writer.append("return arr;").softNewLine(); writer.append("return arr;").softNewLine();
writer.outdent().append("}"); writer.outdent().append("} else if (" + obj + ".constructor === ").appendClass("java.lang.String")
writer.append(" else if (" + obj + ".constructor === ").appendClass("java.lang.String")
.append(") {").indent().softNewLine(); .append(") {").indent().softNewLine();
generateStringToJavaScript(context, writer); generateStringToJavaScript(context, writer);
writer.outdent().append("} else if (" + obj + ".constructor === ").appendClass("java.lang.Integer") writer.outdent().append("} else if (" + obj + ".constructor === ").appendClass("java.lang.Integer")
.append(") {").indent().softNewLine(); .append(") {").indent().softNewLine();
writer.append("return ").appendMethodBody(intValueMethod).append("(" + obj + ");").softNewLine(); writer.append("return ").appendMethodBody(intValueMethod).append("(" + obj + ");").softNewLine();
writer.outdent().append("}"); writer.outdent().append("} else if (" + obj + ".constructor === ").appendClass("java.lang.Boolean")
writer.append(" else {").indent().softNewLine(); .append(") {").indent().softNewLine();
writer.append("return ").appendMethodBody(booleanValueMethod).append("(" + obj + ")!==0;").softNewLine();
writer.outdent().append("} else {").indent().softNewLine();
writer.append("return " + obj + ";").softNewLine(); writer.append("return " + obj + ";").softNewLine();
writer.outdent().append("}").softNewLine(); writer.outdent().append("}").softNewLine();
} }
private void generateFromJavaScript(GeneratorContext context, SourceWriter writer) throws IOException { private void generateFromJavaScript(GeneratorContext context, SourceWriter writer) throws IOException {
String obj = context.getParameterName(1); String obj = context.getParameterName(1);
String type = context.getParameterName(2);
writer.append("if (" + obj +" === null || " + obj + " === undefined)").ws().append("{") writer.append("if (" + obj +" === null || " + obj + " === undefined)").ws().append("{")
.softNewLine().indent(); .softNewLine().indent();
writer.append("return null;").softNewLine(); writer.append("return null;").softNewLine();
writer.outdent().append("} else if (" + obj + " instanceof Array) {").indent().softNewLine(); writer.outdent().append("} else if (" + type + ".$meta.item) {").indent().softNewLine();
writer.append("var arr = $rt_createArray($rt_objcls(), " + obj + ".length);").softNewLine(); writer.append("var arr = $rt_createArray(" + type + ".$meta.item, " + obj + ".length);").softNewLine();
writer.append("for (var i = 0; i < arr.data.length; ++i) {").indent().softNewLine(); writer.append("for (var i = 0; i < arr.data.length; ++i) {").indent().softNewLine();
writer.append("arr.data[i] = ").appendMethodBody(fromJsMethod).append("(" + obj + "[i]);") writer.append("arr.data[i] = ").appendMethodBody(fromJsMethod).append("(" + obj + "[i], " + type + ");")
.softNewLine(); .softNewLine();
writer.outdent().append("}").softNewLine(); writer.outdent().append("}").softNewLine();
writer.append("return arr;").softNewLine(); writer.append("return arr;").softNewLine();
writer.outdent().append("}"); writer.outdent().append("} else if (" + type + " === ").appendClass("java.lang.String")
writer.append(" else if (" + obj + ".constructor === ").appendClass("java.lang.String")
.append(") {").indent().softNewLine(); .append(") {").indent().softNewLine();
writer.append("return $rt_str(" + obj + ");").softNewLine(); writer.append("return $rt_str(" + obj + ");").softNewLine();
writer.outdent().append("} else if (" + obj + " | 0 === " + obj + ") {").indent().softNewLine(); writer.outdent().append("} else if (" + type + " === ").appendClass("java.lang.Integer")
.append(") {").indent().softNewLine();
writer.append("return ").appendMethodBody(valueOfIntMethod).append("(" + obj + ");").softNewLine(); writer.append("return ").appendMethodBody(valueOfIntMethod).append("(" + obj + ");").softNewLine();
writer.outdent().append("} else if (" + type + " === $rt_intcls()) {").indent().softNewLine();
writer.append("return " + obj + "|0;").softNewLine();
writer.outdent().append("} else if (" + type + " === ").appendClass("java.lang.Boolean")
.append(") {").indent().softNewLine();
writer.append("return ").appendMethodBody(valueOfBooleanMethod).append("(" + obj + "?1:0);").softNewLine();
writer.outdent().append("} else if (" + type + " === $rt_booleancls()) {").indent().softNewLine();
writer.append("return " + obj + "?1:0;").softNewLine();
writer.outdent().append("} else if (" + obj + " instanceof Array) {").indent().softNewLine();
writer.append("var arr = $rt_createArray($rt_objcls(), " + obj + ".length);").softNewLine();
writer.append("for (var i = 0; i < arr.data.length; ++i) {").indent().softNewLine();
writer.append("arr.data[i] = ").appendMethodBody(fromJsMethod).append("(" + obj + "[i], $rt_objcls());")
.softNewLine();
writer.outdent().append("}").softNewLine();
writer.append("return arr;").softNewLine();
writer.outdent().append("} else if (typeof " + obj + " === 'number') {").indent().softNewLine();
writer.append("if (" + obj + "|0 === " + obj + ") {").indent().softNewLine();
writer.append("return ").appendMethodBody(valueOfIntMethod).append("(" + obj + ");").softNewLine();
writer.outdent().append("}").softNewLine();
writer.outdent().append("} else if (typeof " + obj + " === 'boolean') {").indent().softNewLine();
writer.append("return ").appendMethodBody(valueOfBooleanMethod).append("(" + obj + "?1:0);").softNewLine();
writer.outdent().append("} else {").indent().softNewLine(); writer.outdent().append("} else {").indent().softNewLine();
writer.append("return ").append(obj).append(";").softNewLine(); writer.append("return ").append(obj).append(";").softNewLine();
writer.outdent().append("}").softNewLine(); writer.outdent().append("}").softNewLine();

View File

@ -27,15 +27,30 @@ public class JavaScriptBodyConversionTests {
@Test @Test
public void convertsInteger() { public void convertsInteger() {
assertEquals(23, returnAsInt(23)); assertEquals(23, returnAsInt(23));
assertEquals(Integer.valueOf(23), returnAsInteger(23));
assertEquals(23, returnAsObject(23));
assertEquals(24, addOne((Object)23));
assertEquals(Integer.valueOf(24), addOne(Integer.valueOf(23)));
assertEquals(24, addOne(23));
} }
@Test @Test
public void convertsIntegerResult() { public void convertsIntegerResult() {
assertEquals(23, returnAsObject(23)); assertEquals(23, returnAsObject(23));
assertEquals(Integer.valueOf(23), returnAsInteger(23));
assertEquals(23, returnAsInt(23));
}
@Test
public void convertsBoolean() {
assertTrue(returnAsBoolean(true));
assertTrue(returnAsBooleanWrapper(true));
assertEquals(Boolean.TRUE, returnAsObject(true));
} }
@Test @Test
public void convertsArray() { public void convertsArray() {
assertEquals(42, getArrayItem(new int[] { 23, 42 }, 1));
assertEquals(42, getArrayItem(new Integer[] { 23, 42 }, 1)); assertEquals(42, getArrayItem(new Integer[] { 23, 42 }, 1));
} }
@ -47,12 +62,46 @@ public class JavaScriptBodyConversionTests {
assertEquals(Integer.valueOf(1), arrayCopy[0]); assertEquals(Integer.valueOf(1), arrayCopy[0]);
} }
@Test
public void createsArrayOfProperType() {
assertEquals(Object[].class, returnAsObject(new int[] { 23, 42 }).getClass());
assertEquals(Integer[].class, returnAsIntegerArray(new Integer[] { 23, 42 }).getClass());
assertEquals(int[].class, returnAsIntArray(new Integer[] { 23, 42 }).getClass());
}
@JavaScriptBody(args = { "value" }, body = "return value;") @JavaScriptBody(args = { "value" }, body = "return value;")
private native int returnAsInt(Object value); private native int returnAsInt(Object value);
@JavaScriptBody(args = { "value" }, body = "return value;")
private native boolean returnAsBoolean(Object value);
@JavaScriptBody(args = { "value" }, body = "return value;")
private native Boolean returnAsBooleanWrapper(boolean value);
@JavaScriptBody(args = { "value" }, body = "return value;")
private native Integer returnAsInteger(Integer value);
@JavaScriptBody(args = { "value" }, body = "return value;") @JavaScriptBody(args = { "value" }, body = "return value;")
private native Object returnAsObject(int value); private native Object returnAsObject(int value);
@JavaScriptBody(args = { "value" }, body = "return value + 1;")
private native int addOne(Object value);
@JavaScriptBody(args = { "value" }, body = "return value + 1;")
private native Integer addOne(Integer value);
@JavaScriptBody(args = { "value" }, body = "return value + 1;")
private native int addOne(int value);
@JavaScriptBody(args = { "value" }, body = "return value;")
private native Object returnAsObject(Object array);
@JavaScriptBody(args = { "value" }, body = "return value;")
private native int[] returnAsIntArray(Object array);
@JavaScriptBody(args = { "value" }, body = "return value;")
private native Integer[] returnAsIntegerArray(Object array);
@JavaScriptBody(args = { "value" }, body = "value[0] = 1; return value;") @JavaScriptBody(args = { "value" }, body = "value[0] = 1; return value;")
private native Object modifyIntegerArray(Object value); private native Object modifyIntegerArray(Object value);