Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,13 @@ public void setIsAnnotation(boolean isAnnotation) {
private boolean finalClass;
private boolean isEnum;
private static Set<String> writableFields = new HashSet<String>();

static void cleanup() {
arrayTypes.clear();
writableFields.clear();
mainClass = null;
saveUnitTests = false;
}

/**
*
Expand Down Expand Up @@ -170,6 +177,10 @@ public void addField(ByteCodeField m) {
public String generateCSharpCode() {
return "";
}

public String generateJavascriptCode(List<ByteCodeClass> allClasses) {
return JavascriptMethodGenerator.generateClassJavascript(this, allClasses);
}

public void addWritableField(String field) {
writableFields.add(field);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ public String extension() {
return "c";
}

},
OUTPUT_TYPE_JAVASCRIPT {
@Override
public String extension() {
return "js";
}

};

public abstract String extension();
Expand Down Expand Up @@ -144,7 +151,7 @@ public static void main(String[] args) throws Exception {
}

if(args.length != 9) {
System.out.println("We accept 9 arguments output type (ios, csharp, clean), input directory, output directory, app name, package name, app dispaly name, version, type (ios/iphone/ipad) and additional frameworks");
System.out.println("We accept 9 arguments output type (ios, csharp, clean, javascript), input directory, output directory, app name, package name, app dispaly name, version, type (ios/iphone/ipad) and additional frameworks");
System.exit(1);
return;
}
Expand All @@ -159,10 +166,14 @@ public static void main(String[] args) throws Exception {
System.out.println("Generating Unit Tests");
ByteCodeClass.setSaveUnitTests(true);
}
if(args[0].equalsIgnoreCase("csharp")) {
if(args[0].equalsIgnoreCase("ios")) {
output = OutputType.OUTPUT_TYPE_IOS;
} else if(args[0].equalsIgnoreCase("csharp")) {
output = OutputType.OUTPUT_TYPE_CSHARP;
} else if(args[0].equalsIgnoreCase("clean")) {
output = OutputType.OUTPUT_TYPE_CLEAN;
} else if(args[0].equalsIgnoreCase("javascript")) {
output = OutputType.OUTPUT_TYPE_JAVASCRIPT;
}
String[] sourceDirectories = args[1].split(";");
File[] sources = new File[sourceDirectories.length];
Expand All @@ -189,6 +200,9 @@ public static void main(String[] args) throws Exception {
case OUTPUT_TYPE_CLEAN:
handleCleanOutput(b, sources, dest, appName);
break;
case OUTPUT_TYPE_JAVASCRIPT:
handleJavascriptOutput(b, sources, dest, appName);
break;
default:
handleDefaultOutput(b, sources, dest);
}
Expand Down Expand Up @@ -250,6 +264,18 @@ private static void handleCleanOutput(ByteCodeTranslator b, File[] sources, File
writeCmakeProject(root, srcRoot, appName);
}

private static void handleJavascriptOutput(ByteCodeTranslator b, File[] sources, File dest, String appName) throws Exception {
File root = new File(dest, "dist");
root.mkdirs();
if(verbose) {
System.out.println("Root is: " + root.getAbsolutePath());
}
File srcRoot = new File(root, appName + "-js");
srcRoot.mkdirs();
b.execute(sources, srcRoot);
Parser.writeOutput(srcRoot);
}

private static void handleIosOutput(ByteCodeTranslator b, File[] sources, File dest, String appName, String appPackageName, String appDisplayName, String appVersion, String appType, String addFrameworks) throws Exception {
File root = new File(dest, "dist");
root.mkdirs();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,44 @@ public void addToConstantPool() {
public boolean isSynchronizedMethod() {
return synchronizedMethod;
}

public List<Instruction> getInstructions() {
return instructions;
}

public List<ByteCodeMethodArg> getArguments() {
return arguments;
}

public ByteCodeMethodArg getReturnType() {
return returnType;
}

public int getMaxStack() {
return maxStack;
}

public int getMaxLocals() {
return maxLocals;
}

public boolean isConstructor() {
return constructor;
}

public String getMethodIdentifier() {
StringBuilder b = new StringBuilder();
b.append(clsName).append("_");
if(methodName.equals("<init>")) {
b.append("__INIT__");
} else if(methodName.equals("<clinit>")) {
b.append("__CLINIT__");
} else {
b.append(getCMethodName());
}
appendMethodSignatureSuffixFromDesc(desc, b, new ArrayList<String>());
return b.toString();
}

private boolean hasLocalVariableWithIndex(char qualifier, int index) {
for (LocalVariable lv : localVariables) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package com.codename1.tools.translator;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;

final class JavascriptBundleWriter {
private static final String RESOURCE_ROOT = "/javascript/";

private JavascriptBundleWriter() {
}

static void write(File outputDirectory, List<ByteCodeClass> classes) throws IOException {
writeRuntime(outputDirectory);
writeTranslatedClasses(outputDirectory, classes);
writeWorker(outputDirectory);
writeIndex(outputDirectory);
}

private static void writeRuntime(File outputDirectory) throws IOException {
writeResource(outputDirectory, "parparvm_runtime.js", "parparvm_runtime.js");
}

private static void writeTranslatedClasses(File outputDirectory, List<ByteCodeClass> classes) throws IOException {
StringBuilder out = new StringBuilder();
for (ByteCodeClass cls : classes) {
out.append(cls.generateJavascriptCode(classes)).append('\n');
}
ByteCodeClass mainClass = ByteCodeClass.getMainClass();
if (mainClass != null) {
out.append("jvm.setMain(\"").append(mainClass.getClsName()).append("\", \"")
.append(JavascriptNameUtil.methodIdentifier(mainClass.getClsName(), "main", "([Ljava/lang/String;)V"))
.append("\");\n");
}
Files.write(new File(outputDirectory, "translated_app.js").toPath(),
out.toString().getBytes(StandardCharsets.UTF_8));
}

private static void writeWorker(File outputDirectory) throws IOException {
List<String> nativeScripts = new ArrayList<String>();
File[] files = outputDirectory.listFiles();
if (files != null) {
for (File file : files) {
String name = file.getName();
if (!name.endsWith(".js")) {
continue;
}
if ("parparvm_runtime.js".equals(name) || "translated_app.js".equals(name) || "worker.js".equals(name)) {
continue;
}
nativeScripts.add(name);
}
}

StringBuilder imports = new StringBuilder();
imports.append("importScripts('parparvm_runtime.js');\n");
for (String script : nativeScripts) {
imports.append("importScripts('").append(script).append("');\n");
}
imports.append("importScripts('translated_app.js');\n");

String worker = loadResource("worker.js").replace("/*__IMPORTS__*/", imports.toString().trim());
Files.write(new File(outputDirectory, "worker.js").toPath(), worker.getBytes(StandardCharsets.UTF_8));
}

private static void writeIndex(File outputDirectory) throws IOException {
writeResource(outputDirectory, "index.html", "index.html");
}

private static void writeResource(File outputDirectory, String targetName, String resourceName) throws IOException {
Files.write(new File(outputDirectory, targetName).toPath(),
loadResource(resourceName).getBytes(StandardCharsets.UTF_8));
}

private static String loadResource(String resourceName) throws IOException {
InputStream input = JavascriptBundleWriter.class.getResourceAsStream(RESOURCE_ROOT + resourceName);
if (input == null) {
throw new IOException("Missing javascript backend resource " + resourceName);
}
try {
byte[] data = new byte[8192];
StringBuilder out = new StringBuilder();
int len;
while ((len = input.read(data)) > -1) {
out.append(new String(data, 0, len, StandardCharsets.UTF_8));
}
return out.toString();
} finally {
input.close();
}
}
}
Loading
Loading