# HG changeset patch # User Martin Soch # Date 1358780221 -3600 # Node ID 95753ad6519225a764d0ec8015c1e42ba96ade1a # Parent 6506c5925775c038cc8d2b54f1344431bea478e7# Parent 974bc55865c78756cc2bb57717074d14449bb349 merge with trunk diff -r 6506c5925775 -r 95753ad65192 core/pom.xml --- a/core/pom.xml Tue Jan 15 11:39:15 2013 +0100 +++ b/core/pom.xml Mon Jan 21 15:57:01 2013 +0100 @@ -19,8 +19,8 @@ maven-compiler-plugin 2.3.2 - 1.6 - 1.6 + 1.7 + 1.7 @@ -35,6 +35,10 @@ 3.8.1 test + + org.netbeans.api + org-openide-util-lookup + Contains esential annotations for associating JavaScript code with methods and classes. diff -r 6506c5925775 -r 95753ad65192 core/src/main/java/org/apidesign/bck2brwsr/core/impl/JavaScriptProcesor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/main/java/org/apidesign/bck2brwsr/core/impl/JavaScriptProcesor.java Mon Jan 21 15:57:01 2013 +0100 @@ -0,0 +1,92 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.apidesign.bck2brwsr.core.impl; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.Completion; +import javax.annotation.processing.Completions; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.tools.Diagnostic; +import org.apidesign.bck2brwsr.core.JavaScriptBody; +import org.openide.util.lookup.ServiceProvider; + +/** + * + * @author Jaroslav Tulach + */ +@ServiceProvider(service = Processor.class) +public final class JavaScriptProcesor extends AbstractProcessor { + @Override + public Set getSupportedAnnotationTypes() { + Set set = new HashSet<>(); + set.add(JavaScriptBody.class.getName()); + return set; + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + for (Element e : roundEnv.getElementsAnnotatedWith(JavaScriptBody.class)) { + if (e.getKind() != ElementKind.METHOD && e.getKind() != ElementKind.CONSTRUCTOR) { + continue; + } + ExecutableElement ee = (ExecutableElement)e; + List params = ee.getParameters(); + + JavaScriptBody jsb = e.getAnnotation(JavaScriptBody.class); + String[] arr = jsb.args(); + if (params.size() != arr.length) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Number of args arguments does not match real arguments!", e); + } + } + return true; + } + + @Override + public Iterable getCompletions(Element e, + AnnotationMirror annotation, ExecutableElement member, String userText + ) { + StringBuilder sb = new StringBuilder(); + if (e.getKind() == ElementKind.METHOD && member.getSimpleName().contentEquals("args")) { + ExecutableElement ee = (ExecutableElement) e; + String sep = ""; + sb.append("{ "); + for (VariableElement ve : ee.getParameters()) { + sb.append(sep).append('"').append(ve.getSimpleName()) + .append('"'); + sep = ", "; + } + sb.append(" }"); + return Collections.nCopies(1, Completions.of(sb.toString())); + } + return null; + } + + +} diff -r 6506c5925775 -r 95753ad65192 emul/src/main/java/java/lang/Class.java --- a/emul/src/main/java/java/lang/Class.java Tue Jan 15 11:39:15 2013 +0100 +++ b/emul/src/main/java/java/lang/Class.java Mon Jan 21 15:57:01 2013 +0100 @@ -145,7 +145,15 @@ * @exception ClassNotFoundException if the class cannot be located */ public static Class forName(String className) - throws ClassNotFoundException { + throws ClassNotFoundException { + if (className.startsWith("[")) { + Class arrType = defineArray(className); + Class c = arrType; + while (c != null && c.isArray()) { + c = c.getComponentType0(); // verify component type is sane + } + return arrType; + } Class c = loadCls(className, className.replace('.', '_')); if (c == null) { throw new ClassNotFoundException(className); @@ -216,7 +224,7 @@ + "\nif (c['cons__V']) {" + "\n if ((c.cons__V.access & 0x1) != 0) {" + "\n var inst = c();" - + "\n c.cons__V(inst);" + + "\n c.cons__V.call(inst);" + "\n return inst;" + "\n }" + "\n return illegal;" @@ -269,7 +277,15 @@ * * @since JDK1.1 */ - public native boolean isInstance(Object obj); + public boolean isInstance(Object obj) { + String prop = "$instOf_" + getName().replace('.', '_'); + return hasProperty(obj, prop); + } + + @JavaScriptBody(args = { "who", "prop" }, body = + "if (who[prop]) return true; else return false;" + ) + private static native boolean hasProperty(Object who, String prop); /** @@ -310,7 +326,7 @@ return (getAccess() & 0x200) != 0; } - @JavaScriptBody(args = "self", body = "return self.access;") + @JavaScriptBody(args = {}, body = "return this.access;") private native int getAccess(); @@ -322,7 +338,7 @@ * @since JDK1.1 */ public boolean isArray() { - return false; + return hasProperty(this, "array"); // NOI18N } @@ -354,8 +370,8 @@ * @see java.lang.Void#TYPE * @since JDK1.1 */ - @JavaScriptBody(args = "self", body = - "if (self.primitive) return true;" + @JavaScriptBody(args = {}, body = + "if (this.primitive) return true;" + "else return false;" ) public native boolean isPrimitive(); @@ -439,7 +455,7 @@ return jvmName().replace('/', '.'); } - @JavaScriptBody(args = "self", body = "return self.jvmName;") + @JavaScriptBody(args = {}, body = "return this.jvmName;") private native String jvmName(); @@ -473,7 +489,7 @@ * * @return the superclass of the class represented by this object. */ - @JavaScriptBody(args = "self", body = "return self.superclass;") + @JavaScriptBody(args = {}, body = "return this.superclass;") public native Class getSuperclass(); /** @@ -1002,9 +1018,59 @@ * @since JDK1.1 */ public Class getComponentType() { + if (isArray()) { + try { + return getComponentType0(); + } catch (ClassNotFoundException cnfe) { + throw new IllegalStateException(cnfe); + } + } return null; } + private Class getComponentType0() throws ClassNotFoundException { + String n = getName().substring(1); + switch (n.charAt(0)) { + case 'L': + n = n.substring(1, n.length() - 1); + return Class.forName(n); + case 'I': + return Integer.TYPE; + case 'J': + return Long.TYPE; + case 'D': + return Double.TYPE; + case 'F': + return Float.TYPE; + case 'B': + return Byte.TYPE; + case 'Z': + return Boolean.TYPE; + case 'S': + return Short.TYPE; + case 'V': + return Void.TYPE; + case 'C': + return Character.TYPE; + case '[': + return defineArray(n); + default: + throw new ClassNotFoundException("Unknown component type of " + getName()); + } + } + + @JavaScriptBody(args = { "sig" }, body = + "var c = Array[sig];\n" + + "if (c) return c;\n" + + "c = vm.java_lang_Class(true);\n" + + "c.jvmName = sig;\n" + + "c.superclass = vm.java_lang_Object(false).$class;\n" + + "c.array = true;\n" + + "Array[sig] = c;\n" + + "return c;" + ) + private static native Class defineArray(String sig); + /** * Returns true if and only if this class was declared as an enum in the * source code. @@ -1070,10 +1136,10 @@ throw new ClassCastException(this.toString()); } - @JavaScriptBody(args = { "self", "ac" }, + @JavaScriptBody(args = { "ac" }, body = - "if (self.anno) {" - + " return self.anno['L' + ac.jvmName + ';'];" + "if (this.anno) {" + + " return this.anno['L' + ac.jvmName + ';'];" + "} else return null;" ) private Object getAnnotationData(Class annotationClass) { @@ -1092,8 +1158,8 @@ * @throws NullPointerException {@inheritDoc} * @since 1.5 */ - @JavaScriptBody(args = { "self", "ac" }, - body = "if (self.anno && self.anno['L' + ac.jvmName + ';']) { return true; }" + @JavaScriptBody(args = { "ac" }, + body = "if (this.anno && this.anno['L' + ac.jvmName + ';']) { return true; }" + "else return false;" ) public boolean isAnnotationPresent( @@ -1104,7 +1170,7 @@ return getAnnotation(annotationClass) != null; } - @JavaScriptBody(args = "self", body = "return self.anno;") + @JavaScriptBody(args = {}, body = "return this.anno;") private Object getAnnotationData() { throw new UnsupportedOperationException(); } diff -r 6506c5925775 -r 95753ad65192 emul/src/main/java/java/lang/Double.java --- a/emul/src/main/java/java/lang/Double.java Tue Jan 15 11:39:15 2013 +0100 +++ b/emul/src/main/java/java/lang/Double.java Mon Jan 21 15:57:01 2013 +0100 @@ -774,8 +774,7 @@ */ public boolean equals(Object obj) { return (obj instanceof Double) - && (doubleToLongBits(((Double)obj).value) == - doubleToLongBits(value)); + && (((Double)obj).value) == value; } /** diff -r 6506c5925775 -r 95753ad65192 emul/src/main/java/java/lang/NegativeArraySizeException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/src/main/java/java/lang/NegativeArraySizeException.java Mon Jan 21 15:57:01 2013 +0100 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +/** + * Thrown if an application tries to create an array with negative size. + * + * @author unascribed + * @since JDK1.0 + */ +public +class NegativeArraySizeException extends RuntimeException { + private static final long serialVersionUID = -8960118058596991861L; + + /** + * Constructs a NegativeArraySizeException with no + * detail message. + */ + public NegativeArraySizeException() { + super(); + } + + /** + * Constructs a NegativeArraySizeException with the + * specified detail message. + * + * @param s the detail message. + */ + public NegativeArraySizeException(String s) { + super(s); + } +} diff -r 6506c5925775 -r 95753ad65192 emul/src/main/java/java/lang/Object.java --- a/emul/src/main/java/java/lang/Object.java Tue Jan 15 11:39:15 2013 +0100 +++ b/emul/src/main/java/java/lang/Object.java Mon Jan 21 15:57:01 2013 +0100 @@ -25,6 +25,7 @@ package java.lang; +import java.lang.reflect.Array; import org.apidesign.bck2brwsr.core.JavaScriptBody; import org.apidesign.bck2brwsr.core.JavaScriptPrototype; @@ -40,8 +41,13 @@ @JavaScriptPrototype(container = "Object.prototype", prototype = "new Object") public class Object { - @JavaScriptBody(args = {}, body = "") - private static native void registerNatives(); + private static void registerNatives() { + try { + Array.get(null, 0); + } catch (Throwable ex) { + // ignore + } + } static { registerNatives(); } @@ -66,7 +72,7 @@ * @see Class Literals, section 15.8.2 of * The Java™ Language Specification. */ - @JavaScriptBody(args="self", body="return self.constructor.$class;") + @JavaScriptBody(args={}, body="return this.constructor.$class;") public final native Class getClass(); /** @@ -104,14 +110,14 @@ * @see java.lang.Object#equals(java.lang.Object) * @see java.lang.System#identityHashCode */ - @JavaScriptBody(args = "self", body = - "if (self.$hashCode) return self.$hashCode;\n" - + "var h = self.computeHashCode__I(self);\n" - + "return self.$hashCode = h & h;" + @JavaScriptBody(args = {}, body = + "if (this.$hashCode) return this.$hashCode;\n" + + "var h = this.computeHashCode__I();\n" + + "return this.$hashCode = h & h;" ) public native int hashCode(); - @JavaScriptBody(args = "self", body = "Math.random() * Math.pow(2, 32);") + @JavaScriptBody(args = {}, body = "Math.random() * Math.pow(2, 32);") native int computeHashCode(); /** diff -r 6506c5925775 -r 95753ad65192 emul/src/main/java/java/lang/String.java --- a/emul/src/main/java/java/lang/String.java Tue Jan 15 11:39:15 2013 +0100 +++ b/emul/src/main/java/java/lang/String.java Mon Jan 21 15:57:01 2013 +0100 @@ -169,11 +169,11 @@ * @param value * The initial value of the string */ - @JavaScriptBody(args = { "self", "charArr" }, body= + @JavaScriptBody(args = { "charArr" }, body= "for (var i = 0; i < charArr.length; i++) {\n" + " if (typeof charArr[i] === 'number') charArr[i] = String.fromCharCode(charArr[i]);\n" + "}\n" - + "self.fld_r = charArr.join('');\n" + + "this.fld_r = charArr.join('');\n" ) public String(char value[]) { } @@ -199,12 +199,12 @@ * If the {@code offset} and {@code count} arguments index * characters outside the bounds of the {@code value} array */ - @JavaScriptBody(args = { "self", "charArr", "off", "cnt" }, body = + @JavaScriptBody(args = { "charArr", "off", "cnt" }, body = "var up = off + cnt;\n" + "for (var i = off; i < up; i++) {\n" + " if (typeof charArr[i] === 'number') charArr[i] = String.fromCharCode(charArr[i]);\n" + "}\n" + - "self.fld_r = charArr.slice(off, up).join(\"\");\n" + "this.fld_r = charArr.slice(off, up).join(\"\");\n" ) public String(char value[], int offset, int count) { } @@ -618,7 +618,7 @@ * @return the length of the sequence of characters represented by this * object. */ - @JavaScriptBody(args = "self", body = "return self.toString().length;") + @JavaScriptBody(args = {}, body = "return this.toString().length;") public int length() { throw new UnsupportedOperationException(); } @@ -631,7 +631,7 @@ * * @since 1.6 */ - @JavaScriptBody(args = "self", body="return self.toString().length === 0;") + @JavaScriptBody(args = {}, body="return this.toString().length === 0;") public boolean isEmpty() { return length() == 0; } @@ -654,8 +654,8 @@ * argument is negative or not less than the length of this * string. */ - @JavaScriptBody(args = { "self", "index" }, - body = "return self.toString().charCodeAt(index);" + @JavaScriptBody(args = { "index" }, + body = "return this.toString().charCodeAt(index);" ) public char charAt(int index) { throw new UnsupportedOperationException(); @@ -780,8 +780,8 @@ * Copy characters from this string into dst starting at dstBegin. * This method doesn't perform any range checking. */ - @JavaScriptBody(args = { "self", "arr", "to" }, body = - "var s = self.toString();\n" + + @JavaScriptBody(args = { "arr", "to" }, body = + "var s = this.toString();\n" + "for (var i = 0; i < s.length; i++) {\n" + " arr[to++] = s[i];\n" + "}" @@ -820,8 +820,8 @@ *
  • dstBegin+(srcEnd-srcBegin) is larger than * dst.length */ - @JavaScriptBody(args = { "self", "beg", "end", "arr", "dst" }, body= - "var s = self.toString();\n" + + @JavaScriptBody(args = { "beg", "end", "arr", "dst" }, body= + "var s = this.toString();\n" + "while (beg < end) {\n" + " arr[dst++] = s[beg++];\n" + "}\n" @@ -993,9 +993,9 @@ * @see #compareTo(String) * @see #equalsIgnoreCase(String) */ - @JavaScriptBody(args = { "self", "obj" }, body = - "return obj.$instOf_java_lang_String && " - + "self.toString() === obj.toString();" + @JavaScriptBody(args = { "obj" }, body = + "return obj != null && obj.$instOf_java_lang_String && " + + "this.toString() === obj.toString();" ) public boolean equals(Object anObject) { if (this == anObject) { @@ -1420,9 +1420,9 @@ * this.substring(toffset).startsWith(prefix) * */ - @JavaScriptBody(args = { "self", "find", "from" }, body= + @JavaScriptBody(args = { "find", "from" }, body= "find = find.toString();\n" + - "return self.toString().substring(from, from + find.length) === find;\n" + "return this.toString().substring(from, from + find.length) === find;\n" ) public boolean startsWith(String prefix, int toffset) { char ta[] = toCharArray(); @@ -1570,9 +1570,9 @@ * than or equal to fromIndex, or -1 * if the character does not occur. */ - @JavaScriptBody(args = { "self", "ch", "from" }, body = + @JavaScriptBody(args = { "ch", "from" }, body = "if (typeof ch === 'number') ch = String.fromCharCode(ch);\n" + - "return self.toString().indexOf(ch, from);\n" + "return this.toString().indexOf(ch, from);\n" ) public int indexOf(int ch, int fromIndex) { if (fromIndex < 0) { @@ -1679,9 +1679,9 @@ * than or equal to fromIndex, or -1 * if the character does not occur before that point. */ - @JavaScriptBody(args = { "self", "ch", "from" }, body = + @JavaScriptBody(args = { "ch", "from" }, body = "if (typeof ch === 'number') ch = String.fromCharCode(ch);\n" + - "return self.toString().lastIndexOf(ch, from);" + "return this.toString().lastIndexOf(ch, from);" ) public int lastIndexOf(int ch, int fromIndex) { if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { @@ -1754,8 +1754,8 @@ * starting at the specified index, * or {@code -1} if there is no such occurrence. */ - @JavaScriptBody(args = { "self", "str", "fromIndex" }, body = - "return self.toString().indexOf(str.toString(), fromIndex);" + @JavaScriptBody(args = { "str", "fromIndex" }, body = + "return this.toString().indexOf(str.toString(), fromIndex);" ) public native int indexOf(String str, int fromIndex); @@ -1794,8 +1794,8 @@ * searching backward from the specified index, * or {@code -1} if there is no such occurrence. */ - @JavaScriptBody(args = { "self", "s", "from" }, body = - "return self.toString().lastIndexOf(s.toString(), from);" + @JavaScriptBody(args = { "s", "from" }, body = + "return this.toString().lastIndexOf(s.toString(), from);" ) public int lastIndexOf(String str, int fromIndex) { return lastIndexOf(toCharArray(), offset(), length(), str.toCharArray(), str.offset(), str.length(), fromIndex); @@ -1903,8 +1903,8 @@ * beginIndex is larger than * endIndex. */ - @JavaScriptBody(args = { "self", "beginIndex", "endIndex" }, body = - "return self.toString().substring(beginIndex, endIndex);" + @JavaScriptBody(args = { "beginIndex", "endIndex" }, body = + "return this.toString().substring(beginIndex, endIndex);" ) public String substring(int beginIndex, int endIndex) { if (beginIndex < 0) { @@ -2012,10 +2012,10 @@ * @return a string derived from this string by replacing every * occurrence of oldChar with newChar. */ - @JavaScriptBody(args = { "self", "arg1", "arg2" }, body = + @JavaScriptBody(args = { "arg1", "arg2" }, body = "if (typeof arg1 === 'number') arg1 = String.fromCharCode(arg1);\n" + "if (typeof arg2 === 'number') arg2 = String.fromCharCode(arg2);\n" + - "var s = self.toString();\n" + + "var s = this.toString();\n" + "for (;;) {\n" + " var ret = s.replace(arg1, arg2);\n" + " if (ret === s) {\n" + @@ -2078,8 +2078,8 @@ * @since 1.4 * @spec JSR-51 */ - @JavaScriptBody(args = { "self", "regex" }, body = - "self = self.toString();\n" + @JavaScriptBody(args = { "regex" }, body = + "var self = this.toString();\n" + "var re = new RegExp(regex.toString());\n" + "var r = re.exec(self);\n" + "return r != null && r.length > 0 && self.length == r[0].length;" @@ -2496,7 +2496,7 @@ * @return the String, converted to lowercase. * @see java.lang.String#toLowerCase(Locale) */ - @JavaScriptBody(args = "self", body = "return self.toLowerCase();") + @JavaScriptBody(args = {}, body = "return this.toLowerCase();") public String toLowerCase() { throw new UnsupportedOperationException("Should be supported but without connection to locale"); } @@ -2662,7 +2662,7 @@ * @return the String, converted to uppercase. * @see java.lang.String#toUpperCase(Locale) */ - @JavaScriptBody(args = "self", body = "return self.toUpperCase();") + @JavaScriptBody(args = {}, body = "return this.toUpperCase();") public String toUpperCase() { throw new UnsupportedOperationException(); } @@ -2718,7 +2718,7 @@ * * @return the string itself. */ - @JavaScriptBody(args = "self", body = "return self.toString();") + @JavaScriptBody(args = {}, body = "return this.toString();") public String toString() { return this; } diff -r 6506c5925775 -r 95753ad65192 emul/src/main/java/java/lang/Throwable.java --- a/emul/src/main/java/java/lang/Throwable.java Tue Jan 15 11:39:15 2013 +0100 +++ b/emul/src/main/java/java/lang/Throwable.java Mon Jan 21 15:57:01 2013 +0100 @@ -26,6 +26,7 @@ package java.lang; import java.io.*; import org.apidesign.bck2brwsr.core.JavaScriptBody; +import org.apidesign.bck2brwsr.core.JavaScriptOnly; /** * The {@code Throwable} class is the superclass of all errors and @@ -234,6 +235,13 @@ private static final String SELF_SUPPRESSION_MESSAGE = "Self-suppression not permitted"; /** Caption for labeling causative exception stack traces */ + @JavaScriptOnly(name="toString", value="function() { return this.toString__Ljava_lang_String_2().toString(); }") + private static void jsToString() { + } + + @JavaScriptOnly(name="valueOf", value="function() { return this.toString().valueOf(); }") + private static void jsValudOf() { + } private static final String CAUSE_CAPTION = "Caused by: "; /** Caption for labeling suppressed exception stack traces */ @@ -783,7 +791,7 @@ return this; } - @JavaScriptBody(args = { "self", "dummy" }, body = "") + @JavaScriptBody(args = { "dummy" }, body = "") private native Throwable fillInStackTrace(int dummy); /** diff -r 6506c5925775 -r 95753ad65192 emul/src/main/java/java/lang/reflect/Array.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/src/main/java/java/lang/reflect/Array.java Mon Jan 21 15:57:01 2013 +0100 @@ -0,0 +1,659 @@ +/* + * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang.reflect; + +import org.apidesign.bck2brwsr.core.JavaScriptBody; +import org.apidesign.bck2brwsr.core.JavaScriptPrototype; + +/** + * The {@code Array} class provides static methods to dynamically create and + * access Java arrays. + * + *

    {@code Array} permits widening conversions to occur during a get or set + * operation, but throws an {@code IllegalArgumentException} if a narrowing + * conversion would occur. + * + * @author Nakul Saraiya + */ +@JavaScriptPrototype(prototype = "new Array", container = "Array.prototype") +public final +class Array { + + /** + * Constructor. Class Array is not instantiable. + */ + private Array() {} + + /** + * Creates a new array with the specified component type and + * length. + * Invoking this method is equivalent to creating an array + * as follows: + *

    + *
    +     * int[] x = {length};
    +     * Array.newInstance(componentType, x);
    +     * 
    + *
    + * + * @param componentType the {@code Class} object representing the + * component type of the new array + * @param length the length of the new array + * @return the new array + * @exception NullPointerException if the specified + * {@code componentType} parameter is null + * @exception IllegalArgumentException if componentType is {@link Void#TYPE} + * @exception NegativeArraySizeException if the specified {@code length} + * is negative + */ + public static Object newInstance(Class componentType, int length) + throws NegativeArraySizeException { + if (length < 0) { + throw new NegativeArraySizeException(); + } + String sig = findSignature(componentType); + return newArray(componentType.isPrimitive(), sig, length); + } + + private static String findSignature(Class type) { + if (type == Integer.TYPE) { + return "[I"; + } + if (type == Long.TYPE) { + return "[J"; + } + if (type == Double.TYPE) { + return "[D"; + } + if (type == Float.TYPE) { + return "[F"; + } + if (type == Byte.TYPE) { + return "[B"; + } + if (type == Boolean.TYPE) { + return "[Z"; + } + if (type == Short.TYPE) { + return "[S"; + } + if (type == Character.TYPE) { + return "[C"; + } + if (type.getName().equals("void")) { + throw new IllegalStateException("Can't create array for " + type); + } + return "[L" + type.getName() + ";"; + } + /** + * Creates a new array + * with the specified component type and dimensions. + * If {@code componentType} + * represents a non-array class or interface, the new array + * has {@code dimensions.length} dimensions and + * {@code componentType} as its component type. If + * {@code componentType} represents an array class, the + * number of dimensions of the new array is equal to the sum + * of {@code dimensions.length} and the number of + * dimensions of {@code componentType}. In this case, the + * component type of the new array is the component type of + * {@code componentType}. + * + *

    The number of dimensions of the new array must not + * exceed the number of array dimensions supported by the + * implementation (typically 255). + * + * @param componentType the {@code Class} object representing the component + * type of the new array + * @param dimensions an array of {@code int} representing the dimensions of + * the new array + * @return the new array + * @exception NullPointerException if the specified + * {@code componentType} argument is null + * @exception IllegalArgumentException if the specified {@code dimensions} + * argument is a zero-dimensional array, or if the number of + * requested dimensions exceeds the limit on the number of array dimensions + * supported by the implementation (typically 255), or if componentType + * is {@link Void#TYPE}. + * @exception NegativeArraySizeException if any of the components in + * the specified {@code dimensions} argument is negative. + */ + public static Object newInstance(Class componentType, int... dimensions) + throws IllegalArgumentException, NegativeArraySizeException { + StringBuilder sig = new StringBuilder(); + for (int i = 1; i < dimensions.length; i++) { + sig.append('['); + } + sig.append(findSignature(componentType)); + return multiNewArray(sig.toString(), dimensions, 0); + } + + /** + * Returns the length of the specified array object, as an {@code int}. + * + * @param array the array + * @return the length of the array + * @exception IllegalArgumentException if the object argument is not + * an array + */ + public static int getLength(Object array) + throws IllegalArgumentException { + if (!array.getClass().isArray()) { + throw new IllegalArgumentException("Argument is not an array"); + } + return length(array); + } + + @JavaScriptBody(args = { "arr" }, body = "return arr.length;") + private static native int length(Object arr); + + /** + * Returns the value of the indexed component in the specified + * array object. The value is automatically wrapped in an object + * if it has a primitive type. + * + * @param array the array + * @param index the index + * @return the (possibly wrapped) value of the indexed component in + * the specified array + * @exception NullPointerException If the specified object is null + * @exception IllegalArgumentException If the specified object is not + * an array + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to the + * length of the specified array + */ + public static Object get(Object array, int index) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + final Class t = array.getClass().getComponentType(); + if (t.isPrimitive()) { + return Array.fromPrimitive(t, array, index); + } else { + return ((Object[])array)[index]; + } + } + + /** + * Returns the value of the indexed component in the specified + * array object, as a {@code boolean}. + * + * @param array the array + * @param index the index + * @return the value of the indexed component in the specified array + * @exception NullPointerException If the specified object is null + * @exception IllegalArgumentException If the specified object is not + * an array, or if the indexed element cannot be converted to the + * return type by an identity or widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to the + * length of the specified array + * @see Array#get + */ + public static native boolean getBoolean(Object array, int index) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException; + + /** + * Returns the value of the indexed component in the specified + * array object, as a {@code byte}. + * + * @param array the array + * @param index the index + * @return the value of the indexed component in the specified array + * @exception NullPointerException If the specified object is null + * @exception IllegalArgumentException If the specified object is not + * an array, or if the indexed element cannot be converted to the + * return type by an identity or widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to the + * length of the specified array + * @see Array#get + */ + public static byte getByte(Object array, int index) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + if (array.getClass().getComponentType() != Byte.TYPE) { + throw new IllegalArgumentException(); + } + byte[] arr = (byte[]) array; + return arr[index]; + } + + /** + * Returns the value of the indexed component in the specified + * array object, as a {@code char}. + * + * @param array the array + * @param index the index + * @return the value of the indexed component in the specified array + * @exception NullPointerException If the specified object is null + * @exception IllegalArgumentException If the specified object is not + * an array, or if the indexed element cannot be converted to the + * return type by an identity or widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to the + * length of the specified array + * @see Array#get + */ + public static native char getChar(Object array, int index) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException; + + /** + * Returns the value of the indexed component in the specified + * array object, as a {@code short}. + * + * @param array the array + * @param index the index + * @return the value of the indexed component in the specified array + * @exception NullPointerException If the specified object is null + * @exception IllegalArgumentException If the specified object is not + * an array, or if the indexed element cannot be converted to the + * return type by an identity or widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to the + * length of the specified array + * @see Array#get + */ + public static short getShort(Object array, int index) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + final Class t = array.getClass().getComponentType(); + if (t == Short.TYPE) { + short[] arr = (short[]) array; + return arr[index]; + } + return getByte(array, index); + } + + /** + * Returns the value of the indexed component in the specified + * array object, as an {@code int}. + * + * @param array the array + * @param index the index + * @return the value of the indexed component in the specified array + * @exception NullPointerException If the specified object is null + * @exception IllegalArgumentException If the specified object is not + * an array, or if the indexed element cannot be converted to the + * return type by an identity or widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to the + * length of the specified array + * @see Array#get + */ + public static int getInt(Object array, int index) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + final Class t = array.getClass().getComponentType(); + if (t == Integer.TYPE) { + int[] arr = (int[]) array; + return arr[index]; + } + return getShort(array, index); + } + + /** + * Returns the value of the indexed component in the specified + * array object, as a {@code long}. + * + * @param array the array + * @param index the index + * @return the value of the indexed component in the specified array + * @exception NullPointerException If the specified object is null + * @exception IllegalArgumentException If the specified object is not + * an array, or if the indexed element cannot be converted to the + * return type by an identity or widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to the + * length of the specified array + * @see Array#get + */ + public static long getLong(Object array, int index) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + final Class t = array.getClass().getComponentType(); + if (t == Long.TYPE) { + long[] arr = (long[]) array; + return arr[index]; + } + return getInt(array, index); + } + + /** + * Returns the value of the indexed component in the specified + * array object, as a {@code float}. + * + * @param array the array + * @param index the index + * @return the value of the indexed component in the specified array + * @exception NullPointerException If the specified object is null + * @exception IllegalArgumentException If the specified object is not + * an array, or if the indexed element cannot be converted to the + * return type by an identity or widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to the + * length of the specified array + * @see Array#get + */ + public static float getFloat(Object array, int index) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + final Class t = array.getClass().getComponentType(); + if (t == Float.TYPE) { + float[] arr = (float[]) array; + return arr[index]; + } + return getLong(array, index); + } + + /** + * Returns the value of the indexed component in the specified + * array object, as a {@code double}. + * + * @param array the array + * @param index the index + * @return the value of the indexed component in the specified array + * @exception NullPointerException If the specified object is null + * @exception IllegalArgumentException If the specified object is not + * an array, or if the indexed element cannot be converted to the + * return type by an identity or widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to the + * length of the specified array + * @see Array#get + */ + public static double getDouble(Object array, int index) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + final Class t = array.getClass().getComponentType(); + if (t == Double.TYPE) { + double[] arr = (double[]) array; + return arr[index]; + } + return getFloat(array, index); + } + + /** + * Sets the value of the indexed component of the specified array + * object to the specified new value. The new value is first + * automatically unwrapped if the array has a primitive component + * type. + * @param array the array + * @param index the index into the array + * @param value the new value of the indexed component + * @exception NullPointerException If the specified object argument + * is null + * @exception IllegalArgumentException If the specified object argument + * is not an array, or if the array component type is primitive and + * an unwrapping conversion fails + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to + * the length of the specified array + */ + public static void set(Object array, int index, Object value) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + if (array.getClass().getComponentType().isPrimitive()) { + throw new IllegalArgumentException(); + } else { + Object[] arr = (Object[])array; + arr[index] = value; + } + } + + /** + * Sets the value of the indexed component of the specified array + * object to the specified {@code boolean} value. + * @param array the array + * @param index the index into the array + * @param z the new value of the indexed component + * @exception NullPointerException If the specified object argument + * is null + * @exception IllegalArgumentException If the specified object argument + * is not an array, or if the specified value cannot be converted + * to the underlying array's component type by an identity or a + * primitive widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to + * the length of the specified array + * @see Array#set + */ + public static native void setBoolean(Object array, int index, boolean z) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException; + + /** + * Sets the value of the indexed component of the specified array + * object to the specified {@code byte} value. + * @param array the array + * @param index the index into the array + * @param b the new value of the indexed component + * @exception NullPointerException If the specified object argument + * is null + * @exception IllegalArgumentException If the specified object argument + * is not an array, or if the specified value cannot be converted + * to the underlying array's component type by an identity or a + * primitive widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to + * the length of the specified array + * @see Array#set + */ + public static void setByte(Object array, int index, byte b) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + Class t = array.getClass().getComponentType(); + if (t == Byte.TYPE) { + byte[] arr = (byte[]) array; + arr[index] = b; + } else { + setShort(array, index, b); + } + } + + /** + * Sets the value of the indexed component of the specified array + * object to the specified {@code char} value. + * @param array the array + * @param index the index into the array + * @param c the new value of the indexed component + * @exception NullPointerException If the specified object argument + * is null + * @exception IllegalArgumentException If the specified object argument + * is not an array, or if the specified value cannot be converted + * to the underlying array's component type by an identity or a + * primitive widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to + * the length of the specified array + * @see Array#set + */ + public static native void setChar(Object array, int index, char c) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException; + + /** + * Sets the value of the indexed component of the specified array + * object to the specified {@code short} value. + * @param array the array + * @param index the index into the array + * @param s the new value of the indexed component + * @exception NullPointerException If the specified object argument + * is null + * @exception IllegalArgumentException If the specified object argument + * is not an array, or if the specified value cannot be converted + * to the underlying array's component type by an identity or a + * primitive widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to + * the length of the specified array + * @see Array#set + */ + public static void setShort(Object array, int index, short s) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + Class t = array.getClass().getComponentType(); + if (t == Short.TYPE) { + short[] arr = (short[]) array; + arr[index] = s; + } else { + setInt(array, index, s); + } + + } + + /** + * Sets the value of the indexed component of the specified array + * object to the specified {@code int} value. + * @param array the array + * @param index the index into the array + * @param i the new value of the indexed component + * @exception NullPointerException If the specified object argument + * is null + * @exception IllegalArgumentException If the specified object argument + * is not an array, or if the specified value cannot be converted + * to the underlying array's component type by an identity or a + * primitive widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to + * the length of the specified array + * @see Array#set + */ + public static void setInt(Object array, int index, int i) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + Class t = array.getClass().getComponentType(); + if (t == Integer.TYPE) { + long[] arr = (long[]) array; + arr[index] = i; + } else { + setLong(array, index, i); + } + } + + /** + * Sets the value of the indexed component of the specified array + * object to the specified {@code long} value. + * @param array the array + * @param index the index into the array + * @param l the new value of the indexed component + * @exception NullPointerException If the specified object argument + * is null + * @exception IllegalArgumentException If the specified object argument + * is not an array, or if the specified value cannot be converted + * to the underlying array's component type by an identity or a + * primitive widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to + * the length of the specified array + * @see Array#set + */ + public static void setLong(Object array, int index, long l) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + Class t = array.getClass().getComponentType(); + if (t == Long.TYPE) { + long[] arr = (long[]) array; + arr[index] = l; + } else { + setFloat(array, index, l); + } + } + + /** + * Sets the value of the indexed component of the specified array + * object to the specified {@code float} value. + * @param array the array + * @param index the index into the array + * @param f the new value of the indexed component + * @exception NullPointerException If the specified object argument + * is null + * @exception IllegalArgumentException If the specified object argument + * is not an array, or if the specified value cannot be converted + * to the underlying array's component type by an identity or a + * primitive widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to + * the length of the specified array + * @see Array#set + */ + public static void setFloat(Object array, int index, float f) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + Class t = array.getClass().getComponentType(); + if (t == Float.TYPE) { + float[] arr = (float[])array; + arr[index] = f; + } else { + setDouble(array, index, f); + } + } + + /** + * Sets the value of the indexed component of the specified array + * object to the specified {@code double} value. + * @param array the array + * @param index the index into the array + * @param d the new value of the indexed component + * @exception NullPointerException If the specified object argument + * is null + * @exception IllegalArgumentException If the specified object argument + * is not an array, or if the specified value cannot be converted + * to the underlying array's component type by an identity or a + * primitive widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to + * the length of the specified array + * @see Array#set + */ + public static void setDouble(Object array, int index, double d) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + Class t = array.getClass().getComponentType(); + if (t == Double.TYPE) { + double[] arr = (double[])array; + arr[index] = d; + } else { + throw new IllegalArgumentException("argument type mismatch"); + } + } + + /* + * Private + */ + + @JavaScriptBody(args = { "primitive", "sig", "length" }, body = + "var arr = new Array(length);\n" + + "var value = primitive ? 0 : null;\n" + + "for(var i = 0; i < length; i++) arr[i] = value;\n" + + "arr.jvmName = sig;\n" + + "return arr;" + ) + private static native Object newArray(boolean primitive, String sig, int length); + + private static Object multiNewArray(String sig, int[] dims, int index) + throws IllegalArgumentException, NegativeArraySizeException { + if (dims.length == index + 1) { + return newArray(sig.length() == 2, sig, dims[index]); + } + Object[] arr = (Object[]) newArray(false, sig, dims[index]); + String compsig = sig.substring(1); + for (int i = 0; i < arr.length; i++) { + arr[i] = multiNewArray(compsig, dims, index + 1); + } + return arr; + } + private static Object fromPrimitive(Class t, Object array, int index) { + return Method.fromPrimitive(t, atArray(array, index)); + } + + @JavaScriptBody(args = { "array", "index" }, body = "return array[index]") + private static native Object atArray(Object array, int index); +} diff -r 6506c5925775 -r 95753ad65192 emul/src/main/java/java/lang/reflect/Method.java --- a/emul/src/main/java/java/lang/reflect/Method.java Tue Jan 15 11:39:15 2013 +0100 +++ b/emul/src/main/java/java/lang/reflect/Method.java Mon Jan 21 15:57:01 2013 +0100 @@ -537,7 +537,7 @@ ) private static native Object invoke0(boolean isStatic, Method m, Object self, Object[] args); - private static Object fromPrimitive(Class type, Object o) { + static Object fromPrimitive(Class type, Object o) { if (type == Integer.TYPE) { return fromRaw(Integer.class, "valueOf__Ljava_lang_Integer_2I", o); } @@ -559,6 +559,9 @@ if (type == Short.TYPE) { return fromRaw(Short.class, "valueOf__Ljava_lang_Short_2S", o); } + if (type == Character.TYPE) { + return fromRaw(Character.class, "valueOf__Ljava_lang_Character_2C", o); + } if (type.getName().equals("void")) { return null; } @@ -592,6 +595,9 @@ if (type == Short.TYPE) { return toRaw("shortValue__S", o); } + if (type == Character.TYPE) { + return toRaw("charValue__C", o); + } if (type.getName().equals("void")) { return o; } @@ -640,10 +646,10 @@ return Modifier.isSynthetic(getModifiers()); } - @JavaScriptBody(args = { "self", "ac" }, + @JavaScriptBody(args = { "ac" }, body = - "if (self.fld_data.anno) {" - + " return self.fld_data.anno['L' + ac.jvmName + ';'];" + "if (this.fld_data.anno) {" + + " return this.fld_data.anno['L' + ac.jvmName + ';'];" + "} else return null;" ) private Object getAnnotationData(Class annotationClass) { diff -r 6506c5925775 -r 95753ad65192 emul/src/main/java/org/apidesign/bck2brwsr/emul/MethodImpl.java --- a/emul/src/main/java/org/apidesign/bck2brwsr/emul/MethodImpl.java Tue Jan 15 11:39:15 2013 +0100 +++ b/emul/src/main/java/org/apidesign/bck2brwsr/emul/MethodImpl.java Mon Jan 21 15:57:01 2013 +0100 @@ -144,6 +144,8 @@ return Short.TYPE; case 'V': return Void.TYPE; + case 'C': + return Character.TYPE; case 'L': try { int up = sig.indexOf("_2"); diff -r 6506c5925775 -r 95753ad65192 emul/src/main/resources/org/apidesign/vm4brwsr/emul/java_lang_String.js --- a/emul/src/main/resources/org/apidesign/vm4brwsr/emul/java_lang_String.js Tue Jan 15 11:39:15 2013 +0100 +++ b/emul/src/main/resources/org/apidesign/vm4brwsr/emul/java_lang_String.js Mon Jan 21 15:57:01 2013 +0100 @@ -1,10 +1,20 @@ -// initialize methods on String constants +// initialize methods on arrays and String constants +vm.java_lang_reflect_Array(false); vm.java_lang_String(false); -// we need initialized arrays -Array.prototype.fillWith = function(value) { - for(var i = 0; i < this.length; i++) this[i] = value; - return this; +Array.prototype.at = function(indx, value) { + if (indx < 0 || indx > this.length) { + var e = vm.java_lang_ArrayIndexOutOfBoundsException(true); + e.constructor.cons__VLjava_lang_String_2.call(e, indx.toString()); + throw e; + } + if (arguments.length === 2) { + this[indx] = value; + } + return this[indx]; +}; +Array.prototype.getClass__Ljava_lang_Class_2 = function() { + return vm.java_lang_Class(false).defineArray__Ljava_lang_Class_2Ljava_lang_String_2(this.jvmName); }; Array.prototype.clone__Ljava_lang_Object_2 = function() { var s = this.length; diff -r 6506c5925775 -r 95753ad65192 javap/src/main/java/org/apidesign/javap/StackMapIterator.java --- a/javap/src/main/java/org/apidesign/javap/StackMapIterator.java Tue Jan 15 11:39:15 2013 +0100 +++ b/javap/src/main/java/org/apidesign/javap/StackMapIterator.java Mon Jan 21 15:57:01 2013 +0100 @@ -123,7 +123,7 @@ } final int length = methodSignature.length(); - int skipType = 0; + boolean skipType = false; int argType; for (int i = 1; i < length; ++i) { switch (methodSignature.charAt(i)) { @@ -156,10 +156,10 @@ // not interested in the return value type return argTypes; case '[': - if (skipType == 0) { + if (!skipType) { argTypes.add(ITEM_Object); + skipType = true; } - ++skipType; continue; default: @@ -167,10 +167,10 @@ "Invalid method signature"); } - if (skipType == 0) { + if (!skipType) { argTypes.add(argType); } else { - --skipType; + skipType = false; } } diff -r 6506c5925775 -r 95753ad65192 javap/src/main/java/org/apidesign/javap/Vector.java --- a/javap/src/main/java/org/apidesign/javap/Vector.java Tue Jan 15 11:39:15 2013 +0100 +++ b/javap/src/main/java/org/apidesign/javap/Vector.java Mon Jan 21 15:57:01 2013 +0100 @@ -37,8 +37,8 @@ void add(Object objectType) { addElement(objectType); } - @JavaScriptBody(args = { "self", "obj" }, body = - "self.push(obj);" + @JavaScriptBody(args = { "obj" }, body = + "this.push(obj);" ) void addElement(Object obj) { final int s = size(); @@ -46,16 +46,16 @@ setElementAt(obj, s); } - @JavaScriptBody(args = { "self" }, body = - "return self.length;" + @JavaScriptBody(args = { }, body = + "return this.length;" ) int size() { return arr == null ? 0 : arr.length; } - @JavaScriptBody(args = { "self", "newArr" }, body = - "for (var i = 0; i < self.length; i++) {\n" - + " newArr[i] = self[i];\n" + @JavaScriptBody(args = { "newArr" }, body = + "for (var i = 0; i < this.length; i++) {\n" + + " newArr[i] = this[i];\n" + "}\n") void copyInto(Object[] newArr) { if (arr == null) { @@ -67,8 +67,8 @@ } } - @JavaScriptBody(args = { "self", "index" }, body = - "return self[index];" + @JavaScriptBody(args = { "index" }, body = + "return this[index];" ) Object elementAt(int index) { return arr[index]; @@ -80,8 +80,8 @@ arr = newArr; } - @JavaScriptBody(args = { "self", "val", "index" }, body = - "self[index] = val;" + @JavaScriptBody(args = { "val", "index" }, body = + "this[index] = val;" ) void setElementAt(Object val, int index) { arr[index] = val; diff -r 6506c5925775 -r 95753ad65192 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Tue Jan 15 11:39:15 2013 +0100 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Mon Jan 21 15:57:01 2013 +0100 @@ -43,7 +43,7 @@ import javax.tools.Diagnostic; import javax.tools.FileObject; import javax.tools.StandardLocation; -import org.apidesign.bck2brwsr.htmlpage.api.OnClick; +import org.apidesign.bck2brwsr.htmlpage.api.On; import org.apidesign.bck2brwsr.htmlpage.api.Page; import org.openide.util.lookup.ServiceProvider; @@ -55,7 +55,7 @@ @ServiceProvider(service=Processor.class) @SupportedAnnotationTypes({ "org.apidesign.bck2brwsr.htmlpage.api.Page", - "org.apidesign.bck2brwsr.htmlpage.api.OnClick" + "org.apidesign.bck2brwsr.htmlpage.api.On" }) public final class PageProcessor extends AbstractProcessor { @Override @@ -95,7 +95,7 @@ append(type).append("(\"").append(id).append("\");\n"); } w.append(" static {\n"); - if (!initializeOnClick(pe, w, pp)) { + if (!initializeOnClick((TypeElement) e, w, pp)) { return false; } w.append(" }\n"); @@ -138,19 +138,18 @@ return id.toUpperCase(Locale.ENGLISH).replace('.', '_'); } - private boolean initializeOnClick(PackageElement pe, Writer w, ProcessPage pp) throws IOException { + private boolean initializeOnClick(TypeElement type, Writer w, ProcessPage pp) throws IOException { TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType(); - for (Element clazz : pe.getEnclosedElements()) { - if (clazz.getKind() != ElementKind.CLASS) { - continue; - } - TypeElement type = (TypeElement)clazz; - for (Element method : clazz.getEnclosedElements()) { - OnClick oc = method.getAnnotation(OnClick.class); + { //for (Element clazz : pe.getEnclosedElements()) { + // if (clazz.getKind() != ElementKind.CLASS) { + // continue; + // } + for (Element method : type.getEnclosedElements()) { + On oc = method.getAnnotation(On.class); if (oc != null) { for (String id : oc.id()) { if (pp.tagNameForId(id) == null) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "id = " + oc.id() + " does not exist in the HTML page. Found only " + pp.ids(), method); + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "id = " + id + " does not exist in the HTML page. Found only " + pp.ids(), method); return false; } ExecutableElement ee = (ExecutableElement)method; @@ -159,21 +158,21 @@ hasParam = false; } else { if (ee.getParameters().size() != 1 || ee.getParameters().get(0).asType() != stringType) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@OnClick method should either have no arguments or one String argument", ee); + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@On method should either have no arguments or one String argument", ee); return false; } hasParam = true; } if (!ee.getModifiers().contains(Modifier.STATIC)) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@OnClick method has to be static", ee); + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@On method has to be static", ee); return false; } if (ee.getModifiers().contains(Modifier.PRIVATE)) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@OnClick method can't be private", ee); + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@On method can't be private", ee); return false; } - w.append(" ").append(cnstnt(id)). - append(".addOnClick(new Runnable() { public void run() {\n"); + w.append(" OnEvent." + oc.event()).append(".of(").append(cnstnt(id)). + append(").perform(new Runnable() { public void run() {\n"); w.append(" ").append(type.getSimpleName().toString()). append('.').append(ee.getSimpleName()).append("("); if (hasParam) { diff -r 6506c5925775 -r 95753ad65192 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.java --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.java Tue Jan 15 11:39:15 2013 +0100 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.java Mon Jan 21 15:57:01 2013 +0100 @@ -37,29 +37,45 @@ body="var e = window.document.getElementById(el.fld_id);\n" + "e[property] = value;\n" ) - static void setAttribute(Element el, String property, Object value) { - throw new UnsupportedOperationException("Needs JavaScript!"); - } + static native void setAttribute(Element el, String property, Object value); @JavaScriptBody( args={"el", "property"}, body="var e = window.document.getElementById(el.fld_id);\n" + "return e[property];\n" ) - static Object getAttribute(Element el, String property) { - throw new UnsupportedOperationException("Needs JavaScript!"); - } + static native Object getAttribute(Element el, String property); /** Executes given runnable when user performs a "click" on the given * element. * @param r the runnable to execute, never null */ @JavaScriptBody( - args={"el", "r"}, - body="var e = window.document.getElementById(el.fld_id);\n" - + "e.onclick = function() { r.run__V(); };\n" + args={ "ev", "r" }, + body="var e = window.document.getElementById(this.fld_id);\n" + + "e[ev.fld_id] = function() { r.run__V(); };\n" ) - public final void addOnClick(Runnable r) { - throw new UnsupportedOperationException("Needs JavaScript!"); + final native void on(OnEvent ev, Runnable r); + + /** Shows alert message dialog in a browser. + * @param msg the message to show + */ + @JavaScriptBody(args = "msg", body = "alert(msg);") + public static native void alert(String msg); + + /** Generic way to query any attribute of this element. + * @param property name of the attribute + */ + public final Object getAttribute(String property) { + return getAttribute(this, property); + } + + /** Generic way to change an attribute of this element. + * + * @param property name of the attribute + * @param value value to associate with the attribute + */ + public final void setAttribute(String property, Object value) { + setAttribute(this, property, value); } } diff -r 6506c5925775 -r 95753ad65192 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/On.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/On.java Mon Jan 21 15:57:01 2013 +0100 @@ -0,0 +1,35 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.apidesign.bck2brwsr.htmlpage.api; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** Adds an onClick handler to an element identified by given id. + * Apply on a public static void method with no arguments. + * + * @author Jaroslav Tulach + */ +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.METHOD) +public @interface On { + OnEvent event(); + String[] id(); +} diff -r 6506c5925775 -r 95753ad65192 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnClick.java --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnClick.java Tue Jan 15 11:39:15 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -/** - * Back 2 Browser Bytecode Translator - * Copyright (C) 2012 Jaroslav Tulach - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. Look for COPYING file in the top folder. - * If not, see http://opensource.org/licenses/GPL-2.0. - */ -package org.apidesign.bck2brwsr.htmlpage.api; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** Adds an onClick handler to an element identified by given id. - * Apply on a public static void method with no arguments. - * - * @author Jaroslav Tulach - */ -@Retention(RetentionPolicy.SOURCE) -@Target(ElementType.METHOD) -public @interface OnClick { - String[] id(); -} diff -r 6506c5925775 -r 95753ad65192 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnController.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnController.java Mon Jan 21 15:57:01 2013 +0100 @@ -0,0 +1,43 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.apidesign.bck2brwsr.htmlpage.api; + +/** Controller created via {@link OnEvent#of(org.apidesign.bck2brwsr.htmlpage.api.Element[])}. + * + * @author Jaroslav Tulach + */ +public final class OnController { + private final Element[] arr; + private final OnEvent event; + + OnController(OnEvent event, Element[] arr) { + this.event = event; + this.arr = arr; + } + + /** Registers a runnable to be performed on associated {@link OnEvent} + * and {@link Element}. + * + * @see OnEvent#of + */ + public void perform(Runnable r) { + for (Element e : arr) { + e.on(event, r); + } + } +} diff -r 6506c5925775 -r 95753ad65192 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnEvent.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnEvent.java Mon Jan 21 15:57:01 2013 +0100 @@ -0,0 +1,95 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.apidesign.bck2brwsr.htmlpage.api; + +/** Type of events to use in connection with {@link On} annotation. + * + * @author Jaroslav Tulach + */ +public enum OnEvent { + ABORT("onabort"), + BLUR("onblur"), + CAN_PLAY("oncanplay"), + CAN_PLAY_THROUGH("oncanplaythrough"), + CLICK("onclick"), + CONTEXT_MENU("oncontextmenu"), + DBL_CLICK("ondblclick"), + DRAG("ondrag"), + DRAG_END("ondragend"), + DRAG_ENTER("ondragenter"), + DRAG_LEAVE("ondragleave"), + DRAG_OVER("ondragover"), + DRAG_START("ondragstart"), + DROP("ondrop"), + DURATION_CHANGE("ondurationchange"), + EMPTIED("onemptied"), + ENDED("onended"), + ERROR("onerror"), + FOCUS("onfocus"), + FORM_CHANGE("onformchange"), + FORM_INPUT("onforminput"), + INPUT("oninput"), + INVALID("oninvalid"), + KEY_DOWN("onkeydown"), + KEY_PRESS("onkeypress"), + KEY_UP("onkeyup"), + LOAD("onload"), + LOADED_DATA("onloadeddata"), + LOADED_META_DATA("onloadedmetadata"), + LOAD_START("onloadstart"), + MOUSE_DOWN("onmousedown"), + MOUSE_MOVE("onmousemove"), + MOUSE_OUT("onmouseout"), + MOUSE_OVER("onmouseover"), + MOUSE_UP("onmouseup"), + MOUSE_WHEEL("onmousewheel"), + PAUSE("onpause"), + PLAY("onplay"), + PLAYING("onplaying"), + PROGRESS("onprogress"), + RATE_CHANGE("onratechange"), + READY_STATE_CHANGE("onreadystatechange"), + SCROLL("onscroll"), + SEEKED("onseeked"), + SEEKING("onseeking"), + SELECT("onselect"), + SHOW("onshow"), + STALLED("onstalled"), + SUBMIT("onsubmit"), + SUSPEND("onsuspend"), + TIME_UPDATE("ontimeupdate"), + VOLUME_CHANGE("onvolumechange"), + WAITING("onwaiting"); + + final String id; + + private OnEvent(String id) { + this.id = id; + } + + /** What should happen when this even happen on one + * of associated elements. Continue by calling {@link OnController#perform(java.lang.Runnable)} + * method. + * + * @param elmnts one or more elements + * @return controller with perform method. + */ + public OnController of(Element... elmnts) { + return new OnController(this, elmnts); + } +} diff -r 6506c5925775 -r 95753ad65192 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Timer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Timer.java Mon Jan 21 15:57:01 2013 +0100 @@ -0,0 +1,59 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.apidesign.bck2brwsr.htmlpage.api; + +import java.io.Closeable; +import org.apidesign.bck2brwsr.core.JavaScriptBody; + +/** + * + * @author Jaroslav Tulach + */ +public class Timer implements Closeable { + private final Object t; + + private Timer(Object t) { + this.t = t; + } + + /** Creates a timer that invokes provided runnable on a fixed interval + * + * @param r the runnable to execute + * @param time milliseconds to invoke the timer periodically + */ + public static Timer create(Runnable r, int time) { + return new Timer(interval(r, time)); + } + + @JavaScriptBody(args = { "r", "time" }, body = + "return window.setInterval(function() { r.run__V(); }, time);" + ) + private static native Object interval(Runnable r, int time); + + @JavaScriptBody(args = { "self" }, body = + "window.clearInterval(self);" + ) + private static native void close(Object self); + + /** Cancels this timer. + */ + @Override + public void close() { + close(t); + } +} diff -r 6506c5925775 -r 95753ad65192 javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ModelTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ModelTest.java Mon Jan 21 15:57:01 2013 +0100 @@ -0,0 +1,34 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.apidesign.bck2brwsr.htmlpage; + +import org.apidesign.bck2brwsr.htmlpage.api.Page; +import static org.testng.Assert.*; +import org.testng.annotations.Test; + +/** + * + * @author Jaroslav Tulach + */ +@Page(xhtml = "Empty.html", className = "Model") +public class ModelTest { + @Test public void classGenerated() { + Class c = Model.class; + assertNotNull(c, "Class for empty page generated"); + } +} diff -r 6506c5925775 -r 95753ad65192 javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageController.java --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageController.java Tue Jan 15 11:39:15 2013 +0100 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageController.java Mon Jan 21 15:57:01 2013 +0100 @@ -17,7 +17,8 @@ */ package org.apidesign.bck2brwsr.htmlpage; -import org.apidesign.bck2brwsr.htmlpage.api.OnClick; +import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*; +import org.apidesign.bck2brwsr.htmlpage.api.On; import org.apidesign.bck2brwsr.htmlpage.api.Page; /** Trivial demo for the bck2brwsr project. First of all start @@ -42,12 +43,12 @@ */ @Page(xhtml="TestPage.html") public class PageController { - @OnClick(id="pg.button") + @On(event = CLICK, id="pg.button") static void updateTitle() { TestPage.PG_TITLE.setText("You want this window to be named " + TestPage.PG_TEXT.getValue()); } - @OnClick(id={ "pg.title", "pg.text" }) + @On(event = CLICK, id={ "pg.title", "pg.text" }) static void click(String id) { if (!id.equals("pg.title")) { throw new IllegalStateException(); diff -r 6506c5925775 -r 95753ad65192 javaquery/api/src/test/resources/org/apidesign/bck2brwsr/htmlpage/Empty.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/test/resources/org/apidesign/bck2brwsr/htmlpage/Empty.html Mon Jan 21 15:57:01 2013 +0100 @@ -0,0 +1,29 @@ + + + + + + Empty + + + Empty page + + diff -r 6506c5925775 -r 95753ad65192 javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/mavenhtml/App.java --- a/javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/mavenhtml/App.java Tue Jan 15 11:39:15 2013 +0100 +++ b/javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/mavenhtml/App.java Mon Jan 21 15:57:01 2013 +0100 @@ -17,7 +17,8 @@ */ package org.apidesign.bck2brwsr.mavenhtml; -import org.apidesign.bck2brwsr.htmlpage.api.OnClick; +import org.apidesign.bck2brwsr.htmlpage.api.On; +import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*; import org.apidesign.bck2brwsr.htmlpage.api.Page; /** HTML5 & Java demo showing the power of @@ -31,21 +32,21 @@ private static double memory; private static String operation; - @OnClick(id="clear") + @On(event = CLICK, id="clear") static void clear() { memory = 0; operation = null; Calculator.DISPLAY.setValue("0"); } - @OnClick(id= { "plus", "minus", "mul", "div" }) + @On(event = CLICK, id= { "plus", "minus", "mul", "div" }) static void applyOp(String op) { memory = getValue(); operation = op; Calculator.DISPLAY.setValue("0"); } - @OnClick(id="result") + @On(event = CLICK, id="result") static void computeTheValue() { switch (operation) { case "plus": setValue(memory + getValue()); break; @@ -56,7 +57,7 @@ } } - @OnClick(id={"n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7", "n8", "n9"}) + @On(event = CLICK, id={"n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7", "n8", "n9"}) static void addDigit(String digit) { digit = digit.substring(1); String v = Calculator.DISPLAY.getValue(); diff -r 6506c5925775 -r 95753ad65192 javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/mavenhtml/App.java --- a/javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/mavenhtml/App.java Tue Jan 15 11:39:15 2013 +0100 +++ b/javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/mavenhtml/App.java Mon Jan 21 15:57:01 2013 +0100 @@ -17,7 +17,8 @@ */ package org.apidesign.bck2brwsr.mavenhtml; -import org.apidesign.bck2brwsr.htmlpage.api.OnClick; +import org.apidesign.bck2brwsr.htmlpage.api.On; +import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*; import org.apidesign.bck2brwsr.htmlpage.api.Page; /** HTML5 & Java demo showing the power of @@ -31,21 +32,21 @@ private static double memory; private static String operation; - @OnClick(id="clear") + @On(event = CLICK, id="clear") static void clear() { memory = 0; operation = null; Calculator.DISPLAY.setValue("0"); } - @OnClick(id= { "plus", "minus", "mul", "div" }) + @On(event = CLICK, id= { "plus", "minus", "mul", "div" }) static void applyOp(String op) { memory = getValue(); operation = op; Calculator.DISPLAY.setValue("0"); } - @OnClick(id="result") + @On(event = CLICK, id="result") static void computeTheValue() { switch (operation) { case "plus": setValue(memory + getValue()); break; @@ -56,7 +57,7 @@ } } - @OnClick(id={"n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7", "n8", "n9"}) + @On(event = CLICK, id={"n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7", "n8", "n9"}) static void addDigit(String digit) { digit = digit.substring(1); String v = Calculator.DISPLAY.getValue(); diff -r 6506c5925775 -r 95753ad65192 launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java --- a/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java Tue Jan 15 11:39:15 2013 +0100 +++ b/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java Mon Jan 21 15:57:01 2013 +0100 @@ -237,20 +237,14 @@ URI uri = new URI("http://localhost:" + port + page); LOG.log(Level.INFO, "Showing {0}", uri); -// try { -// Desktop.getDesktop().browse(uri); -// return null; -// } catch (UnsupportedOperationException ex) - { -// File dir = File.createTempFile("chrome", ".dir"); -// dir.delete(); -// dir.mkdirs(); -// String[] cmd = { -// "google-chrome", "--user-data-dir=" + dir, "--app=" + uri.toString() -// }; -// LOG.log(Level.INFO, "Launching {0}", Arrays.toString(cmd)); -// final Process process = Runtime.getRuntime().exec(cmd); -// return new Object[] { process, dir }; + if (cmd == null) { + try { + java.awt.Desktop.getDesktop().browse(uri); + LOG.log(Level.INFO, "Desktop.browse successfully finished"); + return null; + } catch (UnsupportedOperationException ex) { + LOG.log(Level.INFO, "Desktop.browse not supported", ex); + } } { String cmdName = cmd == null ? "xdg-open" : cmd; @@ -365,8 +359,13 @@ r = r.substring(1); } } - if (r.endsWith(".html") || r.endsWith(".xhtml")) { + if (r.endsWith(".html")) { response.setContentType("text/html"); + LOG.info("Content type text/html"); + } + if (r.endsWith(".xhtml")) { + response.setContentType("application/xhtml+xml"); + LOG.info("Content type application/xhtml+xml"); } OutputStream os = response.getOutputStream(); try (InputStream is = res.get(r)) { diff -r 6506c5925775 -r 95753ad65192 mojo/src/main/resources/archetype-resources/src/main/java/App.java --- a/mojo/src/main/resources/archetype-resources/src/main/java/App.java Tue Jan 15 11:39:15 2013 +0100 +++ b/mojo/src/main/resources/archetype-resources/src/main/java/App.java Mon Jan 21 15:57:01 2013 +0100 @@ -1,6 +1,7 @@ package ${package}; -import org.apidesign.bck2brwsr.htmlpage.api.OnClick; +import org.apidesign.bck2brwsr.htmlpage.api.*; +import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*; import org.apidesign.bck2brwsr.htmlpage.api.Page; /** Edit the index.xhtml file. Use 'id' to name certain HTML elements. @@ -8,8 +9,9 @@ */ @Page(xhtml="index.xhtml", className="Index") public class App { - @OnClick(id="hello") + @On(event = CLICK, id="hello") static void hello() { Index.HELLO.setDisabled(true); + Element.alert("Hello World!"); } } diff -r 6506c5925775 -r 95753ad65192 vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Tue Jan 15 11:39:15 2013 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Mon Jan 21 15:57:01 2013 +0100 @@ -19,6 +19,7 @@ import java.io.IOException; import java.io.InputStream; +import org.apidesign.bck2brwsr.core.JavaScriptBody; import org.apidesign.javap.AnnotationParser; import org.apidesign.javap.ClassData; import org.apidesign.javap.FieldData; @@ -51,7 +52,7 @@ /* * @param resourcePath name of resources to read */ - protected abstract void requireScript(String resourcePath); + protected abstract void requireScript(String resourcePath) throws IOException; /** Allows subclasses to redefine what field a function representing a * class gets assigned. By default it returns the suggested name followed @@ -249,7 +250,7 @@ new LocalsMapper(stackMapIterator.getArguments()); out.append(prefix).append(name).append(" = function("); - lmapper.outputArguments(out); + lmapper.outputArguments(out, m.isStatic()); out.append(") {").append("\n"); final byte[] byteCodes = m.getCode(); @@ -263,32 +264,8 @@ final StackMapper smapper = new StackMapper(); - final int maxLocals = m.getMaxLocals(); - if (maxLocals > 0) { - // TODO: generate only used local variables - for (int j = 0; j <= VarType.LAST; ++j) { - out.append("\n var ").append(Variable.getLocalVariable(j, 0)); - for (int i = 1; i < maxLocals; ++i) { - out.append(", "); - out.append(Variable.getLocalVariable(j, i)); - } - out.append(';'); - } - } - - // maxStack includes two stack positions for every pushed long / double - // so this might generate more stack variables than we need - final int maxStack = m.getMaxStack(); - if (maxStack > 0) { - // TODO: generate only used stack variables - for (int j = 0; j <= VarType.LAST; ++j) { - out.append("\n var ").append(Variable.getStackVariable(j, 0)); - for (int i = 1; i < maxStack; ++i) { - out.append(", "); - out.append(Variable.getStackVariable(j, i)); - } - out.append(';'); - } + if (!m.isStatic()) { + out.append(" var ").append(" lcA0 = this;\n"); } int lastStackFrame = -1; @@ -321,174 +298,184 @@ final int c = readByte(byteCodes, i); switch (c) { case opc_aload_0: - emit(out, "@1 = @2;", smapper.pushA(), lmapper.getA(0)); + emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(0)); break; case opc_iload_0: - emit(out, "@1 = @2;", smapper.pushI(), lmapper.getI(0)); + emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(0)); break; case opc_lload_0: - emit(out, "@1 = @2;", smapper.pushL(), lmapper.getL(0)); + emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(0)); break; case opc_fload_0: - emit(out, "@1 = @2;", smapper.pushF(), lmapper.getF(0)); + emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(0)); break; case opc_dload_0: - emit(out, "@1 = @2;", smapper.pushD(), lmapper.getD(0)); + emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(0)); break; case opc_aload_1: - emit(out, "@1 = @2;", smapper.pushA(), lmapper.getA(1)); + emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(1)); break; case opc_iload_1: - emit(out, "@1 = @2;", smapper.pushI(), lmapper.getI(1)); + emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(1)); break; case opc_lload_1: - emit(out, "@1 = @2;", smapper.pushL(), lmapper.getL(1)); + emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(1)); break; case opc_fload_1: - emit(out, "@1 = @2;", smapper.pushF(), lmapper.getF(1)); + emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(1)); break; case opc_dload_1: - emit(out, "@1 = @2;", smapper.pushD(), lmapper.getD(1)); + emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(1)); break; case opc_aload_2: - emit(out, "@1 = @2;", smapper.pushA(), lmapper.getA(2)); + emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(2)); break; case opc_iload_2: - emit(out, "@1 = @2;", smapper.pushI(), lmapper.getI(2)); + emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(2)); break; case opc_lload_2: - emit(out, "@1 = @2;", smapper.pushL(), lmapper.getL(2)); + emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(2)); break; case opc_fload_2: - emit(out, "@1 = @2;", smapper.pushF(), lmapper.getF(2)); + emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(2)); break; case opc_dload_2: - emit(out, "@1 = @2;", smapper.pushD(), lmapper.getD(2)); + emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(2)); break; case opc_aload_3: - emit(out, "@1 = @2;", smapper.pushA(), lmapper.getA(3)); + emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(3)); break; case opc_iload_3: - emit(out, "@1 = @2;", smapper.pushI(), lmapper.getI(3)); + emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(3)); break; case opc_lload_3: - emit(out, "@1 = @2;", smapper.pushL(), lmapper.getL(3)); + emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(3)); break; case opc_fload_3: - emit(out, "@1 = @2;", smapper.pushF(), lmapper.getF(3)); + emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(3)); break; case opc_dload_3: - emit(out, "@1 = @2;", smapper.pushD(), lmapper.getD(3)); + emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(3)); break; case opc_iload: { final int indx = readByte(byteCodes, ++i); - emit(out, "@1 = @2;", smapper.pushI(), lmapper.getI(indx)); + emit(out, "var @1 = @2;", + smapper.pushI(), lmapper.getI(indx)); break; } case opc_lload: { final int indx = readByte(byteCodes, ++i); - emit(out, "@1 = @2;", smapper.pushL(), lmapper.getL(indx)); + emit(out, "var @1 = @2;", + smapper.pushL(), lmapper.getL(indx)); break; } case opc_fload: { final int indx = readByte(byteCodes, ++i); - emit(out, "@1 = @2;", smapper.pushF(), lmapper.getF(indx)); + emit(out, "var @1 = @2;", + smapper.pushF(), lmapper.getF(indx)); break; } case opc_dload: { final int indx = readByte(byteCodes, ++i); - emit(out, "@1 = @2;", smapper.pushD(), lmapper.getD(indx)); + emit(out, "var @1 = @2;", + smapper.pushD(), lmapper.getD(indx)); break; } case opc_aload: { final int indx = readByte(byteCodes, ++i); - emit(out, "@1 = @2;", smapper.pushA(), lmapper.getA(indx)); + emit(out, "var @1 = @2;", + smapper.pushA(), lmapper.getA(indx)); break; } case opc_istore: { final int indx = readByte(byteCodes, ++i); - emit(out, "@1 = @2;", lmapper.setI(indx), smapper.popI()); + emit(out, "var @1 = @2;", + lmapper.setI(indx), smapper.popI()); break; } case opc_lstore: { final int indx = readByte(byteCodes, ++i); - emit(out, "@1 = @2;", lmapper.setL(indx), smapper.popL()); + emit(out, "var @1 = @2;", + lmapper.setL(indx), smapper.popL()); break; } case opc_fstore: { final int indx = readByte(byteCodes, ++i); - emit(out, "@1 = @2;", lmapper.setF(indx), smapper.popF()); + emit(out, "var @1 = @2;", + lmapper.setF(indx), smapper.popF()); break; } case opc_dstore: { final int indx = readByte(byteCodes, ++i); - emit(out, "@1 = @2;", lmapper.setD(indx), smapper.popD()); + emit(out, "var @1 = @2;", + lmapper.setD(indx), smapper.popD()); break; } case opc_astore: { final int indx = readByte(byteCodes, ++i); - emit(out, "@1 = @2;", lmapper.setA(indx), smapper.popA()); + emit(out, "var @1 = @2;", + lmapper.setA(indx), smapper.popA()); break; } case opc_astore_0: - emit(out, "@1 = @2;", lmapper.setA(0), smapper.popA()); + emit(out, "var @1 = @2;", lmapper.setA(0), smapper.popA()); break; case opc_istore_0: - emit(out, "@1 = @2;", lmapper.setI(0), smapper.popI()); + emit(out, "var @1 = @2;", lmapper.setI(0), smapper.popI()); break; case opc_lstore_0: - emit(out, "@1 = @2;", lmapper.setL(0), smapper.popL()); + emit(out, "var @1 = @2;", lmapper.setL(0), smapper.popL()); break; case opc_fstore_0: - emit(out, "@1 = @2;", lmapper.setF(0), smapper.popF()); + emit(out, "var @1 = @2;", lmapper.setF(0), smapper.popF()); break; case opc_dstore_0: - emit(out, "@1 = @2;", lmapper.setD(0), smapper.popD()); + emit(out, "var @1 = @2;", lmapper.setD(0), smapper.popD()); break; case opc_astore_1: - emit(out, "@1 = @2;", lmapper.setA(1), smapper.popA()); + emit(out, "var @1 = @2;", lmapper.setA(1), smapper.popA()); break; case opc_istore_1: - emit(out, "@1 = @2;", lmapper.setI(1), smapper.popI()); + emit(out, "var @1 = @2;", lmapper.setI(1), smapper.popI()); break; case opc_lstore_1: - emit(out, "@1 = @2;", lmapper.setL(1), smapper.popL()); + emit(out, "var @1 = @2;", lmapper.setL(1), smapper.popL()); break; case opc_fstore_1: - emit(out, "@1 = @2;", lmapper.setF(1), smapper.popF()); + emit(out, "var @1 = @2;", lmapper.setF(1), smapper.popF()); break; case opc_dstore_1: - emit(out, "@1 = @2;", lmapper.setD(1), smapper.popD()); + emit(out, "var @1 = @2;", lmapper.setD(1), smapper.popD()); break; case opc_astore_2: - emit(out, "@1 = @2;", lmapper.setA(2), smapper.popA()); + emit(out, "var @1 = @2;", lmapper.setA(2), smapper.popA()); break; case opc_istore_2: - emit(out, "@1 = @2;", lmapper.setI(2), smapper.popI()); + emit(out, "var @1 = @2;", lmapper.setI(2), smapper.popI()); break; case opc_lstore_2: - emit(out, "@1 = @2;", lmapper.setL(2), smapper.popL()); + emit(out, "var @1 = @2;", lmapper.setL(2), smapper.popL()); break; case opc_fstore_2: - emit(out, "@1 = @2;", lmapper.setF(2), smapper.popF()); + emit(out, "var @1 = @2;", lmapper.setF(2), smapper.popF()); break; case opc_dstore_2: - emit(out, "@1 = @2;", lmapper.setD(2), smapper.popD()); + emit(out, "var @1 = @2;", lmapper.setD(2), smapper.popD()); break; case opc_astore_3: - emit(out, "@1 = @2;", lmapper.setA(3), smapper.popA()); + emit(out, "var @1 = @2;", lmapper.setA(3), smapper.popA()); break; case opc_istore_3: - emit(out, "@1 = @2;", lmapper.setI(3), smapper.popI()); + emit(out, "var @1 = @2;", lmapper.setI(3), smapper.popI()); break; case opc_lstore_3: - emit(out, "@1 = @2;", lmapper.setL(3), smapper.popL()); + emit(out, "var @1 = @2;", lmapper.setL(3), smapper.popL()); break; case opc_fstore_3: - emit(out, "@1 = @2;", lmapper.setF(3), smapper.popF()); + emit(out, "var @1 = @2;", lmapper.setF(3), smapper.popF()); break; case opc_dstore_3: - emit(out, "@1 = @2;", lmapper.setD(3), smapper.popD()); + emit(out, "var @1 = @2;", lmapper.setD(3), smapper.popD()); break; case opc_iadd: emit(out, "@1 = @1.add32(@2);", smapper.getI(1), smapper.popI()); @@ -631,105 +618,105 @@ emit(out, "return @1;", smapper.popA()); break; case opc_i2l: - emit(out, "@2 = @1;", smapper.popI(), smapper.pushL()); + emit(out, "var @2 = @1;", smapper.popI(), smapper.pushL()); break; case opc_i2f: - emit(out, "@2 = @1;", smapper.popI(), smapper.pushF()); + emit(out, "var @2 = @1;", smapper.popI(), smapper.pushF()); break; case opc_i2d: - emit(out, "@2 = @1;", smapper.popI(), smapper.pushD()); + emit(out, "var @2 = @1;", smapper.popI(), smapper.pushD()); break; case opc_l2i: - emit(out, "@2 = @1;", smapper.popL(), smapper.pushI()); + emit(out, "var @2 = @1;", smapper.popL(), smapper.pushI()); break; // max int check? case opc_l2f: - emit(out, "@2 = @1;", smapper.popL(), smapper.pushF()); + emit(out, "var @2 = @1;", smapper.popL(), smapper.pushF()); break; case opc_l2d: - emit(out, "@2 = @1;", smapper.popL(), smapper.pushD()); + emit(out, "var @2 = @1;", smapper.popL(), smapper.pushD()); break; case opc_f2d: - emit(out, "@2 = @1;", smapper.popF(), smapper.pushD()); + emit(out, "var @2 = @1;", smapper.popF(), smapper.pushD()); break; case opc_d2f: - emit(out, "@2 = @1;", smapper.popD(), smapper.pushF()); + emit(out, "var @2 = @1;", smapper.popD(), smapper.pushF()); break; case opc_f2i: - emit(out, "@2 = Math.floor(@1);", + emit(out, "var @2 = Math.floor(@1);", smapper.popF(), smapper.pushI()); break; case opc_f2l: - emit(out, "@2 = Math.floor(@1);", + emit(out, "var @2 = Math.floor(@1);", smapper.popF(), smapper.pushL()); break; case opc_d2i: - emit(out, "@2 = Math.floor(@1);", + emit(out, "var @2 = Math.floor(@1);", smapper.popD(), smapper.pushI()); break; case opc_d2l: - emit(out, "@2 = Math.floor(@1);", + emit(out, "var @2 = Math.floor(@1);", smapper.popD(), smapper.pushL()); break; case opc_i2b: - emit(out, "@1 = @1.toInt8();", smapper.getI(0)); + emit(out, "var @1 = @1.toInt8();", smapper.getI(0)); break; case opc_i2c: out.append("{ /* number conversion */ }"); break; case opc_i2s: - emit(out, "@1 = @1.toInt16();", smapper.getI(0)); + emit(out, "var @1 = @1.toInt16();", smapper.getI(0)); break; case opc_aconst_null: - emit(out, "@1 = null;", smapper.pushA()); + emit(out, "var @1 = null;", smapper.pushA()); break; case opc_iconst_m1: - emit(out, "@1 = -1;", smapper.pushI()); + emit(out, "var @1 = -1;", smapper.pushI()); break; case opc_iconst_0: - emit(out, "@1 = 0;", smapper.pushI()); + emit(out, "var @1 = 0;", smapper.pushI()); break; case opc_dconst_0: - emit(out, "@1 = 0;", smapper.pushD()); + emit(out, "var @1 = 0;", smapper.pushD()); break; case opc_lconst_0: - emit(out, "@1 = 0;", smapper.pushL()); + emit(out, "var @1 = 0;", smapper.pushL()); break; case opc_fconst_0: - emit(out, "@1 = 0;", smapper.pushF()); + emit(out, "var @1 = 0;", smapper.pushF()); break; case opc_iconst_1: - emit(out, "@1 = 1;", smapper.pushI()); + emit(out, "var @1 = 1;", smapper.pushI()); break; case opc_lconst_1: - emit(out, "@1 = 1;", smapper.pushL()); + emit(out, "var @1 = 1;", smapper.pushL()); break; case opc_fconst_1: - emit(out, "@1 = 1;", smapper.pushF()); + emit(out, "var @1 = 1;", smapper.pushF()); break; case opc_dconst_1: - emit(out, "@1 = 1;", smapper.pushD()); + emit(out, "var @1 = 1;", smapper.pushD()); break; case opc_iconst_2: - emit(out, "@1 = 2;", smapper.pushI()); + emit(out, "var @1 = 2;", smapper.pushI()); break; case opc_fconst_2: - emit(out, "@1 = 2;", smapper.pushF()); + emit(out, "var @1 = 2;", smapper.pushF()); break; case opc_iconst_3: - emit(out, "@1 = 3;", smapper.pushI()); + emit(out, "var @1 = 3;", smapper.pushI()); break; case opc_iconst_4: - emit(out, "@1 = 4;", smapper.pushI()); + emit(out, "var @1 = 4;", smapper.pushI()); break; case opc_iconst_5: - emit(out, "@1 = 5;", smapper.pushI()); + emit(out, "var @1 = 5;", smapper.pushI()); break; case opc_ldc: { int indx = readByte(byteCodes, ++i); String v = encodeConstant(indx); int type = VarType.fromConstantType(jc.getTag(indx)); - emit(out, "@1 = @2;", smapper.pushT(type), v); + emit(out, "var @1 = @2;", smapper.pushT(type), v); break; } case opc_ldc_w: @@ -738,21 +725,21 @@ i += 2; String v = encodeConstant(indx); int type = VarType.fromConstantType(jc.getTag(indx)); - emit(out, "@1 = @2;", smapper.pushT(type), v); + emit(out, "var @1 = @2;", smapper.pushT(type), v); break; } case opc_lcmp: - emit(out, "@3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", + emit(out, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", smapper.popL(), smapper.popL(), smapper.pushI()); break; case opc_fcmpl: case opc_fcmpg: - emit(out, "@3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", + emit(out, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", smapper.popF(), smapper.popF(), smapper.pushI()); break; case opc_dcmpl: case opc_dcmpg: - emit(out, "@3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", + emit(out, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", smapper.popD(), smapper.popD(), smapper.pushI()); break; case opc_if_acmpeq: @@ -902,91 +889,108 @@ case opc_new: { int indx = readIntArg(byteCodes, i); String ci = jc.getClassName(indx); - emit(out, "@1 = new @2;", + emit(out, "var @1 = new @2;", smapper.pushA(), accessClass(ci.replace('/', '_'))); addReference(ci); i += 2; break; } case opc_newarray: - ++i; // skip type of array - emit(out, "@2 = new Array(@1).fillWith(0);", - smapper.popI(), smapper.pushA()); + int atype = readByte(byteCodes, ++i); + String jvmType; + switch (atype) { + case 4: jvmType = "[Z"; break; + case 5: jvmType = "[C"; break; + case 6: jvmType = "[F"; break; + case 7: jvmType = "[D"; break; + case 8: jvmType = "[B"; break; + case 9: jvmType = "[S"; break; + case 10: jvmType = "[I"; break; + case 11: jvmType = "[J"; break; + default: throw new IllegalStateException("Array type: " + atype); + } + emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(true, '@3', @1);", + smapper.popI(), smapper.pushA(), jvmType); break; - case opc_anewarray: - i += 2; // skip type of array - emit(out, "@2 = new Array(@1).fillWith(null);", - smapper.popI(), smapper.pushA()); + case opc_anewarray: { + int type = readIntArg(byteCodes, i); + i += 2; + String typeName = jc.getClassName(type); + if (typeName.startsWith("[")) { + typeName = "[" + typeName; + } else { + typeName = "[L" + typeName + ";"; + } + emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(false, '@3', @1);", + smapper.popI(), smapper.pushA(), typeName); break; + } case opc_multianewarray: { + int type = readIntArg(byteCodes, i); i += 2; + String typeName = jc.getClassName(type); int dim = readByte(byteCodes, ++i); - out.append("{ var a0 = new Array(").append(smapper.popI()) - .append(").fillWith(null);"); - for (int d = 1; d < dim; d++) { - out.append("\n var l" + d).append(" = ") - .append(smapper.popI()).append(';'); - out.append("\n for (var i" + d).append (" = 0; i" + d). - append(" < a" + (d - 1)). - append(".length; i" + d).append("++) {"); - out.append("\n var a" + d). - append (" = new Array(l" + d).append(").fillWith(null);"); - out.append("\n a" + (d - 1)).append("[i" + d).append("] = a" + d). - append(";"); + StringBuilder dims = new StringBuilder(); + dims.append('['); + for (int d = 0; d < dim; d++) { + if (d != 0) { + dims.append(","); + } + dims.append(smapper.popI()); } - for (int d = 1; d < dim; d++) { - out.append("\n }"); - } - out.append("\n").append(smapper.pushA()).append(" = a0; }"); + dims.append(']'); + emit(out, "var @2 = Array.prototype.multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3II('@3', @1, 0);", + dims.toString(), smapper.pushA(), typeName); break; } case opc_arraylength: - emit(out, "@2 = @1.length;", smapper.popA(), smapper.pushI()); + emit(out, "var @2 = @1.length;", + smapper.popA(), smapper.pushI()); break; case opc_lastore: - emit(out, "@3[@2] = @1;", + emit(out, "@3.at(@2, @1);", smapper.popL(), smapper.popI(), smapper.popA()); break; case opc_fastore: - emit(out, "@3[@2] = @1;", + emit(out, "@3.at(@2, @1);", smapper.popF(), smapper.popI(), smapper.popA()); break; case opc_dastore: - emit(out, "@3[@2] = @1;", + emit(out, "@3.at(@2, @1);", smapper.popD(), smapper.popI(), smapper.popA()); break; case opc_aastore: - emit(out, "@3[@2] = @1;", + emit(out, "@3.at(@2, @1);", smapper.popA(), smapper.popI(), smapper.popA()); break; case opc_iastore: case opc_bastore: case opc_castore: case opc_sastore: - emit(out, "@3[@2] = @1;", + emit(out, "@3.at(@2, @1);", smapper.popI(), smapper.popI(), smapper.popA()); break; case opc_laload: - emit(out, "@3 = @2[@1];", + emit(out, "var @3 = @2.at(@1);", smapper.popI(), smapper.popA(), smapper.pushL()); break; case opc_faload: - emit(out, "@3 = @2[@1];", + emit(out, "var @3 = @2.at(@1);", smapper.popI(), smapper.popA(), smapper.pushF()); break; case opc_daload: - emit(out, "@3 = @2[@1];", + emit(out, "var @3 = @2.at(@1);", smapper.popI(), smapper.popA(), smapper.pushD()); break; case opc_aaload: - emit(out, "@3 = @2[@1];", + emit(out, "var @3 = @2.at(@1);", smapper.popI(), smapper.popA(), smapper.pushA()); break; case opc_iaload: case opc_baload: case opc_caload: case opc_saload: - emit(out, "@3 = @2[@1];", + emit(out, "var @3 = @2.at(@1);", smapper.popI(), smapper.popA(), smapper.pushI()); break; case opc_pop: @@ -996,17 +1000,18 @@ break; case opc_dup: { final Variable v = smapper.get(0); - emit(out, "@1 = @2;", smapper.pushT(v.getType()), v); + emit(out, "var @1 = @2;", smapper.pushT(v.getType()), v); break; } case opc_dup2: { if (smapper.get(0).isCategory2()) { final Variable v = smapper.get(0); - emit(out, "@1 = @2;", smapper.pushT(v.getType()), v); + emit(out, "var @1 = @2;", + smapper.pushT(v.getType()), v); } else { final Variable v1 = smapper.get(0); final Variable v2 = smapper.get(1); - emit(out, "{ @1 = @2; @3 = @4; }", + emit(out, "var @1 = @2, @3 = @4;", smapper.pushT(v2.getType()), v2, smapper.pushT(v1.getType()), v1); } @@ -1019,7 +1024,7 @@ final Variable vo2 = smapper.pushT(vi2.getType()); final Variable vo1 = smapper.pushT(vi1.getType()); - emit(out, "{ @1 = @2; @3 = @4; @5 = @6; }", + emit(out, "var @1 = @2, @3 = @4, @5 = @6;", vo1, vi1, vo2, vi2, vo3, vo1); break; } @@ -1031,7 +1036,7 @@ final Variable vo2 = smapper.pushT(vi2.getType()); final Variable vo1 = smapper.pushT(vi1.getType()); - emit(out, "{ @1 = @2; @3 = @4; @5 = @6; }", + emit(out, "var @1 = @2, @3 = @4, @5 = @6;", vo1, vi1, vo2, vi2, vo3, vo1); } else { final Variable vi1 = smapper.pop(); @@ -1042,17 +1047,17 @@ final Variable vo2 = smapper.pushT(vi2.getType()); final Variable vo1 = smapper.pushT(vi1.getType()); - emit(out, "{ @1 = @2; @3 = @4; @5 = @6; @7 = @8; }", + emit(out, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;", vo1, vi1, vo2, vi2, vo3, vi3, vo4, vo1); } break; } case opc_bipush: - emit(out, "@1 = @2;", + emit(out, "var @1 = @2;", smapper.pushI(), Integer.toString(byteCodes[++i])); break; case opc_sipush: - emit(out, "@1 = @2;", + emit(out, "var @1 = @2;", smapper.pushI(), Integer.toString(readIntArg(byteCodes, i))); i += 2; @@ -1061,7 +1066,7 @@ int indx = readIntArg(byteCodes, i); String[] fi = jc.getFieldInfoName(indx); final int type = VarType.fromFieldType(fi[2].charAt(0)); - emit(out, "@2 = @1.fld_@3;", + emit(out, "var @2 = @1.fld_@3;", smapper.popA(), smapper.pushT(type), fi[1]); i += 2; break; @@ -1070,7 +1075,7 @@ int indx = readIntArg(byteCodes, i); String[] fi = jc.getFieldInfoName(indx); final int type = VarType.fromFieldType(fi[2].charAt(0)); - emit(out, "@1 = @2(false).constructor.@3;", + emit(out, "var @1 = @2(false).constructor.@3;", smapper.pushT(type), accessClass(fi[0].replace('/', '_')), fi[1]); i += 2; @@ -1113,7 +1118,7 @@ case opc_instanceof: { int indx = readIntArg(byteCodes, i); final String type = jc.getClassName(indx); - emit(out, "@2 = @1.$instOf_@3 ? 1 : 0;", + emit(out, "var @2 = @1.$instOf_@3 ? 1 : 0;", smapper.popA(), smapper.pushI(), type.replace('/', '_')); i += 2; @@ -1123,7 +1128,7 @@ final Variable v = smapper.popA(); smapper.clear(); - emit(out, "{ @1 = @2; throw @2; }", + emit(out, "{ var @1 = @2; throw @2; }", smapper.pushA(), v); break; } @@ -1323,7 +1328,8 @@ } if (returnType[0] != 'V') { - out.append(mapper.pushT(VarType.fromFieldType(returnType[0]))) + out.append("var ") + .append(mapper.pushT(VarType.fromFieldType(returnType[0]))) .append(" = "); } @@ -1334,7 +1340,11 @@ out.append("constructor."); } out.append(mn); - out.append('('); + if (isStatic) { + out.append('('); + } else { + out.append(".call("); + } if (numArguments > 0) { out.append(vars[0]); for (int j = 1; j < numArguments; ++j) { @@ -1363,17 +1373,19 @@ } if (returnType[0] != 'V') { - out.append(mapper.pushT(VarType.fromFieldType(returnType[0]))) + out.append("var ") + .append(mapper.pushT(VarType.fromFieldType(returnType[0]))) .append(" = "); } out.append(vars[0]).append('.'); out.append(mn); out.append('('); - out.append(vars[0]); + String sep = ""; for (int j = 1; j < numArguments; ++j) { - out.append(", "); + out.append(sep); out.append(vars[j]); + sep = ", "; } out.append(");"); i += 2; @@ -1447,15 +1459,8 @@ final String mn = findMethodName(m, cnt); out.append(prefix).append(mn); out.append(" = function("); - String space; - int index; - if (!isStatic) { - space = outputArg(out, p.args, 0); - index = 1; - } else { - space = ""; - index = 0; - } + String space = ""; + int index = 0; for (int i = 0; i < cnt.length(); i++) { out.append(space); space = outputArg(out, p.args, index); @@ -1601,15 +1606,15 @@ addReference(classInternalName); if ("java/lang/Throwable".equals(classInternalName)) { out.append("if (e.$instOf_java_lang_Throwable) {"); - out.append(" stA0 = e;"); + out.append(" var stA0 = e;"); out.append("} else {"); - out.append(" stA0 = vm.java_lang_Throwable(true);"); - out.append(" vm.java_lang_Throwable.cons__VLjava_lang_String_2(stA0, e.toString());"); + out.append(" var stA0 = vm.java_lang_Throwable(true);"); + out.append(" vm.java_lang_Throwable.cons__VLjava_lang_String_2.call(stA0, e.toString());"); out.append("}"); out.append("gt=" + e.handler_pc + "; continue;"); } else { out.append("if (e.$instOf_" + classInternalName.replace('/', '_') + ") {"); - out.append("gt=" + e.handler_pc + "; stA0 = e; continue;"); + out.append("gt=" + e.handler_pc + "; var stA0 = e; continue;"); out.append("}\n"); } } else { @@ -1619,7 +1624,7 @@ if (finallyPC == -1) { out.append("throw e;"); } else { - out.append("gt=" + finallyPC + "; stA0 = e; continue;"); + out.append("gt=" + finallyPC + "; var stA0 = e; continue;"); } out.append("\n}"); } diff -r 6506c5925775 -r 95753ad65192 vm/src/main/java/org/apidesign/vm4brwsr/LocalsMapper.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/LocalsMapper.java Tue Jan 15 11:39:15 2013 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/LocalsMapper.java Mon Jan 21 15:57:01 2013 +0100 @@ -33,13 +33,14 @@ localTypeRecords = new TypeArray(initTypeRecords); } - public void outputArguments(final Appendable out) throws IOException { + public void outputArguments(final Appendable out, boolean isStatic) throws IOException { final int argRecordCount = argTypeRecords.getSize(); - if (argRecordCount > 0) { - Variable variable = getVariable(argTypeRecords, 0); + int first = isStatic ? 0 : 1; + if (argRecordCount > first) { + Variable variable = getVariable(argTypeRecords, first); out.append(variable); - int i = variable.isCategory2() ? 2 : 1; + int i = first + (variable.isCategory2() ? 2 : 1); while (i < argRecordCount) { variable = getVariable(argTypeRecords, i); out.append(", "); diff -r 6506c5925775 -r 95753ad65192 vm/src/main/java/org/apidesign/vm4brwsr/VM.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/VM.java Tue Jan 15 11:39:15 2013 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/VM.java Mon Jan 21 15:57:01 2013 +0100 @@ -117,7 +117,7 @@ + " var loader = {};\n" + " loader.vm = vm;\n" + " loader.loadClass = function(name) {\n" - + " var attr = name.replace__Ljava_lang_String_2CC(name, '.','_');\n" + + " var attr = name.replace__Ljava_lang_String_2CC('.','_');\n" + " var fn = vm[attr];\n" + " if (fn) return fn(false);\n" + " if (!args[0]) throw 'bck2brwsr initialized without loader function, cannot load ' + name;\n" diff -r 6506c5925775 -r 95753ad65192 vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java Tue Jan 15 11:39:15 2013 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java Mon Jan 21 15:57:01 2013 +0100 @@ -19,6 +19,7 @@ import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; import org.apidesign.bck2brwsr.core.JavaScriptBody; /** @@ -112,17 +113,17 @@ this.lazy = vm; } - @JavaScriptBody(args = {"self", "n"}, + @JavaScriptBody(args = {"n"}, body = - "var cls = n.replace__Ljava_lang_String_2CC(n, '/','_').toString();" - + "\nvar dot = n.replace__Ljava_lang_String_2CC(n,'/','.').toString();" - + "\nvar lazy = self.fld_lazy;" + "var cls = n.replace__Ljava_lang_String_2CC('/','_').toString();" + + "\nvar dot = n.replace__Ljava_lang_String_2CC('/','.').toString();" + + "\nvar lazy = this.fld_lazy;" + "\nvar loader = lazy.fld_loader;" + "\nvar vm = loader.vm;" + "\nif (vm[cls]) return false;" + "\nvm[cls] = function() {" + "\n var instance = arguments.length == 0 || arguments[0] === true;" - + "\n return lazy.load__Ljava_lang_Object_2Ljava_lang_String_2Z(lazy, dot, instance);" + + "\n return lazy.load__Ljava_lang_Object_2Ljava_lang_String_2Z(dot, instance);" + "\n};" + "\nreturn true;") @Override @@ -131,7 +132,17 @@ } @Override - protected void requireScript(String resourcePath) { + protected void requireScript(String resourcePath) throws IOException { + InputStream is = getClass().getResourceAsStream(resourcePath); + StringBuilder sb = new StringBuilder(); + for (;;) { + int ch = is.read(); + if (ch == -1) { + break; + } + sb.append((char)ch); + } + applyCode(lazy.loader, null, sb.toString(), false); } @Override diff -r 6506c5925775 -r 95753ad65192 vm/src/test/java/org/apidesign/vm4brwsr/Array.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/Array.java Tue Jan 15 11:39:15 2013 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/Array.java Mon Jan 21 15:57:01 2013 +0100 @@ -51,6 +51,16 @@ return doubles[4][0]; } + static double[][] dbls = new double[1][2]; + public static double twoDoubles() { + return dbls[0][0] + dbls[0][0]; + } + + static int[][] tints = new int[1][2]; + public static int twoInts() { + return tints[0][0] + tints[0][0]; + } + private static final Array[] ARR = { new Array(), new Array(), new Array() }; private static Array[][] arr() { diff -r 6506c5925775 -r 95753ad65192 vm/src/test/java/org/apidesign/vm4brwsr/ArrayTest.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/ArrayTest.java Tue Jan 15 11:39:15 2013 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/ArrayTest.java Mon Jan 21 15:57:01 2013 +0100 @@ -53,6 +53,17 @@ Double.valueOf(105) ); } + + @Test public void twoDoubles() throws Exception { + assertExec("Elements are initialized", Array.class, "twoDoubles__D", + Double.valueOf(0) + ); + } + @Test public void twoInts() throws Exception { + assertExec("Elements are initialized", Array.class, "twoInts__I", + Double.valueOf(0) + ); + } @Test public void doesCopyArrayWork() throws Exception { assertExec("Returns 'a'", Array.class, "copyArray__C", Double.valueOf('a')); diff -r 6506c5925775 -r 95753ad65192 vm/src/test/java/org/apidesign/vm4brwsr/Instance.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/Instance.java Tue Jan 15 11:39:15 2013 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/Instance.java Mon Jan 21 15:57:01 2013 +0100 @@ -125,4 +125,11 @@ public static boolean iofObject() { return jsObj() instanceof Object; } + + public static int jscall() { + return jsgetbytes(new Instance()); + } + + @JavaScriptBody(args = { "instance" }, body = "return instance.getByte__B();") + private static native int jsgetbytes(Instance instance); } diff -r 6506c5925775 -r 95753ad65192 vm/src/test/java/org/apidesign/vm4brwsr/InstanceTest.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/InstanceTest.java Tue Jan 15 11:39:15 2013 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/InstanceTest.java Mon Jan 21 15:57:01 2013 +0100 @@ -131,6 +131,14 @@ Double.valueOf(1) ); } + + @Test public void jsCallingConvention() throws Exception { + assertExec( + "Pointer to 'this' is passed automatically (and not as a first argument)", + Instance.class, "jscall__I", + Double.valueOf(31) + ); + } protected String startCompilationWith() { return "org/apidesign/vm4brwsr/Instance"; diff -r 6506c5925775 -r 95753ad65192 vm/src/test/java/org/apidesign/vm4brwsr/Script.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/Script.java Mon Jan 21 15:57:01 2013 +0100 @@ -0,0 +1,31 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.apidesign.vm4brwsr; + +import org.apidesign.bck2brwsr.core.ExtraJavaScript; +import org.apidesign.bck2brwsr.core.JavaScriptBody; + +/** Test to verify external scripts are processed in lazy mode. + * + * @author Jaroslav Tulach + */ +@ExtraJavaScript(resource = "/org/apidesign/vm4brwsr/ko.js") +public class Script { + @JavaScriptBody(args = { }, body = "return ko !== null;") + public static native boolean checkNotNull(); +} diff -r 6506c5925775 -r 95753ad65192 vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java Tue Jan 15 11:39:15 2013 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java Mon Jan 21 15:57:01 2013 +0100 @@ -67,6 +67,12 @@ ); } + @Test public void loadClassWithAssociatedScript() throws Exception { + assertExec("ko is defined", "test", true, + Script.class.getName(), "checkNotNull__Z" + ); + } + private static void assertExec(String msg, String methodName, Object expRes, Object... args) throws Exception { Object ret = null; try { diff -r 6506c5925775 -r 95753ad65192 vm/src/test/resources/org/apidesign/vm4brwsr/ko.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/src/test/resources/org/apidesign/vm4brwsr/ko.js Mon Jan 21 15:57:01 2013 +0100 @@ -0,0 +1,20 @@ +/* + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +this.ko = {}; + + diff -r 6506c5925775 -r 95753ad65192 vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareByteArrayTest.java --- a/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareByteArrayTest.java Tue Jan 15 11:39:15 2013 +0100 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareByteArrayTest.java Mon Jan 21 15:57:01 2013 +0100 @@ -49,6 +49,36 @@ return sum; } + @Compare public String noOutOfBounds() { + return atIndex(1); + } + + @Compare public String outOfBounds() { + return atIndex(5); + } + + @Compare public String outOfBoundsMinus() { + return atIndex(-1); + } + + @Compare public String toOfBounds() { + return toIndex(5); + } + + @Compare public String toOfBoundsMinus() { + return toIndex(-1); + } + + private static final int[] arr = { 0, 1, 2 }; + public static String atIndex(int at) { + return "at@" + arr[at]; + } + public static String toIndex(int at) { + arr[at] = 10; + return "ok"; + } + + @Factory public static Object[] create() { return VMTest.create(CompareByteArrayTest.class); diff -r 6506c5925775 -r 95753ad65192 vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareHashTest.java --- a/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareHashTest.java Tue Jan 15 11:39:15 2013 +0100 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareHashTest.java Mon Jan 21 15:57:01 2013 +0100 @@ -35,6 +35,10 @@ return o.hashCode() - o.hashCode(); } + @Compare public int initializeInStatic() { + return StaticUse.NON_NULL.hashCode() - StaticUse.NON_NULL.hashCode(); + } + @Compare public int hashOfInt() { return Integer.valueOf(Integer.MAX_VALUE).hashCode(); } diff -r 6506c5925775 -r 95753ad65192 vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareStringsTest.java --- a/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareStringsTest.java Tue Jan 15 11:39:15 2013 +0100 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareStringsTest.java Mon Jan 21 15:57:01 2013 +0100 @@ -28,6 +28,24 @@ * @author Jaroslav Tulach */ public class CompareStringsTest { + @Compare public String firstChar() { + return "" + ("Hello".toCharArray()[0]); + } + + @Compare public String classCast() { + Object o = firstChar(); + return String.class.cast(o); + } + + @Compare public String classCastThrown() { + Object o = null; + return String.class.cast(o); + } + + @Compare public boolean equalToNull() { + return "Ahoj".equals(null); + } + @Compare public static Object compareURLs() throws MalformedURLException { return new URL("http://apidesign.org:8080/wiki/").toExternalForm().toString(); } diff -r 6506c5925775 -r 95753ad65192 vmtest/src/test/java/org/apidesign/bck2brwsr/tck/IntegerArithmeticTest.java --- a/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/IntegerArithmeticTest.java Tue Jan 15 11:39:15 2013 +0100 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/IntegerArithmeticTest.java Mon Jan 21 15:57:01 2013 +0100 @@ -93,21 +93,12 @@ @Compare public int sumTwoDimensions() { int[][] matrix = createMatrix(4, 3); - int sum = 0; - for (int i = 0; i < matrix.length; i++) { - for (int j = 0; j < matrix[i].length; j++) { - sum += matrix[i][j]; - } - } - return sum; + matrix[0][0] += 10; + return matrix[0][0]; } static int[][] createMatrix(int x, int y) { - int[][] m = new int[x][y]; - for (int i = 0; i < Math.min(x, y); i++) { - m[i][i] = i; - } - return m; + return new int[x][y]; } @Factory diff -r 6506c5925775 -r 95753ad65192 vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionArrayTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionArrayTest.java Mon Jan 21 15:57:01 2013 +0100 @@ -0,0 +1,135 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.apidesign.bck2brwsr.tck; + +import java.lang.reflect.Array; +import org.apidesign.bck2brwsr.vmtest.Compare; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class ReflectionArrayTest { + @Compare public int lengthOfStringArray() { + String[] arr = (String[]) Array.newInstance(String.class, 10); + return arr.length; + } + + @Compare public int reflectiveLengthOfStringArray() { + Object arr = Array.newInstance(String.class, 10); + return Array.getLength(arr); + } + + @Compare public int reflectiveLengthOneNonArray() { + Object arr = "non-array"; + return Array.getLength(arr); + } + + @Compare public String compTypeOfStringArray() { + String[] arr = (String[]) Array.newInstance(String.class, 10); + return arr.getClass().getComponentType().getName(); + } + + @Compare public Object negativeArrayExcp() { + return Array.newInstance(String.class, -5); + } + + @Compare public int lengthOfIntArray() { + int[] arr = (int[]) Array.newInstance(Integer.TYPE, 10); + return arr.length; + } + + @Compare public int reflectiveLengthOfIntArray() { + Object arr = Array.newInstance(Integer.TYPE, 10); + return Array.getLength(arr); + } + + @Compare public String compTypeOfIntArray() { + int[] arr = (int[]) Array.newInstance(int.class, 10); + return arr.getClass().getComponentType().getName(); + } + + @Compare public Object intNegativeArrayExcp() { + return Array.newInstance(int.class, -5); + } + + @Compare public Integer verifyAutobox() { + int[] arr = (int[]) Array.newInstance(int.class, 5); + return (Integer) Array.get(arr, 0); + } + @Compare public String verifyObjectArray() { + String[] arr = (String[]) Array.newInstance(String.class, 5); + Array.set(arr, 0, "Hello"); + return (String) Array.get(arr, 0); + } + @Compare public int verifyInt() { + int[] arr = (int[]) Array.newInstance(int.class, 5); + return Array.getInt(arr, 0); + } + @Compare public long verifyConvertToLong() { + int[] arr = (int[]) Array.newInstance(int.class, 5); + return Array.getLong(arr, 0); + } + + @Compare public Object verifySetIntToObject() { + try { + Object[] arr = (Object[]) Array.newInstance(Object.class, 5); + Array.setInt(arr, 0, 10); + return Array.get(arr, 0); + } catch (Exception exception) { + return exception.getClass().getName(); + } + } + @Compare public long verifySetShort() { + int[] arr = (int[]) Array.newInstance(int.class, 5); + Array.setShort(arr, 0, (short)10); + return Array.getLong(arr, 0); + } + @Compare public long verifyCantSetLong() { + int[] arr = (int[]) Array.newInstance(int.class, 5); + Array.setLong(arr, 0, 10); + return Array.getLong(arr, 0); + } + @Compare public float verifyLongToFloat() { + Object arr = Array.newInstance(float.class, 5); + Array.setLong(arr, 0, 10); + return Array.getFloat(arr, 0); + } + + @Compare public double verifyConvertToDouble() { + int[] arr = (int[]) Array.newInstance(int.class, 5); + return Array.getDouble(arr, 0); + } + + @Compare public int multiIntArray() { + int[][][] arr = (int[][][]) Array.newInstance(int.class, 3, 3, 3); + return arr[0][1][2] + 5 + arr[2][2][0]; + } + + @Compare public String multiIntArrayCompType() { + return Array.newInstance(int.class, 3, 3, 3).getClass().getName(); + } + + + @Factory + public static Object[] create() { + return VMTest.create(ReflectionArrayTest.class); + } +} diff -r 6506c5925775 -r 95753ad65192 vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java --- a/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java Tue Jan 15 11:39:15 2013 +0100 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java Mon Jan 21 15:57:01 2013 +0100 @@ -21,6 +21,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; import org.apidesign.bck2brwsr.core.JavaScriptBody; import org.apidesign.bck2brwsr.vmtest.Compare; import org.apidesign.bck2brwsr.vmtest.VMTest; @@ -90,6 +92,86 @@ return (Integer)plus.invoke(null, 2, 3); } + @Compare public String classGetNameForByte() { + return byte.class.getName(); + } + @Compare public String classGetNameForBaseObject() { + return newObject().getClass().getName(); + } + @Compare public String classGetNameForJavaObject() { + return new Object().getClass().getName(); + } + @Compare public String classGetNameForObjectArray() { + return (new Object[3]).getClass().getName(); + } + @Compare public String classGetNameForSimpleIntArray() { + return (new int[3]).getClass().getName(); + } + @Compare public boolean sameClassGetNameForSimpleCharArray() { + return (new char[3]).getClass() == (new char[34]).getClass(); + } + @Compare public String classGetNameForMultiIntArray() { + return (new int[3][4][5][6][7][8][9]).getClass().getName(); + } + @Compare public String classGetNameForMultiIntArrayInner() { + final int[][][][][][][] arr = new int[3][4][5][6][7][8][9]; + int[][][][][][] subarr = arr[0]; + int[][][][][] subsubarr = subarr[0]; + return subsubarr.getClass().getName(); + } + @Compare public String classGetNameForMultiStringArray() { + return (new String[3][4][5][6][7][8][9]).getClass().getName(); + } + + @Compare public String classForByte() throws Exception { + return Class.forName("[Z").getName(); + } + + @Compare public String classForUnknownArray() { + try { + return Class.forName("[W").getName(); + } catch (Exception ex) { + return ex.getClass().getName(); + } + } + + @Compare public String classForUnknownDeepArray() { + try { + return Class.forName("[[[[[W").getName(); + } catch (Exception ex) { + return ex.getClass().getName(); + } + } + + @Compare public String componentGetNameForObjectArray() { + return (new Object[3]).getClass().getComponentType().getName(); + } + @Compare public boolean sameComponentGetNameForObjectArray() { + return (new Object[3]).getClass().getComponentType() == Object.class; + } + @Compare public String componentGetNameForSimpleIntArray() { + return (new int[3]).getClass().getComponentType().getName(); + } + @Compare public String componentGetNameForMultiIntArray() { + return (new int[3][4][5][6][7][8][9]).getClass().getComponentType().getName(); + } + @Compare public String componentGetNameForMultiStringArray() { + Class c = (new String[3][4][5][6][7][8][9]).getClass(); + StringBuilder sb = new StringBuilder(); + for (;;) { + sb.append(c.getName()).append("\n"); + c = c.getComponentType(); + if (c == null) { + break; + } + } + return sb.toString(); + } + + @Compare public boolean isArray() { + return new Object[0].getClass().isArray(); + } + @JavaScriptBody(args = { "arr", "len" }, body="var a = arr.slice(0, len); a.sort(); return a;") private static String[] sort(String[] arr, int len) { List list = Arrays.asList(arr).subList(0, len); @@ -97,6 +179,11 @@ return list.toArray(new String[0]); } + @JavaScriptBody(args = {}, body = "return new Object();") + private static Object newObject() { + return new Object(); + } + @Factory public static Object[] create() { return VMTest.create(ReflectionTest.class);