vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java
branchregisters
changeset 242 8bd4adaf6590
parent 221 3ee23267706c
parent 240 4e88a33d7972
child 281 f2352e0b713e
     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) {