diff -r 3ee23267706c -r 8bd4adaf6590 vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Thu Nov 29 20:19:00 2012 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Mon Dec 03 14:44:49 2012 +0100 @@ -19,7 +19,6 @@ 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,6 +50,16 @@ * @param resourcePath name of resources to read */ protected abstract void requireScript(String resourcePath); + + /** Allows subclasses to redefine what field a function representing a + * class gets assigned. By default it returns the suggested name followed + * by " = "; + * + * @param className suggested name of the class + */ + protected String assignClass(String className) { + return className + " = "; + } /** * Converts a given class file to a JavaScript version. @@ -74,71 +83,95 @@ return null; } } + String[] proto = findAnnotation(arrData, jc, + "org.apidesign.bck2brwsr.core.JavaScriptPrototype", + "container", "prototype" + ); StringArray toInitilize = new StringArray(); - for (MethodData m : jc.getMethods()) { - if (m.isStatic()) { - generateStaticMethod(m, toInitilize); - } else { - generateInstanceMethod(m); + final String className = className(jc); + out.append("\n\n").append(assignClass(className)); + out.append("function CLS() {"); + out.append("\n if (!CLS.prototype.$instOf_").append(className).append(") {"); + for (FieldData v : jc.getFields()) { + if (v.isStatic()) { + out.append("\n CLS.").append(v.getName()).append(initField(v)); } } - final String className = className(jc); - out.append("\nfunction ").append(className); - out.append("() {"); + if (proto == null) { + String sc = jc.getSuperClassName(); // with _ + out.append("\n var p = CLS.prototype = "). + append(sc.replace('/', '_')).append("(true);"); + out.append("\n var c = p;"); + } else { + out.append("\n var p = CLS.prototype = ").append(proto[1]).append(";"); + out.append("\n var c = ").append(proto[0]).append(";"); + } + for (MethodData m : jc.getMethods()) { + byte[] onlyArr = m.findAnnotationData(true); + String[] only = findAnnotation(onlyArr, jc, + "org.apidesign.bck2brwsr.core.JavaScriptOnly", + "name", "value" + ); + if (only != null) { + if (only[0] != null && only[1] != null) { + out.append("\n p.").append(only[0]).append(" = ") + .append(only[1]).append(";"); + } + continue; + } + if (m.isStatic()) { + generateStaticMethod("\n c.", m, toInitilize); + } else { + generateInstanceMethod("\n c.", m); + } + } + out.append("\n c.constructor = CLS;"); + out.append("\n c.$instOf_").append(className).append(" = true;"); + for (String superInterface : jc.getSuperInterfaces()) { + out.append("\n c.$instOf_").append(superInterface.replace('/', '_')).append(" = true;"); + } + out.append("\n }"); + out.append("\n if (arguments.length === 0) {"); + out.append("\n if (!(this instanceof CLS)) {"); + out.append("\n return new CLS();"); + out.append("\n }"); for (FieldData v : jc.getFields()) { + byte[] onlyArr = v.findAnnotationData(true); + String[] only = findAnnotation(onlyArr, jc, + "org.apidesign.bck2brwsr.core.JavaScriptOnly", + "name", "value" + ); + if (only != null) { + if (only[0] != null && only[1] != null) { + out.append("\n p.").append(only[0]).append(" = ") + .append(only[1]).append(";"); + } + continue; + } if (!v.isStatic()) { - out.append("\n this.fld_"). + out.append("\n this.fld_"). append(v.getName()).append(initField(v)); } } - out.append("\n}\n\nfunction ").append(className).append("_proto() {"); - out.append("\n if (").append(className). - append(".prototype.$instOf_").append(className).append(") {"); - out.append("\n return new ").append(className).append(";"); + out.append("\n return this;"); out.append("\n }"); - for (FieldData v : jc.getFields()) { - if (v.isStatic()) { - generateStaticField(v); - } - } - // ClassName sc = jc.getSuperClass(); - String sc = jc.getSuperClassName(); // with _ - if (sc != null) { - out.append("\n var p = ").append(className) - .append(".prototype = "). - append(sc.replace('/', '_')).append("_proto();"); - } else { - out.append("\n var p = ").append(className).append(".prototype;"); - } - for (MethodData m : jc.getMethods()) { - if (!m.getName().contains("")) { - generateMethodReference("\n p.", m); - } - } - out.append("\n p.$instOf_").append(className).append(" = true;"); - for (String superInterface : jc.getSuperInterfaces()) { - out.append("\n p.$instOf_").append(superInterface.replace('/', '_')).append(" = true;"); - } - out.append("\n return new ").append(className).append(";"); + out.append("\n return arguments[0] ? new CLS() : CLS.prototype;"); out.append("\n}"); - out.append("\n").append(className).append("_proto();"); StringBuilder sb = new StringBuilder(); for (String init : toInitilize.toArray()) { sb.append("\n").append(init).append("();"); } return sb.toString(); } - private void generateStaticMethod(MethodData m, StringArray toInitilize) throws IOException { - if (javaScriptBody(m, true)) { + private void generateStaticMethod(String prefix, MethodData m, StringArray toInitilize) throws IOException { + if (javaScriptBody(prefix, m, true)) { return; } StringBuilder argsCnt = new StringBuilder(); final String mn = findMethodName(m, argsCnt); - out.append("\nfunction ").append( - className(jc) - ).append('_').append(mn); + out.append(prefix).append(mn).append(" = function"); if (mn.equals("classV")) { - toInitilize.add(className(jc) + '_' + mn); + toInitilize.add(className(jc) + "(false)." + mn); } out.append('('); String space = ""; @@ -162,26 +195,18 @@ } produceCode(m); } else { - out.append(" /* no code found for ").append(m.getInternalSig()).append(" */\n"); + out.append(" throw 'no code found for ").append(m.getInternalSig()).append("';\n"); } - out.append("}"); + out.append("};"); } - private void generateMethodReference(String prefix, MethodData m) throws IOException { - final String name = findMethodName(m, new StringBuilder()); - out.append(prefix).append(name).append(" = ") - .append(className(jc)) - .append('_').append(name).append(";"); - } - - private void generateInstanceMethod(MethodData m) throws IOException { - if (javaScriptBody(m, false)) { + private void generateInstanceMethod(String prefix, MethodData m) throws IOException { + if (javaScriptBody(prefix, m, false)) { return; } StringBuilder argsCnt = new StringBuilder(); - out.append("\nfunction ").append( - className(jc) - ).append('_').append(findMethodName(m, argsCnt)); + final String mn = findMethodName(m, argsCnt); + out.append(prefix).append(mn).append(" = function"); out.append("(arg0"); String space = ","; for (int index = 1, i = 0; i < argsCnt.length(); i++) { @@ -202,9 +227,9 @@ } produceCode(m); } else { - out.append(" /* no code found for ").append(m.getInternalSig()).append(" */\n"); + out.append(" throw 'no code found for ").append(m.getInternalSig()).append("';\n"); } - out.append("}"); + out.append("};"); } private void produceCode(MethodData m) throws IOException { @@ -987,12 +1012,6 @@ } } - private void generateStaticField(FieldData v) throws IOException { - out.append("\n ") - .append(className(jc)) - .append('.').append(v.getName()).append(initField(v)); - } - private String findMethodName(MethodData m, StringBuilder cnt) { StringBuilder name = new StringBuilder(); if ("".equals(m.getName())) { // NOI18N @@ -1038,7 +1057,7 @@ final String in = mi[0]; out.append(in.replace('/', '_')); - out.append(".prototype."); + out.append("(false)."); out.append(mn); out.append('('); if (numArguments > 0) { @@ -1113,12 +1132,12 @@ return d.replace('[', 'A'); } - private boolean javaScriptBody(MethodData m, boolean isStatic) throws IOException { + private boolean javaScriptBody(String prefix, MethodData m, boolean isStatic) throws IOException { byte[] arr = m.findAnnotationData(true); if (arr == null) { return false; } - final String jvmType = "L" + JavaScriptBody.class.getName().replace('.', '/') + ";"; + final String jvmType = "Lorg/apidesign/bck2brwsr/core/JavaScriptBody;"; class P extends AnnotationParser { int cnt; String[] args = new String[30]; @@ -1143,9 +1162,8 @@ return false; } StringBuilder cnt = new StringBuilder(); - out.append("\nfunction ").append(className(jc)).append('_'). - append(findMethodName(m, cnt)); - out.append("("); + out.append(prefix).append(findMethodName(m, cnt)); + out.append(" = function("); String space; int index; if (!isStatic) {