refactor: greatly improve Environment API
This commit is contained in:
parent
d7f6010319
commit
38acc20a6f
@ -131,10 +131,10 @@ public class Main {
|
|||||||
private static void initTypescript() {
|
private static void initTypescript() {
|
||||||
try {
|
try {
|
||||||
var tsEnv = Internals.apply(new Environment(null, null, null));
|
var tsEnv = Internals.apply(new Environment(null, null, null));
|
||||||
tsEnv.stackVisible = false;
|
tsEnv.stackHidden = false;
|
||||||
tsEnv.global.define(null, "module", false, new ObjectValue());
|
tsEnv.global.define(null, "module", false, new ObjectValue());
|
||||||
var bsEnv = Internals.apply(new Environment(null, null, null));
|
var bsEnv = Internals.apply(new Environment(null, null, null));
|
||||||
bsEnv.stackVisible = false;
|
bsEnv.stackHidden = false;
|
||||||
|
|
||||||
engine.pushMsg(
|
engine.pushMsg(
|
||||||
false, tsEnv,
|
false, tsEnv,
|
||||||
|
@ -10,6 +10,7 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
import me.topchetoeu.jscript.Filename;
|
import me.topchetoeu.jscript.Filename;
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.Location;
|
||||||
|
import me.topchetoeu.jscript.engine.debug.DebugContext;
|
||||||
import me.topchetoeu.jscript.engine.frame.CodeFrame;
|
import me.topchetoeu.jscript.engine.frame.CodeFrame;
|
||||||
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
||||||
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
||||||
@ -17,11 +18,16 @@ import me.topchetoeu.jscript.engine.values.Values;
|
|||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.mapping.SourceMap;
|
import me.topchetoeu.jscript.mapping.SourceMap;
|
||||||
|
|
||||||
public class Context {
|
public class Context extends ExtensionStack {
|
||||||
private final Stack<Environment> env = new Stack<>();
|
private final Stack<Environment> env = new Stack<>();
|
||||||
private final ArrayList<CodeFrame> frames = new ArrayList<>();
|
private final ArrayList<CodeFrame> frames = new ArrayList<>();
|
||||||
public final Engine engine;
|
public final Engine engine;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Extensions[] extensionStack() {
|
||||||
|
return new Extensions[] { environment(), engine.globalEnvironment };
|
||||||
|
}
|
||||||
|
|
||||||
public Environment environment() {
|
public Environment environment() {
|
||||||
return env.empty() ? null : env.peek();
|
return env.empty() ? null : env.peek();
|
||||||
}
|
}
|
||||||
@ -36,7 +42,7 @@ public class Context {
|
|||||||
|
|
||||||
public FunctionValue compile(Filename filename, String raw) {
|
public FunctionValue compile(Filename filename, String raw) {
|
||||||
var env = environment();
|
var env = environment();
|
||||||
var result = env.compile.call(this, null, raw, filename.toString(), env);
|
var result = Environment.compileFunc(this).call(this, null, raw, filename.toString(), env);
|
||||||
|
|
||||||
var function = (FunctionValue)Values.getMember(this, result, "function");
|
var function = (FunctionValue)Values.getMember(this, result, "function");
|
||||||
if (!engine.debugging) return function;
|
if (!engine.debugging) return function;
|
||||||
@ -62,24 +68,23 @@ public class Context {
|
|||||||
breakpoints = newBreakpoints;
|
breakpoints = newBreakpoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
engine.onSource(filename, raw, breakpoints, map);
|
DebugContext.get(this).onSource(filename, raw, breakpoints, map);
|
||||||
|
|
||||||
return function;
|
return function;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void pushFrame(CodeFrame frame) {
|
public void pushFrame(CodeFrame frame) {
|
||||||
frames.add(frame);
|
frames.add(frame);
|
||||||
if (frames.size() > engine.maxStackFrames) throw EngineException.ofRange("Stack overflow!");
|
if (frames.size() > engine.maxStackFrames) throw EngineException.ofRange("Stack overflow!");
|
||||||
pushEnv(frame.function.environment);
|
pushEnv(frame.function.environment);
|
||||||
engine.onFramePush(this, frame);
|
DebugContext.get(this).onFramePush(this, frame);
|
||||||
}
|
}
|
||||||
public boolean popFrame(CodeFrame frame) {
|
public boolean popFrame(CodeFrame frame) {
|
||||||
if (frames.size() == 0) return false;
|
if (frames.size() == 0) return false;
|
||||||
if (frames.get(frames.size() - 1) != frame) return false;
|
if (frames.get(frames.size() - 1) != frame) return false;
|
||||||
frames.remove(frames.size() - 1);
|
frames.remove(frames.size() - 1);
|
||||||
popEnv();
|
popEnv();
|
||||||
engine.onFramePop(this, frame);
|
DebugContext.get(this).onFramePop(this, frame);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public CodeFrame peekFrame() {
|
public CodeFrame peekFrame() {
|
||||||
|
@ -17,7 +17,7 @@ import me.topchetoeu.jscript.exceptions.EngineException;
|
|||||||
import me.topchetoeu.jscript.exceptions.InterruptException;
|
import me.topchetoeu.jscript.exceptions.InterruptException;
|
||||||
import me.topchetoeu.jscript.mapping.SourceMap;
|
import me.topchetoeu.jscript.mapping.SourceMap;
|
||||||
|
|
||||||
public class Engine implements DebugController {
|
public class Engine {
|
||||||
private class UncompiledFunction extends FunctionValue {
|
private class UncompiledFunction extends FunctionValue {
|
||||||
public final Filename filename;
|
public final Filename filename;
|
||||||
public final String raw;
|
public final String raw;
|
||||||
@ -61,47 +61,15 @@ public class Engine implements DebugController {
|
|||||||
private static int nextId = 0;
|
private static int nextId = 0;
|
||||||
public static final HashMap<Long, FunctionBody> functions = new HashMap<>();
|
public static final HashMap<Long, FunctionBody> functions = new HashMap<>();
|
||||||
|
|
||||||
|
public final Environment globalEnvironment = new Environment();
|
||||||
|
|
||||||
public final int id = ++nextId;
|
public final int id = ++nextId;
|
||||||
public final boolean debugging;
|
public final boolean debugging;
|
||||||
public int maxStackFrames = 10000;
|
public int maxStackFrames = 10000;
|
||||||
|
|
||||||
private final HashMap<Filename, String> sources = new HashMap<>();
|
|
||||||
private final HashMap<Filename, TreeSet<Location>> bpts = new HashMap<>();
|
|
||||||
private final HashMap<Filename, SourceMap> maps = new HashMap<>();
|
|
||||||
|
|
||||||
public Location mapToCompiled(Location location) {
|
|
||||||
var map = maps.get(location.filename());
|
|
||||||
if (map == null) return location;
|
|
||||||
return map.toCompiled(location);
|
|
||||||
}
|
|
||||||
public Location mapToOriginal(Location location) {
|
|
||||||
var map = maps.get(location.filename());
|
|
||||||
if (map == null) return location;
|
|
||||||
return map.toOriginal(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
private DebugController debugger;
|
|
||||||
private Thread thread;
|
private Thread thread;
|
||||||
private PriorityBlockingQueue<Task> tasks = new PriorityBlockingQueue<>();
|
private PriorityBlockingQueue<Task> tasks = new PriorityBlockingQueue<>();
|
||||||
|
|
||||||
public synchronized boolean attachDebugger(DebugController debugger) {
|
|
||||||
if (!debugging || this.debugger != null) return false;
|
|
||||||
|
|
||||||
for (var source : sources.entrySet()) debugger.onSource(
|
|
||||||
source.getKey(), source.getValue(),
|
|
||||||
bpts.get(source.getKey()),
|
|
||||||
maps.get(source.getKey())
|
|
||||||
);
|
|
||||||
|
|
||||||
this.debugger = debugger;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
public synchronized boolean detachDebugger() {
|
|
||||||
if (!debugging || this.debugger == null) return false;
|
|
||||||
this.debugger = null;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void runTask(Task task) {
|
private void runTask(Task task) {
|
||||||
try {
|
try {
|
||||||
task.notifier.next(task.func.call(task.ctx, task.thisArg, task.args));
|
task.notifier.next(task.func.call(task.ctx, task.thisArg, task.args));
|
||||||
@ -150,25 +118,6 @@ public class Engine implements DebugController {
|
|||||||
return pushMsg(micro, env, new UncompiledFunction(filename, raw), thisArg, args);
|
return pushMsg(micro, env, new UncompiledFunction(filename, raw), thisArg, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFramePush(Context ctx, CodeFrame frame) {
|
|
||||||
if (debugging && debugger != null) debugger.onFramePush(ctx, frame);
|
|
||||||
}
|
|
||||||
@Override public void onFramePop(Context ctx, CodeFrame frame) {
|
|
||||||
if (debugging && debugger != null) debugger.onFramePop(ctx, frame);
|
|
||||||
}
|
|
||||||
@Override public boolean onInstruction(Context ctx, CodeFrame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught) {
|
|
||||||
if (debugging && debugger != null) return debugger.onInstruction(ctx, frame, instruction, returnVal, error, caught);
|
|
||||||
else return false;
|
|
||||||
}
|
|
||||||
@Override public void onSource(Filename filename, String source, TreeSet<Location> breakpoints, SourceMap map) {
|
|
||||||
if (!debugging) return;
|
|
||||||
if (debugger != null) debugger.onSource(filename, source, breakpoints, map);
|
|
||||||
sources.put(filename, source);
|
|
||||||
bpts.put(filename, breakpoints);
|
|
||||||
maps.put(filename, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Engine(boolean debugging) {
|
public Engine(boolean debugging) {
|
||||||
this.debugging = debugging;
|
this.debugging = debugging;
|
||||||
}
|
}
|
||||||
|
@ -13,117 +13,109 @@ import me.topchetoeu.jscript.engine.values.ObjectValue;
|
|||||||
import me.topchetoeu.jscript.engine.values.Symbol;
|
import me.topchetoeu.jscript.engine.values.Symbol;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.filesystem.RootFilesystem;
|
|
||||||
import me.topchetoeu.jscript.interop.Native;
|
import me.topchetoeu.jscript.interop.Native;
|
||||||
import me.topchetoeu.jscript.interop.NativeGetter;
|
|
||||||
import me.topchetoeu.jscript.interop.NativeSetter;
|
|
||||||
import me.topchetoeu.jscript.interop.NativeWrapperProvider;
|
import me.topchetoeu.jscript.interop.NativeWrapperProvider;
|
||||||
import me.topchetoeu.jscript.modules.RootModuleRepo;
|
|
||||||
import me.topchetoeu.jscript.parsing.Parsing;
|
import me.topchetoeu.jscript.parsing.Parsing;
|
||||||
import me.topchetoeu.jscript.permissions.Permission;
|
|
||||||
import me.topchetoeu.jscript.permissions.PermissionsProvider;
|
|
||||||
|
|
||||||
// TODO: Remove hardcoded extensions form environment
|
// TODO: Remove hardcoded extensions form environment
|
||||||
public class Environment implements PermissionsProvider {
|
@SuppressWarnings("unchecked")
|
||||||
private HashMap<String, ObjectValue> prototypes = new HashMap<>();
|
public class Environment implements Extensions {
|
||||||
|
private static int nextId = 0;
|
||||||
|
|
||||||
public final Data data = new Data();
|
|
||||||
public static final HashMap<String, Symbol> symbols = new HashMap<>();
|
public static final HashMap<String, Symbol> symbols = new HashMap<>();
|
||||||
|
|
||||||
|
public static final Symbol WRAPPERS = Symbol.get("Environment.wrappers");
|
||||||
|
public static final Symbol COMPILE_FUNC = Symbol.get("Environment.compile");
|
||||||
|
|
||||||
|
public static final Symbol REGEX_CONSTR = Symbol.get("Environment.regexConstructor");
|
||||||
|
public static final Symbol STACK = Symbol.get("Environment.stack");
|
||||||
|
public static final Symbol HIDE_STACK = Symbol.get("Environment.hideStack");
|
||||||
|
|
||||||
|
public static final Symbol OBJECT_PROTO = Symbol.get("Environment.objectPrototype");
|
||||||
|
public static final Symbol FUNCTION_PROTO = Symbol.get("Environment.functionPrototype");
|
||||||
|
public static final Symbol ARRAY_PROTO = Symbol.get("Environment.arrayPrototype");
|
||||||
|
public static final Symbol BOOL_PROTO = Symbol.get("Environment.boolPrototype");
|
||||||
|
public static final Symbol NUMBER_PROTO = Symbol.get("Environment.numberPrototype");
|
||||||
|
public static final Symbol STRING_PROTO = Symbol.get("Environment.stringPrototype");
|
||||||
|
public static final Symbol SYMBOL_PROTO = Symbol.get("Environment.symbolPrototype");
|
||||||
|
public static final Symbol ERROR_PROTO = Symbol.get("Environment.errorPrototype");
|
||||||
|
public static final Symbol SYNTAX_ERR_PROTO = Symbol.get("Environment.syntaxErrorPrototype");
|
||||||
|
public static final Symbol TYPE_ERR_PROTO = Symbol.get("Environment.typeErrorPrototype");
|
||||||
|
public static final Symbol RANGE_ERR_PROTO = Symbol.get("Environment.rangeErrorPrototype");
|
||||||
|
|
||||||
|
private HashMap<Symbol, Object> data = new HashMap<>();
|
||||||
|
|
||||||
public GlobalScope global;
|
public GlobalScope global;
|
||||||
public WrappersProvider wrappers;
|
public WrappersProvider wrappers;
|
||||||
|
|
||||||
public PermissionsProvider permissions = null;
|
|
||||||
public final RootFilesystem filesystem = new RootFilesystem(this);
|
|
||||||
public final RootModuleRepo modules = new RootModuleRepo();
|
|
||||||
public String moduleCwd = "/";
|
|
||||||
|
|
||||||
private static int nextId = 0;
|
|
||||||
|
|
||||||
@Native public boolean stackVisible = true;
|
|
||||||
@Native public int id = ++nextId;
|
@Native public int id = ++nextId;
|
||||||
|
|
||||||
@Native public FunctionValue compile = new NativeFunction("compile", (ctx, thisArg, args) -> {
|
@Override public <T> void add(Symbol key, T obj) {
|
||||||
var source = Values.toString(ctx, args[0]);
|
data.put(key, obj);
|
||||||
var filename = Values.toString(ctx, args[1]);
|
}
|
||||||
var isDebug = Values.toBoolean(args[2]);
|
@Override public <T> T get(Symbol key) {
|
||||||
|
return (T)data.get(key);
|
||||||
var env = Values.wrapper(args[2], Environment.class);
|
}
|
||||||
var res = new ObjectValue();
|
@Override public boolean remove(Symbol key) {
|
||||||
|
if (data.containsKey(key)) {
|
||||||
var target = Parsing.compile(env, Filename.parse(filename), source);
|
data.remove(key);
|
||||||
Engine.functions.putAll(target.functions);
|
return true;
|
||||||
Engine.functions.remove(0l);
|
|
||||||
|
|
||||||
res.defineProperty(ctx, "function", target.func(env));
|
|
||||||
res.defineProperty(ctx, "mapChain", new ArrayValue());
|
|
||||||
|
|
||||||
if (isDebug) {
|
|
||||||
res.defineProperty(ctx, "breakpoints", ArrayValue.of(ctx, target.breakpoints.stream().map(Location::toString).collect(Collectors.toList())));
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
return res;
|
|
||||||
});
|
|
||||||
@Native public FunctionValue regexConstructor = new NativeFunction("RegExp", (ctx, thisArg, args) -> {
|
|
||||||
throw EngineException.ofError("Regular expressions not supported.").setCtx(ctx.environment(), ctx.engine);
|
|
||||||
});
|
|
||||||
|
|
||||||
@Native public ObjectValue proto(String name) {
|
|
||||||
return prototypes.get(name);
|
|
||||||
}
|
}
|
||||||
@Native public void setProto(String name, ObjectValue val) {
|
@Override public boolean has(Symbol key) {
|
||||||
prototypes.put(name, val);
|
return data.containsKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Native public Symbol symbol(String name) {
|
public static FunctionValue compileFunc(Extensions ext) {
|
||||||
return getSymbol(name);
|
return ext.init(COMPILE_FUNC, new NativeFunction("compile", (ctx, thisArg, args) -> {
|
||||||
|
var source = Values.toString(ctx, args[0]);
|
||||||
|
var filename = Values.toString(ctx, args[1]);
|
||||||
|
var isDebug = Values.toBoolean(args[2]);
|
||||||
|
|
||||||
|
var env = Values.wrapper(args[2], Environment.class);
|
||||||
|
var res = new ObjectValue();
|
||||||
|
|
||||||
|
var target = Parsing.compile(env, Filename.parse(filename), source);
|
||||||
|
Engine.functions.putAll(target.functions);
|
||||||
|
Engine.functions.remove(0l);
|
||||||
|
|
||||||
|
res.defineProperty(ctx, "function", target.func(env));
|
||||||
|
res.defineProperty(ctx, "mapChain", new ArrayValue());
|
||||||
|
|
||||||
|
if (isDebug) {
|
||||||
|
res.defineProperty(ctx, "breakpoints", ArrayValue.of(ctx, target.breakpoints.stream().map(Location::toString).collect(Collectors.toList())));
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
public static FunctionValue regexConstructor(Extensions ext) {
|
||||||
|
return ext.init(COMPILE_FUNC, new NativeFunction("RegExp", (ctx, thisArg, args) -> {
|
||||||
|
throw EngineException.ofError("Regular expressions not supported.").setCtx(ctx.environment(), ctx.engine);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@NativeGetter("global") public ObjectValue getGlobal() {
|
public Environment fork() {
|
||||||
return global.obj;
|
var res = new Environment(null, global);
|
||||||
}
|
|
||||||
@NativeSetter("global") public void setGlobal(ObjectValue val) {
|
|
||||||
global = new GlobalScope(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Native public Environment fork() {
|
|
||||||
var res = new Environment(compile, null, global);
|
|
||||||
res.wrappers = wrappers.fork(res);
|
res.wrappers = wrappers.fork(res);
|
||||||
res.regexConstructor = regexConstructor;
|
res.global = global;
|
||||||
res.prototypes = new HashMap<>(prototypes);
|
res.data.putAll(data);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@Native public Environment child() {
|
public Environment child() {
|
||||||
var res = fork();
|
var res = fork();
|
||||||
res.global = res.global.globalChild();
|
res.global = res.global.globalChild();
|
||||||
res.permissions = this.permissions;
|
|
||||||
res.filesystem.protocols.putAll(this.filesystem.protocols);
|
|
||||||
res.modules.repos.putAll(this.modules.repos);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public boolean hasPermission(Permission perm, char delim) {
|
|
||||||
return permissions == null || permissions.hasPermission(perm, delim);
|
|
||||||
}
|
|
||||||
@Override public boolean hasPermission(Permission perm) {
|
|
||||||
return permissions == null || permissions.hasPermission(perm);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Context context(Engine engine) {
|
public Context context(Engine engine) {
|
||||||
return new Context(engine, this);
|
return new Context(engine, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Symbol getSymbol(String name) {
|
public Environment(WrappersProvider nativeConverter, GlobalScope global) {
|
||||||
if (symbols.containsKey(name)) return symbols.get(name);
|
|
||||||
else {
|
|
||||||
var res = new Symbol(name);
|
|
||||||
symbols.put(name, res);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Environment(FunctionValue compile, WrappersProvider nativeConverter, GlobalScope global) {
|
|
||||||
if (compile != null) this.compile = compile;
|
|
||||||
if (nativeConverter == null) nativeConverter = new NativeWrapperProvider(this);
|
if (nativeConverter == null) nativeConverter = new NativeWrapperProvider(this);
|
||||||
if (global == null) global = new GlobalScope();
|
if (global == null) global = new GlobalScope();
|
||||||
|
|
||||||
@ -131,6 +123,6 @@ public class Environment implements PermissionsProvider {
|
|||||||
this.global = global;
|
this.global = global;
|
||||||
}
|
}
|
||||||
public Environment() {
|
public Environment() {
|
||||||
this(null, null, null);
|
this(null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
39
src/me/topchetoeu/jscript/engine/ExtensionStack.java
Normal file
39
src/me/topchetoeu/jscript/engine/ExtensionStack.java
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package me.topchetoeu.jscript.engine;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.engine.values.Symbol;
|
||||||
|
|
||||||
|
public abstract class ExtensionStack implements Extensions {
|
||||||
|
protected abstract Extensions[] extensionStack();
|
||||||
|
|
||||||
|
@Override public <T> void add(Symbol key, T obj) {
|
||||||
|
for (var el : extensionStack()) {
|
||||||
|
if (el != null) {
|
||||||
|
el.add(key, obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override public <T> T get(Symbol key) {
|
||||||
|
for (var el : extensionStack()) {
|
||||||
|
if (el != null && el.has(key)) return el.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
@Override public boolean has(Symbol key) {
|
||||||
|
for (var el : extensionStack()) {
|
||||||
|
if (el != null && el.has(key)) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@Override public boolean remove(Symbol key) {
|
||||||
|
var anyRemoved = false;
|
||||||
|
|
||||||
|
for (var el : extensionStack()) {
|
||||||
|
if (el != null) anyRemoved &= el.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return anyRemoved;
|
||||||
|
}
|
||||||
|
}
|
24
src/me/topchetoeu/jscript/engine/Extensions.java
Normal file
24
src/me/topchetoeu/jscript/engine/Extensions.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package me.topchetoeu.jscript.engine;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.engine.values.Symbol;
|
||||||
|
|
||||||
|
public interface Extensions {
|
||||||
|
<T> T get(Symbol key);
|
||||||
|
<T> void add(Symbol key, T obj);
|
||||||
|
|
||||||
|
boolean has(Symbol key);
|
||||||
|
boolean remove(Symbol key);
|
||||||
|
|
||||||
|
default <T> T get(Symbol key, T defaultVal) {
|
||||||
|
if (has(key)) return get(key);
|
||||||
|
else return defaultVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
default <T> T init(Symbol key, T val) {
|
||||||
|
if (has(key)) return get(key);
|
||||||
|
else {
|
||||||
|
add(key, val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
96
src/me/topchetoeu/jscript/engine/debug/DebugContext.java
Normal file
96
src/me/topchetoeu/jscript/engine/debug/DebugContext.java
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package me.topchetoeu.jscript.engine.debug;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.Filename;
|
||||||
|
import me.topchetoeu.jscript.Location;
|
||||||
|
import me.topchetoeu.jscript.compilation.Instruction;
|
||||||
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
|
import me.topchetoeu.jscript.engine.Extensions;
|
||||||
|
import me.topchetoeu.jscript.engine.frame.CodeFrame;
|
||||||
|
import me.topchetoeu.jscript.engine.values.Symbol;
|
||||||
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
|
import me.topchetoeu.jscript.mapping.SourceMap;
|
||||||
|
|
||||||
|
public class DebugContext implements DebugController {
|
||||||
|
public static final Symbol DEBUG_CTX = Symbol.get("Engine.debug");
|
||||||
|
|
||||||
|
private HashMap<Filename, String> sources;
|
||||||
|
private HashMap<Filename, TreeSet<Location>> bpts;
|
||||||
|
private HashMap<Filename, SourceMap> maps;
|
||||||
|
private DebugController debugger;
|
||||||
|
|
||||||
|
public boolean attachDebugger(DebugController debugger) {
|
||||||
|
if (this.debugger != null) return false;
|
||||||
|
|
||||||
|
if (sources != null) {
|
||||||
|
for (var source : sources.entrySet()) debugger.onSource(
|
||||||
|
source.getKey(), source.getValue(),
|
||||||
|
bpts.get(source.getKey()),
|
||||||
|
maps.get(source.getKey())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.debugger = debugger;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public boolean detachDebugger() {
|
||||||
|
this.debugger = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DebugController debugger() {
|
||||||
|
if (debugger == null) return DebugController.empty();
|
||||||
|
else return debugger;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onFramePop(Context ctx, CodeFrame frame) {
|
||||||
|
if (debugger != null) debugger.onFramePop(ctx, frame);
|
||||||
|
}
|
||||||
|
@Override public void onFramePush(Context ctx, CodeFrame frame) {
|
||||||
|
if (debugger != null) debugger.onFramePush(ctx, frame);
|
||||||
|
}
|
||||||
|
@Override public boolean onInstruction(Context ctx, CodeFrame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught) {
|
||||||
|
if (debugger != null) return debugger.onInstruction(ctx, frame, instruction, returnVal, error, caught);
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
@Override public void onSource(Filename filename, String source, TreeSet<Location> breakpoints, SourceMap map) {
|
||||||
|
if (debugger != null) debugger.onSource(filename, source, breakpoints, map);
|
||||||
|
if (sources != null) sources.put(filename, source);
|
||||||
|
if (bpts != null) bpts.put(filename, breakpoints);
|
||||||
|
if (maps != null) maps.put(filename, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location mapToCompiled(Location location) {
|
||||||
|
if (maps == null) return location;
|
||||||
|
|
||||||
|
var map = maps.get(location.filename());
|
||||||
|
if (map == null) return location;
|
||||||
|
return map.toCompiled(location);
|
||||||
|
}
|
||||||
|
public Location mapToOriginal(Location location) {
|
||||||
|
if (maps == null) return location;
|
||||||
|
|
||||||
|
var map = maps.get(location.filename());
|
||||||
|
if (map == null) return location;
|
||||||
|
return map.toOriginal(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DebugContext(boolean enabled) {
|
||||||
|
if (enabled) {
|
||||||
|
sources = new HashMap<>();
|
||||||
|
bpts = new HashMap<>();
|
||||||
|
maps = new HashMap<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DebugContext() {
|
||||||
|
this(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DebugContext get(Extensions exts) {
|
||||||
|
if (exts.has(DEBUG_CTX)) return exts.get(DEBUG_CTX);
|
||||||
|
else return new DebugContext(false);
|
||||||
|
}
|
||||||
|
}
|
@ -48,4 +48,15 @@ public interface DebugController {
|
|||||||
* @param frame The code frame which was popped out
|
* @param frame The code frame which was popped out
|
||||||
*/
|
*/
|
||||||
void onFramePop(Context ctx, CodeFrame frame);
|
void onFramePop(Context ctx, CodeFrame frame);
|
||||||
|
|
||||||
|
public static DebugController empty() {
|
||||||
|
return new DebugController() {
|
||||||
|
@Override public void onFramePop(Context ctx, CodeFrame frame) { }
|
||||||
|
@Override public void onFramePush(Context ctx, CodeFrame frame) { }
|
||||||
|
@Override public boolean onInstruction(Context ctx, CodeFrame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@Override public void onSource(Filename filename, String source, TreeSet<Location> breakpoints, SourceMap map) { }
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import me.topchetoeu.jscript.compilation.Instruction;
|
|||||||
import me.topchetoeu.jscript.compilation.Instruction.Type;
|
import me.topchetoeu.jscript.compilation.Instruction.Type;
|
||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.Engine;
|
import me.topchetoeu.jscript.engine.Engine;
|
||||||
|
import me.topchetoeu.jscript.engine.Environment;
|
||||||
import me.topchetoeu.jscript.engine.frame.CodeFrame;
|
import me.topchetoeu.jscript.engine.frame.CodeFrame;
|
||||||
import me.topchetoeu.jscript.engine.frame.Runners;
|
import me.topchetoeu.jscript.engine.frame.Runners;
|
||||||
import me.topchetoeu.jscript.engine.scope.GlobalScope;
|
import me.topchetoeu.jscript.engine.scope.GlobalScope;
|
||||||
@ -341,7 +342,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
try {
|
try {
|
||||||
defaultToString =
|
defaultToString =
|
||||||
Values.getMember(ctx, obj, "toString") ==
|
Values.getMember(ctx, obj, "toString") ==
|
||||||
Values.getMember(ctx, ctx.environment().proto("object"), "toString");
|
Values.getMember(ctx, ctx.environment().get(Environment.OBJECT_PROTO), "toString");
|
||||||
}
|
}
|
||||||
catch (Exception e) { }
|
catch (Exception e) { }
|
||||||
|
|
||||||
@ -495,7 +496,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
var res = new ArrayValue();
|
var res = new ArrayValue();
|
||||||
var passed = new HashSet<String>();
|
var passed = new HashSet<String>();
|
||||||
var tildas = "~";
|
var tildas = "~";
|
||||||
if (target == null) target = ctx.environment().getGlobal();
|
if (target == null) target = ctx.environment().global;
|
||||||
|
|
||||||
for (var proto = target; proto != null && proto != Values.NULL; proto = Values.getPrototype(ctx, proto)) {
|
for (var proto = target; proto != null && proto != Values.NULL; proto = Values.getPrototype(ctx, proto)) {
|
||||||
for (var el : Values.getMembers(ctx, proto, true, true)) {
|
for (var el : Values.getMembers(ctx, proto, true, true)) {
|
||||||
@ -870,7 +871,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
|
|
||||||
if (!frame.debugData) return false;
|
if (!frame.debugData) return false;
|
||||||
|
|
||||||
if (instruction.location != null) frame.updateLoc(ctx.engine.mapToCompiled(instruction.location));
|
if (instruction.location != null) frame.updateLoc(DebugContext.get(ctx).mapToCompiled(instruction.location));
|
||||||
loc = frame.location;
|
loc = frame.location;
|
||||||
isBreakpointable = loc != null && (instruction.breakpoint.shouldStepIn());
|
isBreakpointable = loc != null && (instruction.breakpoint.shouldStepIn());
|
||||||
|
|
||||||
@ -953,12 +954,12 @@ public class SimpleDebugger implements Debugger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override public synchronized void connect() {
|
@Override public synchronized void connect() {
|
||||||
if (!target.attachDebugger(this)) {
|
if (!DebugContext.get(target.globalEnvironment).attachDebugger(this)) {
|
||||||
ws.send(new V8Error("A debugger is already attached to this engine."));
|
ws.send(new V8Error("A debugger is already attached to this engine."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Override public synchronized void disconnect() {
|
@Override public synchronized void disconnect() {
|
||||||
target.detachDebugger();
|
DebugContext.get(target.globalEnvironment).detachDebugger();
|
||||||
enabled = false;
|
enabled = false;
|
||||||
updateNotifier.next();
|
updateNotifier.next();
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import java.util.Stack;
|
|||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.Location;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
|
import me.topchetoeu.jscript.engine.debug.DebugContext;
|
||||||
import me.topchetoeu.jscript.engine.scope.LocalScope;
|
import me.topchetoeu.jscript.engine.scope.LocalScope;
|
||||||
import me.topchetoeu.jscript.engine.scope.ValueVariable;
|
import me.topchetoeu.jscript.engine.scope.ValueVariable;
|
||||||
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
||||||
@ -198,8 +199,7 @@ public class CodeFrame {
|
|||||||
|
|
||||||
if (instr == null) returnValue = null;
|
if (instr == null) returnValue = null;
|
||||||
else {
|
else {
|
||||||
// System.out.println(instr + "@" + instr.location);
|
DebugContext.get(ctx).onInstruction(ctx, this, instr, Runners.NO_RETURN, null, false);
|
||||||
ctx.engine.onInstruction(ctx, this, instr, Runners.NO_RETURN, null, false);
|
|
||||||
|
|
||||||
if (instr.location != null) prevLoc = instr.location;
|
if (instr.location != null) prevLoc = instr.location;
|
||||||
|
|
||||||
@ -291,11 +291,11 @@ public class CodeFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.engine.onInstruction(ctx, this, instr, null, error, caught);
|
DebugContext.get(ctx).onInstruction(ctx, this, instr, null, error, caught);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
if (returnValue != Runners.NO_RETURN) {
|
if (returnValue != Runners.NO_RETURN) {
|
||||||
ctx.engine.onInstruction(ctx, this, instr, returnValue, null, false);
|
DebugContext.get(ctx).onInstruction(ctx, this, instr, returnValue, null, false);
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import java.util.Collections;
|
|||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.Engine;
|
import me.topchetoeu.jscript.engine.Engine;
|
||||||
|
import me.topchetoeu.jscript.engine.Environment;
|
||||||
import me.topchetoeu.jscript.engine.Operation;
|
import me.topchetoeu.jscript.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.ValueVariable;
|
import me.topchetoeu.jscript.engine.scope.ValueVariable;
|
||||||
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
||||||
@ -197,7 +198,13 @@ public class Runners {
|
|||||||
return execLoadMember(ctx, instr, frame);
|
return execLoadMember(ctx, instr, frame);
|
||||||
}
|
}
|
||||||
public static Object execLoadRegEx(Context ctx, Instruction instr, CodeFrame frame) {
|
public static Object execLoadRegEx(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
frame.push(ctx, ctx.environment().regexConstructor.call(ctx, null, instr.get(0), instr.get(1)));
|
var env = ctx.environment();
|
||||||
|
if (env.has(Environment.REGEX_CONSTR)) {
|
||||||
|
frame.push(ctx, Values.callNew(ctx, env.get(Environment.REGEX_CONSTR)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw EngineException.ofSyntax("Regex is not supported.");
|
||||||
|
}
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
|
import me.topchetoeu.jscript.engine.Environment;
|
||||||
|
|
||||||
public class ObjectValue {
|
public class ObjectValue {
|
||||||
public static enum PlaceholderProto {
|
public static enum PlaceholderProto {
|
||||||
@ -146,13 +147,13 @@ public class ObjectValue {
|
|||||||
|
|
||||||
public ObjectValue getPrototype(Context ctx) {
|
public ObjectValue getPrototype(Context ctx) {
|
||||||
try {
|
try {
|
||||||
if (prototype == OBJ_PROTO) return ctx.environment().proto("object");
|
if (prototype == OBJ_PROTO) return ctx.environment().get(Environment.OBJECT_PROTO);
|
||||||
if (prototype == ARR_PROTO) return ctx.environment().proto("array");
|
if (prototype == ARR_PROTO) return ctx.environment().get(Environment.ARRAY_PROTO);
|
||||||
if (prototype == FUNC_PROTO) return ctx.environment().proto("function");
|
if (prototype == FUNC_PROTO) return ctx.environment().get(Environment.FUNCTION_PROTO);
|
||||||
if (prototype == ERR_PROTO) return ctx.environment().proto("error");
|
if (prototype == ERR_PROTO) return ctx.environment().get(Environment.ERROR_PROTO);
|
||||||
if (prototype == RANGE_ERR_PROTO) return ctx.environment().proto("rangeErr");
|
if (prototype == RANGE_ERR_PROTO) return ctx.environment().get(Environment.RANGE_ERR_PROTO);
|
||||||
if (prototype == SYNTAX_ERR_PROTO) return ctx.environment().proto("syntaxErr");
|
if (prototype == SYNTAX_ERR_PROTO) return ctx.environment().get(Environment.SYNTAX_ERR_PROTO);
|
||||||
if (prototype == TYPE_ERR_PROTO) return ctx.environment().proto("typeErr");
|
if (prototype == TYPE_ERR_PROTO) return ctx.environment().get(Environment.TYPE_ERR_PROTO);
|
||||||
}
|
}
|
||||||
catch (NullPointerException e) { return null; }
|
catch (NullPointerException e) { return null; }
|
||||||
|
|
||||||
@ -170,13 +171,13 @@ public class ObjectValue {
|
|||||||
var obj = Values.object(val);
|
var obj = Values.object(val);
|
||||||
|
|
||||||
if (ctx != null && ctx.environment() != null) {
|
if (ctx != null && ctx.environment() != null) {
|
||||||
if (obj == ctx.environment().proto("object")) prototype = OBJ_PROTO;
|
if (obj == ctx.environment().get(Environment.OBJECT_PROTO)) prototype = OBJ_PROTO;
|
||||||
else if (obj == ctx.environment().proto("array")) prototype = ARR_PROTO;
|
else if (obj == ctx.environment().get(Environment.ARRAY_PROTO)) prototype = ARR_PROTO;
|
||||||
else if (obj == ctx.environment().proto("function")) prototype = FUNC_PROTO;
|
else if (obj == ctx.environment().get(Environment.FUNCTION_PROTO)) prototype = FUNC_PROTO;
|
||||||
else if (obj == ctx.environment().proto("error")) prototype = ERR_PROTO;
|
else if (obj == ctx.environment().get(Environment.ERROR_PROTO)) prototype = ERR_PROTO;
|
||||||
else if (obj == ctx.environment().proto("syntaxErr")) prototype = SYNTAX_ERR_PROTO;
|
else if (obj == ctx.environment().get(Environment.SYNTAX_ERR_PROTO)) prototype = SYNTAX_ERR_PROTO;
|
||||||
else if (obj == ctx.environment().proto("typeErr")) prototype = TYPE_ERR_PROTO;
|
else if (obj == ctx.environment().get(Environment.TYPE_ERR_PROTO)) prototype = TYPE_ERR_PROTO;
|
||||||
else if (obj == ctx.environment().proto("rangeErr")) prototype = RANGE_ERR_PROTO;
|
else if (obj == ctx.environment().get(Environment.RANGE_ERR_PROTO)) prototype = RANGE_ERR_PROTO;
|
||||||
else prototype = obj;
|
else prototype = obj;
|
||||||
}
|
}
|
||||||
else prototype = obj;
|
else prototype = obj;
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
package me.topchetoeu.jscript.engine.values;
|
package me.topchetoeu.jscript.engine.values;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
public final class Symbol {
|
public final class Symbol {
|
||||||
|
private static final HashMap<String, Symbol> registry = new HashMap<>();
|
||||||
|
|
||||||
public final String value;
|
public final String value;
|
||||||
|
|
||||||
public Symbol(String value) {
|
public Symbol(String value) {
|
||||||
@ -12,4 +16,13 @@ public final class Symbol {
|
|||||||
if (value == null) return "Symbol";
|
if (value == null) return "Symbol";
|
||||||
else return "@@" + value;
|
else return "@@" + value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Symbol get(String name) {
|
||||||
|
if (registry.containsKey(name)) return registry.get(name);
|
||||||
|
else {
|
||||||
|
var res = new Symbol(name);
|
||||||
|
registry.put(name, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
|
import me.topchetoeu.jscript.engine.Environment;
|
||||||
import me.topchetoeu.jscript.engine.Operation;
|
import me.topchetoeu.jscript.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.frame.ConvertHint;
|
import me.topchetoeu.jscript.engine.frame.ConvertHint;
|
||||||
import me.topchetoeu.jscript.exceptions.ConvertException;
|
import me.topchetoeu.jscript.exceptions.ConvertException;
|
||||||
@ -346,10 +347,10 @@ public class Values {
|
|||||||
if (isObject(obj)) return object(obj).getPrototype(ctx);
|
if (isObject(obj)) return object(obj).getPrototype(ctx);
|
||||||
if (ctx == null) return null;
|
if (ctx == null) return null;
|
||||||
|
|
||||||
if (obj instanceof String) return ctx.environment().proto("string");
|
if (obj instanceof String) return ctx.environment().get(Environment.STRING_PROTO);
|
||||||
else if (obj instanceof Number) return ctx.environment().proto("number");
|
else if (obj instanceof Number) return ctx.environment().get(Environment.NUMBER_PROTO);
|
||||||
else if (obj instanceof Boolean) return ctx.environment().proto("bool");
|
else if (obj instanceof Boolean) return ctx.environment().get(Environment.BOOL_PROTO);
|
||||||
else if (obj instanceof Symbol) return ctx.environment().proto("symbol");
|
else if (obj instanceof Symbol) return ctx.environment().get(Environment.SYMBOL_PROTO);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -550,7 +551,7 @@ public class Values {
|
|||||||
public static Iterable<Object> fromJSIterator(Context ctx, Object obj) {
|
public static Iterable<Object> fromJSIterator(Context ctx, Object obj) {
|
||||||
return () -> {
|
return () -> {
|
||||||
try {
|
try {
|
||||||
var symbol = ctx.environment().symbol("Symbol.iterator");
|
var symbol = Symbol.get("Symbol.iterator");
|
||||||
|
|
||||||
var iteratorFunc = getMember(ctx, obj, symbol);
|
var iteratorFunc = getMember(ctx, obj, symbol);
|
||||||
if (!isFunction(iteratorFunc)) return Collections.emptyIterator();
|
if (!isFunction(iteratorFunc)) return Collections.emptyIterator();
|
||||||
@ -604,7 +605,7 @@ public class Values {
|
|||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var key = getMember(ctx, getMember(ctx, ctx.environment().proto("symbol"), "constructor"), "iterator");
|
var key = getMember(ctx, getMember(ctx, ctx.environment().get(Environment.SYMBOL_PROTO), "constructor"), "iterator");
|
||||||
res.defineProperty(ctx, key, new NativeFunction("", (_ctx, thisArg, args) -> thisArg));
|
res.defineProperty(ctx, key, new NativeFunction("", (_ctx, thisArg, args) -> thisArg));
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException | NullPointerException e) { }
|
catch (IllegalArgumentException | NullPointerException e) { }
|
||||||
@ -629,7 +630,7 @@ public class Values {
|
|||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var key = getMemberPath(ctx, ctx.environment().proto("symbol"), "constructor", "asyncIterator");
|
var key = getMemberPath(ctx, ctx.environment().get(Environment.SYMBOL_PROTO), "constructor", "asyncIterator");
|
||||||
res.defineProperty(ctx, key, new NativeFunction("", (_ctx, thisArg, args) -> thisArg));
|
res.defineProperty(ctx, key, new NativeFunction("", (_ctx, thisArg, args) -> thisArg));
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException | NullPointerException e) { }
|
catch (IllegalArgumentException | NullPointerException e) { }
|
||||||
|
@ -7,6 +7,7 @@ import me.topchetoeu.jscript.Location;
|
|||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.Engine;
|
import me.topchetoeu.jscript.engine.Engine;
|
||||||
import me.topchetoeu.jscript.engine.Environment;
|
import me.topchetoeu.jscript.engine.Environment;
|
||||||
|
import me.topchetoeu.jscript.engine.debug.DebugContext;
|
||||||
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
import me.topchetoeu.jscript.engine.values.ObjectValue.PlaceholderProto;
|
import me.topchetoeu.jscript.engine.values.ObjectValue.PlaceholderProto;
|
||||||
@ -18,13 +19,13 @@ public class EngineException extends RuntimeException {
|
|||||||
public final Context ctx;
|
public final Context ctx;
|
||||||
|
|
||||||
public boolean visible() {
|
public boolean visible() {
|
||||||
return ctx == null || ctx.environment() == null || ctx.environment().stackVisible;
|
return ctx == null || ctx.environment() == null || !ctx.environment().get(Environment.HIDE_STACK, false);
|
||||||
}
|
}
|
||||||
public String toString() {
|
public String toString() {
|
||||||
var res = "";
|
var res = "";
|
||||||
var loc = location;
|
var loc = location;
|
||||||
|
|
||||||
if (loc != null && ctx != null && ctx.engine != null) loc = ctx.engine.mapToCompiled(loc);
|
if (loc != null && ctx != null && ctx.engine != null) loc = DebugContext.get(ctx).mapToCompiled(loc);
|
||||||
|
|
||||||
if (loc != null) res += "at " + loc.toString() + " ";
|
if (loc != null) res += "at " + loc.toString() + " ";
|
||||||
if (function != null && !function.equals("")) res += "in " + function + " ";
|
if (function != null && !function.equals("")) res += "in " + function + " ";
|
||||||
|
@ -8,6 +8,7 @@ import me.topchetoeu.jscript.engine.WrappersProvider;
|
|||||||
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
||||||
import me.topchetoeu.jscript.engine.values.NativeFunction;
|
import me.topchetoeu.jscript.engine.values.NativeFunction;
|
||||||
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
||||||
|
import me.topchetoeu.jscript.engine.values.Symbol;
|
||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.exceptions.UncheckedException;
|
import me.topchetoeu.jscript.exceptions.UncheckedException;
|
||||||
|
|
||||||
@ -28,7 +29,7 @@ public class NativeWrapperProvider implements WrappersProvider {
|
|||||||
if (nat.thisArg() && !member || !nat.thisArg() && !memberMatch) continue;
|
if (nat.thisArg() && !member || !nat.thisArg() && !memberMatch) continue;
|
||||||
|
|
||||||
Object name = nat.value();
|
Object name = nat.value();
|
||||||
if (((String)name).startsWith("@@")) name = env.symbol(((String)name).substring(2));
|
if (name.toString().startsWith("@@")) name = Symbol.get(name.toString().substring(2));
|
||||||
else if (name.equals("")) name = method.getName();
|
else if (name.equals("")) name = method.getName();
|
||||||
|
|
||||||
var val = target.values.get(name);
|
var val = target.values.get(name);
|
||||||
@ -42,7 +43,7 @@ public class NativeWrapperProvider implements WrappersProvider {
|
|||||||
if (get.thisArg() && !member || !get.thisArg() && !memberMatch) continue;
|
if (get.thisArg() && !member || !get.thisArg() && !memberMatch) continue;
|
||||||
|
|
||||||
Object name = get.value();
|
Object name = get.value();
|
||||||
if (((String)name).startsWith("@@")) name = env.symbol(((String)name).substring(2));
|
if (((String)name).startsWith("@@")) name = Symbol.get(((String)name).substring(2));
|
||||||
else if (name.equals("")) name = method.getName();
|
else if (name.equals("")) name = method.getName();
|
||||||
|
|
||||||
var prop = target.properties.get(name);
|
var prop = target.properties.get(name);
|
||||||
@ -59,7 +60,7 @@ public class NativeWrapperProvider implements WrappersProvider {
|
|||||||
if (set.thisArg() && !member || !set.thisArg() && !memberMatch) continue;
|
if (set.thisArg() && !member || !set.thisArg() && !memberMatch) continue;
|
||||||
|
|
||||||
Object name = set.value();
|
Object name = set.value();
|
||||||
if (((String)name).startsWith("@@")) name = env.symbol(((String)name).substring(2));
|
if (((String)name).startsWith("@@")) name = Symbol.get(((String)name).substring(2));
|
||||||
else if (name.equals("")) name = method.getName();
|
else if (name.equals("")) name = method.getName();
|
||||||
|
|
||||||
var prop = target.properties.get(name);
|
var prop = target.properties.get(name);
|
||||||
@ -82,7 +83,7 @@ public class NativeWrapperProvider implements WrappersProvider {
|
|||||||
|
|
||||||
if (nat != null) {
|
if (nat != null) {
|
||||||
Object name = nat.value();
|
Object name = nat.value();
|
||||||
if (((String)name).startsWith("@@")) name = env.symbol(((String)name).substring(2));
|
if (((String)name).startsWith("@@")) name = Symbol.get(((String)name).substring(2));
|
||||||
else if (name.equals("")) name = field.getName();
|
else if (name.equals("")) name = field.getName();
|
||||||
|
|
||||||
var getter = OverloadFunction.of("get " + name, Overload.getterFromField(field));
|
var getter = OverloadFunction.of("get " + name, Overload.getterFromField(field));
|
||||||
@ -98,7 +99,7 @@ public class NativeWrapperProvider implements WrappersProvider {
|
|||||||
|
|
||||||
if (nat != null) {
|
if (nat != null) {
|
||||||
Object name = nat.value();
|
Object name = nat.value();
|
||||||
if (((String)name).startsWith("@@")) name = env.symbol(((String)name).substring(2));
|
if (((String)name).startsWith("@@")) name = Symbol.get(((String)name).substring(2));
|
||||||
else if (name.equals("")) name = cl.getName();
|
else if (name.equals("")) name = cl.getName();
|
||||||
|
|
||||||
var getter = new NativeFunction("get " + name, (ctx, thisArg, args) -> cl);
|
var getter = new NativeFunction("get " + name, (ctx, thisArg, args) -> cl);
|
||||||
@ -123,7 +124,7 @@ public class NativeWrapperProvider implements WrappersProvider {
|
|||||||
public static ObjectValue makeProto(Environment ctx, Class<?> clazz) {
|
public static ObjectValue makeProto(Environment ctx, Class<?> clazz) {
|
||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
|
|
||||||
res.defineProperty(null, ctx.symbol("Symbol.typeName"), getName(clazz));
|
res.defineProperty(null, Symbol.get("Symbol.typeName"), getName(clazz));
|
||||||
|
|
||||||
for (var overload : clazz.getDeclaredMethods()) {
|
for (var overload : clazz.getDeclaredMethods()) {
|
||||||
var init = overload.getAnnotation(NativeInit.class);
|
var init = overload.getAnnotation(NativeInit.class);
|
||||||
|
@ -4,6 +4,7 @@ import me.topchetoeu.jscript.engine.Context;
|
|||||||
import me.topchetoeu.jscript.engine.Environment;
|
import me.topchetoeu.jscript.engine.Environment;
|
||||||
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
||||||
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
||||||
|
import me.topchetoeu.jscript.engine.values.Symbol;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
import me.topchetoeu.jscript.engine.values.ObjectValue.PlaceholderProto;
|
import me.topchetoeu.jscript.engine.values.ObjectValue.PlaceholderProto;
|
||||||
import me.topchetoeu.jscript.interop.InitType;
|
import me.topchetoeu.jscript.interop.InitType;
|
||||||
@ -35,7 +36,7 @@ import me.topchetoeu.jscript.interop.NativeInit;
|
|||||||
if (thisArg instanceof ObjectValue) {
|
if (thisArg instanceof ObjectValue) {
|
||||||
var stack = Values.getMember(ctx, thisArg, "stack");
|
var stack = Values.getMember(ctx, thisArg, "stack");
|
||||||
if (!(stack instanceof ArrayValue)) stack = null;
|
if (!(stack instanceof ArrayValue)) stack = null;
|
||||||
var cause = Values.getMember(ctx, thisArg, ctx.environment().symbol("Symbol.cause"));
|
var cause = Values.getMember(ctx, thisArg, Symbol.get("Symbol.cause"));
|
||||||
return toString(ctx,
|
return toString(ctx,
|
||||||
thisArg == cause,
|
thisArg == cause,
|
||||||
cause,
|
cause,
|
||||||
|
@ -10,6 +10,7 @@ import me.topchetoeu.jscript.engine.DataKey;
|
|||||||
import me.topchetoeu.jscript.engine.Environment;
|
import me.topchetoeu.jscript.engine.Environment;
|
||||||
import me.topchetoeu.jscript.engine.scope.GlobalScope;
|
import me.topchetoeu.jscript.engine.scope.GlobalScope;
|
||||||
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
||||||
|
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.interop.Native;
|
import me.topchetoeu.jscript.interop.Native;
|
||||||
@ -17,9 +18,6 @@ import me.topchetoeu.jscript.interop.NativeGetter;
|
|||||||
import me.topchetoeu.jscript.parsing.Parsing;
|
import me.topchetoeu.jscript.parsing.Parsing;
|
||||||
|
|
||||||
public class Internals {
|
public class Internals {
|
||||||
private static final DataKey<HashMap<Integer, Thread>> THREADS = new DataKey<>();
|
|
||||||
private static final DataKey<Integer> I = new DataKey<>();
|
|
||||||
|
|
||||||
@Native public static Object require(Context ctx, String name) {
|
@Native public static Object require(Context ctx, String name) {
|
||||||
var env = ctx.environment();
|
var env = ctx.environment();
|
||||||
var res = env.modules.getModule(ctx, env.moduleCwd, name);
|
var res = env.modules.getModule(ctx, env.moduleCwd, name);
|
||||||
@ -47,7 +45,7 @@ public class Internals {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Native public static int setTimeout(Context ctx, FunctionValue func, int delay, Object ...args) {
|
@Native public static Thread setTimeout(Context ctx, FunctionValue func, int delay, Object ...args) {
|
||||||
var thread = new Thread(() -> {
|
var thread = new Thread(() -> {
|
||||||
var ms = (long)delay;
|
var ms = (long)delay;
|
||||||
var ns = (int)((delay - ms) * 10000000);
|
var ns = (int)((delay - ms) * 10000000);
|
||||||
@ -61,12 +59,9 @@ public class Internals {
|
|||||||
});
|
});
|
||||||
thread.start();
|
thread.start();
|
||||||
|
|
||||||
int i = ctx.environment().data.increase(I, 1, 0);
|
return thread;
|
||||||
var threads = ctx.environment().data.get(THREADS, new HashMap<>());
|
|
||||||
threads.put(++i, thread);
|
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
@Native public static int setInterval(Context ctx, FunctionValue func, int delay, Object ...args) {
|
@Native public static Thread setInterval(Context ctx, FunctionValue func, int delay, Object ...args) {
|
||||||
var thread = new Thread(() -> {
|
var thread = new Thread(() -> {
|
||||||
var ms = (long)delay;
|
var ms = (long)delay;
|
||||||
var ns = (int)((delay - ms) * 10000000);
|
var ns = (int)((delay - ms) * 10000000);
|
||||||
@ -76,26 +71,19 @@ public class Internals {
|
|||||||
Thread.sleep(ms, ns);
|
Thread.sleep(ms, ns);
|
||||||
}
|
}
|
||||||
catch (InterruptedException e) { return; }
|
catch (InterruptedException e) { return; }
|
||||||
|
|
||||||
ctx.engine.pushMsg(false, ctx.environment(), func, null, args);
|
ctx.engine.pushMsg(false, ctx.environment(), func, null, args);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
thread.start();
|
|
||||||
|
|
||||||
int i = ctx.environment().data.increase(I, 1, 0);
|
return thread;
|
||||||
var threads = ctx.environment().data.get(THREADS, new HashMap<>());
|
|
||||||
threads.put(++i, thread);
|
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Native public static void clearTimeout(Context ctx, int i) {
|
@Native public static void clearTimeout(Context ctx, Thread t) {
|
||||||
var threads = ctx.environment().data.get(THREADS, new HashMap<>());
|
t.interrupt();
|
||||||
|
|
||||||
var thread = threads.remove(i);
|
|
||||||
if (thread != null) thread.interrupt();
|
|
||||||
}
|
}
|
||||||
@Native public static void clearInterval(Context ctx, int i) {
|
@Native public static void clearInterval(Context ctx, Thread t) {
|
||||||
clearTimeout(ctx, i);
|
t.interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Native public static double parseInt(Context ctx, String val) {
|
@Native public static double parseInt(Context ctx, String val) {
|
||||||
@ -205,22 +193,22 @@ public class Internals {
|
|||||||
glob.define(false, wp.getConstr(TypeErrorLib.class));
|
glob.define(false, wp.getConstr(TypeErrorLib.class));
|
||||||
glob.define(false, wp.getConstr(RangeErrorLib.class));
|
glob.define(false, wp.getConstr(RangeErrorLib.class));
|
||||||
|
|
||||||
env.setProto("object", wp.getProto(ObjectLib.class));
|
env.add(Environment.OBJECT_PROTO, wp.getProto(ObjectLib.class));
|
||||||
env.setProto("function", wp.getProto(FunctionLib.class));
|
env.add(Environment.FUNCTION_PROTO, wp.getProto(FunctionLib.class));
|
||||||
env.setProto("array", wp.getProto(ArrayLib.class));
|
env.add(Environment.ARRAY_PROTO, wp.getProto(ArrayLib.class));
|
||||||
|
|
||||||
env.setProto("bool", wp.getProto(BooleanLib.class));
|
env.add(Environment.BOOL_PROTO, wp.getProto(BooleanLib.class));
|
||||||
env.setProto("number", wp.getProto(NumberLib.class));
|
env.add(Environment.NUMBER_PROTO, wp.getProto(NumberLib.class));
|
||||||
env.setProto("string", wp.getProto(StringLib.class));
|
env.add(Environment.STRING_PROTO, wp.getProto(StringLib.class));
|
||||||
env.setProto("symbol", wp.getProto(SymbolLib.class));
|
env.add(Environment.SYMBOL_PROTO, wp.getProto(SymbolLib.class));
|
||||||
|
|
||||||
env.setProto("error", wp.getProto(ErrorLib.class));
|
env.add(Environment.ERROR_PROTO, wp.getProto(ErrorLib.class));
|
||||||
env.setProto("syntaxErr", wp.getProto(SyntaxErrorLib.class));
|
env.add(Environment.SYNTAX_ERR_PROTO, wp.getProto(SyntaxErrorLib.class));
|
||||||
env.setProto("typeErr", wp.getProto(TypeErrorLib.class));
|
env.add(Environment.TYPE_ERR_PROTO, wp.getProto(TypeErrorLib.class));
|
||||||
env.setProto("rangeErr", wp.getProto(RangeErrorLib.class));
|
env.add(Environment.RANGE_ERR_PROTO, wp.getProto(RangeErrorLib.class));
|
||||||
|
|
||||||
wp.getProto(ObjectLib.class).setPrototype(null, null);
|
wp.getProto(ObjectLib.class).setPrototype(null, null);
|
||||||
env.regexConstructor = wp.getConstr(RegExpLib.class);
|
env.add(Environment.REGEX_CONSTR, wp.getConstr(RegExpLib.class));
|
||||||
|
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ import me.topchetoeu.jscript.interop.NativeConstructor;
|
|||||||
return thisArg;
|
return thisArg;
|
||||||
}
|
}
|
||||||
@Native(thisArg = true) public static String toString(Context ctx, Object thisArg) {
|
@Native(thisArg = true) public static String toString(Context ctx, Object thisArg) {
|
||||||
var name = Values.getMember(ctx, thisArg, ctx.environment().symbol("Symbol.typeName"));
|
var name = Values.getMember(ctx, thisArg, Symbol.get("Symbol.typeName"));
|
||||||
if (name == null) name = "Unknown";
|
if (name == null) name = "Unknown";
|
||||||
else name = Values.toString(ctx, name);
|
else name = Values.toString(ctx, name);
|
||||||
|
|
||||||
|
@ -3,9 +3,11 @@ package me.topchetoeu.jscript.lib;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.Context;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
|
import me.topchetoeu.jscript.engine.Environment;
|
||||||
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
||||||
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
||||||
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
||||||
|
import me.topchetoeu.jscript.engine.values.Symbol;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.interop.Native;
|
import me.topchetoeu.jscript.interop.Native;
|
||||||
@ -80,7 +82,7 @@ import me.topchetoeu.jscript.interop.NativeGetter;
|
|||||||
var val = passThis(ctx, "indexOf", thisArg);
|
var val = passThis(ctx, "indexOf", thisArg);
|
||||||
|
|
||||||
if (term != null && term != Values.NULL && !(term instanceof String)) {
|
if (term != null && term != Values.NULL && !(term instanceof String)) {
|
||||||
var search = Values.getMember(ctx, term, ctx.environment().symbol("Symbol.search"));
|
var search = Values.getMember(ctx, term, Symbol.get("Symbol.search"));
|
||||||
if (search instanceof FunctionValue) {
|
if (search instanceof FunctionValue) {
|
||||||
return (int)Values.toNumber(ctx, ((FunctionValue)search).call(ctx, term, val, false, start));
|
return (int)Values.toNumber(ctx, ((FunctionValue)search).call(ctx, term, val, false, start));
|
||||||
}
|
}
|
||||||
@ -92,7 +94,7 @@ import me.topchetoeu.jscript.interop.NativeGetter;
|
|||||||
var val = passThis(ctx, "lastIndexOf", thisArg);
|
var val = passThis(ctx, "lastIndexOf", thisArg);
|
||||||
|
|
||||||
if (term != null && term != Values.NULL && !(term instanceof String)) {
|
if (term != null && term != Values.NULL && !(term instanceof String)) {
|
||||||
var search = Values.getMember(ctx, term, ctx.environment().symbol("Symbol.search"));
|
var search = Values.getMember(ctx, term, Symbol.get("Symbol.search"));
|
||||||
if (search instanceof FunctionValue) {
|
if (search instanceof FunctionValue) {
|
||||||
return (int)Values.toNumber(ctx, ((FunctionValue)search).call(ctx, term, val, true, pos));
|
return (int)Values.toNumber(ctx, ((FunctionValue)search).call(ctx, term, val, true, pos));
|
||||||
}
|
}
|
||||||
@ -109,7 +111,7 @@ import me.topchetoeu.jscript.interop.NativeGetter;
|
|||||||
var val = passThis(ctx, "replace", thisArg);
|
var val = passThis(ctx, "replace", thisArg);
|
||||||
|
|
||||||
if (term != null && term != Values.NULL && !(term instanceof String)) {
|
if (term != null && term != Values.NULL && !(term instanceof String)) {
|
||||||
var replace = Values.getMember(ctx, term, ctx.environment().symbol("Symbol.replace"));
|
var replace = Values.getMember(ctx, term, Symbol.get("Symbol.replace"));
|
||||||
if (replace instanceof FunctionValue) {
|
if (replace instanceof FunctionValue) {
|
||||||
return Values.toString(ctx, ((FunctionValue)replace).call(ctx, term, val, replacement));
|
return Values.toString(ctx, ((FunctionValue)replace).call(ctx, term, val, replacement));
|
||||||
}
|
}
|
||||||
@ -121,7 +123,7 @@ import me.topchetoeu.jscript.interop.NativeGetter;
|
|||||||
var val = passThis(ctx, "replaceAll", thisArg);
|
var val = passThis(ctx, "replaceAll", thisArg);
|
||||||
|
|
||||||
if (term != null && term != Values.NULL && !(term instanceof String)) {
|
if (term != null && term != Values.NULL && !(term instanceof String)) {
|
||||||
var replace = Values.getMember(ctx, term, ctx.environment().symbol("Symbol.replace"));
|
var replace = Values.getMember(ctx, term, Symbol.get("Symbol.replace"));
|
||||||
if (replace instanceof FunctionValue) {
|
if (replace instanceof FunctionValue) {
|
||||||
return Values.toString(ctx, ((FunctionValue)replace).call(ctx, term, val, replacement));
|
return Values.toString(ctx, ((FunctionValue)replace).call(ctx, term, val, replacement));
|
||||||
}
|
}
|
||||||
@ -136,11 +138,11 @@ import me.topchetoeu.jscript.interop.NativeGetter;
|
|||||||
FunctionValue match;
|
FunctionValue match;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var _match = Values.getMember(ctx, term, ctx.environment().symbol("Symbol.match"));
|
var _match = Values.getMember(ctx, term, Symbol.get("Symbol.match"));
|
||||||
if (_match instanceof FunctionValue) match = (FunctionValue)_match;
|
if (_match instanceof FunctionValue) match = (FunctionValue)_match;
|
||||||
else if (ctx.environment().regexConstructor != null) {
|
else if (ctx.environment().has(Environment.REGEX_CONSTR)) {
|
||||||
var regex = Values.callNew(ctx, ctx.environment().regexConstructor, Values.toString(ctx, term), "");
|
var regex = Values.callNew(ctx, ctx.environment().get(Environment.REGEX_CONSTR), Values.toString(ctx, term), "");
|
||||||
_match = Values.getMember(ctx, regex, ctx.environment().symbol("Symbol.match"));
|
_match = Values.getMember(ctx, regex, Symbol.get("Symbol.match"));
|
||||||
if (_match instanceof FunctionValue) match = (FunctionValue)_match;
|
if (_match instanceof FunctionValue) match = (FunctionValue)_match;
|
||||||
else throw EngineException.ofError("Regular expressions don't support matching.");
|
else throw EngineException.ofError("Regular expressions don't support matching.");
|
||||||
}
|
}
|
||||||
@ -158,14 +160,14 @@ import me.topchetoeu.jscript.interop.NativeGetter;
|
|||||||
FunctionValue match = null;
|
FunctionValue match = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var _match = Values.getMember(ctx, term, ctx.environment().symbol("Symbol.matchAll"));
|
var _match = Values.getMember(ctx, term, Symbol.get("Symbol.matchAll"));
|
||||||
if (_match instanceof FunctionValue) match = (FunctionValue)_match;
|
if (_match instanceof FunctionValue) match = (FunctionValue)_match;
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException e) { }
|
catch (IllegalArgumentException e) { }
|
||||||
|
|
||||||
if (match == null && ctx.environment().regexConstructor != null) {
|
if (match == null && ctx.environment().has(Environment.REGEX_CONSTR)) {
|
||||||
var regex = Values.callNew(ctx, ctx.environment().regexConstructor, Values.toString(ctx, term), "g");
|
var regex = Values.callNew(ctx, ctx.environment().get(Environment.REGEX_CONSTR), Values.toString(ctx, term), "g");
|
||||||
var _match = Values.getMember(ctx, regex, ctx.environment().symbol("Symbol.matchAll"));
|
var _match = Values.getMember(ctx, regex, Symbol.get("Symbol.matchAll"));
|
||||||
if (_match instanceof FunctionValue) match = (FunctionValue)_match;
|
if (_match instanceof FunctionValue) match = (FunctionValue)_match;
|
||||||
else throw EngineException.ofError("Regular expressions don't support matching.");
|
else throw EngineException.ofError("Regular expressions don't support matching.");
|
||||||
}
|
}
|
||||||
@ -180,7 +182,7 @@ import me.topchetoeu.jscript.interop.NativeGetter;
|
|||||||
if (lim != null) lim = Values.toNumber(ctx, lim);
|
if (lim != null) lim = Values.toNumber(ctx, lim);
|
||||||
|
|
||||||
if (term != null && term != Values.NULL && !(term instanceof String)) {
|
if (term != null && term != Values.NULL && !(term instanceof String)) {
|
||||||
var replace = Values.getMember(ctx, term, ctx.environment().symbol("Symbol.replace"));
|
var replace = Values.getMember(ctx, term, Symbol.get("Symbol.replace"));
|
||||||
if (replace instanceof FunctionValue) {
|
if (replace instanceof FunctionValue) {
|
||||||
var tmp = ((FunctionValue)replace).call(ctx, term, val, lim, sensible);
|
var tmp = ((FunctionValue)replace).call(ctx, term, val, lim, sensible);
|
||||||
|
|
||||||
|
@ -10,20 +10,19 @@ import me.topchetoeu.jscript.engine.values.Values;
|
|||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.interop.Native;
|
import me.topchetoeu.jscript.interop.Native;
|
||||||
import me.topchetoeu.jscript.interop.NativeConstructor;
|
import me.topchetoeu.jscript.interop.NativeConstructor;
|
||||||
import me.topchetoeu.jscript.interop.NativeGetter;
|
|
||||||
|
|
||||||
@Native("Symbol") public class SymbolLib {
|
@Native("Symbol") public class SymbolLib {
|
||||||
private static final Map<String, Symbol> symbols = new HashMap<>();
|
private static final Map<String, Symbol> symbols = new HashMap<>();
|
||||||
|
|
||||||
@NativeGetter public static Symbol typeName(Context ctx) { return ctx.environment().symbol("Symbol.typeName"); }
|
@Native public static final Symbol typeName = Symbol.get("Symbol.typeName");
|
||||||
@NativeGetter public static Symbol replace(Context ctx) { return ctx.environment().symbol("Symbol.replace"); }
|
@Native public static final Symbol replace = Symbol.get("Symbol.replace");
|
||||||
@NativeGetter public static Symbol match(Context ctx) { return ctx.environment().symbol("Symbol.match"); }
|
@Native public static final Symbol match = Symbol.get("Symbol.match");
|
||||||
@NativeGetter public static Symbol matchAll(Context ctx) { return ctx.environment().symbol("Symbol.matchAll"); }
|
@Native public static final Symbol matchAll = Symbol.get("Symbol.matchAll");
|
||||||
@NativeGetter public static Symbol split(Context ctx) { return ctx.environment().symbol("Symbol.split"); }
|
@Native public static final Symbol split = Symbol.get("Symbol.split");
|
||||||
@NativeGetter public static Symbol search(Context ctx) { return ctx.environment().symbol("Symbol.search"); }
|
@Native public static final Symbol search = Symbol.get("Symbol.search");
|
||||||
@NativeGetter public static Symbol iterator(Context ctx) { return ctx.environment().symbol("Symbol.iterator"); }
|
@Native public static final Symbol iterator = Symbol.get("Symbol.iterator");
|
||||||
@NativeGetter public static Symbol asyncIterator(Context ctx) { return ctx.environment().symbol("Symbol.asyncIterator"); }
|
@Native public static final Symbol asyncIterator = Symbol.get("Symbol.asyncIterator");
|
||||||
@NativeGetter public static Symbol cause(Context ctx) { return ctx.environment().symbol("Symbol.cause"); }
|
@Native public static final Symbol cause = Symbol.get("Symbol.cause");
|
||||||
|
|
||||||
public final Symbol value;
|
public final Symbol value;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user