# HG changeset patch # User Jaroslav Tulach # Date 1346036910 -7200 # Node ID 71aab30ab2b784581c116e5a6ca24ddc986c377a Initial version of the Bytecode to JavaScript translator diff -r 000000000000 -r 71aab30ab2b7 pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pom.xml Mon Aug 27 05:08:30 2012 +0200 @@ -0,0 +1,86 @@ + + 4.0.0 + + org.apidesign + java4browser + 0.1-SNAPSHOT + jar + + java4browser + http://java4browser.apidesign.org + + + UTF-8 + Jaroslav Tulach + jaroslav.tulach@apidesign.org + + + + + netbeans + NetBeans + http://bits.netbeans.org/maven2/ + + + + + mc-release + Local Maven repository of releases + http://mc-repo.googlecode.com/svn/maven2/releases + + false + + + true + + + + + scm:hg:http://source.apidesign.org/hg/quoridor + http://source.apidesign.org/hg/quoridor + + + + GPL-2.0 + http://opensource.org/licenses/GPL-2.0 + repo + + + + API Design + http://apidesign.org + + + + + com.mycila.maven-license-plugin + maven-license-plugin + 1.9.0 + +
src/header.txt
+
+
+
+
+ + + org.testng + testng + 6.7 + test + + + junit + junit + + + + + org.netbeans.api + org-netbeans-modules-classfile + RELEASE72 + jar + + +
diff -r 000000000000 -r 71aab30ab2b7 src/header.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/header.txt Mon Aug 27 05:08:30 2012 +0200 @@ -0,0 +1,15 @@ +Java 4 Browser Bytecode Translator +Copyright (C) 2012-${year} Jaroslav Tulach + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. Look for COPYING file in the top folder. +If not, see http://opensource.org/licenses/GPL-2.0. diff -r 000000000000 -r 71aab30ab2b7 src/main/java/org/apidesign/java4browser/ByteCodeToJavaScript.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/org/apidesign/java4browser/ByteCodeToJavaScript.java Mon Aug 27 05:08:30 2012 +0200 @@ -0,0 +1,121 @@ +/* +Java 4 Browser Bytecode Translator +Copyright (C) 2012-2012 Jaroslav Tulach + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. Look for COPYING file in the top folder. +If not, see http://opensource.org/licenses/GPL-2.0. +*/ +package org.apidesign.java4browser; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import org.netbeans.modules.classfile.ByteCodes; +import org.netbeans.modules.classfile.ClassFile; +import org.netbeans.modules.classfile.Code; +import org.netbeans.modules.classfile.Method; +import org.netbeans.modules.classfile.Parameter; + +/** Translator of the code inside class files to JavaScript. + * + * @author Jaroslav Tulach + */ +public final class ByteCodeToJavaScript { + private final ClassFile jc; + private final Appendable out; + + private ByteCodeToJavaScript(ClassFile jc, Appendable out) { + this.jc = jc; + this.out = out; + } + + /** Converts a given class file to a JavaScript version. + * @param fileName the name of the file we are reading + * @param classFile input stream with code of the .class file + * @param out a {@link StringBuilder} or similar to generate the output to + * @throws IOException if something goes wrong during read or write or translating + */ + public static void compile(String fileName, InputStream classFile, Appendable out) throws IOException { + ClassFile jc = new ClassFile(classFile, true); + ByteCodeToJavaScript compiler = new ByteCodeToJavaScript(jc, out); + for (Method m : jc.getMethods()) { + if (m.isStatic()) { + compiler.generateStaticMethod(m); + } + } + } + private void generateStaticMethod(Method m) throws IOException { + out.append("function ").append( + jc.getName().getExternalName().replace('.', '_') + ).append('_').append( + m.getName() + ); + out.append(m.getReturnType()); + List args = m.getParameters(); + for (Parameter t : args) { + out.append(t.getDescriptor()); + } + out.append('('); + String space = ""; + for (int i = 0; i < args.size(); i++) { + out.append(space); + out.append("arg").append(String.valueOf(i)); + space = ","; + } + out.append(") {").append("\n var "); + final Code code = m.getCode(); + int len = code.getMaxLocals(); + space = ""; + for (int i = 0; i < len; i++) { + out.append(space); + out.append("var").append(String.valueOf(i)); + space = ","; + } + out.append(";\n var stack = new Array("); + out.append(Integer.toString(code.getMaxStack())); + out.append(");\n"); + produceCode(code.getByteCodes()); + out.append(";\nreturn 1;"); + out.append("}"); + } + + private void produceCode(byte[] byteCodes) throws IOException { + for (int i = 0; i < byteCodes.length; i++) { + int prev = i; + out.append(" "); + final int c = (byteCodes[i] + 256) % 256; + switch (c) { + case ByteCodes.bc_aload_0: + case ByteCodes.bc_iload_0: + out.append("stack.push(arg0);"); + break; + case ByteCodes.bc_aload_1: + case ByteCodes.bc_iload_1: + out.append("stack.push(arg1);"); + break; + case ByteCodes.bc_iadd: + out.append("stack.push(stack.pop() + stack.pop());"); + break; + case ByteCodes.bc_ireturn: + out.append("return stack.pop();"); + } + out.append("/*"); + for (int j = prev; j <= i; j++) { + out.append(" "); + final int cc = (byteCodes[j] + 256) % 256; + out.append(Integer.toString(cc)); + } + out.append("*/\n"); + } + } +} diff -r 000000000000 -r 71aab30ab2b7 src/test/java/org/apidesign/java4browser/StaticMethod.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test/java/org/apidesign/java4browser/StaticMethod.java Mon Aug 27 05:08:30 2012 +0200 @@ -0,0 +1,28 @@ +/* +Java 4 Browser Bytecode Translator +Copyright (C) 2012-2012 Jaroslav Tulach + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. Look for COPYING file in the top folder. +If not, see http://opensource.org/licenses/GPL-2.0. +*/ +package org.apidesign.java4browser; + +/** + * + * @author Jaroslav Tulach + */ +public class StaticMethod { + public static int sum(int x, int y) { + return x + y; + } +} diff -r 000000000000 -r 71aab30ab2b7 src/test/java/org/apidesign/java4browser/StaticMethodTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test/java/org/apidesign/java4browser/StaticMethodTest.java Mon Aug 27 05:08:30 2012 +0200 @@ -0,0 +1,57 @@ +/* +Java 4 Browser Bytecode Translator +Copyright (C) 2012-2012 Jaroslav Tulach + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. Look for COPYING file in the top folder. +If not, see http://opensource.org/licenses/GPL-2.0. +*/ +package org.apidesign.java4browser; + +import java.io.IOException; +import java.io.InputStream; +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import static org.testng.Assert.*; +import org.testng.annotations.Test; + +/** Checks the basic behavior of the translator. + * + * @author Jaroslav Tulach + */ +public class StaticMethodTest { + @Test public void threePlusFour() throws Exception { + Invocable i = compileClass("StaticMethod.class"); + + Object ret = i.invokeFunction("org_apidesign_java4browser_StaticMethod_sumIII", 3, 4); + assertEquals(ret, Double.valueOf(7), "Should be seven"); + } + + static Invocable compileClass(String name) throws ScriptException, IOException { + InputStream is = StaticMethodTest.class.getResourceAsStream(name); + assertNotNull(is, "Class file found"); + StringBuilder sb = new StringBuilder(); + ByteCodeToJavaScript.compile(name, is, sb); + ScriptEngineManager sem = new ScriptEngineManager(); + ScriptEngine js = sem.getEngineByExtension("js"); + try { + Object res = js.eval(sb.toString()); + assertTrue(js instanceof Invocable, "It is invocable object: " + res); + return (Invocable)js; + } catch (ScriptException ex) { + fail("Could not compile:\n" + sb, ex); + return null; + } + } +}