vm/src/main/java/org/apidesign/vm4brwsr/GenJS.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Mon, 08 Oct 2012 17:10:27 -0700
branchemul
changeset 93 a236a9f137ac
parent 91 f3b685bd7243
child 97 437df2a719e7
permissions -rw-r--r--
Concatanation of strings sort of works (but produces wrong result)
     1 package org.apidesign.vm4brwsr;
     2 
     3 import java.io.BufferedWriter;
     4 import java.io.FileWriter;
     5 import java.io.IOException;
     6 import java.io.InputStream;
     7 import java.io.Writer;
     8 import java.net.URL;
     9 import java.util.Arrays;
    10 import java.util.Enumeration;
    11 import java.util.HashSet;
    12 import java.util.LinkedList;
    13 import java.util.List;
    14 import java.util.Set;
    15 
    16 /** Generator of JavaScript from bytecode of classes on classpath of the VM.
    17  *
    18  * @author Jaroslav Tulach <jtulach@netbeans.org>
    19  */
    20 final class GenJS {
    21     private GenJS() {}
    22     
    23     public static void main(String... args) throws IOException {
    24         if (args.length < 2) {
    25             System.err.println("Usage: java -cp ... -jar ... <file_to_generate_js_code_to> java/lang/Class org/your/App ...");
    26             return;
    27         }
    28         
    29         Writer w = new BufferedWriter(new FileWriter(args[0]));
    30         List<String> classes = Arrays.asList(args).subList(1, args.length);
    31         compile(w, classes);
    32         w.close();
    33     }
    34     
    35     static void compile(Appendable out, String... names) throws IOException {
    36         compile(out, Arrays.asList(names));
    37     }
    38     static void compile(Appendable out, List<String> names) throws IOException {
    39         Set<String> processed = new HashSet<String>();
    40         LinkedList<String> toProcess = new LinkedList<String>(names);
    41         for (;;) {
    42             toProcess.removeAll(processed);
    43             if (toProcess.isEmpty()) {
    44                 break;
    45             }
    46             String name = toProcess.getFirst();
    47             processed.add(name);
    48             if (name.startsWith("java/")
    49                 && !name.equals("java/lang/Object")
    50                 && !name.equals("java/lang/Class")
    51                 && !name.equals("java/lang/Number")
    52                 && !name.equals("java/lang/Integer")
    53                 && !name.equals("java/lang/Throwable")
    54                 && !name.equals("java/lang/Exception")
    55                 && !name.equals("java/lang/RuntimeException")
    56                 && !name.equals("java/lang/UnsupportedOperationException")
    57                 && !name.equals("java/lang/String")
    58                 && !name.equals("java/lang/String$CaseInsensitiveComparator")
    59                 && !name.equals("java/lang/StringBuilder")
    60                 && !name.equals("java/lang/AbstractStringBuilder")
    61             ) {
    62                 continue;
    63             }            
    64             InputStream is = loadClass(name);
    65             if (is == null) {
    66                 throw new IOException("Can't find class " + name); 
    67             }
    68             LinkedList<String> scripts = new LinkedList<String>();
    69             try {
    70                 ByteCodeToJavaScript.compile(is, out, toProcess, scripts);
    71             } catch (RuntimeException ex) {
    72                 if (out instanceof CharSequence) {
    73                     CharSequence seq = (CharSequence)out;
    74                     int lastBlock = seq.length();
    75                     while (lastBlock-- >= 0) {
    76                         if (seq.charAt(lastBlock) == '{') {
    77                             break;
    78                         }
    79                     }
    80                     throw new IOException("Error while compiling " + name + "\n" 
    81                         + seq.subSequence(lastBlock + 1, seq.length()), ex
    82                     );
    83                 } else {
    84                     throw new IOException("Error while compiling " + name + "\n" 
    85                         + out, ex
    86                     );
    87                 }
    88             }
    89             for (String resource : scripts) {
    90                 InputStream emul = GenJS.class.getResourceAsStream(resource);
    91                 if (emul == null) {
    92                     throw new IOException("Can't find " + resource);
    93                 }
    94                 readResource(emul, out);
    95             }
    96         }
    97     }
    98     private static void readResource(InputStream emul, Appendable out) throws IOException {
    99         try {
   100             int state = 0;
   101             for (;;) {
   102                 int ch = emul.read();
   103                 if (ch == -1) {
   104                     break;
   105                 }
   106                 if (ch < 0 || ch > 255) {
   107                     throw new IOException("Invalid char in emulation " + ch);
   108                 }
   109                 switch (state) {
   110                     case 0: 
   111                         if (ch == '/') {
   112                             state = 1;
   113                         } else {
   114                             out.append((char)ch);
   115                         }
   116                         break;
   117                     case 1:
   118                         if (ch == '*') {
   119                             state = 2;
   120                         } else {
   121                             out.append('/').append((char)ch);
   122                             state = 0;
   123                         }
   124                         break;
   125                     case 2:
   126                         if (ch == '*') {
   127                             state = 3;
   128                         }
   129                         break;
   130                     case 3:
   131                         if (ch == '/') {
   132                             state = 0;
   133                         } else {
   134                             state = 2;
   135                         }
   136                         break;
   137                 }
   138             }
   139         } finally {
   140             emul.close();
   141         }
   142     }
   143 
   144     private static InputStream loadClass(String name) throws IOException {
   145         Enumeration<URL> en = ClassLoader.getSystemClassLoader().getResources(name + ".class");
   146         URL u = null;
   147         while (en.hasMoreElements()) {
   148             u = en.nextElement();
   149         }
   150         if (u == null) {
   151             throw new IOException("Can't find " + name);
   152         }
   153         return u.openStream();
   154     }
   155     
   156 }