vm/src/main/java/org/apidesign/vm4brwsr/GenJS.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Fri, 28 Sep 2012 07:27:34 +0200
branchstrings
changeset 35 7cfa9b56f888
parent 34 6fcc0dfbe324
child 36 95330dd02c47
permissions -rw-r--r--
Basic emulation of java.lang.String that supports charAt
     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.util.Arrays;
     9 import java.util.HashSet;
    10 import java.util.LinkedList;
    11 import java.util.List;
    12 import java.util.Set;
    13 
    14 /** Generator of JavaScript from bytecode of classes on classpath of the VM.
    15  *
    16  * @author Jaroslav Tulach <jtulach@netbeans.org>
    17  */
    18 final class GenJS {
    19     private GenJS() {}
    20     
    21     public static void main(String... args) throws IOException {
    22         if (args.length < 2) {
    23             System.err.println("Usage: java -cp ... -jar ... <file_to_generate_js_code_to> java/lang/Class org/your/App ...");
    24             return;
    25         }
    26         
    27         Writer w = new BufferedWriter(new FileWriter(args[0]));
    28         List<String> classes = Arrays.asList(args).subList(1, args.length);
    29         compile(w, classes);
    30         w.close();
    31     }
    32     
    33     static void compile(Appendable out, String... names) throws IOException {
    34         compile(out, Arrays.asList(names));
    35     }
    36     static void compile(Appendable out, List<String> names) throws IOException {
    37         Set<String> processed = new HashSet<String>();
    38         LinkedList<String> toProcess = new LinkedList<String>(names);
    39         for (;;) {
    40             toProcess.removeAll(processed);
    41             if (toProcess.isEmpty()) {
    42                 break;
    43             }
    44             String name = toProcess.getFirst();
    45             processed.add(name);
    46             if (name.startsWith("java/") 
    47                 && !name.equals("java/lang/Object")
    48                 && !name.equals("java/lang/String")
    49             ) {
    50                 continue;
    51             }
    52             InputStream emul = GenJS.class.getResourceAsStream("emulation/" + name.replace('/', '_') + ".js");
    53             if (emul != null) {
    54                 try {
    55                     int state = 0;
    56                     for (;;) {
    57                         int ch = emul.read();
    58                         if (ch == -1) {
    59                             break;
    60                         }
    61                         if (ch < 0 || ch > 255) {
    62                             throw new IOException("Invalid char in emulation " + ch);
    63                         }
    64                         switch (state) {
    65                             case 0: 
    66                                 if (ch == '/') {
    67                                     state = 1;
    68                                 } else {
    69                                     out.append((char)ch);
    70                                 }
    71                                 break;
    72                             case 1:
    73                                 if (ch == '*') {
    74                                     state = 2;
    75                                 } else {
    76                                     out.append('/').append((char)ch);
    77                                     state = 0;
    78                                 }
    79                                 break;
    80                             case 2:
    81                                 if (ch == '*') {
    82                                     state = 3;
    83                                 }
    84                                 break;
    85                             case 3:
    86                                 if (ch == '/') {
    87                                     state = 0;
    88                                 } else {
    89                                     state = 2;
    90                                 }
    91                                 break;
    92                         }
    93                     }
    94                 } finally {
    95                     emul.close();
    96                 }
    97                 continue;
    98             }
    99             
   100             InputStream is = GenJS.class.getClassLoader().getResourceAsStream(name + ".class");
   101             if (is == null) {
   102                 throw new IOException("Can't find class " + name); 
   103             }
   104             try {
   105                 ByteCodeToJavaScript.compile(is, out, toProcess);
   106             } catch (RuntimeException ex) {
   107                 if (out instanceof CharSequence) {
   108                     CharSequence seq = (CharSequence)out;
   109                     int lastBlock = seq.length();
   110                     while (lastBlock-- >= 0) {
   111                         if (seq.charAt(lastBlock) == '{') {
   112                             break;
   113                         }
   114                     }
   115                     throw new IOException("Error while compiling " + name + "\n" 
   116                         + seq.subSequence(lastBlock + 1, seq.length()), ex
   117                     );
   118                 } else {
   119                     throw new IOException("Error while compiling " + name + "\n" 
   120                         + out, ex
   121                     );
   122                 }
   123             }
   124         }
   125     }
   126     
   127 }