mirror of
https://github.com/quinton-ashley/java2js
synced 2024-12-29 10:11:54 +01:00
1.1.9
This commit is contained in:
parent
ba69a3c8b0
commit
8de0c299bb
31
README.md
31
README.md
@ -1,8 +1,10 @@
|
|||||||
# Java to Javascript
|
# Java to JavaScript (java2js)
|
||||||
|
|
||||||
I've built on top of the [java-to-javascript](https://github.com/wyattades/java-to-javascript) transpiler by @wyattades and got inspiration from the barebones JDK (Java Development Kit) implementation in [java2javascript](https://github.com/java2script/java2script) by @BobHanson, @zhourenjian, @abego, and others.
|
`java2js` can translate simple Java programs to JavaScript and runs them using a JavaScript based JDK.
|
||||||
|
|
||||||
I created this project so intro level computer science students could write Java code but still use my [QuintOS](https://github.com/quinton-ashley/quintos) retro game engine library, which is web based. Yes, I went to all this trouble just so my students don't have to run their programs in a boring Java console! To achieve this I've been working on a JDK implementation in modern Javascript.
|
I made significant improvements to the [java-to-javascript](https://github.com/wyattades/java-to-javascript) transpiler by @wyattades. I also did a modern JS implementation of the fundamental classes in the JDK (Java Development Kit), inspired by [java2javascript](https://github.com/java2script/java2script) by @BobHanson, @zhourenjian, @abego, and others.
|
||||||
|
|
||||||
|
I created this project so intro level computer science students could write Java code but still use my [QuintOS](https://github.com/quinton-ashley/quintos) retro game engine library, which is web based.
|
||||||
|
|
||||||
## Java Classes Included in the JS JDK
|
## Java Classes Included in the JS JDK
|
||||||
|
|
||||||
@ -37,13 +39,13 @@ I created this project so intro level computer science students could write Java
|
|||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
### jdk.init(root)
|
### await jdk.init(root)
|
||||||
|
|
||||||
- root (optional) can be a local path or url to the parent folder of the JS `jdk` folder, by default it links to 'https://unpkg.com/java2js' (this package) so you don't need to change it
|
- root (optional) path to the parent folder of the JS `jdk` folder, by default it is `./` you could also link to this package online 'https://unpkg.com/java2js'
|
||||||
|
|
||||||
This function imports much of the standard Java lang classes into the global scope. You must use it before translating or running files.
|
This function imports much of the standard Java lang classes into the global scope. You must use it before translating or running files.
|
||||||
|
|
||||||
### jdk.translate(javaFile)
|
### await jdk.translate(javaFile)
|
||||||
|
|
||||||
- javaFile is a string with contents of a Java file
|
- javaFile is a string with contents of a Java file
|
||||||
|
|
||||||
@ -59,9 +61,22 @@ Loads the JS class file but doesn't run the main method.
|
|||||||
|
|
||||||
Runs the main method with optional JVM arguments.
|
Runs the main method with optional JVM arguments.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- imports
|
||||||
|
- static classes
|
||||||
|
- static methods
|
||||||
|
- array literals
|
||||||
|
- arrays with initial size
|
||||||
|
- two dimensional arrays
|
||||||
|
- lambda arrow functions
|
||||||
|
- triple quotes
|
||||||
|
|
||||||
## Known limitations
|
## Known limitations
|
||||||
|
|
||||||
- casting to int truncation workaround requires parenthesis around the number being cast `int x = (int) (Math.random() * 100);`
|
- not very good error reporting
|
||||||
|
|
||||||
|
- casting to int (truncation) requires parenthesis around the number being cast `int x = (int) (Math.random() * 100);`
|
||||||
|
|
||||||
- no support for method overloading, though a workaround might be possible by making a function with the og name route to each of the variations of the overloaded function
|
- no support for method overloading, though a workaround might be possible by making a function with the og name route to each of the variations of the overloaded function
|
||||||
|
|
||||||
@ -71,7 +86,7 @@ Runs the main method with optional JVM arguments.
|
|||||||
|
|
||||||
- no third level static classes
|
- no third level static classes
|
||||||
|
|
||||||
- not much error checking
|
- no method can be named `.length()` because it will be replaced with `.length` for getting the length of Strings in JS
|
||||||
|
|
||||||
## Contribute
|
## Contribute
|
||||||
|
|
||||||
|
7
ide.js
7
ide.js
@ -3,8 +3,11 @@
|
|||||||
await jdk.init();
|
await jdk.init();
|
||||||
|
|
||||||
let file0 = document.getElementById('javaFile');
|
let file0 = document.getElementById('javaFile');
|
||||||
file0.onchange = () => {
|
file0.onchange = async () => {
|
||||||
jdk.log.value = '';
|
jdk.log.value = '';
|
||||||
jdk.run(file0.value);
|
let translation = await jdk.translate(file0.value);
|
||||||
|
console.log(translation);
|
||||||
|
jdk.load(translation);
|
||||||
|
jdk.run();
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
52
jdk.js
52
jdk.js
@ -48,7 +48,7 @@
|
|||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
async init(root) {
|
async init(root) {
|
||||||
this.root = root || 'https://unpkg.com/java2js';
|
this.root = root || './';
|
||||||
this.java = {};
|
this.java = {};
|
||||||
let pkgs = ['com', 'io', 'lang', 'org', 'security', 'time', 'util'];
|
let pkgs = ['com', 'io', 'lang', 'org', 'security', 'time', 'util'];
|
||||||
for (let pkg of pkgs) {
|
for (let pkg of pkgs) {
|
||||||
@ -98,17 +98,6 @@
|
|||||||
this.main = () => {};
|
this.main = () => {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// async load() {
|
|
||||||
// // load all imported classes
|
|
||||||
// for (let className in this.imports) {
|
|
||||||
// let imp = this.imports[className];
|
|
||||||
// imp.classPath ??= className.split('.');
|
|
||||||
// await imp.load();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// this.launch();
|
|
||||||
// }
|
|
||||||
|
|
||||||
run(jvmArgs) {
|
run(jvmArgs) {
|
||||||
this.main(jvmArgs);
|
this.main(jvmArgs);
|
||||||
}
|
}
|
||||||
@ -148,9 +137,9 @@
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const script = document.createElement('script');
|
const script = document.createElement('script');
|
||||||
document.body.appendChild(script);
|
document.body.appendChild(script);
|
||||||
|
script.async = true;
|
||||||
script.onload = resolve;
|
script.onload = resolve;
|
||||||
script.onerror = reject;
|
script.onerror = reject;
|
||||||
script.async = true;
|
|
||||||
script.src = src;
|
script.src = src;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -172,11 +161,14 @@
|
|||||||
// bodge fix to avoid getting the index of a commented out class
|
// bodge fix to avoid getting the index of a commented out class
|
||||||
// (only works with normal comments)
|
// (only works with normal comments)
|
||||||
let classLine = file.indexOf('\npublic class');
|
let classLine = file.indexOf('\npublic class');
|
||||||
if (classLine < 0) classLine = file.indexOf('public class');
|
if (classLine < 0) {
|
||||||
|
classLine = file.indexOf('public class');
|
||||||
|
} else {
|
||||||
|
classLine += 1;
|
||||||
|
}
|
||||||
let imports = file.slice(0, classLine);
|
let imports = file.slice(0, classLine);
|
||||||
imports = imports.match(/(?<=^import )[^;]*/gm) || [];
|
imports = imports.match(/(?<=^import )[^;]*/gm) || [];
|
||||||
|
|
||||||
let userName = window?.QuintOS?.userName || 'quinton-ashley';
|
|
||||||
let className = file.slice(classLine + 13, file.indexOf(' {', classLine + 13));
|
let className = file.slice(classLine + 13, file.indexOf(' {', classLine + 13));
|
||||||
|
|
||||||
// workaround hack for converting triple quotes to a normal string
|
// workaround hack for converting triple quotes to a normal string
|
||||||
@ -229,7 +221,6 @@
|
|||||||
|
|
||||||
// cast to int, truncates the number (just removes decimal value)
|
// cast to int, truncates the number (just removes decimal value)
|
||||||
file = file.replace(/\(int\)\s*/gm, 'Math.floor');
|
file = file.replace(/\(int\)\s*/gm, 'Math.floor');
|
||||||
file = file.replace(/\(int\)\s*\-/gm, 'Math.ceil');
|
|
||||||
|
|
||||||
let trans = await java_to_javascript(file);
|
let trans = await java_to_javascript(file);
|
||||||
|
|
||||||
@ -269,21 +260,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
load(trans) {
|
load(trans) {
|
||||||
return new Promise(async (resolve, reject) => {
|
const script = document.createElement('script');
|
||||||
const script = document.createElement('script');
|
script.innerHTML = trans;
|
||||||
script.async = false;
|
document.body.appendChild(script);
|
||||||
script.onload = function () {
|
|
||||||
// log('loaded: ' + src);
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
script.onerror = (e) => {
|
|
||||||
reject(e);
|
|
||||||
};
|
|
||||||
|
|
||||||
script.innerHTML = trans;
|
|
||||||
|
|
||||||
document.body.appendChild(script);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
window.jdk = new JDK();
|
window.jdk = new JDK();
|
||||||
@ -19131,9 +19110,13 @@
|
|||||||
|
|
||||||
let asyncMethods = [];
|
let asyncMethods = [];
|
||||||
if (typeof QuintOS != 'undefined') {
|
if (typeof QuintOS != 'undefined') {
|
||||||
|
// asyncMethods = {
|
||||||
|
// Sprite: ['move']
|
||||||
|
// };
|
||||||
asyncMethods = [
|
asyncMethods = [
|
||||||
'alert',
|
'alert',
|
||||||
'delay',
|
'delay',
|
||||||
|
'erase',
|
||||||
'eraseRect',
|
'eraseRect',
|
||||||
'frame',
|
'frame',
|
||||||
'move',
|
'move',
|
||||||
@ -19212,7 +19195,7 @@
|
|||||||
return `${parseExpr(expr.leftOperand)} ${op} ${parseExpr(expr.rightOperand)}`;
|
return `${parseExpr(expr.leftOperand)} ${op} ${parseExpr(expr.rightOperand)}`;
|
||||||
case 'MethodInvocation':
|
case 'MethodInvocation':
|
||||||
let str = '';
|
let str = '';
|
||||||
if (asyncMethods.includes(expr.name.identifier)) {
|
if (asyncMethods.includes(expr.name.identifier) && !expr.isInConstructor) {
|
||||||
str += 'await ';
|
str += 'await ';
|
||||||
}
|
}
|
||||||
if (expr.expression) {
|
if (expr.expression) {
|
||||||
@ -19354,10 +19337,13 @@
|
|||||||
const statements = [];
|
const statements = [];
|
||||||
|
|
||||||
for (const stat of block.statements) {
|
for (const stat of block.statements) {
|
||||||
|
if (method && stat.node == 'ExpressionStatement') {
|
||||||
|
stat.expression.isInConstructor = method.constructor;
|
||||||
|
}
|
||||||
const str = parseStatement(stat);
|
const str = parseStatement(stat);
|
||||||
const arr = Array.isArray(str) ? str : [str];
|
const arr = Array.isArray(str) ? str : [str];
|
||||||
statements.push(...arr.map(semicolon));
|
statements.push(...arr.map(semicolon));
|
||||||
if (method && !method.isAsync && statements.join('').includes('await')) {
|
if (method && !method.isAsync && !method.constructor && statements.join('').includes('await')) {
|
||||||
asyncMethods.push(method.name.identifier);
|
asyncMethods.push(method.name.identifier);
|
||||||
method.isAsync = true;
|
method.isAsync = true;
|
||||||
}
|
}
|
||||||
|
@ -43,10 +43,10 @@ jdk.imports['java.io.PrintStream'].load = async () => {
|
|||||||
}
|
}
|
||||||
if (ln) str += '\n';
|
if (ln) str += '\n';
|
||||||
this.log += str;
|
this.log += str;
|
||||||
if (window?.ide) {
|
if (jdk.log) {
|
||||||
ide.log.value += str;
|
jdk.log.value += str;
|
||||||
this._onPrint(str.length);
|
|
||||||
}
|
}
|
||||||
|
this._onPrint(str.length);
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "java2js",
|
"name": "java2js",
|
||||||
"version": "1.1.8",
|
"version": "1.1.9",
|
||||||
"description": "Converts Java to JavaScript with support for p5.js and QuintOS.",
|
"description": "Converts Java to JavaScript with support for p5.js and QuintOS.",
|
||||||
"main": "jdk.js",
|
"main": "jdk.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user