1
0
mirror of https://github.com/quinton-ashley/java2js synced 2024-12-29 10:11:54 +01:00
This commit is contained in:
Quinton Ashley 2021-09-24 00:36:29 -05:00
parent e2ed130148
commit 159919e856
29 changed files with 93 additions and 119 deletions

20
ide.js
View File

@ -1,9 +1,13 @@
window.ide = {}; (async () => {
ide.log = document.getElementById('javaConsole'); window.ide = {};
ide.file0 = document.getElementById('javaFile'); ide.log = document.getElementById('javaConsole');
ide.file0 = document.getElementById('javaFile');
ide.file0.onchange = () => { await jdk.init();
ide.log.value = '';
let file = ide.file0.value; ide.file0.onchange = () => {
jdk.run(file); ide.log.value = '';
}; let file = ide.file0.value;
jdk.run(file);
};
})();

122
jdk.js
View File

@ -45,7 +45,9 @@
/* JDK implementation in modern JavaScript */ /* JDK implementation in modern JavaScript */
class JDK { class JDK {
constructor() { constructor() {}
async init() {
this.java = {}; this.java = {};
let pkgs = ['com', 'lang', 'org', 'io', 'util']; let pkgs = ['com', 'lang', 'org', 'io', 'util'];
for (let pkg of pkgs) { for (let pkg of pkgs) {
@ -76,50 +78,23 @@
for (let name of names) { for (let name of names) {
lang.push('java.lang.' + name); lang.push('java.lang.' + name);
} }
this.import(lang); await this.import(lang);
} catch (e) {} } catch (e) {}
// stub main for now // stub main for now
this.main = () => {}; this.main = () => {};
this.load();
} }
load() { // async load() {
let ready = 0; // // load all imported classes
// load all imported classes // for (let className in this.imports) {
for (let className in this.imports) { // let imp = this.imports[className];
let imp = this.imports[className]; // imp.classPath ??= className.split('.');
if (imp.classPath) { // await imp.load();
imp.classPath = className.split('.'); // }
}
if (imp.ready) { // this.launch();
ready++; // }
continue;
}
if (imp.load) {
try {
imp.load();
} catch (e) {
console.log(e);
continue;
}
imp.load = null;
imp.ready = true;
ready++;
}
}
// some classes may load slower than others,
// wait for them all before launching the Java program
if (ready != Object.keys(this.imports).length) {
let _this = this;
setTimeout(() => {
_this.load();
}, 100);
} else {
this.launch();
}
}
launch() { launch() {
// make java.lang classes global // make java.lang classes global
@ -144,15 +119,15 @@
return _class; return _class;
} }
import(classNames) { async import(classNames) {
if (!classNames) return; if (!classNames) return;
if (typeof classNames == 'string') { if (typeof classNames == 'string') {
classNames = [classNames]; classNames = [classNames];
} }
let ready = 0; let classes = [];
for (let className of classNames) { for (let className of classNames) {
log('importing ' + className);
let imp = this.imports[className]; let imp = this.imports[className];
if (imp) { if (imp) {
// class is ready for use // class is ready for use
@ -170,34 +145,29 @@
} }
src += '.js'; src += '.js';
const getJS = new Promise((resolve, reject) => { const loadJS = () => {
const script = document.createElement('script'); return new Promise((resolve, reject) => {
document.body.appendChild(script); const script = document.createElement('script');
script.onload = resolve; document.body.appendChild(script);
script.onerror = reject; script.onload = resolve;
script.async = true; script.onerror = reject;
script.src = src; script.async = true;
}); script.src = src;
});
};
getJS.then(() => {}); await loadJS();
}
if (ready != classNames.length) { await imp.load();
throw 'loading java classes';
}
let classes = [];
for (let className of classNames) {
let imp = this.imports[className];
classes.push(this.getClass(imp.classPath)); classes.push(this.getClass(imp.classPath));
} }
if (classNames.length == 1) {
classes = classes[0]; if (classNames.length == 1) classes = classes[0];
}
return classes; return classes;
} }
run(file) { async run(file) {
let classLine = file.indexOf('public class'); let classLine = file.indexOf('public class');
let imports = file.slice(0, classLine); let imports = file.slice(0, classLine);
imports = imports.match(/(?<=^import )[^;]*/gm) || []; imports = imports.match(/(?<=^import )[^;]*/gm) || [];
@ -205,17 +175,6 @@
let userName = window?.QuintOS?.userName || 'quinton-ashley'; 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));
let prefix = `(jdk.imports['com.${userName}.${className}'] = {}).load = () => {\n\n`;
// handle Java class imports
for (let i = 0; i < imports.length; i++) {
let imp = imports[i];
let impPath = imp.split('.');
let impName = impPath[impPath.length - 1];
prefix += `let ${impName} = jdk.import('${imp}');\n`;
}
prefix += '\n';
// hacky support for Java 15 triple quotes // hacky support for Java 15 triple quotes
file = file.replaceAll(/"""([^"]*)"""/g, (match, str) => { file = file.replaceAll(/"""([^"]*)"""/g, (match, str) => {
str = str.replaceAll(/(.*)(\n|$)/g, '"$1\\n"+').slice(0, -1); str = str.replaceAll(/(.*)(\n|$)/g, '"$1\\n"+').slice(0, -1);
@ -234,8 +193,6 @@
// log(file); // log(file);
let suffix = `\njdk.main = ${className}.main;\n}`;
window.file0 = file; window.file0 = file;
let trans = java_to_javascript(file); let trans = java_to_javascript(file);
@ -245,14 +202,27 @@
trans = trans.replace(/(\([^\)]*\) =>)/gm, 'async $1'); trans = trans.replace(/(\([^\)]*\) =>)/gm, 'async $1');
trans = trans.replace(/([\w_\$]+\.next(Int|Float|Double|Line|Short|Long)*\(\))/gm, 'await $1'); trans = trans.replace(/([\w_\$]+\.next(Int|Float|Double|Line|Short|Long)*\(\))/gm, 'await $1');
let prefix = `((jdk.imports['com.${userName}.${className}'] = {}).load = async () => {\n\n`;
// handle Java class imports
for (let i = 0; i < imports.length; i++) {
let imp = imports[i];
let impPath = imp.split('.');
let impName = impPath[impPath.length - 1];
prefix += `let ${impName} = await jdk.import('${imp}');\n`;
}
prefix += '\n';
let suffix = `\njdk.main = ${className}.main;\njdk.launch();\n})();`;
trans = prefix + trans + suffix; trans = prefix + trans + suffix;
log(trans); log(trans);
try { try {
eval(trans); eval(trans);
this.load();
} catch (e) { } catch (e) {
console.error(e);
if (window?.ide) ide.log.value += e; if (window?.ide) ide.log.value += e;
} }
} }

View File

@ -1,4 +1,4 @@
jdk.imports['java.io.File'].load = () => { jdk.imports['java.io.File'].load = async () => {
class File { class File {
constructor(file) { constructor(file) {
this.absPath = file; this.absPath = file;

View File

@ -1,4 +1,4 @@
jdk.imports['java.io.InputStream'].load = () => { jdk.imports['java.io.InputStream'].load = async () => {
class InputStream { class InputStream {
constructor() { constructor() {
this.reset(); this.reset();

View File

@ -1,4 +1,4 @@
jdk.imports['java.io.PrintStream'].load = () => { jdk.imports['java.io.PrintStream'].load = async () => {
class PrintStream { class PrintStream {
constructor() { constructor() {
this.log = ''; this.log = '';

View File

@ -1,4 +1,4 @@
jdk.imports['java.lang.Character'].load = () => { jdk.imports['java.lang.Character'].load = async () => {
class Character {} class Character {}
Character.isDigit = (c) => { Character.isDigit = (c) => {
c = c.charCodeAt(0); c = c.charCodeAt(0);

View File

@ -1,4 +1,4 @@
jdk.imports['java.lang.Double'].load = () => { jdk.imports['java.lang.Double'].load = async () => {
class Double { class Double {
constructor() { constructor() {
throw 'new Double() not supported'; throw 'new Double() not supported';

View File

@ -1,4 +1,4 @@
jdk.imports['java.lang.Float'].load = () => { jdk.imports['java.lang.Float'].load = async () => {
class Float {} class Float {}
Float.parseFloat = (d) => { Float.parseFloat = (d) => {
return parseFloat(d); return parseFloat(d);

View File

@ -1,4 +1,4 @@
jdk.imports['java.lang.Integer'].load = () => { jdk.imports['java.lang.Integer'].load = async () => {
class Integer {} class Integer {}
Integer.parseInt = (d) => { Integer.parseInt = (d) => {
return parseInt(d); return parseInt(d);

View File

@ -1,4 +1,4 @@
jdk.imports['java.lang.Long'].load = () => { jdk.imports['java.lang.Long'].load = async () => {
class Long {} class Long {}
Long.parseLong = (d) => { Long.parseLong = (d) => {
return parseInt(d); return parseInt(d);

View File

@ -1,4 +1,4 @@
jdk.imports['java.lang.Short'].load = () => { jdk.imports['java.lang.Short'].load = async () => {
class Short {} class Short {}
Short.parseShort = (d) => { Short.parseShort = (d) => {
return parseInt(d); return parseInt(d);

View File

@ -1,4 +1,4 @@
jdk.imports['java.lang.String'].load = () => {}; jdk.imports['java.lang.String'].load = async () => {};
// String is special, I just extended js String prototype // String is special, I just extended js String prototype
String.prototype.hashCode = () => { String.prototype.hashCode = () => {
let h = this._hashCode; let h = this._hashCode;

View File

@ -1,4 +1,4 @@
jdk.imports['java.lang.StringBuilder'].load = () => { jdk.imports['java.lang.StringBuilder'].load = async () => {
class StringBuilder { class StringBuilder {
constructor() { constructor() {
this._str = ''; this._str = '';

View File

@ -1,7 +1,7 @@
jdk.imports['java.lang.System'].load = () => { jdk.imports['java.lang.System'].load = async () => {
const Formatter = jdk.import('java.util.Formatter'); const Formatter = await jdk.import('java.util.Formatter');
const InputStream = jdk.import('java.io.InputStream'); const InputStream = await jdk.import('java.io.InputStream');
const PrintStream = jdk.import('java.io.PrintStream'); const PrintStream = await jdk.import('java.io.PrintStream');
class System {} class System {}

View File

@ -1,4 +1,4 @@
jdk.imports['java.lang.Thread'].load = () => { jdk.imports['java.lang.Thread'].load = async () => {
class Thread { class Thread {
async sleep(millis) { async sleep(millis) {
await setTimeout(millis); await setTimeout(millis);

View File

@ -1,5 +1,5 @@
jdk.imports['java.util.AbstractList'].load = () => { jdk.imports['java.util.AbstractList'].load = async () => {
const Itr = jdk.import('java.util.Itr'); const Itr = await jdk.import('java.util.Itr');
class AbstractList { class AbstractList {
constructor() { constructor() {

View File

@ -1,5 +1,5 @@
jdk.imports['java.util.ArrayList'].load = () => { jdk.imports['java.util.ArrayList'].load = async () => {
let AbstractList = jdk.import('java.util.AbstractList'); let AbstractList = await jdk.import('java.util.AbstractList');
class ArrayList extends AbstractList { class ArrayList extends AbstractList {
constructor(...args) { constructor(...args) {

View File

@ -1,4 +1,4 @@
jdk.imports['java.util.Arrays'].load = () => { jdk.imports['java.util.Arrays'].load = async () => {
class Arrays { class Arrays {
fill(data, begin, nbElem, param) { fill(data, begin, nbElem, param) {
const max = begin + nbElem; const max = begin + nbElem;

View File

@ -1,4 +1,4 @@
jdk.imports['java.util.Collections'].load = () => { jdk.imports['java.util.Collections'].load = async () => {
class Collections { class Collections {
sort(list) { sort(list) {
if (!list.size()) return; if (!list.size()) return;

View File

@ -1,5 +1,5 @@
jdk.imports['java.util.Formatter'].load = () => { jdk.imports['java.util.Formatter'].load = async () => {
const IllegalFormatException = jdk.import('java.util.IllegalFormatException'); const IllegalFormatException = await jdk.import('java.util.IllegalFormatException');
class Formatter { class Formatter {
format(format, ...args) { format(format, ...args) {

View File

@ -1,4 +1,4 @@
jdk.imports['java.util.HashMap'].load = () => { jdk.imports['java.util.HashMap'].load = async () => {
class HashMap { class HashMap {
constructor() { constructor() {
this.content = {}; this.content = {};

View File

@ -1,4 +1,4 @@
jdk.imports['java.util.HashSet'].load = () => { jdk.imports['java.util.HashSet'].load = async () => {
class HashSet { class HashSet {
constructor() { constructor() {
this.content = {}; this.content = {};

View File

@ -1,4 +1,4 @@
jdk.imports['java.util.IllegalFormatException'].load = () => { jdk.imports['java.util.IllegalFormatException'].load = async () => {
// TODO import and extend exception // TODO import and extend exception
class IllegalFormatException { class IllegalFormatException {

View File

@ -1,4 +1,4 @@
jdk.imports['java.util.Itr'].load = () => { jdk.imports['java.util.Itr'].load = async () => {
class Itr { class Itr {
constructor(list) { constructor(list) {
this.cursor = 0; this.cursor = 0;

View File

@ -1,5 +1,5 @@
jdk.imports['java.util.LinkedList'].load = () => { jdk.imports['java.util.LinkedList'].load = async () => {
let AbstractList = jdk.import('java.util.AbstractList'); let AbstractList = await jdk.import('java.util.AbstractList');
class LinkedList extends AbstractList { class LinkedList extends AbstractList {
constructor(...args) { constructor(...args) {

View File

@ -1,4 +1,4 @@
jdk.imports['java.util.Random'].load = () => { jdk.imports['java.util.Random'].load = async () => {
class Random { class Random {
constructor() { constructor() {
this.seed = undefined; this.seed = undefined;

View File

@ -1,5 +1,5 @@
jdk.imports['java.util.Scanner'].load = () => { jdk.imports['java.util.Scanner'].load = async () => {
const File = jdk.import('java.io.File'); const File = await jdk.import('java.io.File');
class Scanner { class Scanner {
constructor(input) { constructor(input) {

View File

@ -1,4 +1,4 @@
jdk.imports['java.util.Stack'].load = () => { jdk.imports['java.util.Stack'].load = async () => {
class Stack { class Stack {
constructor() { constructor() {
this.content = new Array(); this.content = new Array();

View File

@ -1,6 +1,6 @@
{ {
"name": "java2js", "name": "java2js",
"version": "1.0.3", "version": "1.0.4",
"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": "java2js.js", "main": "java2js.js",
"scripts": { "scripts": {