mirror of
https://github.com/quinton-ashley/java2js
synced 2024-12-29 10:11:54 +01:00
1.0.1
This commit is contained in:
commit
fcf49e5a8d
0
LICENSE.md
Normal file
0
LICENSE.md
Normal file
11
README.md
Normal file
11
README.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Java to Javascript for QuintOS
|
||||
|
||||
I've built on top of the "Java to Javascript" transpiler by @wyattades and got inspiration from the JRE implementation in "java2javascript" by @BobHanson and others.
|
||||
|
||||
The purpose of this project was to allow intro level CS students to write Java code but still use my QuintOS library which is web based instead of just having them run their programs in a Java console which is boring. I made a barebones JRE implementation in modern Javascript to acheive this.
|
||||
|
||||
## Known limitations
|
||||
|
||||
- casting to int requires putting the element being cast in parenthesis
|
||||
|
||||
- no support for method overloading
|
38
demo.html
Executable file
38
demo.html
Executable file
@ -0,0 +1,38 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>java2js test</title>
|
||||
<style>
|
||||
body,
|
||||
textarea {
|
||||
background: #000;
|
||||
color: #eee;
|
||||
}
|
||||
|
||||
textarea {
|
||||
-moz-tab-size: 2;
|
||||
-o-tab-size: 2;
|
||||
tab-size: 2;
|
||||
}
|
||||
|
||||
#javaFile {
|
||||
width: 47vw;
|
||||
height: 90vh;
|
||||
}
|
||||
|
||||
#javaConsole {
|
||||
width: 47vw;
|
||||
height: 90vh;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<textarea id="javaFile" spellcheck="false" autocomplete="off" autocorrect="off" autocapitalize="off"></textarea>
|
||||
<textarea id="javaConsole" spellcheck="false" autocomplete="off" autocorrect="off" autocapitalize="off"></textarea>
|
||||
<script type="text/javascript" src="jre.js"></script>
|
||||
<script type="text/javascript" src="ide.js"></script>
|
||||
<script type="text/javascript" src="transpiler.js"></script>
|
||||
</body>
|
||||
</html>
|
76
ide.js
Normal file
76
ide.js
Normal file
@ -0,0 +1,76 @@
|
||||
function ide(require, module, exports) {
|
||||
const log = console.log;
|
||||
|
||||
window.java = {};
|
||||
java.log = document.getElementById('javaConsole');
|
||||
java.file0 = document.getElementById('javaFile');
|
||||
|
||||
window.java2js = (file) => {
|
||||
const java_to_javascript = require('java-to-javascript');
|
||||
|
||||
let classLine = file.indexOf('public class');
|
||||
let imports = file.slice(0, classLine);
|
||||
imports = imports.match(/(?<=^import )[^;]*/gm) || [];
|
||||
|
||||
let userName = window?.QuintOS?.userName || 'quinton-ashley';
|
||||
let className = file.slice(classLine + 13, file.indexOf(' {', classLine + 13));
|
||||
|
||||
let prefix = `(jre.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} = jre.import('${imp}');\n`;
|
||||
}
|
||||
prefix += '\n';
|
||||
|
||||
// hacky support for Java 15 triple quotes
|
||||
file = file.replaceAll(/"""([^"]*)"""/g, (match, str) => {
|
||||
str = str.replaceAll(/(.*)(\n|$)/g, '"$1\\n"+').slice(0, -1);
|
||||
return str;
|
||||
});
|
||||
|
||||
// hacky support for Array literals
|
||||
file = file.replaceAll(/=\s*new \w*\[\]\s*\{/g, '= {');
|
||||
|
||||
// convert string .length() method
|
||||
file = file.replaceAll(/\.length\(\)/g, '.length');
|
||||
|
||||
// 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.ceil');
|
||||
|
||||
// log(file);
|
||||
|
||||
let suffix = `\njre.main = ${className}.main;\n}`;
|
||||
|
||||
window.file0 = file;
|
||||
|
||||
let trans = java_to_javascript(file);
|
||||
|
||||
// log(trans);
|
||||
|
||||
trans = trans.replace(/(\([^\)]*\) =>)/gm, 'async $1');
|
||||
trans = trans.replace(/([\w_\$]+\.next(Int|Float|Double|Line|Short|Long)*\(\))/gm, 'await $1');
|
||||
|
||||
trans = prefix + trans + suffix;
|
||||
|
||||
log(trans);
|
||||
|
||||
try {
|
||||
eval(trans);
|
||||
jre.run();
|
||||
} catch (e) {
|
||||
java.log.value += e;
|
||||
}
|
||||
};
|
||||
|
||||
java.file0.onchange = () => {
|
||||
java.log.value = '';
|
||||
let file = java.file0.value;
|
||||
|
||||
java2js(file);
|
||||
};
|
||||
}
|
141
jre.js
Executable file
141
jre.js
Executable file
@ -0,0 +1,141 @@
|
||||
class JRE {
|
||||
constructor() {
|
||||
this.java = {};
|
||||
let pkgs = ['com', 'lang', 'org', 'io', 'util'];
|
||||
for (let pkg of pkgs) {
|
||||
this.java[pkg] = {};
|
||||
}
|
||||
this.imports = {};
|
||||
|
||||
try {
|
||||
let names = [
|
||||
'Character', 'Double', 'Float', 'Integer', 'Long', 'Short', 'String',
|
||||
'StringBuilder', 'System', 'Thread'
|
||||
];
|
||||
let lang = [];
|
||||
for (let name of names) {
|
||||
lang.push('java.lang.' + name);
|
||||
}
|
||||
this.import(lang);
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
|
||||
this.main = () => {};
|
||||
this.run();
|
||||
}
|
||||
|
||||
run() {
|
||||
this.load();
|
||||
}
|
||||
|
||||
load() {
|
||||
let ready = 0;
|
||||
for (let className in this.imports) {
|
||||
let imp = this.imports[className];
|
||||
if (imp.classPath) {
|
||||
imp.classPath = className.split('.');
|
||||
}
|
||||
if (imp.ready) {
|
||||
ready++;
|
||||
continue;
|
||||
}
|
||||
if (imp.load) {
|
||||
try {
|
||||
imp.load();
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
continue;
|
||||
}
|
||||
imp.load = null;
|
||||
imp.ready = true;
|
||||
ready++;
|
||||
}
|
||||
}
|
||||
if (ready != Object.keys(this.imports).length) {
|
||||
let _this = this;
|
||||
setTimeout(() => {
|
||||
_this.load();
|
||||
}, 100);
|
||||
} else {
|
||||
this.launch();
|
||||
}
|
||||
}
|
||||
|
||||
launch() {
|
||||
// make java.lang classes global
|
||||
for (let name in this.java.lang) {
|
||||
if (name == 'String') continue;
|
||||
window[name] = this.java.lang[name];
|
||||
}
|
||||
|
||||
System.in.reset();
|
||||
System.out.reset();
|
||||
|
||||
this.main(this.vmArgs);
|
||||
}
|
||||
|
||||
getClass(classPath) {
|
||||
let _class = this;
|
||||
|
||||
for (let part of classPath) {
|
||||
_class = _class[part];
|
||||
if (!_class) return;
|
||||
}
|
||||
return _class;
|
||||
}
|
||||
|
||||
import(classNames) {
|
||||
if (!classNames) return;
|
||||
if (typeof classNames == 'string') {
|
||||
classNames = [classNames];
|
||||
}
|
||||
|
||||
let ready = 0;
|
||||
|
||||
for (let className of classNames) {
|
||||
let imp = this.imports[className];
|
||||
if (imp) {
|
||||
// class is ready for use
|
||||
if (imp.ready) ready++;
|
||||
// class file loaded but not ready yet
|
||||
continue;
|
||||
}
|
||||
imp = (this.imports[className] = {});
|
||||
imp.load = null;
|
||||
imp.classPath = className.split('.');
|
||||
|
||||
let src = './jre';
|
||||
for (let part of imp.classPath) {
|
||||
src += '/' + part;
|
||||
}
|
||||
src += '.js';
|
||||
|
||||
const getJS = new Promise((resolve, reject) => {
|
||||
const script = document.createElement('script');
|
||||
document.body.appendChild(script);
|
||||
script.onload = resolve;
|
||||
script.onerror = reject;
|
||||
script.async = true;
|
||||
script.src = src;
|
||||
});
|
||||
|
||||
getJS.then(() => {});
|
||||
}
|
||||
|
||||
if (ready != classNames.length) {
|
||||
throw 'loading java classes';
|
||||
}
|
||||
|
||||
let classes = [];
|
||||
for (let className of classNames) {
|
||||
let imp = this.imports[className];
|
||||
classes.push(this.getClass(imp.classPath));
|
||||
}
|
||||
if (classNames.length == 1) {
|
||||
classes = classes[0];
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
}
|
||||
window.jre = new JRE();
|
14
jre/java/io/File.js
Executable file
14
jre/java/io/File.js
Executable file
@ -0,0 +1,14 @@
|
||||
jre.imports['java.io.File'].load = () => {
|
||||
|
||||
class File {
|
||||
constructor(file) {
|
||||
this.absPath = file;
|
||||
}
|
||||
getAbsolutePath() {
|
||||
return this.absPath;
|
||||
}
|
||||
}
|
||||
File.seperator = File.seperatorChar = '/';
|
||||
File.pathSeparator = File.pathSeparatorChar = '/';
|
||||
jre.java.io.File = File;
|
||||
}
|
19
jre/java/io/InputStream.js
Executable file
19
jre/java/io/InputStream.js
Executable file
@ -0,0 +1,19 @@
|
||||
jre.imports['java.io.InputStream'].load = () => {
|
||||
class InputStream {
|
||||
constructor() {
|
||||
this.reset();
|
||||
let _this = this;
|
||||
java.log.onkeyup = () => {
|
||||
_this.stream = java.log.value;
|
||||
};
|
||||
}
|
||||
reset() {
|
||||
this.stream = '';
|
||||
this.mark = 0;
|
||||
}
|
||||
read(length) {
|
||||
this.mark += length;
|
||||
}
|
||||
}
|
||||
jre.java.io.InputStream = InputStream;
|
||||
};
|
44
jre/java/io/PrintStream.js
Executable file
44
jre/java/io/PrintStream.js
Executable file
@ -0,0 +1,44 @@
|
||||
jre.imports['java.io.PrintStream'].load = () => {
|
||||
class PrintStream {
|
||||
constructor() {
|
||||
this.log = '';
|
||||
this.onPrint = () => {};
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.log = '';
|
||||
}
|
||||
|
||||
_onPrint(length) {
|
||||
this.onPrint(length);
|
||||
}
|
||||
|
||||
print(arg) {
|
||||
let str = arg.toString();
|
||||
this.log += str;
|
||||
if (java.log) {
|
||||
java.log.value += str;
|
||||
this._onPrint(str.length);
|
||||
}
|
||||
}
|
||||
|
||||
println(arg) {
|
||||
let str = arg.toString() + '\n';
|
||||
this.log += str;
|
||||
if (java.log) {
|
||||
java.log.value += str;
|
||||
this._onPrint(str.length);
|
||||
}
|
||||
}
|
||||
|
||||
printf(format, ...args) {
|
||||
let str = new Formatter().format(format, args);
|
||||
this.log += str;
|
||||
if (java.log) {
|
||||
java.log.value += str;
|
||||
this._onPrint(str.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
jre.java.io.PrintStream = PrintStream;
|
||||
};
|
1
jre/java/lang/Boolean.js
Executable file
1
jre/java/lang/Boolean.js
Executable file
@ -0,0 +1 @@
|
||||
|
0
jre/java/lang/Byte.js
Executable file
0
jre/java/lang/Byte.js
Executable file
31
jre/java/lang/Character.js
Executable file
31
jre/java/lang/Character.js
Executable file
@ -0,0 +1,31 @@
|
||||
jre.imports['java.lang.Character'].load = () => {
|
||||
class Character {}
|
||||
Character.isDigit = (c) => {
|
||||
c = c.charCodeAt(0);
|
||||
if (0x0030 <= c && c <= 0x0039) return true;
|
||||
if (0x0660 <= c && c <= 0x0669) return true;
|
||||
if (0x06f0 <= c && c <= 0x06f9) return true;
|
||||
if (0x0966 <= c && c <= 0x096f) return true;
|
||||
if (0xff10 <= c && c <= 0xff19) return true;
|
||||
return false;
|
||||
};
|
||||
Character.isUpperCase = (c) => {
|
||||
return 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.includes(c);
|
||||
};
|
||||
Character.isLowerCase = (c) => {
|
||||
return 'abcdefghijklmnopqrstuvwxyz'.includes(c);
|
||||
};
|
||||
Character.isLetter = (c) => {
|
||||
return Character.isLowerCase(c) || Character.isUpperCase(c);
|
||||
};
|
||||
Character.isAlphabetic = (c) => {
|
||||
return Character.isLetter(c);
|
||||
};
|
||||
Character.compare = (a, b) => {
|
||||
return a.charCodeAt(0) - b.charCodeAt(0);
|
||||
};
|
||||
Character.toString = (c) => {
|
||||
return c;
|
||||
};
|
||||
jre.java.lang.Character = Character;
|
||||
};
|
19
jre/java/lang/Double.js
Executable file
19
jre/java/lang/Double.js
Executable file
@ -0,0 +1,19 @@
|
||||
jre.imports['java.lang.Double'].load = () => {
|
||||
|
||||
class Double {
|
||||
constructor() {
|
||||
throw "new Double() not supported";
|
||||
}
|
||||
}
|
||||
Double.parseDouble = (d) => {
|
||||
return parseFloat(d);
|
||||
}
|
||||
Double.compare = (a, b) => {
|
||||
return a - b;
|
||||
}
|
||||
Double.MAX_VALUE = Number.MAX_VALUE;
|
||||
Double.POSITIVE_INFINITY = Number.POSITIVE_INFINITY;
|
||||
Double.NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY;
|
||||
Double.NaN = NaN;
|
||||
jre.java.lang.Double = Double;
|
||||
}
|
0
jre/java/lang/Exception.js
Executable file
0
jre/java/lang/Exception.js
Executable file
15
jre/java/lang/Float.js
Executable file
15
jre/java/lang/Float.js
Executable file
@ -0,0 +1,15 @@
|
||||
jre.imports['java.lang.Float'].load = () => {
|
||||
|
||||
class Float {}
|
||||
Float.parseFloat = (d) => {
|
||||
return parseFloat(d);
|
||||
}
|
||||
Float.compare = (a, b) => {
|
||||
return a - b;
|
||||
}
|
||||
Float.MAX_VALUE = Number.MAX_VALUE;
|
||||
Float.POSITIVE_INFINITY = Number.POSITIVE_INFINITY;
|
||||
Float.NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY;
|
||||
Float.NaN = NaN;
|
||||
jre.java.lang.Float = Float;
|
||||
}
|
15
jre/java/lang/Integer.js
Executable file
15
jre/java/lang/Integer.js
Executable file
@ -0,0 +1,15 @@
|
||||
jre.imports['java.lang.Integer'].load = () => {
|
||||
|
||||
class Integer {}
|
||||
Integer.parseInt = (d) => {
|
||||
return parseInt(d);
|
||||
}
|
||||
Integer.compare = (a, b) => {
|
||||
return a - b;
|
||||
}
|
||||
Integer.MAX_VALUE = Number.MAX_VALUE;
|
||||
Integer.POSITIVE_INFINITY = Number.POSITIVE_INFINITY;
|
||||
Integer.NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY;
|
||||
Integer.NaN = NaN;
|
||||
jre.java.lang.Integer = Integer;
|
||||
}
|
15
jre/java/lang/Long.js
Executable file
15
jre/java/lang/Long.js
Executable file
@ -0,0 +1,15 @@
|
||||
jre.imports['java.lang.Long'].load = () => {
|
||||
|
||||
class Long {}
|
||||
Long.parseLong = (d) => {
|
||||
return parseInt(d);
|
||||
}
|
||||
Long.compare = (a, b) => {
|
||||
return a - b;
|
||||
}
|
||||
Long.MAX_VALUE = Number.MAX_VALUE;
|
||||
Long.POSITIVE_INFINITY = Number.POSITIVE_INFINITY;
|
||||
Long.NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY;
|
||||
Long.NaN = NaN;
|
||||
jre.java.lang.Long = Long;
|
||||
}
|
15
jre/java/lang/Short.js
Executable file
15
jre/java/lang/Short.js
Executable file
@ -0,0 +1,15 @@
|
||||
jre.imports['java.lang.Short'].load = () => {
|
||||
|
||||
class Short {}
|
||||
Short.parseShort = (d) => {
|
||||
return parseInt(d);
|
||||
}
|
||||
Short.compare = (a, b) => {
|
||||
return a - b;
|
||||
}
|
||||
Short.MAX_VALUE = Number.MAX_VALUE;
|
||||
Short.POSITIVE_INFINITY = Number.POSITIVE_INFINITY;
|
||||
Short.NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY;
|
||||
Short.NaN = NaN;
|
||||
jre.java.lang.Short = Short;
|
||||
}
|
24
jre/java/lang/String.js
Executable file
24
jre/java/lang/String.js
Executable file
@ -0,0 +1,24 @@
|
||||
jre.imports['java.lang.String'].load = () => {};
|
||||
// String is special, I just extended js String prototype
|
||||
String.prototype.hashCode = () => {
|
||||
let h = this._hashCode;
|
||||
if (!h && this.length > 0) {
|
||||
const val = this;
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
h = 31 * h + this.charCodeAt(i);
|
||||
}
|
||||
this._hashCode = h;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
String.prototype.isEmpty = () => {
|
||||
return this.length == 0
|
||||
}
|
||||
String.prototype.contains = (substr) => {
|
||||
return this.includes(substr);
|
||||
}
|
||||
// static methods
|
||||
String.valueOf = (c) => {
|
||||
return c.toString();
|
||||
}
|
||||
jre.java.lang.String = String;
|
20
jre/java/lang/StringBuilder.js
Executable file
20
jre/java/lang/StringBuilder.js
Executable file
@ -0,0 +1,20 @@
|
||||
jre.imports['java.lang.StringBuilder'].load = () => {
|
||||
|
||||
class StringBuilder {
|
||||
constructor() {
|
||||
this._str = "";
|
||||
}
|
||||
append(val) {
|
||||
this._str = this._str + val;
|
||||
return this;
|
||||
}
|
||||
insert(position, val) {
|
||||
this._str = this._str.slice(0, position) + val + this._str.slice(position);
|
||||
return this;
|
||||
}
|
||||
toString() {
|
||||
return this._str;
|
||||
}
|
||||
}
|
||||
jre.java.lang.StringBuilder = StringBuilder;
|
||||
}
|
35
jre/java/lang/System.js
Executable file
35
jre/java/lang/System.js
Executable file
@ -0,0 +1,35 @@
|
||||
jre.imports['java.lang.System'].load = () => {
|
||||
const Formatter = jre.import('java.util.Formatter');
|
||||
const InputStream = jre.import('java.io.InputStream');
|
||||
const PrintStream = jre.import('java.io.PrintStream');
|
||||
|
||||
class System {}
|
||||
|
||||
System.in = new InputStream();
|
||||
System.out = new PrintStream();
|
||||
System.out.onPrint = (length) => {
|
||||
System.in.mark += length;
|
||||
};
|
||||
|
||||
System.arraycopy = (src, srcPos, dest, destPos, numElements) => {
|
||||
if (
|
||||
(dest instanceof Float64Array || dest instanceof Int32Array) &&
|
||||
(src instanceof Float64Array || src instanceof Int32Array)
|
||||
) {
|
||||
if (numElements == src.length) {
|
||||
dest.set(src, destPos);
|
||||
} else {
|
||||
dest.set(src.subarray(srcPos, srcPos + numElements), destPos);
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < numElements; i++) {
|
||||
dest[destPos + i] = src[srcPos + i];
|
||||
}
|
||||
}
|
||||
};
|
||||
System.exit = (code) => {
|
||||
console.log('Exited with code: ' + code);
|
||||
if (window.exit) exit();
|
||||
};
|
||||
jre.java.lang.System = System;
|
||||
};
|
9
jre/java/lang/Thread.js
Executable file
9
jre/java/lang/Thread.js
Executable file
@ -0,0 +1,9 @@
|
||||
jre.imports['java.lang.Thread'].load = () => {
|
||||
|
||||
class Thread {
|
||||
async sleep(millis) {
|
||||
await setTimeout(millis);
|
||||
}
|
||||
}
|
||||
jre.java.lang.Thread = Thread;
|
||||
}
|
0
jre/java/lang/Throwable.js
Executable file
0
jre/java/lang/Throwable.js
Executable file
87
jre/java/util/AbstractList.js
Executable file
87
jre/java/util/AbstractList.js
Executable file
@ -0,0 +1,87 @@
|
||||
jre.imports['java.util.AbstractList'].load = () => {
|
||||
|
||||
const Itr = jre.import('java.util.Itr');
|
||||
|
||||
class AbstractList {
|
||||
constructor() {
|
||||
// TODO
|
||||
this.content = [];
|
||||
}
|
||||
|
||||
addAll(index, vals) {
|
||||
const tempArray = vals.toArray(null);
|
||||
for (let i = 0; i < tempArray.length; i++) {
|
||||
this.content.push(tempArray[i]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.content = [];
|
||||
}
|
||||
|
||||
poll() {
|
||||
return this.content.shift();
|
||||
}
|
||||
|
||||
remove(indexOrElem) {
|
||||
this.content.splice(indexOrElem, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
removeAll() {
|
||||
this.content = [];
|
||||
return true;
|
||||
}
|
||||
|
||||
toArray(a) {
|
||||
return this.content;
|
||||
}
|
||||
|
||||
size() {
|
||||
return this.content.length;
|
||||
}
|
||||
|
||||
add(index, elem) {
|
||||
if (typeof elem !== 'undefined') {
|
||||
this.content.splice(index, 0, elem);
|
||||
} else {
|
||||
this.content.push(index);
|
||||
}
|
||||
}
|
||||
|
||||
get(index) {
|
||||
return this.content[index];
|
||||
}
|
||||
|
||||
contains(val) {
|
||||
return this.content.indexOf(val) != -1;
|
||||
}
|
||||
|
||||
containsAll(elems) {
|
||||
return false;
|
||||
}
|
||||
|
||||
isEmpty() {
|
||||
return this.content.length == 0;
|
||||
}
|
||||
|
||||
set(index, element) {
|
||||
this.content[index] = element;
|
||||
return element;
|
||||
}
|
||||
|
||||
indexOf(element) {
|
||||
return this.content.indexOf(element);
|
||||
}
|
||||
|
||||
lastIndexOf(element) {
|
||||
return this.content.lastIndexOf(element);
|
||||
}
|
||||
|
||||
iterator() {
|
||||
return new Itr(this);
|
||||
}
|
||||
}
|
||||
jre.java.util.AbstractList = AbstractList;
|
||||
}
|
11
jre/java/util/ArrayList.js
Executable file
11
jre/java/util/ArrayList.js
Executable file
@ -0,0 +1,11 @@
|
||||
jre.imports['java.util.ArrayList'].load = () => {
|
||||
|
||||
let AbstractList = jre.import('java.util.AbstractList');
|
||||
|
||||
class ArrayList extends AbstractList {
|
||||
constructor(...args) {
|
||||
super(args);
|
||||
}
|
||||
}
|
||||
jre.java.util.ArrayList = ArrayList;
|
||||
}
|
17
jre/java/util/Arrays.js
Executable file
17
jre/java/util/Arrays.js
Executable file
@ -0,0 +1,17 @@
|
||||
jre.imports['java.util.Arrays'].load = () => {
|
||||
|
||||
class Arrays {
|
||||
fill(data, begin, nbElem, param) {
|
||||
const max = begin + nbElem;
|
||||
for (let i = begin; i < max; i++) {
|
||||
data[i] = param;
|
||||
}
|
||||
}
|
||||
copyOf(original, newLength, ignore) {
|
||||
const copy = new Array(newLength);
|
||||
jre.java.lang.System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
jre.java.util.Arrays = Arrays;
|
||||
}
|
18
jre/java/util/Collections.js
Executable file
18
jre/java/util/Collections.js
Executable file
@ -0,0 +1,18 @@
|
||||
jre.imports['java.util.Collections'].load = () => {
|
||||
|
||||
class Collections {
|
||||
sort(list) {
|
||||
if (!list.size()) return;
|
||||
if (list.get(0).compareTo) {
|
||||
list.sort(list.get(0).compareTo);
|
||||
} else {
|
||||
list.sort();
|
||||
}
|
||||
}
|
||||
swap(list, i, j) {
|
||||
const l = list;
|
||||
l.set(i, l.set(j, l.get(i)));
|
||||
}
|
||||
}
|
||||
jre.java.util.Collections = Collections;
|
||||
}
|
18
jre/java/util/Formatter.js
Executable file
18
jre/java/util/Formatter.js
Executable file
@ -0,0 +1,18 @@
|
||||
jre.imports['java.util.Formatter'].load = () => {
|
||||
|
||||
const IllegalFormatException = jre.import('java.util.IllegalFormatException');
|
||||
|
||||
class Formatter {
|
||||
format(format, ...args) {
|
||||
let regex = /%[0-9\.]*[\w]/;
|
||||
for (let arg of args) {
|
||||
if (!regex.test(format)) {
|
||||
throw new IllegalFormatException();
|
||||
}
|
||||
format = format.replace(regex, arg.toString());
|
||||
}
|
||||
return format;
|
||||
}
|
||||
}
|
||||
jre.java.util.Formatter = Formatter;
|
||||
};
|
61
jre/java/util/HashMap.js
Executable file
61
jre/java/util/HashMap.js
Executable file
@ -0,0 +1,61 @@
|
||||
jre.imports['java.util.HashMap'].load = () => {
|
||||
|
||||
class HashMap {
|
||||
constructor() {
|
||||
this.content = {};
|
||||
}
|
||||
|
||||
get(key) {
|
||||
return this.content[key];
|
||||
}
|
||||
|
||||
put(key, value) {
|
||||
const previous_val = this.content[key];
|
||||
this.content[key] = value;
|
||||
return previous_val;
|
||||
}
|
||||
|
||||
containsKey(key) {
|
||||
return this.content.hasOwnProperty(key);
|
||||
}
|
||||
|
||||
remove(key) {
|
||||
const tmp = this.content[key];
|
||||
delete this.content[key];
|
||||
return tmp;
|
||||
}
|
||||
|
||||
keySet() {
|
||||
const result = new HashSet();
|
||||
for (const p in this.content) {
|
||||
if (this.content.hasOwnProperty(p)) {
|
||||
result.add(p);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
isEmpty() {
|
||||
return Object.keys(this.content).length == 0;
|
||||
}
|
||||
|
||||
values() {
|
||||
const result = new HashSet();
|
||||
for (const p in this.content) {
|
||||
if (this.content.hasOwnProperty(p)) {
|
||||
result.add(this.content[p]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.content = {};
|
||||
}
|
||||
|
||||
size() {
|
||||
return Object.keys(this.content).length;
|
||||
}
|
||||
}
|
||||
jre.java.util.HashMap = HashMap;
|
||||
}
|
73
jre/java/util/HashSet.js
Executable file
73
jre/java/util/HashSet.js
Executable file
@ -0,0 +1,73 @@
|
||||
jre.imports['java.util.HashSet'].load = () => {
|
||||
|
||||
class HashSet {
|
||||
constructor() {
|
||||
this.content = {};
|
||||
}
|
||||
|
||||
add(val) {
|
||||
this.content[val] = val;
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.content = {};
|
||||
}
|
||||
|
||||
contains(val) {
|
||||
return this.content.hasOwnProperty(val);
|
||||
}
|
||||
|
||||
containsAll(elems) {
|
||||
return false;
|
||||
}
|
||||
|
||||
addAll(vals) {
|
||||
const tempArray = vals.toArray(null);
|
||||
for (let i = 0; i < tempArray.length; i++) {
|
||||
this.content[tempArray[i]] = tempArray[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
remove(val) {
|
||||
let b = false;
|
||||
if (this.content[val]) {
|
||||
b = true;
|
||||
}
|
||||
delete this.content[val];
|
||||
return b;
|
||||
}
|
||||
|
||||
removeAll() {
|
||||
return false;
|
||||
}
|
||||
|
||||
size() {
|
||||
return Object.keys(this.content).length;
|
||||
}
|
||||
|
||||
isEmpty() {
|
||||
return this.size() == 0;
|
||||
}
|
||||
|
||||
toArray(a) {
|
||||
const _this = this;
|
||||
return Object.keys(this.content).map(key => _this.content[key]);
|
||||
}
|
||||
|
||||
iterator() {
|
||||
return new java.util.Itr(this);
|
||||
}
|
||||
|
||||
forEach(f) {
|
||||
for (const p in this.content) {
|
||||
f(this.content[p]);
|
||||
}
|
||||
}
|
||||
|
||||
get(index) {
|
||||
return this.content[index];
|
||||
}
|
||||
}
|
||||
jre.java.util.HashSet = HashSet;
|
||||
}
|
11
jre/java/util/IllegalFormatException.js
Executable file
11
jre/java/util/IllegalFormatException.js
Executable file
@ -0,0 +1,11 @@
|
||||
jre.imports['java.util.IllegalFormatException'].load = () => {
|
||||
|
||||
// TODO import and extend exception
|
||||
|
||||
class IllegalFormatException {
|
||||
constructor(message) {
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
jre.java.util.IllegalFormatException = IllegalFormatException;
|
||||
};
|
32
jre/java/util/Itr.js
Executable file
32
jre/java/util/Itr.js
Executable file
@ -0,0 +1,32 @@
|
||||
jre.imports['java.util.Itr'].load = () => {
|
||||
|
||||
class Itr {
|
||||
constructor(list) {
|
||||
this.cursor = 0;
|
||||
this.lastRet = -1;
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
hasNext() {
|
||||
return this.cursor != this.list.size();
|
||||
}
|
||||
|
||||
next() {
|
||||
try {
|
||||
const i = this.cursor;
|
||||
const next = this.list.get(i);
|
||||
this.lastRet = i;
|
||||
this.cursor = i + 1;
|
||||
return next;
|
||||
} catch ($ex$) {
|
||||
if ($ex$ instanceof Error) {
|
||||
const e = $ex$;
|
||||
throw new Error("no such element exception");
|
||||
} else {
|
||||
throw $ex$;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
jre.java.util.Itr = Itr;
|
||||
}
|
11
jre/java/util/LinkedList.js
Executable file
11
jre/java/util/LinkedList.js
Executable file
@ -0,0 +1,11 @@
|
||||
jre.imports['java.util.LinkedList'].load = () => {
|
||||
|
||||
let AbstractList = jre.import('java.util.AbstractList');
|
||||
|
||||
class LinkedList extends AbstractList {
|
||||
constructor(...args) {
|
||||
super(args);
|
||||
}
|
||||
}
|
||||
jre.java.util.LinkedList = LinkedList;
|
||||
}
|
48
jre/java/util/Random.js
Executable file
48
jre/java/util/Random.js
Executable file
@ -0,0 +1,48 @@
|
||||
jre.imports['java.util.Random'].load = () => {
|
||||
|
||||
class Random {
|
||||
constructor() {
|
||||
this.seed = undefined;
|
||||
}
|
||||
|
||||
nextInt(max) {
|
||||
if (typeof max === 'undefined') {
|
||||
max = Math.pow(2, 32);
|
||||
}
|
||||
if (this.seed == undefined) {
|
||||
return Math.floor(Math.random() * max);
|
||||
} else {
|
||||
return Math.floor(this.nextSeeded(0, max));
|
||||
}
|
||||
}
|
||||
|
||||
nextDouble() {
|
||||
if (this.seed == undefined) {
|
||||
return Math.random();
|
||||
} else {
|
||||
return this.nextSeeded();
|
||||
}
|
||||
}
|
||||
|
||||
nextBoolean() {
|
||||
if (this.seed == undefined) {
|
||||
return Math.random() >= 0.5;
|
||||
} else {
|
||||
return this.nextSeeded() >= 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
setSeed(seed) {
|
||||
this.seed = seed;
|
||||
}
|
||||
|
||||
nextSeeded(min, max) {
|
||||
var max = max || 1;
|
||||
var min = min || 0;
|
||||
this.seed = (this.seed * 9301 + 49297) % 233280;
|
||||
const rnd = this.seed / 233280;
|
||||
return min + rnd * (max - min);
|
||||
}
|
||||
}
|
||||
jre.java.util.Random = Random;
|
||||
}
|
54
jre/java/util/Scanner.js
Executable file
54
jre/java/util/Scanner.js
Executable file
@ -0,0 +1,54 @@
|
||||
jre.imports['java.util.Scanner'].load = () => {
|
||||
const File = jre.import('java.io.File');
|
||||
|
||||
class Scanner {
|
||||
constructor(input) {
|
||||
if (input instanceof File) {
|
||||
this.inputType = 'File';
|
||||
throw 'unsupported Scanner input type: File';
|
||||
}
|
||||
this.in = input;
|
||||
}
|
||||
hasNext(pattern) {
|
||||
if (pattern instanceof RegExp) {
|
||||
return pattern.test(this.in.stream.slice(this.in.mark));
|
||||
}
|
||||
// if pattern is string
|
||||
return this.in.stream.includes(pattern);
|
||||
}
|
||||
hasNextLine() {
|
||||
return this.hasNext('\n');
|
||||
}
|
||||
async nextLine() {
|
||||
return await this.next(/.*\n/);
|
||||
}
|
||||
async next(pattern) {
|
||||
while (!this.hasNext(pattern)) {
|
||||
await new Promise((done) => setTimeout(() => done(), 100));
|
||||
}
|
||||
let buf = this.in.stream.slice(this.in.mark);
|
||||
let substr = buf.match(pattern)[0];
|
||||
let start = buf.indexOf(substr);
|
||||
let end = buf.indexOf('\n');
|
||||
this.in.read(end - start + 1);
|
||||
return buf.slice(start, end);
|
||||
}
|
||||
async nextShort() {
|
||||
return await this.nextInt();
|
||||
}
|
||||
async nextInt() {
|
||||
return Number(await this.next(/\d+\D/));
|
||||
}
|
||||
async nextLong() {
|
||||
return await this.nextInt();
|
||||
}
|
||||
async nextFloat() {
|
||||
return Number(await this.next(/[0-9\.]+[^0-9\.]/));
|
||||
}
|
||||
async nextDouble() {
|
||||
return await this.nextFloat();
|
||||
}
|
||||
close() {}
|
||||
}
|
||||
jre.java.util.Scanner = Scanner;
|
||||
};
|
24
jre/java/util/Stack.js
Executable file
24
jre/java/util/Stack.js
Executable file
@ -0,0 +1,24 @@
|
||||
jre.imports['java.util.Stack'].load = () => {
|
||||
class Stack {
|
||||
constructor() {
|
||||
this.content = new Array();
|
||||
}
|
||||
|
||||
pop() {
|
||||
return this.content.pop();
|
||||
}
|
||||
|
||||
push(t) {
|
||||
this.content.push(t);
|
||||
}
|
||||
|
||||
isEmpty() {
|
||||
return this.content.length == 0;
|
||||
}
|
||||
|
||||
peek() {
|
||||
return this.content.slice(-1)[0];
|
||||
}
|
||||
}
|
||||
jre.java.util.Stack = Stack;
|
||||
}
|
24
package.json
Normal file
24
package.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "java2js",
|
||||
"version": "1.0.1",
|
||||
"description": "Converts Java to JavaScript with support for p5.js and QuintOS.",
|
||||
"main": "java2js.js",
|
||||
"scripts": {
|
||||
"start": "open demo.html",
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"v": "npm version patch --force",
|
||||
"V": "npm version minor --force",
|
||||
"version": "git add -A",
|
||||
"postversion": "git push"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/quinton-ashley/java2js.git"
|
||||
},
|
||||
"author": "quinton-ashley",
|
||||
"license": "GPL-3.0-only",
|
||||
"bugs": {
|
||||
"url": "https://github.com/quinton-ashley/java2js/issues"
|
||||
},
|
||||
"homepage": "https://github.com/quinton-ashley/java2js#readme"
|
||||
}
|
19275
transpiler.js
Executable file
19275
transpiler.js
Executable file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user