1.1 --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Thu Nov 29 20:19:00 2012 +0100
1.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Mon Dec 03 14:44:49 2012 +0100
1.3 @@ -19,7 +19,6 @@
1.4
1.5 import java.io.IOException;
1.6 import java.io.InputStream;
1.7 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
1.8 import org.apidesign.javap.AnnotationParser;
1.9 import org.apidesign.javap.ClassData;
1.10 import org.apidesign.javap.FieldData;
1.11 @@ -51,6 +50,16 @@
1.12 * @param resourcePath name of resources to read
1.13 */
1.14 protected abstract void requireScript(String resourcePath);
1.15 +
1.16 + /** Allows subclasses to redefine what field a function representing a
1.17 + * class gets assigned. By default it returns the suggested name followed
1.18 + * by <code>" = "</code>;
1.19 + *
1.20 + * @param className suggested name of the class
1.21 + */
1.22 + protected String assignClass(String className) {
1.23 + return className + " = ";
1.24 + }
1.25
1.26 /**
1.27 * Converts a given class file to a JavaScript version.
1.28 @@ -74,71 +83,95 @@
1.29 return null;
1.30 }
1.31 }
1.32 + String[] proto = findAnnotation(arrData, jc,
1.33 + "org.apidesign.bck2brwsr.core.JavaScriptPrototype",
1.34 + "container", "prototype"
1.35 + );
1.36 StringArray toInitilize = new StringArray();
1.37 - for (MethodData m : jc.getMethods()) {
1.38 - if (m.isStatic()) {
1.39 - generateStaticMethod(m, toInitilize);
1.40 - } else {
1.41 - generateInstanceMethod(m);
1.42 + final String className = className(jc);
1.43 + out.append("\n\n").append(assignClass(className));
1.44 + out.append("function CLS() {");
1.45 + out.append("\n if (!CLS.prototype.$instOf_").append(className).append(") {");
1.46 + for (FieldData v : jc.getFields()) {
1.47 + if (v.isStatic()) {
1.48 + out.append("\n CLS.").append(v.getName()).append(initField(v));
1.49 }
1.50 }
1.51 - final String className = className(jc);
1.52 - out.append("\nfunction ").append(className);
1.53 - out.append("() {");
1.54 + if (proto == null) {
1.55 + String sc = jc.getSuperClassName(); // with _
1.56 + out.append("\n var p = CLS.prototype = ").
1.57 + append(sc.replace('/', '_')).append("(true);");
1.58 + out.append("\n var c = p;");
1.59 + } else {
1.60 + out.append("\n var p = CLS.prototype = ").append(proto[1]).append(";");
1.61 + out.append("\n var c = ").append(proto[0]).append(";");
1.62 + }
1.63 + for (MethodData m : jc.getMethods()) {
1.64 + byte[] onlyArr = m.findAnnotationData(true);
1.65 + String[] only = findAnnotation(onlyArr, jc,
1.66 + "org.apidesign.bck2brwsr.core.JavaScriptOnly",
1.67 + "name", "value"
1.68 + );
1.69 + if (only != null) {
1.70 + if (only[0] != null && only[1] != null) {
1.71 + out.append("\n p.").append(only[0]).append(" = ")
1.72 + .append(only[1]).append(";");
1.73 + }
1.74 + continue;
1.75 + }
1.76 + if (m.isStatic()) {
1.77 + generateStaticMethod("\n c.", m, toInitilize);
1.78 + } else {
1.79 + generateInstanceMethod("\n c.", m);
1.80 + }
1.81 + }
1.82 + out.append("\n c.constructor = CLS;");
1.83 + out.append("\n c.$instOf_").append(className).append(" = true;");
1.84 + for (String superInterface : jc.getSuperInterfaces()) {
1.85 + out.append("\n c.$instOf_").append(superInterface.replace('/', '_')).append(" = true;");
1.86 + }
1.87 + out.append("\n }");
1.88 + out.append("\n if (arguments.length === 0) {");
1.89 + out.append("\n if (!(this instanceof CLS)) {");
1.90 + out.append("\n return new CLS();");
1.91 + out.append("\n }");
1.92 for (FieldData v : jc.getFields()) {
1.93 + byte[] onlyArr = v.findAnnotationData(true);
1.94 + String[] only = findAnnotation(onlyArr, jc,
1.95 + "org.apidesign.bck2brwsr.core.JavaScriptOnly",
1.96 + "name", "value"
1.97 + );
1.98 + if (only != null) {
1.99 + if (only[0] != null && only[1] != null) {
1.100 + out.append("\n p.").append(only[0]).append(" = ")
1.101 + .append(only[1]).append(";");
1.102 + }
1.103 + continue;
1.104 + }
1.105 if (!v.isStatic()) {
1.106 - out.append("\n this.fld_").
1.107 + out.append("\n this.fld_").
1.108 append(v.getName()).append(initField(v));
1.109 }
1.110 }
1.111 - out.append("\n}\n\nfunction ").append(className).append("_proto() {");
1.112 - out.append("\n if (").append(className).
1.113 - append(".prototype.$instOf_").append(className).append(") {");
1.114 - out.append("\n return new ").append(className).append(";");
1.115 + out.append("\n return this;");
1.116 out.append("\n }");
1.117 - for (FieldData v : jc.getFields()) {
1.118 - if (v.isStatic()) {
1.119 - generateStaticField(v);
1.120 - }
1.121 - }
1.122 - // ClassName sc = jc.getSuperClass();
1.123 - String sc = jc.getSuperClassName(); // with _
1.124 - if (sc != null) {
1.125 - out.append("\n var p = ").append(className)
1.126 - .append(".prototype = ").
1.127 - append(sc.replace('/', '_')).append("_proto();");
1.128 - } else {
1.129 - out.append("\n var p = ").append(className).append(".prototype;");
1.130 - }
1.131 - for (MethodData m : jc.getMethods()) {
1.132 - if (!m.getName().contains("<cinit>")) {
1.133 - generateMethodReference("\n p.", m);
1.134 - }
1.135 - }
1.136 - out.append("\n p.$instOf_").append(className).append(" = true;");
1.137 - for (String superInterface : jc.getSuperInterfaces()) {
1.138 - out.append("\n p.$instOf_").append(superInterface.replace('/', '_')).append(" = true;");
1.139 - }
1.140 - out.append("\n return new ").append(className).append(";");
1.141 + out.append("\n return arguments[0] ? new CLS() : CLS.prototype;");
1.142 out.append("\n}");
1.143 - out.append("\n").append(className).append("_proto();");
1.144 StringBuilder sb = new StringBuilder();
1.145 for (String init : toInitilize.toArray()) {
1.146 sb.append("\n").append(init).append("();");
1.147 }
1.148 return sb.toString();
1.149 }
1.150 - private void generateStaticMethod(MethodData m, StringArray toInitilize) throws IOException {
1.151 - if (javaScriptBody(m, true)) {
1.152 + private void generateStaticMethod(String prefix, MethodData m, StringArray toInitilize) throws IOException {
1.153 + if (javaScriptBody(prefix, m, true)) {
1.154 return;
1.155 }
1.156 StringBuilder argsCnt = new StringBuilder();
1.157 final String mn = findMethodName(m, argsCnt);
1.158 - out.append("\nfunction ").append(
1.159 - className(jc)
1.160 - ).append('_').append(mn);
1.161 + out.append(prefix).append(mn).append(" = function");
1.162 if (mn.equals("classV")) {
1.163 - toInitilize.add(className(jc) + '_' + mn);
1.164 + toInitilize.add(className(jc) + "(false)." + mn);
1.165 }
1.166 out.append('(');
1.167 String space = "";
1.168 @@ -162,26 +195,18 @@
1.169 }
1.170 produceCode(m);
1.171 } else {
1.172 - out.append(" /* no code found for ").append(m.getInternalSig()).append(" */\n");
1.173 + out.append(" throw 'no code found for ").append(m.getInternalSig()).append("';\n");
1.174 }
1.175 - out.append("}");
1.176 + out.append("};");
1.177 }
1.178
1.179 - private void generateMethodReference(String prefix, MethodData m) throws IOException {
1.180 - final String name = findMethodName(m, new StringBuilder());
1.181 - out.append(prefix).append(name).append(" = ")
1.182 - .append(className(jc))
1.183 - .append('_').append(name).append(";");
1.184 - }
1.185 -
1.186 - private void generateInstanceMethod(MethodData m) throws IOException {
1.187 - if (javaScriptBody(m, false)) {
1.188 + private void generateInstanceMethod(String prefix, MethodData m) throws IOException {
1.189 + if (javaScriptBody(prefix, m, false)) {
1.190 return;
1.191 }
1.192 StringBuilder argsCnt = new StringBuilder();
1.193 - out.append("\nfunction ").append(
1.194 - className(jc)
1.195 - ).append('_').append(findMethodName(m, argsCnt));
1.196 + final String mn = findMethodName(m, argsCnt);
1.197 + out.append(prefix).append(mn).append(" = function");
1.198 out.append("(arg0");
1.199 String space = ",";
1.200 for (int index = 1, i = 0; i < argsCnt.length(); i++) {
1.201 @@ -202,9 +227,9 @@
1.202 }
1.203 produceCode(m);
1.204 } else {
1.205 - out.append(" /* no code found for ").append(m.getInternalSig()).append(" */\n");
1.206 + out.append(" throw 'no code found for ").append(m.getInternalSig()).append("';\n");
1.207 }
1.208 - out.append("}");
1.209 + out.append("};");
1.210 }
1.211
1.212 private void produceCode(MethodData m) throws IOException {
1.213 @@ -987,12 +1012,6 @@
1.214 }
1.215 }
1.216
1.217 - private void generateStaticField(FieldData v) throws IOException {
1.218 - out.append("\n ")
1.219 - .append(className(jc))
1.220 - .append('.').append(v.getName()).append(initField(v));
1.221 - }
1.222 -
1.223 private String findMethodName(MethodData m, StringBuilder cnt) {
1.224 StringBuilder name = new StringBuilder();
1.225 if ("<init>".equals(m.getName())) { // NOI18N
1.226 @@ -1038,7 +1057,7 @@
1.227
1.228 final String in = mi[0];
1.229 out.append(in.replace('/', '_'));
1.230 - out.append(".prototype.");
1.231 + out.append("(false).");
1.232 out.append(mn);
1.233 out.append('(');
1.234 if (numArguments > 0) {
1.235 @@ -1113,12 +1132,12 @@
1.236 return d.replace('[', 'A');
1.237 }
1.238
1.239 - private boolean javaScriptBody(MethodData m, boolean isStatic) throws IOException {
1.240 + private boolean javaScriptBody(String prefix, MethodData m, boolean isStatic) throws IOException {
1.241 byte[] arr = m.findAnnotationData(true);
1.242 if (arr == null) {
1.243 return false;
1.244 }
1.245 - final String jvmType = "L" + JavaScriptBody.class.getName().replace('.', '/') + ";";
1.246 + final String jvmType = "Lorg/apidesign/bck2brwsr/core/JavaScriptBody;";
1.247 class P extends AnnotationParser {
1.248 int cnt;
1.249 String[] args = new String[30];
1.250 @@ -1143,9 +1162,8 @@
1.251 return false;
1.252 }
1.253 StringBuilder cnt = new StringBuilder();
1.254 - out.append("\nfunction ").append(className(jc)).append('_').
1.255 - append(findMethodName(m, cnt));
1.256 - out.append("(");
1.257 + out.append(prefix).append(findMethodName(m, cnt));
1.258 + out.append(" = function(");
1.259 String space;
1.260 int index;
1.261 if (!isStatic) {