jaroslav@29: package org.apidesign.vm4brwsr; jaroslav@29: jaroslav@29: import java.io.BufferedWriter; jaroslav@29: import java.io.FileWriter; jaroslav@29: import java.io.IOException; jaroslav@29: import java.io.InputStream; jaroslav@29: import java.io.Writer; jaroslav@29: import java.util.Arrays; jaroslav@29: import java.util.HashSet; jaroslav@29: import java.util.LinkedList; jaroslav@29: import java.util.List; jaroslav@29: import java.util.Set; jaroslav@29: jaroslav@29: /** Generator of JavaScript from bytecode of classes on classpath of the VM. jaroslav@29: * jaroslav@29: * @author Jaroslav Tulach jaroslav@29: */ jaroslav@29: final class GenJS { jaroslav@29: private GenJS() {} jaroslav@29: jaroslav@29: public static void main(String... args) throws IOException { jaroslav@29: if (args.length < 2) { jaroslav@29: System.err.println("Usage: java -cp ... -jar ... java/lang/Class org/your/App ..."); jaroslav@29: return; jaroslav@29: } jaroslav@29: jaroslav@29: Writer w = new BufferedWriter(new FileWriter(args[0])); jaroslav@29: List classes = Arrays.asList(args).subList(1, args.length); jaroslav@29: compile(w, classes); jaroslav@29: w.close(); jaroslav@29: } jaroslav@29: jaroslav@29: static void compile(Appendable out, String... names) throws IOException { jaroslav@29: compile(out, Arrays.asList(names)); jaroslav@29: } jaroslav@29: static void compile(Appendable out, List names) throws IOException { jaroslav@29: Set processed = new HashSet(); jaroslav@29: LinkedList toProcess = new LinkedList(names); jaroslav@29: for (;;) { jaroslav@29: toProcess.removeAll(processed); jaroslav@29: if (toProcess.isEmpty()) { jaroslav@29: break; jaroslav@29: } jaroslav@29: String name = toProcess.getFirst(); jaroslav@29: processed.add(name); jaroslav@36: if (name.startsWith("sun/")) { jaroslav@36: continue; jaroslav@36: } jaroslav@34: if (name.startsWith("java/") jaroslav@34: && !name.equals("java/lang/Object") jaroslav@34: && !name.equals("java/lang/String") jaroslav@36: && !name.equals("java/lang/StringBuilder") jaroslav@36: && !name.equals("java/lang/AbstractStringBuilder") jaroslav@34: ) { jaroslav@29: continue; jaroslav@29: } jaroslav@35: InputStream emul = GenJS.class.getResourceAsStream("emulation/" + name.replace('/', '_') + ".js"); jaroslav@35: if (emul != null) { jaroslav@90: readResource(emul, out); jaroslav@35: continue; jaroslav@35: } jaroslav@35: jaroslav@29: InputStream is = GenJS.class.getClassLoader().getResourceAsStream(name + ".class"); jaroslav@29: if (is == null) { jaroslav@29: throw new IOException("Can't find class " + name); jaroslav@29: } jaroslav@29: try { jaroslav@29: ByteCodeToJavaScript.compile(is, out, toProcess); jaroslav@29: } catch (RuntimeException ex) { jaroslav@29: if (out instanceof CharSequence) { jaroslav@29: CharSequence seq = (CharSequence)out; jaroslav@29: int lastBlock = seq.length(); jaroslav@29: while (lastBlock-- >= 0) { jaroslav@29: if (seq.charAt(lastBlock) == '{') { jaroslav@29: break; jaroslav@29: } jaroslav@29: } jaroslav@29: throw new IOException("Error while compiling " + name + "\n" jaroslav@29: + seq.subSequence(lastBlock + 1, seq.length()), ex jaroslav@29: ); jaroslav@29: } else { jaroslav@29: throw new IOException("Error while compiling " + name + "\n" jaroslav@29: + out, ex jaroslav@29: ); jaroslav@29: } jaroslav@29: } jaroslav@29: } jaroslav@29: } jaroslav@90: private static void readResource(InputStream emul, Appendable out) throws IOException { jaroslav@90: try { jaroslav@90: int state = 0; jaroslav@90: for (;;) { jaroslav@90: int ch = emul.read(); jaroslav@90: if (ch == -1) { jaroslav@90: break; jaroslav@90: } jaroslav@90: if (ch < 0 || ch > 255) { jaroslav@90: throw new IOException("Invalid char in emulation " + ch); jaroslav@90: } jaroslav@90: switch (state) { jaroslav@90: case 0: jaroslav@90: if (ch == '/') { jaroslav@90: state = 1; jaroslav@90: } else { jaroslav@90: out.append((char)ch); jaroslav@90: } jaroslav@90: break; jaroslav@90: case 1: jaroslav@90: if (ch == '*') { jaroslav@90: state = 2; jaroslav@90: } else { jaroslav@90: out.append('/').append((char)ch); jaroslav@90: state = 0; jaroslav@90: } jaroslav@90: break; jaroslav@90: case 2: jaroslav@90: if (ch == '*') { jaroslav@90: state = 3; jaroslav@90: } jaroslav@90: break; jaroslav@90: case 3: jaroslav@90: if (ch == '/') { jaroslav@90: state = 0; jaroslav@90: } else { jaroslav@90: state = 2; jaroslav@90: } jaroslav@90: break; jaroslav@90: } jaroslav@90: } jaroslav@90: } finally { jaroslav@90: emul.close(); jaroslav@90: } jaroslav@90: } jaroslav@29: jaroslav@29: }