separate more stuff into lib project
This commit is contained in:
parent
ee8268b144
commit
8b1c2a5e4e
@ -4,15 +4,6 @@ plugins {
|
|||||||
|
|
||||||
description = "A compiler of EcmaScript 5 code to J2S bytecode";
|
description = "A compiler of EcmaScript 5 code to J2S bytecode";
|
||||||
|
|
||||||
tasks.processResources {
|
|
||||||
filesMatching("metadata.json", {
|
|
||||||
expand(
|
|
||||||
"version" to properties["project_version"],
|
|
||||||
"name" to properties["project_name"],
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.test {
|
tasks.test {
|
||||||
useJUnitPlatform();
|
useJUnitPlatform();
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
import com.github.gradle.node.npm.task.NpmTask;
|
import com.github.gradle.node.npm.task.NpmTask;
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("common");
|
id("common-java");
|
||||||
id("com.github.node-gradle.node") version "5.0.0";
|
id("com.github.node-gradle.node") version "5.0.0";
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.compileJava {
|
dependencies {
|
||||||
enabled = false;
|
implementation(project(":common"));
|
||||||
}
|
implementation(project(":compilation"));
|
||||||
tasks.classes {
|
implementation(project(":runtime"));
|
||||||
enabled = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
node {
|
node {
|
||||||
@ -27,16 +26,38 @@ tasks.register<NpmTask>("compileStdlib") {
|
|||||||
|
|
||||||
args.set(listOf("run", "build-env"));
|
args.set(listOf("run", "build-env"));
|
||||||
}
|
}
|
||||||
tasks.register<NpmTask>("compileTranspiler") {
|
tasks.register<NpmTask>("compileBabel") {
|
||||||
dependsOn("npmInstall");
|
dependsOn("npmInstall");
|
||||||
|
|
||||||
inputs.files("rollup.config.js");
|
inputs.files("rollup.config.js");
|
||||||
inputs.dir("src/transpiler");
|
inputs.dir("src/transpiler");
|
||||||
outputs.files("build/js/transpiler.js");
|
outputs.files("build/js/babel.js");
|
||||||
// nom nom tasty ram
|
// nom nom tasty ram
|
||||||
environment.put("NODE_OPTIONS", "--max-old-space-size=4096");
|
environment.put("NODE_OPTIONS", "--max-old-space-size=4096");
|
||||||
|
|
||||||
args.set(listOf("run", "build-ts"));
|
args.set(listOf("run", "build-babel"));
|
||||||
|
}
|
||||||
|
tasks.register<NpmTask>("compileTypescript") {
|
||||||
|
dependsOn("npmInstall");
|
||||||
|
|
||||||
|
inputs.files("rollup.config.js");
|
||||||
|
inputs.dir("src/transpiler");
|
||||||
|
outputs.files("build/js/typescript.js");
|
||||||
|
// nom nom tasty ram
|
||||||
|
environment.put("NODE_OPTIONS", "--max-old-space-size=4096");
|
||||||
|
|
||||||
|
args.set(listOf("run", "build-typescript"));
|
||||||
|
}
|
||||||
|
tasks.register<NpmTask>("compileCoffee") {
|
||||||
|
dependsOn("npmInstall");
|
||||||
|
|
||||||
|
inputs.files("rollup.config.js");
|
||||||
|
inputs.dir("src/transpiler");
|
||||||
|
outputs.files("build/js/coffee.js");
|
||||||
|
// nom nom tasty ram
|
||||||
|
environment.put("NODE_OPTIONS", "--max-old-space-size=4096");
|
||||||
|
|
||||||
|
args.set(listOf("run", "build-coffee"));
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.jar {
|
tasks.jar {
|
||||||
@ -50,7 +71,9 @@ tasks.jar {
|
|||||||
|
|
||||||
tasks.processResources {
|
tasks.processResources {
|
||||||
dependsOn("compileStdlib");
|
dependsOn("compileStdlib");
|
||||||
dependsOn("compileTranspiler");
|
dependsOn("compileTypescript");
|
||||||
|
dependsOn("compileBabel");
|
||||||
|
dependsOn("compileCoffee");
|
||||||
|
|
||||||
from("build/js") {
|
from("build/js") {
|
||||||
into("lib");
|
into("lib");
|
||||||
@ -58,11 +81,4 @@ tasks.processResources {
|
|||||||
from("src/lib") {
|
from("src/lib") {
|
||||||
into("lib");
|
into("lib");
|
||||||
}
|
}
|
||||||
|
|
||||||
filesMatching("metadata.json", {
|
|
||||||
expand(
|
|
||||||
"version" to properties["project_version"].toString(),
|
|
||||||
"name" to properties["project_name"].toString(),
|
|
||||||
);
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build-env": "rollup -c --environment INPUT:src/stdlib/_entry.ts,OUTPUT:build/js/stdlib.js,POLYFILLS:src/polyfills",
|
"build-env": "rollup -c --environment INPUT:src/stdlib/_entry.ts,OUTPUT:build/js/stdlib.js,POLYFILLS:src/polyfills",
|
||||||
"build-ts": "rollup -c --environment INPUT:src/transpiler/_entry.ts,OUTPUT:build/js/transpiler.js"
|
"build-babel": "rollup -c --environment INPUT:src/transpiler/_entry-babel.ts,OUTPUT:build/js/babel.js",
|
||||||
|
"build-coffee": "rollup -c --environment INPUT:src/transpiler/_entry-coffee.ts,OUTPUT:build/js/coffee.js",
|
||||||
|
"build-typescript": "rollup -c --environment INPUT:src/transpiler/_entry-typescript.ts,OUTPUT:build/js/typescript.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.26.0",
|
"@babel/core": "^7.26.0",
|
||||||
|
123
lib/src/main/java/me/topchetoeu/j2s/lib/Compilers.java
Normal file
123
lib/src/main/java/me/topchetoeu/j2s/lib/Compilers.java
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
package me.topchetoeu.j2s.lib;
|
||||||
|
|
||||||
|
import me.topchetoeu.j2s.common.Environment;
|
||||||
|
import me.topchetoeu.j2s.common.Filename;
|
||||||
|
import me.topchetoeu.j2s.common.Metadata;
|
||||||
|
import me.topchetoeu.j2s.common.Reading;
|
||||||
|
import me.topchetoeu.j2s.common.SyntaxException;
|
||||||
|
import me.topchetoeu.j2s.compilation.JavaScript;
|
||||||
|
import me.topchetoeu.j2s.runtime.Compiler;
|
||||||
|
import me.topchetoeu.j2s.runtime.debug.DebugHandler;
|
||||||
|
import me.topchetoeu.j2s.runtime.exceptions.EngineException;
|
||||||
|
import me.topchetoeu.j2s.runtime.values.Value;
|
||||||
|
import me.topchetoeu.j2s.runtime.values.functions.CodeFunction;
|
||||||
|
import me.topchetoeu.j2s.runtime.values.functions.FunctionValue;
|
||||||
|
import me.topchetoeu.j2s.runtime.values.functions.NativeFunction;
|
||||||
|
import me.topchetoeu.j2s.runtime.values.primitives.StringValue;
|
||||||
|
|
||||||
|
public class Compilers {
|
||||||
|
public static Compiler jsCompiler() {
|
||||||
|
return (env, filename, raw, mapper) -> {
|
||||||
|
try {
|
||||||
|
var res = JavaScript.compile(env, filename, raw, true);
|
||||||
|
var body = res.body();
|
||||||
|
|
||||||
|
DebugHandler.get(env).onSourceLoad(filename, raw);
|
||||||
|
for (var el : res.all()) {
|
||||||
|
DebugHandler.get(env).onFunctionLoad(el.body(), el.map(mapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CodeFunction(env, filename.toString(), body, new Value[0][]);
|
||||||
|
}
|
||||||
|
catch (SyntaxException e) {
|
||||||
|
var res = EngineException.ofSyntax(e.msg);
|
||||||
|
res.add(env, e.loc.filename() + "", e.loc);
|
||||||
|
throw res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Compiler wrap(Compiler first, Environment compilerEnv, Environment targetEnv, FunctionValue factory) {
|
||||||
|
var curr = new NativeFunction(args -> {
|
||||||
|
var filename = Filename.parse(args.get(0).toString(args.env));
|
||||||
|
var src = args.get(1).toString(args.env);
|
||||||
|
var mapper = (FunctionValue)args.get(2);
|
||||||
|
return first.compile(targetEnv, filename, src, NativeMapper.unwrap(args.env, mapper));
|
||||||
|
});
|
||||||
|
|
||||||
|
var next = (FunctionValue)factory.apply(compilerEnv, Value.UNDEFINED, curr);
|
||||||
|
|
||||||
|
return (env, filename, source, map) -> {
|
||||||
|
return (FunctionValue)next.apply(
|
||||||
|
compilerEnv, Value.UNDEFINED,
|
||||||
|
StringValue.of(filename.toString()),
|
||||||
|
StringValue.of(source),
|
||||||
|
new NativeMapper(map)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Compiler transpilerFromSource(Compiler prev, Environment target, Filename compilerName, String compilerSrc) {
|
||||||
|
var env = StdLib.apply(null);
|
||||||
|
|
||||||
|
var glob = Value.global(env);
|
||||||
|
var compilerFactory = new FunctionValue[1];
|
||||||
|
|
||||||
|
glob.defineOwnField(env, "getResource", new NativeFunction(args -> {
|
||||||
|
var name = args.get(0).toString(args.env);
|
||||||
|
var src = Reading.resourceToString("lib/" + name);
|
||||||
|
|
||||||
|
if (src == null) return Value.UNDEFINED;
|
||||||
|
else return StringValue.of(src);
|
||||||
|
}));
|
||||||
|
glob.defineOwnField(env, "register", new NativeFunction(args -> {
|
||||||
|
var func = (FunctionValue)args.get(0);
|
||||||
|
compilerFactory[0] = func;
|
||||||
|
return Value.UNDEFINED;
|
||||||
|
}));
|
||||||
|
glob.defineOwnField(env, "registerSource", new NativeFunction(args -> {
|
||||||
|
var filename = Filename.parse(args.get(0).toString(args.env));
|
||||||
|
var src = args.get(1).toString(args.env);
|
||||||
|
DebugHandler.get(target).onSourceLoad(filename, src);
|
||||||
|
return Value.UNDEFINED;
|
||||||
|
}));
|
||||||
|
|
||||||
|
var compiled = JavaScript.compile(compilerName, compilerSrc, false);
|
||||||
|
new CodeFunction(env, "intializer", compiled.body(), new Value[0][]).apply(env, Value.UNDEFINED);
|
||||||
|
|
||||||
|
return wrap(prev, env, target, compilerFactory[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Compiler babelCompiler(Compiler prev, Environment target) {
|
||||||
|
return transpilerFromSource(prev, target,
|
||||||
|
new Filename(Metadata.name(), "babel.js"),
|
||||||
|
Reading.resourceToString("lib/babel.js")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
public static Compiler typescriptCompiler(Compiler prev, Environment target) {
|
||||||
|
return transpilerFromSource(prev, target,
|
||||||
|
new Filename(Metadata.name(), "typescript.js"),
|
||||||
|
Reading.resourceToString("lib/typescript.js")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
public static Compiler coffeescriptCompiler(Compiler prev, Environment target) {
|
||||||
|
return transpilerFromSource(prev, target,
|
||||||
|
new Filename(Metadata.name(), "coffee.js"),
|
||||||
|
Reading.resourceToString("lib/coffee.js")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static interface TranspilerFactory {
|
||||||
|
Compiler create(Compiler prev, Environment target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Compiler chainTranspilers(Environment target, Compiler base, TranspilerFactory ...factories) {
|
||||||
|
var res = base;
|
||||||
|
|
||||||
|
for (var el : factories) {
|
||||||
|
res = el.create(res, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.j2s.repl;
|
package me.topchetoeu.j2s.lib;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.j2s.repl.mapping;
|
package me.topchetoeu.j2s.lib;
|
||||||
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
694
lib/src/main/java/me/topchetoeu/j2s/lib/Primordials.java
Normal file
694
lib/src/main/java/me/topchetoeu/j2s/lib/Primordials.java
Normal file
@ -0,0 +1,694 @@
|
|||||||
|
package me.topchetoeu.j2s.lib;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.regex.PatternSyntaxException;
|
||||||
|
|
||||||
|
import me.topchetoeu.j2s.runtime.Compiler;
|
||||||
|
import me.topchetoeu.j2s.runtime.EventLoop;
|
||||||
|
import me.topchetoeu.j2s.common.Environment;
|
||||||
|
import me.topchetoeu.j2s.common.Filename;
|
||||||
|
import me.topchetoeu.j2s.common.Key;
|
||||||
|
import me.topchetoeu.j2s.common.Metadata;
|
||||||
|
import me.topchetoeu.j2s.common.SyntaxException;
|
||||||
|
import me.topchetoeu.j2s.compilation.json.JSON;
|
||||||
|
import me.topchetoeu.j2s.compilation.parsing.Parsing;
|
||||||
|
import me.topchetoeu.j2s.compilation.parsing.Source;
|
||||||
|
import me.topchetoeu.j2s.lib.buffers.Int32ArrayValue;
|
||||||
|
import me.topchetoeu.j2s.lib.buffers.Int8ArrayValue;
|
||||||
|
import me.topchetoeu.j2s.lib.buffers.TypedArrayValue;
|
||||||
|
import me.topchetoeu.j2s.lib.buffers.Uint8ArrayValue;
|
||||||
|
import me.topchetoeu.j2s.runtime.ArgumentsValue;
|
||||||
|
import me.topchetoeu.j2s.runtime.Frame;
|
||||||
|
import me.topchetoeu.j2s.runtime.exceptions.EngineException;
|
||||||
|
import me.topchetoeu.j2s.runtime.values.Value;
|
||||||
|
import me.topchetoeu.j2s.runtime.values.functions.FunctionValue;
|
||||||
|
import me.topchetoeu.j2s.runtime.values.functions.NativeFunction;
|
||||||
|
import me.topchetoeu.j2s.runtime.values.objects.ArrayLikeValue;
|
||||||
|
import me.topchetoeu.j2s.runtime.values.objects.ArrayValue;
|
||||||
|
import me.topchetoeu.j2s.runtime.values.objects.ObjectValue;
|
||||||
|
import me.topchetoeu.j2s.runtime.values.primitives.BoolValue;
|
||||||
|
import me.topchetoeu.j2s.runtime.values.primitives.StringValue;
|
||||||
|
import me.topchetoeu.j2s.runtime.values.primitives.SymbolValue;
|
||||||
|
import me.topchetoeu.j2s.runtime.values.primitives.UserValue;
|
||||||
|
import me.topchetoeu.j2s.runtime.values.primitives.VoidValue;
|
||||||
|
import me.topchetoeu.j2s.runtime.values.primitives.numbers.NumberValue;
|
||||||
|
|
||||||
|
public class Primordials {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static ObjectValue mapPrimordials(Environment env) {
|
||||||
|
var res = new ObjectValue();
|
||||||
|
res.setPrototype(null, null);
|
||||||
|
|
||||||
|
var prototype = new ObjectValue[1];
|
||||||
|
NativeFunction mapConstr = new NativeFunction(args -> {
|
||||||
|
var isWeak = args.get(0).toBoolean();
|
||||||
|
return UserValue.of(isWeak ? new WeakHashMap<>() : new LinkedHashMap<>(), prototype[0]);
|
||||||
|
});
|
||||||
|
mapConstr.prototype.defineOwnField(env, "get", new NativeFunction(getArgs -> {
|
||||||
|
var map = getArgs.self(Map.class);
|
||||||
|
var key = getArgs.get(0);
|
||||||
|
var val = map.get(key);
|
||||||
|
return val == null ? Value.UNDEFINED : (Value)val;
|
||||||
|
}));
|
||||||
|
mapConstr.prototype.defineOwnField(env, "set", new NativeFunction(getArgs -> {
|
||||||
|
var map = getArgs.self(Map.class);
|
||||||
|
var key = getArgs.get(0);
|
||||||
|
var val = getArgs.get(1);
|
||||||
|
map.put(key, val);
|
||||||
|
|
||||||
|
return Value.UNDEFINED;
|
||||||
|
}));
|
||||||
|
mapConstr.prototype.defineOwnField(env, "has", new NativeFunction(getArgs -> {
|
||||||
|
var map = getArgs.self(Map.class);
|
||||||
|
var key = getArgs.get(0);
|
||||||
|
return BoolValue.of(map.containsKey(key));
|
||||||
|
}));
|
||||||
|
mapConstr.prototype.defineOwnField(env, "delete", new NativeFunction(getArgs -> {
|
||||||
|
var map = getArgs.self(Map.class);
|
||||||
|
var key = getArgs.get(0);
|
||||||
|
map.remove(key);
|
||||||
|
return Value.UNDEFINED;
|
||||||
|
}));
|
||||||
|
mapConstr.prototype.defineOwnField(env, "keys", new NativeFunction(getArgs -> {
|
||||||
|
var map = getArgs.self(Map.class);
|
||||||
|
return ArrayValue.of(map.keySet());
|
||||||
|
}));
|
||||||
|
mapConstr.prototype.defineOwnField(env, "clear", new NativeFunction(getArgs -> {
|
||||||
|
getArgs.self(Map.class).clear();
|
||||||
|
return Value.UNDEFINED;
|
||||||
|
}));
|
||||||
|
mapConstr.prototype.defineOwnField(env, "size", new NativeFunction(getArgs -> {
|
||||||
|
return NumberValue.of(getArgs.self(Map.class).size());
|
||||||
|
}));
|
||||||
|
prototype[0] = (ObjectValue)mapConstr.prototype;
|
||||||
|
|
||||||
|
return mapConstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String processRegex(String src) {
|
||||||
|
var n = 0;
|
||||||
|
|
||||||
|
var source = new StringBuilder();
|
||||||
|
|
||||||
|
StringBuilder bracesSource = null;
|
||||||
|
StringBuilder bracketsSource = null;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (n >= src.length()) break;
|
||||||
|
var c = src.charAt(n++);
|
||||||
|
|
||||||
|
if (c == '\\' && n + 1 < src.length() && src.charAt(n) == 'b') {
|
||||||
|
c = '\b';
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bracesSource != null) {
|
||||||
|
var failed = true;
|
||||||
|
|
||||||
|
if (Character.isDigit(c)) {
|
||||||
|
bracesSource.append(c);
|
||||||
|
failed = false;
|
||||||
|
}
|
||||||
|
else if (c == ',' && bracesSource.indexOf(",") < 0) {
|
||||||
|
bracesSource.append(c);
|
||||||
|
failed = false;
|
||||||
|
}
|
||||||
|
else if (c == '}' && bracesSource.length() > 0) {
|
||||||
|
bracesSource.append(c);
|
||||||
|
source.append(bracesSource);
|
||||||
|
bracesSource = null;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failed) {
|
||||||
|
source.append("\\");
|
||||||
|
source.append(bracesSource);
|
||||||
|
bracesSource = null;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (bracketsSource != null) {
|
||||||
|
if (c == '[') bracketsSource.append("\\[");
|
||||||
|
else if (c == ']') {
|
||||||
|
var res = bracketsSource.append(']').toString();
|
||||||
|
bracketsSource = null;
|
||||||
|
if (res.equals("[^]")) res = "[\\s\\S]";
|
||||||
|
else if (res.equals("[]")) res = "[^\\s\\S]";
|
||||||
|
source.append(res);
|
||||||
|
}
|
||||||
|
else if (c == '\\') {
|
||||||
|
if (n >= src.length()) break;
|
||||||
|
bracketsSource.append(c).append(src.charAt(n++));
|
||||||
|
}
|
||||||
|
else bracketsSource.append(c);
|
||||||
|
}
|
||||||
|
else if (c == '\\') {
|
||||||
|
if (n >= src.length()) throw new PatternSyntaxException("Unexpected end", src, n);
|
||||||
|
c = src.charAt(n++);
|
||||||
|
source.append('\\').append(c);
|
||||||
|
}
|
||||||
|
else if (c == '[') {
|
||||||
|
bracketsSource = new StringBuilder("[");
|
||||||
|
}
|
||||||
|
else if (c == '{' && bracketsSource == null) {
|
||||||
|
bracesSource = new StringBuilder("{");
|
||||||
|
}
|
||||||
|
else source.append(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bracesSource != null) {
|
||||||
|
source.append("\\");
|
||||||
|
source.append(bracesSource);
|
||||||
|
}
|
||||||
|
if (bracketsSource != null) throw new PatternSyntaxException("Unmatched '['", src, n - bracketsSource.length());
|
||||||
|
|
||||||
|
return source.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectValue regexPrimordials(Environment env) {
|
||||||
|
var res = new ObjectValue();
|
||||||
|
res.setPrototype(null, null);
|
||||||
|
|
||||||
|
var prototype = new ObjectValue[1];
|
||||||
|
NativeFunction mapConstr = new NativeFunction(args -> {
|
||||||
|
var flags = 0;
|
||||||
|
if (args.get(1).toBoolean()) flags |= Pattern.MULTILINE;
|
||||||
|
if (args.get(2).toBoolean()) flags |= Pattern.CASE_INSENSITIVE;
|
||||||
|
if (args.get(3).toBoolean()) flags |= Pattern.DOTALL;
|
||||||
|
if (args.get(4).toBoolean()) flags |= Pattern.UNICODE_CASE | Pattern.CANON_EQ;
|
||||||
|
if (args.get(5).toBoolean()) flags |= Pattern.UNICODE_CHARACTER_CLASS;
|
||||||
|
try {
|
||||||
|
var pattern = Pattern.compile(processRegex(args.get(0).toString(args.env)), flags);
|
||||||
|
return UserValue.of(pattern, prototype[0]);
|
||||||
|
}
|
||||||
|
catch (PatternSyntaxException e) {
|
||||||
|
throw EngineException.ofSyntax("(regex):" + e.getIndex() + ": " + e.getDescription());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mapConstr.prototype.defineOwnField(env, "exec", new NativeFunction(args -> {
|
||||||
|
var pattern = args.self(Pattern.class);
|
||||||
|
var target = args.get(0).toString(args.env);
|
||||||
|
var offset = args.get(1).toNumber(args.env).getInt();
|
||||||
|
var index = args.get(2).toBoolean();
|
||||||
|
|
||||||
|
if (offset > target.length()) return Value.NULL;
|
||||||
|
|
||||||
|
var matcher = pattern.matcher(target).region(offset, target.length());
|
||||||
|
if (!matcher.find()) return Value.NULL;
|
||||||
|
|
||||||
|
var matchesArr = new ArrayValue(matcher.groupCount() + 1);
|
||||||
|
for (var i = 0; i < matcher.groupCount() + 1; i++) {
|
||||||
|
var group = matcher.group(i);
|
||||||
|
if (group == null) continue;
|
||||||
|
matchesArr.set(args.env, i, StringValue.of(group));
|
||||||
|
}
|
||||||
|
|
||||||
|
matchesArr.defineOwnField(args.env, "index", NumberValue.of(matcher.start()));
|
||||||
|
matchesArr.defineOwnField(args.env, "input", StringValue.of(target));
|
||||||
|
if (index) {
|
||||||
|
var indices = new ArrayValue();
|
||||||
|
indices.setPrototype(args.env, null);
|
||||||
|
for (var i = 0; i < matcher.groupCount(); i++) {
|
||||||
|
matchesArr.set(args.env, i, ArrayValue.of(Arrays.asList(
|
||||||
|
NumberValue.of(matcher.start(i)),
|
||||||
|
NumberValue.of(matcher.end(i))
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var obj = new ObjectValue();
|
||||||
|
obj.defineOwnField(args.env, "matches", matchesArr);
|
||||||
|
obj.defineOwnField(args.env, "end", NumberValue.of(matcher.end()));
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
// return val == null ? Value.UNDEFINED : (Value)val;
|
||||||
|
}));
|
||||||
|
mapConstr.prototype.defineOwnField(env, "groupCount", new NativeFunction(args -> {
|
||||||
|
var pattern = args.self(Pattern.class);
|
||||||
|
return NumberValue.of(pattern.matcher("").groupCount());
|
||||||
|
}));
|
||||||
|
prototype[0] = (ObjectValue)mapConstr.prototype;
|
||||||
|
|
||||||
|
return mapConstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectValue symbolPrimordials(Environment env) {
|
||||||
|
var res = new ObjectValue();
|
||||||
|
res.setPrototype(null, null);
|
||||||
|
|
||||||
|
res.defineOwnField(env, "makeSymbol", new NativeFunction(args -> new SymbolValue(args.get(0).toString(args.env))));
|
||||||
|
res.defineOwnField(env, "getSymbol", new NativeFunction(args -> SymbolValue.get(args.get(0).toString(args.env))));
|
||||||
|
res.defineOwnField(env, "getSymbolKey", new NativeFunction(args -> ((SymbolValue)args.get(0)).key()));
|
||||||
|
res.defineOwnField(env, "getSymbolDescriptor", new NativeFunction(args -> StringValue.of(((SymbolValue)args.get(0)).value)));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectValue numberPrimordials(Environment env) {
|
||||||
|
var res = new ObjectValue();
|
||||||
|
res.setPrototype(null, null);
|
||||||
|
|
||||||
|
res.defineOwnField(env, "parseInt", new NativeFunction(args -> {
|
||||||
|
var nradix = args.get(1).toNumber(env);
|
||||||
|
var radix = nradix.isInt() ? nradix.getInt() : 10;
|
||||||
|
|
||||||
|
if (radix != 10 && args.get(0) instanceof NumberValue num) {
|
||||||
|
if (num.isInt()) return num;
|
||||||
|
else return NumberValue.of(num.getDouble() - num.getDouble() % 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (radix < 2 || radix > 36) return NumberValue.NAN;
|
||||||
|
|
||||||
|
var str = args.get(0).toString().trim();
|
||||||
|
var numRes = Parsing.parseInt(new Source(str), 0, "0123456789abcdefghijklmnopqrstuvwxyz".substring(0, radix), true);
|
||||||
|
if (numRes.isSuccess()) {
|
||||||
|
if (numRes.n == str.length()) return NumberValue.of(numRes.result);
|
||||||
|
}
|
||||||
|
return NumberValue.NAN;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "parseFloat", new NativeFunction(args -> {
|
||||||
|
if (args.get(0) instanceof NumberValue) {
|
||||||
|
return args.get(0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var str = args.get(0).toString().trim();
|
||||||
|
var numRes = Parsing.parseFloat(new Source(str), 0, true);
|
||||||
|
if (numRes.isSuccess()) {
|
||||||
|
if (numRes.n == str.length()) return NumberValue.of(numRes.result);
|
||||||
|
}
|
||||||
|
return NumberValue.NAN;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "isNaN", new NativeFunction(args -> BoolValue.of(args.get(0).isNaN())));
|
||||||
|
|
||||||
|
res.defineOwnField(env, "pow", new NativeFunction(args -> {
|
||||||
|
return NumberValue.of(Math.pow(args.get(0).toNumber(args.env).getDouble(), args.get(1).toNumber(args.env).getDouble()));
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "log", new NativeFunction(args -> {
|
||||||
|
return NumberValue.of(Math.log(args.get(0).toNumber(args.env).getDouble()));
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.defineOwnField(env, "NaN", NumberValue.NAN);
|
||||||
|
res.defineOwnField(env, "Infinity", NumberValue.of(Double.POSITIVE_INFINITY));
|
||||||
|
res.defineOwnField(env, "PI", NumberValue.of(Math.PI));
|
||||||
|
res.defineOwnField(env, "E", NumberValue.of(Math.E));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectValue stringPrimordials(Environment env) {
|
||||||
|
var res = new ObjectValue();
|
||||||
|
res.setPrototype(null, null);
|
||||||
|
|
||||||
|
res.defineOwnField(env, "stringBuild", new NativeFunction(args -> {
|
||||||
|
var parts = ((ArrayValue)args.get(0)).toArray();
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
|
for (var i = 0; i < parts.length; i++) {
|
||||||
|
sb.append(((StringValue)parts[i]).value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return StringValue.of(sb.toString());
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.defineOwnField(env, "fromCharCode", new NativeFunction(args -> {
|
||||||
|
return StringValue.of(new String(new char[] { (char)args.get(0).toNumber(args.env).getInt() }));
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.defineOwnField(env, "toCharCode", new NativeFunction(args -> {
|
||||||
|
return NumberValue.of(args.get(0).toString(args.env).charAt(0));
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "toCodePoint", new NativeFunction(args -> {
|
||||||
|
return NumberValue.of(args.get(0).toString(args.env).codePointAt(args.get(1).toNumber(args.env).getInt()));
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.defineOwnField(env, "substring", new NativeFunction(args -> {
|
||||||
|
var str = args.get(0).toString(args.env);
|
||||||
|
var start = args.get(1).toNumber(args.env).getInt();
|
||||||
|
var end = args.get(2).toNumber(args.env).getInt();
|
||||||
|
|
||||||
|
if (end <= start) return StringValue.of("");
|
||||||
|
|
||||||
|
start = Math.max(Math.min(start, str.length()), 0);
|
||||||
|
end = Math.max(Math.min(end, str.length()), 0);
|
||||||
|
|
||||||
|
return StringValue.of(str.substring(start, end));
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.defineOwnField(env, "indexOf", new NativeFunction(args -> {
|
||||||
|
var str = args.get(0).toString(args.env);
|
||||||
|
var search = args.get(1).toString(args.env);
|
||||||
|
var start = args.get(2).toNumber(args.env).getInt();
|
||||||
|
if (start > str.length()) return NumberValue.of(-1);
|
||||||
|
var reverse = args.get(3).toBoolean();
|
||||||
|
|
||||||
|
if (reverse) return NumberValue.of(str.lastIndexOf(search, start));
|
||||||
|
else return NumberValue.of(str.indexOf(search, start));
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.defineOwnField(env, "lower", new NativeFunction(args -> {
|
||||||
|
return StringValue.of(args.get(0).toString(args.env).toLowerCase());
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "upper", new NativeFunction(args -> {
|
||||||
|
return StringValue.of(args.get(0).toString(args.env).toUpperCase());
|
||||||
|
}));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectValue objectPrimordials(Environment env) {
|
||||||
|
var res = new ObjectValue();
|
||||||
|
res.setPrototype(null, null);
|
||||||
|
|
||||||
|
res.defineOwnField(env, "defineField", new NativeFunction(args -> {
|
||||||
|
var obj = (ObjectValue)args.get(0);
|
||||||
|
var key = args.get(1);
|
||||||
|
var desc = (ObjectValue)args.get(2);
|
||||||
|
|
||||||
|
var valField = desc.getOwnMember(env, "v");
|
||||||
|
var writeField = desc.getOwnMember(env, "w");
|
||||||
|
var configField = desc.getOwnMember(env, "c");
|
||||||
|
var enumField = desc.getOwnMember(env, "e");
|
||||||
|
|
||||||
|
var enumerable = enumField == null ? null : enumField.get(env, desc).toBoolean();
|
||||||
|
var configurable = configField == null ? null : configField.get(env, desc).toBoolean();
|
||||||
|
var writable = writeField == null ? null : writeField.get(env, desc).toBoolean();
|
||||||
|
var value = valField == null ? null : valField.get(env, desc);
|
||||||
|
|
||||||
|
return BoolValue.of(obj.defineOwnField(args.env, key, value, configurable, enumerable, writable));
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "defineProperty", new NativeFunction(args -> {
|
||||||
|
var obj = (ObjectValue)args.get(0);
|
||||||
|
var key = args.get(1);
|
||||||
|
var desc = args.get(2);
|
||||||
|
|
||||||
|
var configField = desc.getOwnMember(env, "c");
|
||||||
|
var enumField = desc.getOwnMember(env, "e");
|
||||||
|
var getField = desc.getOwnMember(env, "g");
|
||||||
|
var setField = desc.getOwnMember(env, "s");
|
||||||
|
|
||||||
|
var enumerable = enumField == null ? null : enumField.get(env, desc).toBoolean();
|
||||||
|
var configurable = configField == null ? null : configField.get(env, desc).toBoolean();
|
||||||
|
Optional<FunctionValue> getter = null, setter = null;
|
||||||
|
|
||||||
|
if (getField != null) {
|
||||||
|
var getVal = getField.get(env, desc);
|
||||||
|
if (getVal == Value.UNDEFINED) getter = Optional.empty();
|
||||||
|
else getter = Optional.of((FunctionValue)getVal);
|
||||||
|
}
|
||||||
|
if (setField != null) {
|
||||||
|
var setVal = setField.get(env, desc);
|
||||||
|
if (setVal == Value.UNDEFINED) setter = Optional.empty();
|
||||||
|
else setter = Optional.of((FunctionValue)setVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BoolValue.of(obj.defineOwnProperty(args.env, key, getter, setter, configurable, enumerable));
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "getPrototype", new NativeFunction(args -> {
|
||||||
|
var proto = args.get(0).getPrototype(env);
|
||||||
|
if (proto == null) return Value.NULL;
|
||||||
|
else return proto;
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "setPrototype", new NativeFunction(args -> {
|
||||||
|
var proto = args.get(1) instanceof VoidValue ? null : (ObjectValue)args.get(1);
|
||||||
|
args.get(0).setPrototype(env, proto);
|
||||||
|
return args.get(0);
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "getMembers", new NativeFunction(args -> {
|
||||||
|
var val = new ArrayValue();
|
||||||
|
|
||||||
|
for (var key : args.get(0).getMembers(env, args.get(1).toBoolean(), args.get(2).toBoolean())) {
|
||||||
|
val.set(args.env, val.size(), StringValue.of(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "getSymbolMembers", new NativeFunction(args -> {
|
||||||
|
return ArrayValue.of(args.get(0).getSymbolMembers(env, args.get(1).toBoolean(), args.get(2).toBoolean()));
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "getOwnMember", new NativeFunction(args -> {
|
||||||
|
var obj = args.get(0);
|
||||||
|
var key = args.get(1);
|
||||||
|
|
||||||
|
var member = obj.getOwnMember(args.env, key);
|
||||||
|
if (member == null) return Value.UNDEFINED;
|
||||||
|
else return member.descriptor(args.env, obj);
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "preventExt", new NativeFunction(args -> {
|
||||||
|
args.get(0).preventExtensions();
|
||||||
|
return VoidValue.UNDEFINED;
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "seal", new NativeFunction(args -> {
|
||||||
|
args.get(0).seal();
|
||||||
|
return VoidValue.UNDEFINED;
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "freeze", new NativeFunction(args -> {
|
||||||
|
args.get(0).freeze();
|
||||||
|
return VoidValue.UNDEFINED;
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "memcpy", new NativeFunction(args -> {
|
||||||
|
var src = (ArrayValue)args.get(0);
|
||||||
|
var dst = (ArrayValue)args.get(1);
|
||||||
|
var srcI = args.get(2).toNumber(args.env).getInt();
|
||||||
|
var dstI = args.get(3).toNumber(args.env).getInt();
|
||||||
|
var n = args.get(4).toNumber(args.env).getInt();
|
||||||
|
|
||||||
|
src.copyTo(dst, srcI, dstI, n);
|
||||||
|
|
||||||
|
return VoidValue.UNDEFINED;
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "sort", new NativeFunction(args -> {
|
||||||
|
var arr = (ArrayValue)args.get(0);
|
||||||
|
var func = (FunctionValue)args.get(1);
|
||||||
|
|
||||||
|
arr.sort((a, b) -> {
|
||||||
|
return func.apply(args.env, Value.UNDEFINED, a, b).toNumber(args.env).getInt();
|
||||||
|
});
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.defineOwnField(env, "isArray", new NativeFunction(args -> {
|
||||||
|
return BoolValue.of(args.get(0) instanceof ArrayLikeValue);
|
||||||
|
}));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectValue bufferPrimordials(Environment env) {
|
||||||
|
var buffProto = new ObjectValue();
|
||||||
|
buffProto.defineOwnProperty(env, "length", Optional.of(new NativeFunction(args -> {
|
||||||
|
return NumberValue.of(args.self(byte[].class).length);
|
||||||
|
})), Optional.empty(), false, true);
|
||||||
|
|
||||||
|
var res = new ObjectValue();
|
||||||
|
res.setPrototype(null, null);
|
||||||
|
|
||||||
|
res.defineOwnField(env, "buff", new NativeFunction(args -> {
|
||||||
|
var size = args.get(0).toNumber(env).getInt();
|
||||||
|
return TypedArrayValue.buffer(new byte[size], buffProto);
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.defineOwnField(env, "uint8", new NativeFunction(args -> {
|
||||||
|
var buff = args.get(byte[].class, 0);
|
||||||
|
var start = args.get(1).toNumber(env).getInt();
|
||||||
|
var end = args.get(2).toNumber(env).getInt();
|
||||||
|
return new Uint8ArrayValue(buff, start, end);
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "int8", new NativeFunction(args -> {
|
||||||
|
var buff = args.get(byte[].class, 0);
|
||||||
|
var start = args.get(1).toNumber(env).getInt();
|
||||||
|
var end = args.get(2).toNumber(env).getInt();
|
||||||
|
return new Int8ArrayValue(buff, start, end);
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "int32", new NativeFunction(args -> {
|
||||||
|
var buff = args.get(byte[].class, 0);
|
||||||
|
var start = args.get(1).toNumber(env).getInt();
|
||||||
|
var end = args.get(2).toNumber(env).getInt();
|
||||||
|
return new Int32ArrayValue(buff, start, end);
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.defineOwnField(env, "isUint8", new NativeFunction(args -> {
|
||||||
|
return BoolValue.of(args.get(0) instanceof Uint8ArrayValue);
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "isInt8", new NativeFunction(args -> {
|
||||||
|
return BoolValue.of(args.get(0) instanceof Int8ArrayValue);
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "isInt32", new NativeFunction(args -> {
|
||||||
|
return BoolValue.of(args.get(0) instanceof Int32ArrayValue);
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.defineOwnField(env, "is", new NativeFunction(args -> {
|
||||||
|
return BoolValue.of(args.get(0) instanceof TypedArrayValue);
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "isBuff", new NativeFunction(args -> {
|
||||||
|
return BoolValue.of(args.get(byte[].class, 0) != null);
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.defineOwnField(env, "backer", new NativeFunction(args -> {
|
||||||
|
return TypedArrayValue.buffer(((TypedArrayValue)args.get(0)).buffer, buffProto);
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "start", new NativeFunction(args -> {
|
||||||
|
return NumberValue.of(((TypedArrayValue)args.get(0)).start);
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "end", new NativeFunction(args -> {
|
||||||
|
return NumberValue.of(((TypedArrayValue)args.get(0)).end);
|
||||||
|
}));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectValue functionPrimordials(Environment env) {
|
||||||
|
var res = new ObjectValue();
|
||||||
|
res.setPrototype(null, null);
|
||||||
|
|
||||||
|
res.defineOwnField(env, "setCallable", new NativeFunction(args -> {
|
||||||
|
var func = (FunctionValue)args.get(0);
|
||||||
|
func.enableApply = args.get(1).toBoolean();
|
||||||
|
return Value.UNDEFINED;
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "setConstructable", new NativeFunction(args -> {
|
||||||
|
var func = (FunctionValue)args.get(0);
|
||||||
|
func.enableConstruct = args.get(1).toBoolean();
|
||||||
|
return Value.UNDEFINED;
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "invokeType", new NativeFunction(args -> {
|
||||||
|
if (((ArgumentsValue)args.get(0)).frame.isNew) return StringValue.of("new");
|
||||||
|
else return StringValue.of("call");
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "invokeTypeInfer", new NativeFunction(args -> {
|
||||||
|
var frame = Frame.get(args.env, args.get(0).toNumber(args.env).getInt());
|
||||||
|
if (frame.isNew) return StringValue.of("new");
|
||||||
|
else return StringValue.of("call");
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "target", new NativeFunction(args -> {
|
||||||
|
var frame = Frame.get(args.env, args.get(0).toNumber(args.env).getInt());
|
||||||
|
if (frame.target == null) return Value.UNDEFINED;
|
||||||
|
else return frame.target;
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.defineOwnField(env, "invoke", new NativeFunction(args -> {
|
||||||
|
var func = (FunctionValue)args.get(0);
|
||||||
|
var self = args.get(1);
|
||||||
|
var funcArgs = (ArrayLikeValue)args.get(2);
|
||||||
|
|
||||||
|
return func.apply(env, self, funcArgs.toArray());
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "construct", new NativeFunction(args -> {
|
||||||
|
var func = (FunctionValue)args.get(0);
|
||||||
|
var target = args.get(1);
|
||||||
|
var funcArgs = (ArrayLikeValue)args.get(2);
|
||||||
|
|
||||||
|
if (target == Value.UNDEFINED) return func.constructNoSelf(env, funcArgs.toArray());
|
||||||
|
else return func.construct(env, target, funcArgs.toArray());
|
||||||
|
}));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectValue jsonPrimordials(Environment env) {
|
||||||
|
var res = new ObjectValue();
|
||||||
|
res.setPrototype(null, null);
|
||||||
|
|
||||||
|
res.defineOwnField(env, "stringify", new NativeFunction(args -> {
|
||||||
|
return StringValue.of(JSON.stringify(JSONConverter.fromJs(env, args.get(0))));
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "parse", new NativeFunction(args -> {
|
||||||
|
try {
|
||||||
|
return JSONConverter.toJs(JSON.parse(null, args.get(0).toString(env)));
|
||||||
|
}
|
||||||
|
catch (SyntaxException e) {
|
||||||
|
throw EngineException.ofSyntax(e.msg).add(env, e.loc.filename() + "", e.loc);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setProto(Environment env, Environment target, Key<ObjectValue> key, ObjectValue repo, String name) {
|
||||||
|
var val = repo.getMember(env, name);
|
||||||
|
if (val instanceof ObjectValue obj) {
|
||||||
|
target.add(key, obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectValue create(Environment env) {
|
||||||
|
var res = new ObjectValue();
|
||||||
|
res.setPrototype(null, null);
|
||||||
|
|
||||||
|
res.defineOwnField(env, "symbol", symbolPrimordials(env));
|
||||||
|
res.defineOwnField(env, "number", numberPrimordials(env));
|
||||||
|
res.defineOwnField(env, "string", stringPrimordials(env));
|
||||||
|
res.defineOwnField(env, "object", objectPrimordials(env));
|
||||||
|
res.defineOwnField(env, "buffer", bufferPrimordials(env));
|
||||||
|
res.defineOwnField(env, "function", functionPrimordials(env));
|
||||||
|
res.defineOwnField(env, "json", jsonPrimordials(env));
|
||||||
|
res.defineOwnField(env, "map", mapPrimordials(env));
|
||||||
|
res.defineOwnField(env, "regex", regexPrimordials(env));
|
||||||
|
|
||||||
|
int[] i = new int[1];
|
||||||
|
|
||||||
|
res.defineOwnField(env, "setGlobalPrototypes", new NativeFunction(args -> {
|
||||||
|
var obj = (ObjectValue)args.get(0);
|
||||||
|
|
||||||
|
setProto(args.env, env, Value.OBJECT_PROTO, obj, "object");
|
||||||
|
setProto(args.env, env, Value.FUNCTION_PROTO, obj, "function");
|
||||||
|
setProto(args.env, env, Value.ARRAY_PROTO, obj, "array");
|
||||||
|
setProto(args.env, env, Value.BOOL_PROTO, obj, "boolean");
|
||||||
|
setProto(args.env, env, Value.NUMBER_PROTO, obj, "number");
|
||||||
|
setProto(args.env, env, Value.STRING_PROTO, obj, "string");
|
||||||
|
setProto(args.env, env, Value.SYMBOL_PROTO, obj, "symbol");
|
||||||
|
setProto(args.env, env, Value.ERROR_PROTO, obj, "error");
|
||||||
|
setProto(args.env, env, Value.SYNTAX_ERR_PROTO, obj, "syntax");
|
||||||
|
setProto(args.env, env, Value.TYPE_ERR_PROTO, obj, "type");
|
||||||
|
setProto(args.env, env, Value.RANGE_ERR_PROTO, obj, "range");
|
||||||
|
setProto(args.env, env, Value.UINT8_ARR_PROTO, obj, "uint8");
|
||||||
|
setProto(args.env, env, Value.INT32_ARR_PROTO, obj, "int32");
|
||||||
|
return Value.UNDEFINED;
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "setIntrinsic", new NativeFunction(args -> {
|
||||||
|
var name = args.get(0).toString(env);
|
||||||
|
var val = args.get(1);
|
||||||
|
|
||||||
|
Value.intrinsics(env).put(name, val);
|
||||||
|
|
||||||
|
return Value.UNDEFINED;
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "compile", new NativeFunction(args -> {
|
||||||
|
var nameVal = args.get(1);
|
||||||
|
var name = nameVal instanceof VoidValue ?
|
||||||
|
new Filename(Metadata.name(), "func" + i[0]++ + ".js") :
|
||||||
|
Filename.parse(nameVal.toString(args.env));
|
||||||
|
|
||||||
|
return Compiler.compileFunc(env, name, args.get(0).toString(env));
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "now", new NativeFunction(args -> {
|
||||||
|
return NumberValue.of(System.currentTimeMillis());
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "next", new NativeFunction(args -> {
|
||||||
|
var func = (FunctionValue)args.get(0);
|
||||||
|
EventLoop.get(env).pushMsg(() -> {
|
||||||
|
func.apply(env, Value.UNDEFINED);
|
||||||
|
}, true);
|
||||||
|
return Value.UNDEFINED;
|
||||||
|
}));
|
||||||
|
res.defineOwnField(env, "print", new NativeFunction(args -> {
|
||||||
|
for (var el : args.args) {
|
||||||
|
if (el instanceof StringValue) System.out.print(((StringValue)el).value + " \t");
|
||||||
|
else System.out.print(el.toReadable(args.env) + " \t");
|
||||||
|
}
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
return Value.UNDEFINED;
|
||||||
|
}));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
29
lib/src/main/java/me/topchetoeu/j2s/lib/StdLib.java
Normal file
29
lib/src/main/java/me/topchetoeu/j2s/lib/StdLib.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package me.topchetoeu.j2s.lib;
|
||||||
|
|
||||||
|
import me.topchetoeu.j2s.common.Environment;
|
||||||
|
import me.topchetoeu.j2s.common.Filename;
|
||||||
|
import me.topchetoeu.j2s.common.Metadata;
|
||||||
|
import me.topchetoeu.j2s.common.Reading;
|
||||||
|
import me.topchetoeu.j2s.compilation.CompileResult;
|
||||||
|
import me.topchetoeu.j2s.compilation.JavaScript;
|
||||||
|
import me.topchetoeu.j2s.runtime.values.Value;
|
||||||
|
import me.topchetoeu.j2s.runtime.values.functions.CodeFunction;
|
||||||
|
|
||||||
|
public class StdLib {
|
||||||
|
private static final CompileResult RUNNER = JavaScript.compile(new Filename(Metadata.name(), "init.js"), Reading.resourceToString("lib/stdlib.js"), false);
|
||||||
|
|
||||||
|
public static Environment apply(Environment env) {
|
||||||
|
if (env == null) {
|
||||||
|
env = new Environment();
|
||||||
|
}
|
||||||
|
|
||||||
|
var stubEnv = new Environment();
|
||||||
|
Value.global(stubEnv).defineOwnField(stubEnv, "target", Value.global(env));
|
||||||
|
Value.global(stubEnv).defineOwnField(stubEnv, "primordials", Primordials.create(env));
|
||||||
|
|
||||||
|
var func = new CodeFunction(stubEnv, "intializer", RUNNER.body(), new Value[0][]);
|
||||||
|
func.apply(stubEnv, Value.UNDEFINED);
|
||||||
|
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.j2s.repl.buffers;
|
package me.topchetoeu.j2s.lib.buffers;
|
||||||
|
|
||||||
public final class Int32ArrayValue extends TypedArrayValue {
|
public final class Int32ArrayValue extends TypedArrayValue {
|
||||||
@Override protected int onGet(int i) {
|
@Override protected int onGet(int i) {
|
@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.j2s.repl.buffers;
|
package me.topchetoeu.j2s.lib.buffers;
|
||||||
|
|
||||||
public final class Int8ArrayValue extends TypedArrayValue {
|
public final class Int8ArrayValue extends TypedArrayValue {
|
||||||
@Override protected int onGet(int i) {
|
@Override protected int onGet(int i) {
|
@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.j2s.repl.buffers;
|
package me.topchetoeu.j2s.lib.buffers;
|
||||||
|
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package me.topchetoeu.j2s.repl.buffers;
|
package me.topchetoeu.j2s.lib.buffers;
|
||||||
|
|
||||||
public final class Uint8ArrayValue extends TypedArrayValue {
|
public final class Uint8ArrayValue extends TypedArrayValue {
|
||||||
@Override protected int onGet(int i) {
|
@Override protected int onGet(int i) {
|
@ -1,4 +1,4 @@
|
|||||||
import { object, setGlobalPrototypes, setIntrinsic, target } from "./primordials.ts";
|
import { now, object, print, setGlobalPrototypes, setIntrinsic, target } from "./primordials.ts";
|
||||||
import { Error, RangeError, SyntaxError, TypeError } from "./values/errors.ts";
|
import { Error, RangeError, SyntaxError, TypeError } from "./values/errors.ts";
|
||||||
import { Boolean } from "./values/boolean.ts";
|
import { Boolean } from "./values/boolean.ts";
|
||||||
import { Function } from "./values/function.ts";
|
import { Function } from "./values/function.ts";
|
||||||
@ -21,11 +21,6 @@ import { Uint8Array } from "./arrays/Uint8Array.ts";
|
|||||||
import { Int32Array } from "./arrays/Int32Array.ts";
|
import { Int32Array } from "./arrays/Int32Array.ts";
|
||||||
import { TypedArray } from "./arrays/TypedArray.ts";
|
import { TypedArray } from "./arrays/TypedArray.ts";
|
||||||
|
|
||||||
declare global {
|
|
||||||
function print(...args: any[]): void;
|
|
||||||
function measure(func: Function): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
function fixup<T extends Function>(clazz: T) {
|
function fixup<T extends Function>(clazz: T) {
|
||||||
object.setPrototype(clazz, Function.prototype);
|
object.setPrototype(clazz, Function.prototype);
|
||||||
object.setPrototype(clazz.prototype as any, Object.prototype);
|
object.setPrototype(clazz.prototype as any, Object.prototype);
|
||||||
@ -72,6 +67,16 @@ target.NaN = Number.NaN;
|
|||||||
target.Infinity = Number.POSITIVE_INFINITY;
|
target.Infinity = Number.POSITIVE_INFINITY;
|
||||||
target.encodeURI = encodeURI;
|
target.encodeURI = encodeURI;
|
||||||
target.encodeURIComponent = encodeURIComponent;
|
target.encodeURIComponent = encodeURIComponent;
|
||||||
|
target.print = print;
|
||||||
|
target.measure = (func: () => void) => {
|
||||||
|
const start = now();
|
||||||
|
try {
|
||||||
|
return func();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
print(`Took ${now() - start}ms`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
setGlobalPrototypes({
|
setGlobalPrototypes({
|
||||||
string: String.prototype,
|
string: String.prototype,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { func, json, object } from "../primordials.ts";
|
import { func, object, print } from "../primordials.ts";
|
||||||
|
|
||||||
export const console = {};
|
export const console = {};
|
||||||
|
|
||||||
|
@ -111,6 +111,7 @@ export interface Primordials {
|
|||||||
next(func: () => void): void;
|
next(func: () => void): void;
|
||||||
schedule(func: () => void, delay: number): () => void;
|
schedule(func: () => void, delay: number): () => void;
|
||||||
setIntrinsic(key: string, val: any): void;
|
setIntrinsic(key: string, val: any): void;
|
||||||
|
print(...args: any[]): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
// prevent optimization to "undefined", which doesn't exist yet
|
// prevent optimization to "undefined", which doesn't exist yet
|
||||||
@ -134,6 +135,7 @@ export const {
|
|||||||
next,
|
next,
|
||||||
schedule,
|
schedule,
|
||||||
setIntrinsic,
|
setIntrinsic,
|
||||||
|
print,
|
||||||
} = primordials;
|
} = primordials;
|
||||||
|
|
||||||
export type regex = InstanceType<typeof regex>;
|
export type regex = InstanceType<typeof regex>;
|
3
lib/src/transpiler/_entry-coffee.ts
Normal file
3
lib/src/transpiler/_entry-coffee.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import coffee from "./coffeescript.ts";
|
||||||
|
|
||||||
|
register(coffee);
|
3
lib/src/transpiler/_entry-typescript.ts
Normal file
3
lib/src/transpiler/_entry-typescript.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import ts from "./typescript.ts";
|
||||||
|
|
||||||
|
register(ts);
|
@ -47,6 +47,7 @@ export default function babel(next: Compiler): Compiler {
|
|||||||
availablePlugins["transform-exponentiation-operator"],
|
availablePlugins["transform-exponentiation-operator"],
|
||||||
|
|
||||||
// ES2015
|
// ES2015
|
||||||
|
availablePlugins["transform-regenerator"],
|
||||||
availablePlugins["transform-arrow-functions"],
|
availablePlugins["transform-arrow-functions"],
|
||||||
availablePlugins["transform-block-scoping"],
|
availablePlugins["transform-block-scoping"],
|
||||||
availablePlugins["transform-classes"],
|
availablePlugins["transform-classes"],
|
||||||
|
@ -5,15 +5,6 @@ plugins {
|
|||||||
|
|
||||||
description = "A simple REPL for the interpreter, can be used for simple prototyping";
|
description = "A simple REPL for the interpreter, can be used for simple prototyping";
|
||||||
|
|
||||||
tasks.processResources {
|
|
||||||
filesMatching("metadata.json", {
|
|
||||||
expand(
|
|
||||||
"version" to properties["project_version"],
|
|
||||||
"name" to properties["project_name"],
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.test {
|
tasks.test {
|
||||||
useJUnitPlatform();
|
useJUnitPlatform();
|
||||||
}
|
}
|
||||||
|
@ -6,15 +6,8 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.WeakHashMap;
|
|
||||||
import java.util.concurrent.CancellationException;
|
import java.util.concurrent.CancellationException;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import java.util.regex.PatternSyntaxException;
|
|
||||||
|
|
||||||
import me.topchetoeu.j2s.common.Environment;
|
import me.topchetoeu.j2s.common.Environment;
|
||||||
import me.topchetoeu.j2s.common.Filename;
|
import me.topchetoeu.j2s.common.Filename;
|
||||||
@ -22,63 +15,24 @@ import me.topchetoeu.j2s.common.Key;
|
|||||||
import me.topchetoeu.j2s.common.Metadata;
|
import me.topchetoeu.j2s.common.Metadata;
|
||||||
import me.topchetoeu.j2s.common.Reading;
|
import me.topchetoeu.j2s.common.Reading;
|
||||||
import me.topchetoeu.j2s.common.SyntaxException;
|
import me.topchetoeu.j2s.common.SyntaxException;
|
||||||
import me.topchetoeu.j2s.compilation.JavaScript;
|
import me.topchetoeu.j2s.lib.Compilers;
|
||||||
import me.topchetoeu.j2s.compilation.json.JSON;
|
import me.topchetoeu.j2s.lib.StdLib;
|
||||||
import me.topchetoeu.j2s.compilation.parsing.Parsing;
|
|
||||||
import me.topchetoeu.j2s.compilation.parsing.Source;
|
|
||||||
import me.topchetoeu.j2s.repl.buffers.Int32ArrayValue;
|
|
||||||
import me.topchetoeu.j2s.repl.buffers.Int8ArrayValue;
|
|
||||||
import me.topchetoeu.j2s.repl.buffers.TypedArrayValue;
|
|
||||||
import me.topchetoeu.j2s.repl.buffers.Uint8ArrayValue;
|
|
||||||
import me.topchetoeu.j2s.repl.debug.SimpleDebugHandler;
|
import me.topchetoeu.j2s.repl.debug.SimpleDebugHandler;
|
||||||
import me.topchetoeu.j2s.repl.debug.DebugServer;
|
import me.topchetoeu.j2s.repl.debug.DebugServer;
|
||||||
import me.topchetoeu.j2s.repl.debug.Debugger;
|
import me.topchetoeu.j2s.repl.debug.Debugger;
|
||||||
import me.topchetoeu.j2s.repl.debug.SimpleDebugger;
|
import me.topchetoeu.j2s.repl.debug.SimpleDebugger;
|
||||||
import me.topchetoeu.j2s.repl.mapping.NativeMapper;
|
|
||||||
import me.topchetoeu.j2s.runtime.ArgumentsValue;
|
|
||||||
import me.topchetoeu.j2s.runtime.Compiler;
|
import me.topchetoeu.j2s.runtime.Compiler;
|
||||||
import me.topchetoeu.j2s.runtime.Engine;
|
import me.topchetoeu.j2s.runtime.Engine;
|
||||||
import me.topchetoeu.j2s.runtime.EventLoop;
|
import me.topchetoeu.j2s.runtime.EventLoop;
|
||||||
import me.topchetoeu.j2s.runtime.Frame;
|
|
||||||
import me.topchetoeu.j2s.runtime.debug.DebugHandler;
|
import me.topchetoeu.j2s.runtime.debug.DebugHandler;
|
||||||
import me.topchetoeu.j2s.runtime.exceptions.EngineException;
|
import me.topchetoeu.j2s.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.j2s.runtime.values.Value;
|
import me.topchetoeu.j2s.runtime.values.Value;
|
||||||
import me.topchetoeu.j2s.runtime.values.functions.CodeFunction;
|
|
||||||
import me.topchetoeu.j2s.runtime.values.functions.FunctionValue;
|
|
||||||
import me.topchetoeu.j2s.runtime.values.functions.NativeFunction;
|
import me.topchetoeu.j2s.runtime.values.functions.NativeFunction;
|
||||||
import me.topchetoeu.j2s.runtime.values.objects.ArrayLikeValue;
|
|
||||||
import me.topchetoeu.j2s.runtime.values.objects.ArrayValue;
|
|
||||||
import me.topchetoeu.j2s.runtime.values.objects.ObjectValue;
|
|
||||||
import me.topchetoeu.j2s.runtime.values.primitives.BoolValue;
|
|
||||||
import me.topchetoeu.j2s.runtime.values.primitives.StringValue;
|
|
||||||
import me.topchetoeu.j2s.runtime.values.primitives.SymbolValue;
|
|
||||||
import me.topchetoeu.j2s.runtime.values.primitives.UserValue;
|
|
||||||
import me.topchetoeu.j2s.runtime.values.primitives.VoidValue;
|
|
||||||
import me.topchetoeu.j2s.runtime.values.primitives.numbers.NumberValue;
|
|
||||||
|
|
||||||
public class SimpleRepl {
|
public class SimpleRepl {
|
||||||
public static final Compiler DEFAULT_COMPILER = (env, filename, raw, mapper) -> {
|
|
||||||
try {
|
|
||||||
var res = JavaScript.compile(env, filename, raw, true);
|
|
||||||
var body = res.body();
|
|
||||||
|
|
||||||
DebugHandler.get(env).onSourceLoad(filename, raw);
|
|
||||||
for (var el : res.all()) {
|
|
||||||
DebugHandler.get(env).onFunctionLoad(el.body(), el.map(mapper));
|
|
||||||
}
|
|
||||||
|
|
||||||
return new CodeFunction(env, filename.toString(), body, new Value[0][]);
|
|
||||||
}
|
|
||||||
catch (SyntaxException e) {
|
|
||||||
var res = EngineException.ofSyntax(e.msg);
|
|
||||||
res.add(env, e.loc.filename() + "", e.loc);
|
|
||||||
throw res;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static Thread engineTask, debugTask;
|
static Thread engineTask, debugTask;
|
||||||
static Engine engine = new Engine();
|
static Engine engine = new Engine();
|
||||||
static Environment environment = Environment.empty(), tsEnvironment;
|
static Environment environment = Environment.empty();
|
||||||
static DebugServer server;
|
static DebugServer server;
|
||||||
static Debugger debugger;
|
static Debugger debugger;
|
||||||
static Key<OutputStream> STDOUT = new Key<>();
|
static Key<OutputStream> STDOUT = new Key<>();
|
||||||
@ -90,28 +44,12 @@ public class SimpleRepl {
|
|||||||
|
|
||||||
private static void reader() {
|
private static void reader() {
|
||||||
try {
|
try {
|
||||||
try {
|
|
||||||
environment = createESEnv();
|
|
||||||
tsEnvironment = createESEnv();
|
|
||||||
}
|
|
||||||
catch (ExecutionException e) { throw e.getCause(); }
|
|
||||||
|
|
||||||
server = new DebugServer();
|
server = new DebugServer();
|
||||||
debugTask = server.start(new InetSocketAddress("127.0.0.1", 9229), true);
|
debugTask = server.start(new InetSocketAddress("127.0.0.1", 9229), true);
|
||||||
server.targets.put("default", (socket, req) -> new SimpleDebugger(socket)
|
server.targets.put("default", (socket, req) -> new SimpleDebugger(socket)
|
||||||
.attach((SimpleDebugHandler)DebugHandler.get(environment))
|
.attach((SimpleDebugHandler)DebugHandler.get(environment))
|
||||||
.attach((SimpleDebugHandler)DebugHandler.get(tsEnvironment))
|
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
|
||||||
try { initGlobals(); } catch (ExecutionException e) { throw e.getCause(); }
|
|
||||||
}
|
|
||||||
catch (EngineException | SyntaxException e) {
|
|
||||||
System.err.println("Failed to load stdlib. Falling back to barebones environment...");
|
|
||||||
System.err.println(Value.errorToReadable(environment, e, null));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
System.out.println(String.format("Running %s v%s by %s", Metadata.name(), Metadata.version(), Metadata.author()));
|
System.out.println(String.format("Running %s v%s by %s", Metadata.name(), Metadata.version(), Metadata.author()));
|
||||||
|
|
||||||
for (var arg : args) {
|
for (var arg : args) {
|
||||||
@ -165,691 +103,12 @@ public class SimpleRepl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
private static Environment createESEnv() {
|
||||||
private static ObjectValue mapPrimordials(Environment env) {
|
|
||||||
var res = new ObjectValue();
|
|
||||||
res.setPrototype(null, null);
|
|
||||||
|
|
||||||
var prototype = new ObjectValue[1];
|
|
||||||
NativeFunction mapConstr = new NativeFunction(args -> {
|
|
||||||
var isWeak = args.get(0).toBoolean();
|
|
||||||
return UserValue.of(isWeak ? new WeakHashMap<>() : new LinkedHashMap<>(), prototype[0]);
|
|
||||||
});
|
|
||||||
mapConstr.prototype.defineOwnField(env, "get", new NativeFunction(getArgs -> {
|
|
||||||
var map = getArgs.self(Map.class);
|
|
||||||
var key = getArgs.get(0);
|
|
||||||
var val = map.get(key);
|
|
||||||
return val == null ? Value.UNDEFINED : (Value)val;
|
|
||||||
}));
|
|
||||||
mapConstr.prototype.defineOwnField(env, "set", new NativeFunction(getArgs -> {
|
|
||||||
var map = getArgs.self(Map.class);
|
|
||||||
var key = getArgs.get(0);
|
|
||||||
var val = getArgs.get(1);
|
|
||||||
map.put(key, val);
|
|
||||||
|
|
||||||
return Value.UNDEFINED;
|
|
||||||
}));
|
|
||||||
mapConstr.prototype.defineOwnField(env, "has", new NativeFunction(getArgs -> {
|
|
||||||
var map = getArgs.self(Map.class);
|
|
||||||
var key = getArgs.get(0);
|
|
||||||
return BoolValue.of(map.containsKey(key));
|
|
||||||
}));
|
|
||||||
mapConstr.prototype.defineOwnField(env, "delete", new NativeFunction(getArgs -> {
|
|
||||||
var map = getArgs.self(Map.class);
|
|
||||||
var key = getArgs.get(0);
|
|
||||||
map.remove(key);
|
|
||||||
return Value.UNDEFINED;
|
|
||||||
}));
|
|
||||||
mapConstr.prototype.defineOwnField(env, "keys", new NativeFunction(getArgs -> {
|
|
||||||
var map = getArgs.self(Map.class);
|
|
||||||
return ArrayValue.of(map.keySet());
|
|
||||||
}));
|
|
||||||
mapConstr.prototype.defineOwnField(env, "clear", new NativeFunction(getArgs -> {
|
|
||||||
getArgs.self(Map.class).clear();
|
|
||||||
return Value.UNDEFINED;
|
|
||||||
}));
|
|
||||||
mapConstr.prototype.defineOwnField(env, "size", new NativeFunction(getArgs -> {
|
|
||||||
return NumberValue.of(getArgs.self(Map.class).size());
|
|
||||||
}));
|
|
||||||
prototype[0] = (ObjectValue)mapConstr.prototype;
|
|
||||||
|
|
||||||
return mapConstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String processRegex(String src) {
|
|
||||||
var n = 0;
|
|
||||||
|
|
||||||
var source = new StringBuilder();
|
|
||||||
|
|
||||||
StringBuilder bracesSource = null;
|
|
||||||
StringBuilder bracketsSource = null;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (n >= src.length()) break;
|
|
||||||
var c = src.charAt(n++);
|
|
||||||
|
|
||||||
if (c == '\\' && n + 1 < src.length() && src.charAt(n) == 'b') {
|
|
||||||
c = '\b';
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bracesSource != null) {
|
|
||||||
var failed = true;
|
|
||||||
|
|
||||||
if (Character.isDigit(c)) {
|
|
||||||
bracesSource.append(c);
|
|
||||||
failed = false;
|
|
||||||
}
|
|
||||||
else if (c == ',' && bracesSource.indexOf(",") < 0) {
|
|
||||||
bracesSource.append(c);
|
|
||||||
failed = false;
|
|
||||||
}
|
|
||||||
else if (c == '}' && bracesSource.length() > 0) {
|
|
||||||
bracesSource.append(c);
|
|
||||||
source.append(bracesSource);
|
|
||||||
bracesSource = null;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (failed) {
|
|
||||||
source.append("\\");
|
|
||||||
source.append(bracesSource);
|
|
||||||
bracesSource = null;
|
|
||||||
n--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (bracketsSource != null) {
|
|
||||||
if (c == '[') bracketsSource.append("\\[");
|
|
||||||
else if (c == ']') {
|
|
||||||
var res = bracketsSource.append(']').toString();
|
|
||||||
bracketsSource = null;
|
|
||||||
if (res.equals("[^]")) res = "[\\s\\S]";
|
|
||||||
else if (res.equals("[]")) res = "[^\\s\\S]";
|
|
||||||
source.append(res);
|
|
||||||
}
|
|
||||||
else if (c == '\\') {
|
|
||||||
if (n >= src.length()) break;
|
|
||||||
bracketsSource.append(c).append(src.charAt(n++));
|
|
||||||
}
|
|
||||||
else bracketsSource.append(c);
|
|
||||||
}
|
|
||||||
else if (c == '\\') {
|
|
||||||
if (n >= src.length()) throw new PatternSyntaxException("Unexpected end", src, n);
|
|
||||||
c = src.charAt(n++);
|
|
||||||
source.append('\\').append(c);
|
|
||||||
}
|
|
||||||
else if (c == '[') {
|
|
||||||
bracketsSource = new StringBuilder("[");
|
|
||||||
}
|
|
||||||
else if (c == '{' && bracketsSource == null) {
|
|
||||||
bracesSource = new StringBuilder("{");
|
|
||||||
}
|
|
||||||
else source.append(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bracesSource != null) {
|
|
||||||
source.append("\\");
|
|
||||||
source.append(bracesSource);
|
|
||||||
}
|
|
||||||
if (bracketsSource != null) throw new PatternSyntaxException("Unmatched '['", src, n - bracketsSource.length());
|
|
||||||
|
|
||||||
return source.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ObjectValue regexPrimordials(Environment env) {
|
|
||||||
var res = new ObjectValue();
|
|
||||||
res.setPrototype(null, null);
|
|
||||||
|
|
||||||
var prototype = new ObjectValue[1];
|
|
||||||
NativeFunction mapConstr = new NativeFunction(args -> {
|
|
||||||
var flags = 0;
|
|
||||||
if (args.get(1).toBoolean()) flags |= Pattern.MULTILINE;
|
|
||||||
if (args.get(2).toBoolean()) flags |= Pattern.CASE_INSENSITIVE;
|
|
||||||
if (args.get(3).toBoolean()) flags |= Pattern.DOTALL;
|
|
||||||
if (args.get(4).toBoolean()) flags |= Pattern.UNICODE_CASE | Pattern.CANON_EQ;
|
|
||||||
if (args.get(5).toBoolean()) flags |= Pattern.UNICODE_CHARACTER_CLASS;
|
|
||||||
try {
|
|
||||||
var pattern = Pattern.compile(processRegex(args.get(0).toString(args.env)), flags);
|
|
||||||
return UserValue.of(pattern, prototype[0]);
|
|
||||||
}
|
|
||||||
catch (PatternSyntaxException e) {
|
|
||||||
throw EngineException.ofSyntax("(regex):" + e.getIndex() + ": " + e.getDescription());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mapConstr.prototype.defineOwnField(env, "exec", new NativeFunction(args -> {
|
|
||||||
var pattern = args.self(Pattern.class);
|
|
||||||
var target = args.get(0).toString(args.env);
|
|
||||||
var offset = args.get(1).toNumber(args.env).getInt();
|
|
||||||
var index = args.get(2).toBoolean();
|
|
||||||
|
|
||||||
if (offset > target.length()) return Value.NULL;
|
|
||||||
|
|
||||||
var matcher = pattern.matcher(target).region(offset, target.length());
|
|
||||||
if (!matcher.find()) return Value.NULL;
|
|
||||||
|
|
||||||
var matchesArr = new ArrayValue(matcher.groupCount() + 1);
|
|
||||||
for (var i = 0; i < matcher.groupCount() + 1; i++) {
|
|
||||||
var group = matcher.group(i);
|
|
||||||
if (group == null) continue;
|
|
||||||
matchesArr.set(args.env, i, StringValue.of(group));
|
|
||||||
}
|
|
||||||
|
|
||||||
matchesArr.defineOwnField(args.env, "index", NumberValue.of(matcher.start()));
|
|
||||||
matchesArr.defineOwnField(args.env, "input", StringValue.of(target));
|
|
||||||
if (index) {
|
|
||||||
var indices = new ArrayValue();
|
|
||||||
indices.setPrototype(args.env, null);
|
|
||||||
for (var i = 0; i < matcher.groupCount(); i++) {
|
|
||||||
matchesArr.set(args.env, i, ArrayValue.of(Arrays.asList(
|
|
||||||
NumberValue.of(matcher.start(i)),
|
|
||||||
NumberValue.of(matcher.end(i))
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var obj = new ObjectValue();
|
|
||||||
obj.defineOwnField(args.env, "matches", matchesArr);
|
|
||||||
obj.defineOwnField(args.env, "end", NumberValue.of(matcher.end()));
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
// return val == null ? Value.UNDEFINED : (Value)val;
|
|
||||||
}));
|
|
||||||
mapConstr.prototype.defineOwnField(env, "groupCount", new NativeFunction(args -> {
|
|
||||||
var pattern = args.self(Pattern.class);
|
|
||||||
return NumberValue.of(pattern.matcher("").groupCount());
|
|
||||||
}));
|
|
||||||
prototype[0] = (ObjectValue)mapConstr.prototype;
|
|
||||||
|
|
||||||
return mapConstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ObjectValue symbolPrimordials(Environment env) {
|
|
||||||
var res = new ObjectValue();
|
|
||||||
res.setPrototype(null, null);
|
|
||||||
|
|
||||||
res.defineOwnField(env, "makeSymbol", new NativeFunction(args -> new SymbolValue(args.get(0).toString(args.env))));
|
|
||||||
res.defineOwnField(env, "getSymbol", new NativeFunction(args -> SymbolValue.get(args.get(0).toString(args.env))));
|
|
||||||
res.defineOwnField(env, "getSymbolKey", new NativeFunction(args -> ((SymbolValue)args.get(0)).key()));
|
|
||||||
res.defineOwnField(env, "getSymbolDescriptor", new NativeFunction(args -> StringValue.of(((SymbolValue)args.get(0)).value)));
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ObjectValue numberPrimordials(Environment env) {
|
|
||||||
var res = new ObjectValue();
|
|
||||||
res.setPrototype(null, null);
|
|
||||||
|
|
||||||
res.defineOwnField(env, "parseInt", new NativeFunction(args -> {
|
|
||||||
var nradix = args.get(1).toNumber(env);
|
|
||||||
var radix = nradix.isInt() ? nradix.getInt() : 10;
|
|
||||||
|
|
||||||
if (radix != 10 && args.get(0) instanceof NumberValue num) {
|
|
||||||
if (num.isInt()) return num;
|
|
||||||
else return NumberValue.of(num.getDouble() - num.getDouble() % 1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (radix < 2 || radix > 36) return NumberValue.NAN;
|
|
||||||
|
|
||||||
var str = args.get(0).toString().trim();
|
|
||||||
var numRes = Parsing.parseInt(new Source(str), 0, "0123456789abcdefghijklmnopqrstuvwxyz".substring(0, radix), true);
|
|
||||||
if (numRes.isSuccess()) {
|
|
||||||
if (numRes.n == str.length()) return NumberValue.of(numRes.result);
|
|
||||||
}
|
|
||||||
return NumberValue.NAN;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "parseFloat", new NativeFunction(args -> {
|
|
||||||
if (args.get(0) instanceof NumberValue) {
|
|
||||||
return args.get(0);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var str = args.get(0).toString().trim();
|
|
||||||
var numRes = Parsing.parseFloat(new Source(str), 0, true);
|
|
||||||
if (numRes.isSuccess()) {
|
|
||||||
if (numRes.n == str.length()) return NumberValue.of(numRes.result);
|
|
||||||
}
|
|
||||||
return NumberValue.NAN;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "isNaN", new NativeFunction(args -> BoolValue.of(args.get(0).isNaN())));
|
|
||||||
|
|
||||||
res.defineOwnField(env, "pow", new NativeFunction(args -> {
|
|
||||||
return NumberValue.of(Math.pow(args.get(0).toNumber(args.env).getDouble(), args.get(1).toNumber(args.env).getDouble()));
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "log", new NativeFunction(args -> {
|
|
||||||
return NumberValue.of(Math.log(args.get(0).toNumber(args.env).getDouble()));
|
|
||||||
}));
|
|
||||||
|
|
||||||
res.defineOwnField(env, "NaN", NumberValue.NAN);
|
|
||||||
res.defineOwnField(env, "Infinity", NumberValue.of(Double.POSITIVE_INFINITY));
|
|
||||||
res.defineOwnField(env, "PI", NumberValue.of(Math.PI));
|
|
||||||
res.defineOwnField(env, "E", NumberValue.of(Math.E));
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ObjectValue stringPrimordials(Environment env) {
|
|
||||||
var res = new ObjectValue();
|
|
||||||
res.setPrototype(null, null);
|
|
||||||
|
|
||||||
res.defineOwnField(env, "stringBuild", new NativeFunction(args -> {
|
|
||||||
var parts = ((ArrayValue)args.get(0)).toArray();
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
|
|
||||||
for (var i = 0; i < parts.length; i++) {
|
|
||||||
sb.append(((StringValue)parts[i]).value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return StringValue.of(sb.toString());
|
|
||||||
}));
|
|
||||||
|
|
||||||
res.defineOwnField(env, "fromCharCode", new NativeFunction(args -> {
|
|
||||||
return StringValue.of(new String(new char[] { (char)args.get(0).toNumber(args.env).getInt() }));
|
|
||||||
}));
|
|
||||||
|
|
||||||
res.defineOwnField(env, "toCharCode", new NativeFunction(args -> {
|
|
||||||
return NumberValue.of(args.get(0).toString(args.env).charAt(0));
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "toCodePoint", new NativeFunction(args -> {
|
|
||||||
return NumberValue.of(args.get(0).toString(args.env).codePointAt(args.get(1).toNumber(args.env).getInt()));
|
|
||||||
}));
|
|
||||||
|
|
||||||
res.defineOwnField(env, "substring", new NativeFunction(args -> {
|
|
||||||
var str = args.get(0).toString(args.env);
|
|
||||||
var start = args.get(1).toNumber(args.env).getInt();
|
|
||||||
var end = args.get(2).toNumber(args.env).getInt();
|
|
||||||
|
|
||||||
if (end <= start) return StringValue.of("");
|
|
||||||
|
|
||||||
start = Math.max(Math.min(start, str.length()), 0);
|
|
||||||
end = Math.max(Math.min(end, str.length()), 0);
|
|
||||||
|
|
||||||
return StringValue.of(str.substring(start, end));
|
|
||||||
}));
|
|
||||||
|
|
||||||
res.defineOwnField(env, "indexOf", new NativeFunction(args -> {
|
|
||||||
var str = args.get(0).toString(args.env);
|
|
||||||
var search = args.get(1).toString(args.env);
|
|
||||||
var start = args.get(2).toNumber(args.env).getInt();
|
|
||||||
if (start > str.length()) return NumberValue.of(-1);
|
|
||||||
var reverse = args.get(3).toBoolean();
|
|
||||||
|
|
||||||
if (reverse) return NumberValue.of(str.lastIndexOf(search, start));
|
|
||||||
else return NumberValue.of(str.indexOf(search, start));
|
|
||||||
}));
|
|
||||||
|
|
||||||
res.defineOwnField(env, "lower", new NativeFunction(args -> {
|
|
||||||
return StringValue.of(args.get(0).toString(args.env).toLowerCase());
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "upper", new NativeFunction(args -> {
|
|
||||||
return StringValue.of(args.get(0).toString(args.env).toUpperCase());
|
|
||||||
}));
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ObjectValue objectPrimordials(Environment env) {
|
|
||||||
var res = new ObjectValue();
|
|
||||||
res.setPrototype(null, null);
|
|
||||||
|
|
||||||
res.defineOwnField(env, "defineField", new NativeFunction(args -> {
|
|
||||||
var obj = (ObjectValue)args.get(0);
|
|
||||||
var key = args.get(1);
|
|
||||||
var desc = (ObjectValue)args.get(2);
|
|
||||||
|
|
||||||
var valField = desc.getOwnMember(env, "v");
|
|
||||||
var writeField = desc.getOwnMember(env, "w");
|
|
||||||
var configField = desc.getOwnMember(env, "c");
|
|
||||||
var enumField = desc.getOwnMember(env, "e");
|
|
||||||
|
|
||||||
var enumerable = enumField == null ? null : enumField.get(env, desc).toBoolean();
|
|
||||||
var configurable = configField == null ? null : configField.get(env, desc).toBoolean();
|
|
||||||
var writable = writeField == null ? null : writeField.get(env, desc).toBoolean();
|
|
||||||
var value = valField == null ? null : valField.get(env, desc);
|
|
||||||
|
|
||||||
return BoolValue.of(obj.defineOwnField(args.env, key, value, configurable, enumerable, writable));
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "defineProperty", new NativeFunction(args -> {
|
|
||||||
var obj = (ObjectValue)args.get(0);
|
|
||||||
var key = args.get(1);
|
|
||||||
var desc = args.get(2);
|
|
||||||
|
|
||||||
var configField = desc.getOwnMember(env, "c");
|
|
||||||
var enumField = desc.getOwnMember(env, "e");
|
|
||||||
var getField = desc.getOwnMember(env, "g");
|
|
||||||
var setField = desc.getOwnMember(env, "s");
|
|
||||||
|
|
||||||
var enumerable = enumField == null ? null : enumField.get(env, desc).toBoolean();
|
|
||||||
var configurable = configField == null ? null : configField.get(env, desc).toBoolean();
|
|
||||||
Optional<FunctionValue> getter = null, setter = null;
|
|
||||||
|
|
||||||
if (getField != null) {
|
|
||||||
var getVal = getField.get(env, desc);
|
|
||||||
if (getVal == Value.UNDEFINED) getter = Optional.empty();
|
|
||||||
else getter = Optional.of((FunctionValue)getVal);
|
|
||||||
}
|
|
||||||
if (setField != null) {
|
|
||||||
var setVal = setField.get(env, desc);
|
|
||||||
if (setVal == Value.UNDEFINED) setter = Optional.empty();
|
|
||||||
else setter = Optional.of((FunctionValue)setVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
return BoolValue.of(obj.defineOwnProperty(args.env, key, getter, setter, configurable, enumerable));
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "getPrototype", new NativeFunction(args -> {
|
|
||||||
var proto = args.get(0).getPrototype(env);
|
|
||||||
if (proto == null) return Value.NULL;
|
|
||||||
else return proto;
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "setPrototype", new NativeFunction(args -> {
|
|
||||||
var proto = args.get(1) instanceof VoidValue ? null : (ObjectValue)args.get(1);
|
|
||||||
args.get(0).setPrototype(env, proto);
|
|
||||||
return args.get(0);
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "getMembers", new NativeFunction(args -> {
|
|
||||||
var val = new ArrayValue();
|
|
||||||
|
|
||||||
for (var key : args.get(0).getMembers(env, args.get(1).toBoolean(), args.get(2).toBoolean())) {
|
|
||||||
val.set(args.env, val.size(), StringValue.of(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "getSymbolMembers", new NativeFunction(args -> {
|
|
||||||
return ArrayValue.of(args.get(0).getSymbolMembers(env, args.get(1).toBoolean(), args.get(2).toBoolean()));
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "getOwnMember", new NativeFunction(args -> {
|
|
||||||
var obj = args.get(0);
|
|
||||||
var key = args.get(1);
|
|
||||||
|
|
||||||
var member = obj.getOwnMember(args.env, key);
|
|
||||||
if (member == null) return Value.UNDEFINED;
|
|
||||||
else return member.descriptor(args.env, obj);
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "preventExt", new NativeFunction(args -> {
|
|
||||||
args.get(0).preventExtensions();
|
|
||||||
return VoidValue.UNDEFINED;
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "seal", new NativeFunction(args -> {
|
|
||||||
args.get(0).seal();
|
|
||||||
return VoidValue.UNDEFINED;
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "freeze", new NativeFunction(args -> {
|
|
||||||
args.get(0).freeze();
|
|
||||||
return VoidValue.UNDEFINED;
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "memcpy", new NativeFunction(args -> {
|
|
||||||
var src = (ArrayValue)args.get(0);
|
|
||||||
var dst = (ArrayValue)args.get(1);
|
|
||||||
var srcI = args.get(2).toNumber(args.env).getInt();
|
|
||||||
var dstI = args.get(3).toNumber(args.env).getInt();
|
|
||||||
var n = args.get(4).toNumber(args.env).getInt();
|
|
||||||
|
|
||||||
src.copyTo(dst, srcI, dstI, n);
|
|
||||||
|
|
||||||
return VoidValue.UNDEFINED;
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "sort", new NativeFunction(args -> {
|
|
||||||
var arr = (ArrayValue)args.get(0);
|
|
||||||
var func = (FunctionValue)args.get(1);
|
|
||||||
|
|
||||||
arr.sort((a, b) -> {
|
|
||||||
return func.apply(args.env, Value.UNDEFINED, a, b).toNumber(args.env).getInt();
|
|
||||||
});
|
|
||||||
|
|
||||||
return arr;
|
|
||||||
}));
|
|
||||||
|
|
||||||
res.defineOwnField(env, "isArray", new NativeFunction(args -> {
|
|
||||||
return BoolValue.of(args.get(0) instanceof ArrayLikeValue);
|
|
||||||
}));
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ObjectValue bufferPrimordials(Environment env) {
|
|
||||||
var buffProto = new ObjectValue();
|
|
||||||
buffProto.defineOwnProperty(env, "length", Optional.of(new NativeFunction(args -> {
|
|
||||||
return NumberValue.of(args.self(byte[].class).length);
|
|
||||||
})), Optional.empty(), false, true);
|
|
||||||
|
|
||||||
var res = new ObjectValue();
|
|
||||||
res.setPrototype(null, null);
|
|
||||||
|
|
||||||
res.defineOwnField(env, "buff", new NativeFunction(args -> {
|
|
||||||
var size = args.get(0).toNumber(env).getInt();
|
|
||||||
return TypedArrayValue.buffer(new byte[size], buffProto);
|
|
||||||
}));
|
|
||||||
|
|
||||||
res.defineOwnField(env, "uint8", new NativeFunction(args -> {
|
|
||||||
var buff = args.get(byte[].class, 0);
|
|
||||||
var start = args.get(1).toNumber(env).getInt();
|
|
||||||
var end = args.get(2).toNumber(env).getInt();
|
|
||||||
return new Uint8ArrayValue(buff, start, end);
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "int8", new NativeFunction(args -> {
|
|
||||||
var buff = args.get(byte[].class, 0);
|
|
||||||
var start = args.get(1).toNumber(env).getInt();
|
|
||||||
var end = args.get(2).toNumber(env).getInt();
|
|
||||||
return new Int8ArrayValue(buff, start, end);
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "int32", new NativeFunction(args -> {
|
|
||||||
var buff = args.get(byte[].class, 0);
|
|
||||||
var start = args.get(1).toNumber(env).getInt();
|
|
||||||
var end = args.get(2).toNumber(env).getInt();
|
|
||||||
return new Int32ArrayValue(buff, start, end);
|
|
||||||
}));
|
|
||||||
|
|
||||||
res.defineOwnField(env, "isUint8", new NativeFunction(args -> {
|
|
||||||
return BoolValue.of(args.get(0) instanceof Uint8ArrayValue);
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "isInt8", new NativeFunction(args -> {
|
|
||||||
return BoolValue.of(args.get(0) instanceof Int8ArrayValue);
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "isInt32", new NativeFunction(args -> {
|
|
||||||
return BoolValue.of(args.get(0) instanceof Int32ArrayValue);
|
|
||||||
}));
|
|
||||||
|
|
||||||
res.defineOwnField(env, "is", new NativeFunction(args -> {
|
|
||||||
return BoolValue.of(args.get(0) instanceof TypedArrayValue);
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "isBuff", new NativeFunction(args -> {
|
|
||||||
return BoolValue.of(args.get(byte[].class, 0) != null);
|
|
||||||
}));
|
|
||||||
|
|
||||||
res.defineOwnField(env, "backer", new NativeFunction(args -> {
|
|
||||||
return TypedArrayValue.buffer(((TypedArrayValue)args.get(0)).buffer, buffProto);
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "start", new NativeFunction(args -> {
|
|
||||||
return NumberValue.of(((TypedArrayValue)args.get(0)).start);
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "end", new NativeFunction(args -> {
|
|
||||||
return NumberValue.of(((TypedArrayValue)args.get(0)).end);
|
|
||||||
}));
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ObjectValue functionPrimordials(Environment env) {
|
|
||||||
var res = new ObjectValue();
|
|
||||||
res.setPrototype(null, null);
|
|
||||||
|
|
||||||
res.defineOwnField(env, "setCallable", new NativeFunction(args -> {
|
|
||||||
var func = (FunctionValue)args.get(0);
|
|
||||||
func.enableApply = args.get(1).toBoolean();
|
|
||||||
return Value.UNDEFINED;
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "setConstructable", new NativeFunction(args -> {
|
|
||||||
var func = (FunctionValue)args.get(0);
|
|
||||||
func.enableConstruct = args.get(1).toBoolean();
|
|
||||||
return Value.UNDEFINED;
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "invokeType", new NativeFunction(args -> {
|
|
||||||
if (((ArgumentsValue)args.get(0)).frame.isNew) return StringValue.of("new");
|
|
||||||
else return StringValue.of("call");
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "invokeTypeInfer", new NativeFunction(args -> {
|
|
||||||
var frame = Frame.get(args.env, args.get(0).toNumber(args.env).getInt());
|
|
||||||
if (frame.isNew) return StringValue.of("new");
|
|
||||||
else return StringValue.of("call");
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "target", new NativeFunction(args -> {
|
|
||||||
var frame = Frame.get(args.env, args.get(0).toNumber(args.env).getInt());
|
|
||||||
if (frame.target == null) return Value.UNDEFINED;
|
|
||||||
else return frame.target;
|
|
||||||
}));
|
|
||||||
|
|
||||||
res.defineOwnField(env, "invoke", new NativeFunction(args -> {
|
|
||||||
var func = (FunctionValue)args.get(0);
|
|
||||||
var self = args.get(1);
|
|
||||||
var funcArgs = (ArrayLikeValue)args.get(2);
|
|
||||||
|
|
||||||
return func.apply(env, self, funcArgs.toArray());
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "construct", new NativeFunction(args -> {
|
|
||||||
var func = (FunctionValue)args.get(0);
|
|
||||||
var target = args.get(1);
|
|
||||||
var funcArgs = (ArrayLikeValue)args.get(2);
|
|
||||||
|
|
||||||
if (target == Value.UNDEFINED) return func.constructNoSelf(env, funcArgs.toArray());
|
|
||||||
else return func.construct(env, target, funcArgs.toArray());
|
|
||||||
}));
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ObjectValue jsonPrimordials(Environment env) {
|
|
||||||
var res = new ObjectValue();
|
|
||||||
res.setPrototype(null, null);
|
|
||||||
|
|
||||||
res.defineOwnField(env, "stringify", new NativeFunction(args -> {
|
|
||||||
return StringValue.of(JSON.stringify(JSONConverter.fromJs(env, args.get(0))));
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "parse", new NativeFunction(args -> {
|
|
||||||
try {
|
|
||||||
return JSONConverter.toJs(JSON.parse(null, args.get(0).toString(env)));
|
|
||||||
}
|
|
||||||
catch (SyntaxException e) {
|
|
||||||
throw EngineException.ofSyntax(e.msg).add(env, e.loc.filename() + "", e.loc);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void setProto(Environment env, Environment target, Key<ObjectValue> key, ObjectValue repo, String name) {
|
|
||||||
var val = repo.getMember(env, name);
|
|
||||||
if (val instanceof ObjectValue obj) {
|
|
||||||
target.add(key, obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ObjectValue primordials(Environment env) {
|
|
||||||
var res = new ObjectValue();
|
|
||||||
res.setPrototype(null, null);
|
|
||||||
|
|
||||||
res.defineOwnField(env, "symbol", symbolPrimordials(env));
|
|
||||||
res.defineOwnField(env, "number", numberPrimordials(env));
|
|
||||||
res.defineOwnField(env, "string", stringPrimordials(env));
|
|
||||||
res.defineOwnField(env, "object", objectPrimordials(env));
|
|
||||||
res.defineOwnField(env, "buffer", bufferPrimordials(env));
|
|
||||||
res.defineOwnField(env, "function", functionPrimordials(env));
|
|
||||||
res.defineOwnField(env, "json", jsonPrimordials(env));
|
|
||||||
res.defineOwnField(env, "map", mapPrimordials(env));
|
|
||||||
res.defineOwnField(env, "regex", regexPrimordials(env));
|
|
||||||
|
|
||||||
int[] i = new int[1];
|
|
||||||
|
|
||||||
res.defineOwnField(env, "setGlobalPrototypes", new NativeFunction(args -> {
|
|
||||||
var obj = (ObjectValue)args.get(0);
|
|
||||||
|
|
||||||
setProto(args.env, env, Value.OBJECT_PROTO, obj, "object");
|
|
||||||
setProto(args.env, env, Value.FUNCTION_PROTO, obj, "function");
|
|
||||||
setProto(args.env, env, Value.ARRAY_PROTO, obj, "array");
|
|
||||||
setProto(args.env, env, Value.BOOL_PROTO, obj, "boolean");
|
|
||||||
setProto(args.env, env, Value.NUMBER_PROTO, obj, "number");
|
|
||||||
setProto(args.env, env, Value.STRING_PROTO, obj, "string");
|
|
||||||
setProto(args.env, env, Value.SYMBOL_PROTO, obj, "symbol");
|
|
||||||
setProto(args.env, env, Value.ERROR_PROTO, obj, "error");
|
|
||||||
setProto(args.env, env, Value.SYNTAX_ERR_PROTO, obj, "syntax");
|
|
||||||
setProto(args.env, env, Value.TYPE_ERR_PROTO, obj, "type");
|
|
||||||
setProto(args.env, env, Value.RANGE_ERR_PROTO, obj, "range");
|
|
||||||
setProto(args.env, env, Value.UINT8_ARR_PROTO, obj, "uint8");
|
|
||||||
setProto(args.env, env, Value.INT32_ARR_PROTO, obj, "int32");
|
|
||||||
return Value.UNDEFINED;
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "setIntrinsic", new NativeFunction(args -> {
|
|
||||||
var name = args.get(0).toString(env);
|
|
||||||
var val = args.get(1);
|
|
||||||
|
|
||||||
Value.intrinsics(env).put(name, val);
|
|
||||||
|
|
||||||
return Value.UNDEFINED;
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "compile", new NativeFunction(args -> {
|
|
||||||
var nameVal = args.get(1);
|
|
||||||
var name = nameVal instanceof VoidValue ?
|
|
||||||
new Filename(Metadata.name(), "func" + i[0]++ + ".js") :
|
|
||||||
Filename.parse(nameVal.toString(args.env));
|
|
||||||
|
|
||||||
return Compiler.compileFunc(env, name, args.get(0).toString(env));
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "now", new NativeFunction(args -> {
|
|
||||||
return NumberValue.of(System.currentTimeMillis());
|
|
||||||
}));
|
|
||||||
res.defineOwnField(env, "next", new NativeFunction(args -> {
|
|
||||||
var func = (FunctionValue)args.get(0);
|
|
||||||
EventLoop.get(env).pushMsg(() -> {
|
|
||||||
func.apply(env, Value.UNDEFINED);
|
|
||||||
}, true);
|
|
||||||
return Value.UNDEFINED;
|
|
||||||
}));
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Environment createESEnv() throws InterruptedException, ExecutionException {
|
|
||||||
var env = initEnv();
|
|
||||||
var stubEnv = initEnv();
|
|
||||||
Value.global(stubEnv).defineOwnField(stubEnv, "target", Value.global(env));
|
|
||||||
Value.global(stubEnv).defineOwnField(stubEnv, "primordials", primordials(env));
|
|
||||||
|
|
||||||
EventLoop.get(stubEnv).pushMsg(
|
|
||||||
false, stubEnv,
|
|
||||||
new Filename(Metadata.name(), "init.js"), Reading.resourceToString("lib/stdlib.js"),
|
|
||||||
Value.UNDEFINED
|
|
||||||
).get();
|
|
||||||
|
|
||||||
return env;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Compiler wrap(Compiler first, Environment compilerEnv, Environment targetEnv, FunctionValue factory) {
|
|
||||||
var curr = new NativeFunction(args -> {
|
|
||||||
var filename = Filename.parse(args.get(0).toString(args.env));
|
|
||||||
var src = args.get(1).toString(args.env);
|
|
||||||
var mapper = (FunctionValue)args.get(2);
|
|
||||||
return first.compile(targetEnv, filename, src, NativeMapper.unwrap(args.env, mapper));
|
|
||||||
});
|
|
||||||
|
|
||||||
var next = (FunctionValue)factory.apply(compilerEnv, Value.UNDEFINED, curr);
|
|
||||||
|
|
||||||
return (env, filename, source, map) -> {
|
|
||||||
return (FunctionValue)next.apply(
|
|
||||||
compilerEnv, Value.UNDEFINED,
|
|
||||||
StringValue.of(filename.toString()),
|
|
||||||
StringValue.of(source),
|
|
||||||
new NativeMapper(map)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static Environment initEnv() {
|
|
||||||
var env = new Environment();
|
var env = new Environment();
|
||||||
env.add(EventLoop.KEY, engine);
|
env.add(EventLoop.KEY, engine);
|
||||||
env.add(DebugHandler.KEY, new SimpleDebugHandler());
|
env.add(DebugHandler.KEY, new SimpleDebugHandler());
|
||||||
env.add(Compiler.KEY, DEFAULT_COMPILER);
|
env.add(Compiler.KEY, Compilers.chainTranspilers(environment, Compilers.jsCompiler(), Compilers::babelCompiler, Compilers::coffeescriptCompiler));
|
||||||
// env.add(CompileResult.DEBUG_LOG);
|
StdLib.apply(env);
|
||||||
|
|
||||||
var glob = Value.global(env);
|
var glob = Value.global(env);
|
||||||
|
|
||||||
@ -857,76 +116,19 @@ public class SimpleRepl {
|
|||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
throw new CancellationException();
|
throw new CancellationException();
|
||||||
}));
|
}));
|
||||||
glob.defineOwnField(null, "print", new NativeFunction("print", args -> {
|
|
||||||
for (var el : args.args) {
|
|
||||||
if (el instanceof StringValue) System.out.print(((StringValue)el).value + " \t");
|
|
||||||
else System.out.print(el.toReadable(args.env) + " \t");
|
|
||||||
}
|
|
||||||
System.out.println();
|
|
||||||
|
|
||||||
return Value.UNDEFINED;
|
|
||||||
}));
|
|
||||||
glob.defineOwnField(null, "measure", new NativeFunction("measure", args -> {
|
|
||||||
var start = System.nanoTime();
|
|
||||||
|
|
||||||
((FunctionValue)args.get(0)).apply(args.env, Value.UNDEFINED);
|
|
||||||
|
|
||||||
System.out.println(String.format("Finished in %sms", (System.nanoTime() - start) / 1000000.));
|
|
||||||
|
|
||||||
return Value.UNDEFINED;
|
|
||||||
}));
|
|
||||||
|
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void initEngine() {
|
private static void initEngine() {
|
||||||
engineTask = engine.start();
|
engineTask = engine.start();
|
||||||
}
|
}
|
||||||
private static void initGlobals() throws InterruptedException, ExecutionException {
|
|
||||||
var res = new FunctionValue[1];
|
|
||||||
var setter = new NativeFunction(args -> {
|
|
||||||
res[0] = (FunctionValue)args.get(0);
|
|
||||||
return Value.UNDEFINED;
|
|
||||||
});
|
|
||||||
|
|
||||||
var tsGlob = Value.global(tsEnvironment);
|
|
||||||
var tsCompilerFactory = new FunctionValue[1];
|
|
||||||
|
|
||||||
tsGlob.defineOwnField(tsEnvironment, "getResource", new NativeFunction(args -> {
|
|
||||||
var name = args.get(0).toString(args.env);
|
|
||||||
var src = Reading.resourceToString("lib/" + name);
|
|
||||||
|
|
||||||
if (src == null) return Value.UNDEFINED;
|
|
||||||
else return StringValue.of(src);
|
|
||||||
}));
|
|
||||||
tsGlob.defineOwnField(tsEnvironment, "register", new NativeFunction(args -> {
|
|
||||||
var func = (FunctionValue)args.get(0);
|
|
||||||
tsCompilerFactory[0] = func;
|
|
||||||
return Value.UNDEFINED;
|
|
||||||
}));
|
|
||||||
tsGlob.defineOwnField(tsEnvironment, "registerSource", new NativeFunction(args -> {
|
|
||||||
var filename = Filename.parse(args.get(0).toString(args.env));
|
|
||||||
var src = args.get(1).toString(args.env);
|
|
||||||
DebugHandler.get(environment).onSourceLoad(filename, src);
|
|
||||||
return Value.UNDEFINED;
|
|
||||||
}));
|
|
||||||
|
|
||||||
var ts = Reading.resourceToString("lib/transpiler.js");
|
|
||||||
if (ts != null) EventLoop.get(tsEnvironment).pushMsg(
|
|
||||||
false, tsEnvironment,
|
|
||||||
new Filename(Metadata.name(), "transpiler.js"), ts,
|
|
||||||
Value.UNDEFINED, setter
|
|
||||||
).get();
|
|
||||||
|
|
||||||
var tsCompiler = wrap(Compiler.get(environment), tsEnvironment, environment, tsCompilerFactory[0]);
|
|
||||||
environment.add(Compiler.KEY, tsCompiler);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void main(String args[]) throws InterruptedException {
|
public static void main(String args[]) throws InterruptedException {
|
||||||
SimpleRepl.args = args;
|
SimpleRepl.args = args;
|
||||||
var reader = new Thread(SimpleRepl::reader);
|
var reader = new Thread(SimpleRepl::reader);
|
||||||
|
|
||||||
environment = initEnv();
|
environment = createESEnv();
|
||||||
|
|
||||||
initEngine();
|
initEngine();
|
||||||
|
|
||||||
|
@ -24,8 +24,8 @@ import me.topchetoeu.j2s.compilation.json.JSON;
|
|||||||
import me.topchetoeu.j2s.compilation.json.JSONElement;
|
import me.topchetoeu.j2s.compilation.json.JSONElement;
|
||||||
import me.topchetoeu.j2s.compilation.json.JSONList;
|
import me.topchetoeu.j2s.compilation.json.JSONList;
|
||||||
import me.topchetoeu.j2s.compilation.json.JSONMap;
|
import me.topchetoeu.j2s.compilation.json.JSONMap;
|
||||||
import me.topchetoeu.j2s.repl.JSONConverter;
|
import me.topchetoeu.j2s.lib.Compilers;
|
||||||
import me.topchetoeu.j2s.repl.SimpleRepl;
|
import me.topchetoeu.j2s.lib.JSONConverter;
|
||||||
import me.topchetoeu.j2s.runtime.Compiler;
|
import me.topchetoeu.j2s.runtime.Compiler;
|
||||||
import me.topchetoeu.j2s.runtime.Engine;
|
import me.topchetoeu.j2s.runtime.Engine;
|
||||||
import me.topchetoeu.j2s.runtime.EventLoop;
|
import me.topchetoeu.j2s.runtime.EventLoop;
|
||||||
@ -625,7 +625,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
env.remove(DebugHandler.KEY);
|
env.remove(DebugHandler.KEY);
|
||||||
env.remove(EventLoop.KEY);
|
env.remove(EventLoop.KEY);
|
||||||
env.remove(Value.GLOBAL);
|
env.remove(Value.GLOBAL);
|
||||||
env.add(Compiler.KEY, SimpleRepl.DEFAULT_COMPILER);
|
env.add(Compiler.KEY, Compilers.jsCompiler());
|
||||||
env.add(EventLoop.KEY, engine);
|
env.add(EventLoop.KEY, engine);
|
||||||
env.add(Value.GLOBAL, codeFrame.variables);
|
env.add(Value.GLOBAL, codeFrame.variables);
|
||||||
|
|
||||||
@ -1080,7 +1080,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
|
|
||||||
frame = getFrame(cf);
|
frame = getFrame(cf);
|
||||||
|
|
||||||
var map = DebugHandler.get(env).getMap(env, frame.frame.function);
|
var map = DebugHandler.get(env).getMapOrEmpty(env, frame.frame.function);
|
||||||
|
|
||||||
frame.updateLoc(map.toLocation(frame.frame.codePtr));
|
frame.updateLoc(map.toLocation(frame.frame.codePtr));
|
||||||
loc = frame.location;
|
loc = frame.location;
|
||||||
|
@ -4,15 +4,6 @@ plugins {
|
|||||||
|
|
||||||
description = "The runtime of J2S, used to execute J2S bytecode";
|
description = "The runtime of J2S, used to execute J2S bytecode";
|
||||||
|
|
||||||
tasks.processResources {
|
|
||||||
filesMatching("metadata.json", {
|
|
||||||
expand(
|
|
||||||
"version" to properties["project_version"],
|
|
||||||
"name" to properties["project_name"],
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.test {
|
tasks.test {
|
||||||
useJUnitPlatform();
|
useJUnitPlatform();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user