From f27c641d32a5a2f93ad53c6f890eba339ebfacdd Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Tue, 18 Feb 2014 17:21:26 +0400 Subject: [PATCH] Improves value conversion support for JavaScriptBody --- .../html4j/JavaScriptBodyDependency.java | 2 + .../teavm/html4j/JavaScriptBodyGenerator.java | 22 +++----- .../java/org/teavm/html4j/JavaScriptConv.java | 2 +- .../teavm/html4j/JavaScriptConvGenerator.java | 50 +++++++++++++++---- .../test/JavaScriptBodyConversionTests.java | 49 ++++++++++++++++++ 5 files changed, 99 insertions(+), 26 deletions(-) diff --git a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java index d056e635c..72d742454 100644 --- a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java +++ b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java @@ -79,6 +79,8 @@ public class JavaScriptBodyDependency implements DependencyListener { dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.toJsMethod, DependencyStack.ROOT); dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.intValueMethod, DependencyStack.ROOT); dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.valueOfIntMethod, DependencyStack.ROOT); + dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.booleanValueMethod, DependencyStack.ROOT); + dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.valueOfBooleanMethod, DependencyStack.ROOT); } @Override diff --git a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyGenerator.java b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyGenerator.java index f89c13033..9a9cf809a 100644 --- a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyGenerator.java +++ b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyGenerator.java @@ -20,6 +20,7 @@ import java.util.List; import net.java.html.js.JavaScriptBody; import org.teavm.codegen.NamingStrategy; import org.teavm.codegen.SourceWriter; +import org.teavm.javascript.Renderer; import org.teavm.javascript.ni.Generator; import org.teavm.javascript.ni.GeneratorContext; import org.teavm.model.*; @@ -53,7 +54,7 @@ public class JavaScriptBodyGenerator implements Generator { writer.outdent().append("}).call(").append(context.getParameterName(0)); for (int i = 0; i < args.size(); ++i) { writer.append(",").ws(); - wrapParameter(writer, methodRef.getDescriptor().parameterType(i), context.getParameterName(i + 1)); + wrapParameter(writer, context.getParameterName(i + 1)); } writer.append(")").softNewLine(); writer.append("return "); @@ -61,22 +62,15 @@ public class JavaScriptBodyGenerator implements Generator { writer.append(";").softNewLine(); } - private void wrapParameter(SourceWriter writer, ValueType type, String param) throws IOException { - if (type.isObject("java.lang.Object")) { - writer.appendMethodBody(JavaScriptConvGenerator.toJsMethod); - writer.append("(").append(param).append(")"); - } else { - writer.append(param); - } + private void wrapParameter(SourceWriter writer, String param) throws IOException { + writer.appendMethodBody(JavaScriptConvGenerator.toJsMethod); + writer.append("(").append(param).append(")"); } private void unwrapValue(SourceWriter writer, ValueType type, String param) throws IOException { - if (type.isObject("java.lang.Object")) { - writer.appendMethodBody(JavaScriptConvGenerator.fromJsMethod); - writer.append("(").append(param).append(")"); - } else { - writer.append(param); - } + writer.appendMethodBody(JavaScriptConvGenerator.fromJsMethod); + writer.append("(").append(param).append(",").ws().append(Renderer.typeToClsString(writer.getNaming(), type)) + .append(")"); } private static class GeneratorJsCallback extends JsCallback { diff --git a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptConv.java b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptConv.java index 4139f076c..9d7b41127 100644 --- a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptConv.java +++ b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptConv.java @@ -29,5 +29,5 @@ public final class JavaScriptConv { public static native Object toJavaScript(Object obj); @GeneratedBy(JavaScriptConvGenerator.class) - public static native Object fromJavaScript(Object obj); + public static native Object fromJavaScript(Object obj, Object cls); } diff --git a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptConvGenerator.java b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptConvGenerator.java index e9ba59792..190f129bc 100644 --- a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptConvGenerator.java +++ b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptConvGenerator.java @@ -29,13 +29,17 @@ public class JavaScriptConvGenerator implements Generator { private static final String convCls = JavaScriptConv.class.getName(); static final MethodReference intValueMethod = new MethodReference("java.lang.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", 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"); static final MethodReference toJsMethod = new MethodReference(convCls, new MethodDescriptor( "toJavaScript", objType, objType)); static final MethodReference fromJsMethod = new MethodReference(convCls, new MethodDescriptor( - "fromJavaScript", objType, objType)); + "fromJavaScript", objType, objType, objType)); @Override 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); writer.append("if (" + obj + " === null) {").softNewLine().indent(); 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.append("var arr = new Array(" + obj + ".data.length);").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.outdent().append("}").softNewLine(); writer.append("return arr;").softNewLine(); - writer.outdent().append("}"); - writer.append(" else if (" + obj + ".constructor === ").appendClass("java.lang.String") + writer.outdent().append("} else if (" + obj + ".constructor === ").appendClass("java.lang.String") .append(") {").indent().softNewLine(); generateStringToJavaScript(context, writer); writer.outdent().append("} else if (" + obj + ".constructor === ").appendClass("java.lang.Integer") .append(") {").indent().softNewLine(); writer.append("return ").appendMethodBody(intValueMethod).append("(" + obj + ");").softNewLine(); - writer.outdent().append("}"); - writer.append(" else {").indent().softNewLine(); + writer.outdent().append("} else if (" + obj + ".constructor === ").appendClass("java.lang.Boolean") + .append(") {").indent().softNewLine(); + writer.append("return ").appendMethodBody(booleanValueMethod).append("(" + obj + ")!==0;").softNewLine(); + writer.outdent().append("} else {").indent().softNewLine(); writer.append("return " + obj + ";").softNewLine(); writer.outdent().append("}").softNewLine(); } private void generateFromJavaScript(GeneratorContext context, SourceWriter writer) throws IOException { String obj = context.getParameterName(1); + String type = context.getParameterName(2); writer.append("if (" + obj +" === null || " + obj + " === undefined)").ws().append("{") .softNewLine().indent(); writer.append("return null;").softNewLine(); - writer.outdent().append("} else if (" + obj + " instanceof Array) {").indent().softNewLine(); - writer.append("var arr = $rt_createArray($rt_objcls(), " + obj + ".length);").softNewLine(); + writer.outdent().append("} else if (" + type + ".$meta.item) {").indent().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("arr.data[i] = ").appendMethodBody(fromJsMethod).append("(" + obj + "[i]);") + writer.append("arr.data[i] = ").appendMethodBody(fromJsMethod).append("(" + obj + "[i], " + type + ");") .softNewLine(); writer.outdent().append("}").softNewLine(); writer.append("return arr;").softNewLine(); - writer.outdent().append("}"); - writer.append(" else if (" + obj + ".constructor === ").appendClass("java.lang.String") + writer.outdent().append("} else if (" + type + " === ").appendClass("java.lang.String") .append(") {").indent().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.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.append("return ").append(obj).append(";").softNewLine(); writer.outdent().append("}").softNewLine(); diff --git a/teavm-html4j/src/test/java/org/teavm/html4j/test/JavaScriptBodyConversionTests.java b/teavm-html4j/src/test/java/org/teavm/html4j/test/JavaScriptBodyConversionTests.java index a31e4b237..0cfaa1185 100644 --- a/teavm-html4j/src/test/java/org/teavm/html4j/test/JavaScriptBodyConversionTests.java +++ b/teavm-html4j/src/test/java/org/teavm/html4j/test/JavaScriptBodyConversionTests.java @@ -27,15 +27,30 @@ public class JavaScriptBodyConversionTests { @Test public void convertsInteger() { 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 public void convertsIntegerResult() { 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 public void convertsArray() { + assertEquals(42, getArrayItem(new int[] { 23, 42 }, 1)); assertEquals(42, getArrayItem(new Integer[] { 23, 42 }, 1)); } @@ -47,12 +62,46 @@ public class JavaScriptBodyConversionTests { 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;") 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;") 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;") private native Object modifyIntegerArray(Object value);