Integrate typescript #8
@ -1,131 +1,150 @@
|
|||||||
package me.topchetoeu.jscript;
|
package me.topchetoeu.jscript;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
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.DebugServer;
|
import me.topchetoeu.jscript.engine.StackData;
|
||||||
import me.topchetoeu.jscript.engine.debug.SimpleDebugger;
|
import me.topchetoeu.jscript.engine.debug.DebugServer;
|
||||||
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
import me.topchetoeu.jscript.engine.debug.SimpleDebugger;
|
||||||
import me.topchetoeu.jscript.engine.values.NativeFunction;
|
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.engine.values.NativeFunction;
|
||||||
import me.topchetoeu.jscript.events.Observer;
|
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
import me.topchetoeu.jscript.exceptions.InterruptException;
|
import me.topchetoeu.jscript.events.Observer;
|
||||||
import me.topchetoeu.jscript.exceptions.SyntaxException;
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.exceptions.UncheckedException;
|
import me.topchetoeu.jscript.exceptions.InterruptException;
|
||||||
import me.topchetoeu.jscript.lib.Internals;
|
import me.topchetoeu.jscript.exceptions.SyntaxException;
|
||||||
|
import me.topchetoeu.jscript.lib.Internals;
|
||||||
public class Main {
|
|
||||||
static Thread engineTask, debugTask;
|
public class Main {
|
||||||
static Engine engine;
|
static Thread engineTask, debugTask;
|
||||||
static Environment env;
|
static Engine engine;
|
||||||
static int j = 0;
|
static Environment env;
|
||||||
|
static int j = 0;
|
||||||
private static Observer<Object> valuePrinter = new Observer<Object>() {
|
|
||||||
public void next(Object data) {
|
private static Observer<Object> valuePrinter = new Observer<Object>() {
|
||||||
Values.printValue(null, data);
|
public void next(Object data) {
|
||||||
System.out.println();
|
Values.printValue(null, data);
|
||||||
}
|
System.out.println();
|
||||||
|
}
|
||||||
public void error(RuntimeException err) {
|
|
||||||
Values.printError(err, null);
|
public void error(RuntimeException err) {
|
||||||
}
|
Values.printError(err, null);
|
||||||
|
}
|
||||||
@Override
|
|
||||||
public void finish() {
|
@Override
|
||||||
engineTask.interrupt();
|
public void finish() {
|
||||||
}
|
engineTask.interrupt();
|
||||||
};
|
}
|
||||||
|
};
|
||||||
public static void main(String args[]) {
|
|
||||||
System.out.println(String.format("Running %s v%s by %s", Metadata.NAME, Metadata.VERSION, Metadata.AUTHOR));
|
public static void main(String args[]) {
|
||||||
engine = new Engine();
|
System.out.println(String.format("Running %s v%s by %s", Metadata.NAME, Metadata.VERSION, Metadata.AUTHOR));
|
||||||
|
engine = new Engine(true);
|
||||||
env = new Environment(null, null, null);
|
|
||||||
var exited = new boolean[1];
|
env = new Environment(null, null, null);
|
||||||
var server = new DebugServer();
|
var exited = new boolean[1];
|
||||||
server.targets.put("target", (ws, req) -> SimpleDebugger.get(ws, engine));
|
var server = new DebugServer();
|
||||||
|
server.targets.put("target", (ws, req) -> new SimpleDebugger(ws, engine));
|
||||||
engineTask = engine.start();
|
|
||||||
debugTask = server.start(new InetSocketAddress("127.0.0.1", 9229), true);
|
engineTask = engine.start();
|
||||||
// server.awaitConnection();
|
debugTask = server.start(new InetSocketAddress("127.0.0.1", 9229), true);
|
||||||
|
|
||||||
engine.pushMsg(false, null, new NativeFunction((ctx, thisArg, _a) -> {
|
engine.pushMsg(false, null, new NativeFunction((ctx, thisArg, _a) -> {
|
||||||
new Internals().apply(env);
|
new Internals().apply(env);
|
||||||
|
|
||||||
env.global.define("exit", _ctx -> {
|
env.global.define("exit", _ctx -> {
|
||||||
exited[0] = true;
|
exited[0] = true;
|
||||||
throw new InterruptException();
|
throw new InterruptException();
|
||||||
});
|
});
|
||||||
env.global.define("go", _ctx -> {
|
env.global.define("go", _ctx -> {
|
||||||
try {
|
try {
|
||||||
var f = Path.of("do.js");
|
var f = Path.of("do.js");
|
||||||
var func = _ctx.compile(new Filename("do", "do/" + j++ + ".js"), new String(Files.readAllBytes(f)));
|
var func = _ctx.compile(new Filename("do", "do/" + j++ + ".js"), new String(Files.readAllBytes(f)));
|
||||||
return func.call(_ctx);
|
return func.call(_ctx);
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
throw new EngineException("Couldn't open do.js");
|
throw new EngineException("Couldn't open do.js");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// TODO: make better API
|
||||||
return null;
|
env.global.define(true, new NativeFunction("include", (_ctx, th, __args) -> {
|
||||||
}), null).await();
|
try {
|
||||||
|
var currFilename = StackData.peekFrame(_ctx).function.loc().filename();
|
||||||
try {
|
var loc = Path.of("").toAbsolutePath();
|
||||||
var ts = engine.pushMsg(
|
if (currFilename.protocol.equals("file")) loc = Path.of(currFilename.path).getParent();
|
||||||
false, new Context(engine).pushEnv(env),
|
var path = loc.resolve(Path.of(__args.length >= 1 ? Values.toString(_ctx, __args[0]) : ""));
|
||||||
new Filename("file", "/mnt/data/repos/java-jscript/src/me/topchetoeu/jscript/js/ts.js"),
|
var src = Files.readString(path);
|
||||||
Reading.resourceToString("js/ts.js"), null
|
var func = _ctx.compile(Filename.fromFile(path.toFile()), src);
|
||||||
).await();
|
var callArgs = new ArrayValue();
|
||||||
System.out.println("Loaded typescript!");
|
if (__args.length >= 2 && __args[1] instanceof ArrayValue) callArgs = (ArrayValue)__args[1];
|
||||||
engine.pushMsg(
|
return func.call(_ctx, null, callArgs);
|
||||||
false, new Context(engine).pushEnv(env.child()),
|
}
|
||||||
new Filename("jscript", "internals/bootstrap.js"), Reading.resourceToString("js/bootstrap.js"), null,
|
catch (IOException e) { throw EngineException.ofError("IOError", "Couldn't open file."); }
|
||||||
ts, env, new ArrayValue(null, Reading.resourceToString("js/lib.d.ts"))
|
}));
|
||||||
).await();
|
|
||||||
}
|
return null;
|
||||||
catch (EngineException e) {
|
}), null).await();
|
||||||
Values.printError(e, "(while initializing TS)");
|
|
||||||
System.out.println("engine reported stack trace:");
|
try {
|
||||||
for (var el : e.stackTrace) {
|
var tsEnv = env.child();
|
||||||
System.out.println(el);
|
tsEnv.global.define(null, "module", false, new ObjectValue());
|
||||||
}
|
engine.pushMsg(
|
||||||
}
|
false, new Context(engine).pushEnv(tsEnv),
|
||||||
|
new Filename("jscript", "ts.js"),
|
||||||
|
Reading.resourceToString("js/ts.js"), null
|
||||||
var reader = new Thread(() -> {
|
).await();
|
||||||
try {
|
System.out.println("Loaded typescript!");
|
||||||
for (var i = 0; ; i++) {
|
engine.pushMsg(
|
||||||
try {
|
false, new Context(engine).pushEnv(env.child()),
|
||||||
var raw = Reading.read();
|
new Filename("jscript", "internals/bootstrap.js"), Reading.resourceToString("js/bootstrap.js"), null,
|
||||||
|
tsEnv.global.obj, env, new ArrayValue(null, Reading.resourceToString("js/lib.d.ts"))
|
||||||
if (raw == null) break;
|
).await();
|
||||||
valuePrinter.next(engine.pushMsg(false, new Context(engine).pushEnv(env), new Filename("jscript", "repl/" + i + ".js"), raw, null).await());
|
}
|
||||||
}
|
catch (EngineException e) {
|
||||||
catch (EngineException e) { Values.printError(e, ""); }
|
Values.printError(e, "(while initializing TS)");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (IOException e) { return; }
|
var reader = new Thread(() -> {
|
||||||
catch (SyntaxException ex) {
|
try {
|
||||||
if (exited[0]) return;
|
for (var arg : args) {
|
||||||
System.out.println("Syntax error:" + ex.msg);
|
try {
|
||||||
}
|
var file = Path.of(arg);
|
||||||
catch (RuntimeException ex) {
|
var raw = Files.readString(file);
|
||||||
if (!exited[0]) {
|
valuePrinter.next(engine.pushMsg(false, new Context(engine).pushEnv(env), Filename.fromFile(file.toFile()), raw, null).await());
|
||||||
System.out.println("Internal error ocurred:");
|
}
|
||||||
ex.printStackTrace();
|
catch (EngineException e) { Values.printError(e, ""); }
|
||||||
}
|
}
|
||||||
}
|
for (var i = 0; ; i++) {
|
||||||
catch (Throwable e) { throw new UncheckedException(e); }
|
try {
|
||||||
if (exited[0]) debugTask.interrupt();
|
var raw = Reading.read();
|
||||||
});
|
|
||||||
reader.setDaemon(true);
|
if (raw == null) break;
|
||||||
reader.setName("STD Reader");
|
valuePrinter.next(engine.pushMsg(false, new Context(engine).pushEnv(env), new Filename("jscript", "repl/" + i + ".js"), raw, null).await());
|
||||||
reader.start();
|
}
|
||||||
}
|
catch (EngineException e) { Values.printError(e, ""); }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (IOException e) { exited[0] = true; }
|
||||||
|
catch (SyntaxException ex) {
|
||||||
|
if (exited[0]) return;
|
||||||
|
System.out.println("Syntax error:" + ex.msg);
|
||||||
|
}
|
||||||
|
catch (RuntimeException ex) {
|
||||||
|
if (!exited[0]) {
|
||||||
|
System.out.println("Internal error ocurred:");
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (exited[0]) debugTask.interrupt();
|
||||||
|
});
|
||||||
|
reader.setDaemon(true);
|
||||||
|
reader.setName("STD Reader");
|
||||||
|
reader.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,7 +6,6 @@ import java.util.TreeSet;
|
|||||||
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.values.FunctionValue;
|
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
||||||
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.Values;
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
import me.topchetoeu.jscript.parsing.Parsing;
|
import me.topchetoeu.jscript.parsing.Parsing;
|
||||||
@ -40,10 +39,9 @@ public class Context {
|
|||||||
}
|
}
|
||||||
else source = Values.toString(this, transpiled);
|
else source = Values.toString(this, transpiled);
|
||||||
|
|
||||||
var debugger = StackData.getDebugger(this);
|
|
||||||
var breakpoints = new TreeSet<Location>();
|
var breakpoints = new TreeSet<Location>();
|
||||||
FunctionValue res = Parsing.compile(engine.functions, breakpoints, environment(), filename, source);
|
FunctionValue res = Parsing.compile(engine.functions, breakpoints, environment(), filename, source);
|
||||||
if (debugger != null) debugger.onSource(filename, source, breakpoints);
|
engine.onSource(filename, source, breakpoints);
|
||||||
|
|
||||||
if (runner != null) res = (FunctionValue)runner.call(this, null, res);
|
if (runner != null) res = (FunctionValue)runner.call(this, null, res);
|
||||||
|
|
||||||
|
@ -1,16 +1,22 @@
|
|||||||
package me.topchetoeu.jscript.engine;
|
package me.topchetoeu.jscript.engine;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.TreeSet;
|
||||||
import java.util.concurrent.LinkedBlockingDeque;
|
import java.util.concurrent.LinkedBlockingDeque;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Filename;
|
import me.topchetoeu.jscript.Filename;
|
||||||
|
import me.topchetoeu.jscript.Location;
|
||||||
import me.topchetoeu.jscript.compilation.FunctionBody;
|
import me.topchetoeu.jscript.compilation.FunctionBody;
|
||||||
|
import me.topchetoeu.jscript.compilation.Instruction;
|
||||||
|
import me.topchetoeu.jscript.engine.debug.DebugController;
|
||||||
|
import me.topchetoeu.jscript.engine.frame.CodeFrame;
|
||||||
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
||||||
import me.topchetoeu.jscript.events.Awaitable;
|
import me.topchetoeu.jscript.events.Awaitable;
|
||||||
import me.topchetoeu.jscript.events.DataNotifier;
|
import me.topchetoeu.jscript.events.DataNotifier;
|
||||||
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.exceptions.InterruptException;
|
import me.topchetoeu.jscript.exceptions.InterruptException;
|
||||||
|
|
||||||
public class Engine {
|
public class Engine implements DebugController {
|
||||||
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;
|
||||||
@ -51,8 +57,42 @@ public class Engine {
|
|||||||
private LinkedBlockingDeque<Task> microTasks = new LinkedBlockingDeque<>();
|
private LinkedBlockingDeque<Task> microTasks = new LinkedBlockingDeque<>();
|
||||||
|
|
||||||
public final int id = ++nextId;
|
public final int id = ++nextId;
|
||||||
|
public final Data data = new Data().set(StackData.MAX_FRAMES, 200);
|
||||||
public final HashMap<Long, FunctionBody> functions = new HashMap<>();
|
public final HashMap<Long, FunctionBody> functions = new HashMap<>();
|
||||||
public final Data data = new Data().set(StackData.MAX_FRAMES, 10000);
|
public final boolean debugging;
|
||||||
|
private final HashMap<Filename, String> sources = new HashMap<>();
|
||||||
|
private final HashMap<Filename, TreeSet<Location>> bpts = new HashMap<>();
|
||||||
|
private DebugController debugger;
|
||||||
|
|
||||||
|
public 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()));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.debugger = debugger;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public boolean detachDebugger() {
|
||||||
|
if (!debugging || this.debugger == null) return false;
|
||||||
|
this.debugger = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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) {
|
||||||
|
if (!debugging) return;
|
||||||
|
if (debugger != null) debugger.onSource(filename, source, breakpoints);
|
||||||
|
sources.put(filename, source);
|
||||||
|
bpts.put(filename, breakpoints);
|
||||||
|
}
|
||||||
|
|
||||||
private void runTask(Task task) {
|
private void runTask(Task task) {
|
||||||
try {
|
try {
|
||||||
@ -108,4 +148,8 @@ public class Engine {
|
|||||||
public Awaitable<Object> pushMsg(boolean micro, Context ctx, Filename filename, String raw, Object thisArg, Object ...args) {
|
public Awaitable<Object> pushMsg(boolean micro, Context ctx, Filename filename, String raw, Object thisArg, Object ...args) {
|
||||||
return pushMsg(micro, ctx, new UncompiledFunction(filename, raw), thisArg, args);
|
return pushMsg(micro, ctx, new UncompiledFunction(filename, raw), thisArg, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Engine(boolean debugging) {
|
||||||
|
this.debugging = debugging;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,8 +40,7 @@ public class Environment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Native public Symbol symbol(String name) {
|
@Native public Symbol symbol(String name) {
|
||||||
if (symbols.containsKey(name))
|
if (symbols.containsKey(name)) return symbols.get(name);
|
||||||
return symbols.get(name);
|
|
||||||
else {
|
else {
|
||||||
var res = new Symbol(name);
|
var res = new Symbol(name);
|
||||||
symbols.put(name, res);
|
symbols.put(name, res);
|
||||||
|
@ -4,6 +4,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.Location;
|
||||||
import me.topchetoeu.jscript.engine.debug.Debugger;
|
import me.topchetoeu.jscript.engine.debug.Debugger;
|
||||||
import me.topchetoeu.jscript.engine.frame.CodeFrame;
|
import me.topchetoeu.jscript.engine.frame.CodeFrame;
|
||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
@ -25,8 +26,7 @@ public class StackData {
|
|||||||
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);
|
||||||
ctx.popEnv();
|
ctx.popEnv();
|
||||||
var dbg = getDebugger(ctx);
|
ctx.engine.onFramePop(ctx, frame);
|
||||||
if (dbg != null) dbg.onFramePop(ctx, frame);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public static CodeFrame peekFrame(Context ctx) {
|
public static CodeFrame peekFrame(Context ctx) {
|
||||||
@ -45,7 +45,11 @@ public class StackData {
|
|||||||
for (var i = frames.size() - 1; i >= 0; i--) {
|
for (var i = frames.size() - 1; i >= 0; i--) {
|
||||||
var el = frames.get(i);
|
var el = frames.get(i);
|
||||||
var name = el.function.name;
|
var name = el.function.name;
|
||||||
var loc = el.function.loc();
|
Location loc = null;
|
||||||
|
|
||||||
|
for (var j = el.codePtr; j >= 0 && loc == null; j--) loc = el.function.body[j].location;
|
||||||
|
if (loc == null) loc = el.function.loc();
|
||||||
|
|
||||||
var trace = "";
|
var trace = "";
|
||||||
|
|
||||||
if (loc != null) trace += "at " + loc.toString() + " ";
|
if (loc != null) trace += "at " + loc.toString() + " ";
|
||||||
@ -58,8 +62,4 @@ public class StackData {
|
|||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Debugger getDebugger(Context ctx) {
|
|
||||||
return ctx.data.get(DEBUGGER);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,4 @@ 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);
|
||||||
|
|
||||||
void connect();
|
|
||||||
void disconnect();
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package me.topchetoeu.jscript.engine.debug;
|
package me.topchetoeu.jscript.engine.debug;
|
||||||
|
|
||||||
public interface Debugger extends DebugHandler, DebugController {
|
public interface Debugger extends DebugHandler, DebugController {
|
||||||
|
void connect();
|
||||||
|
void disconnect();
|
||||||
}
|
}
|
||||||
|
@ -31,12 +31,6 @@ import me.topchetoeu.jscript.json.JSON;
|
|||||||
import me.topchetoeu.jscript.json.JSONElement;
|
import me.topchetoeu.jscript.json.JSONElement;
|
||||||
import me.topchetoeu.jscript.json.JSONList;
|
import me.topchetoeu.jscript.json.JSONList;
|
||||||
import me.topchetoeu.jscript.json.JSONMap;
|
import me.topchetoeu.jscript.json.JSONMap;
|
||||||
import me.topchetoeu.jscript.lib.DateLib;
|
|
||||||
import me.topchetoeu.jscript.lib.MapLib;
|
|
||||||
import me.topchetoeu.jscript.lib.PromiseLib;
|
|
||||||
import me.topchetoeu.jscript.lib.RegExpLib;
|
|
||||||
import me.topchetoeu.jscript.lib.SetLib;
|
|
||||||
import me.topchetoeu.jscript.lib.GeneratorLib.Generator;
|
|
||||||
|
|
||||||
public class SimpleDebugger implements Debugger {
|
public class SimpleDebugger implements Debugger {
|
||||||
public static final String CHROME_GET_PROP_FUNC = "function s(e){let t=this;const n=JSON.parse(e);for(let e=0,i=n.length;e<i;++e)t=t[n[e]];return t}";
|
public static final String CHROME_GET_PROP_FUNC = "function s(e){let t=this;const n=JSON.parse(e);for(let e=0,i=n.length;e<i;++e)t=t[n[e]];return t}";
|
||||||
@ -403,7 +397,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private RunResult run(Frame codeFrame, String code) {
|
private RunResult run(Frame codeFrame, String code) {
|
||||||
var engine = new Engine();
|
var engine = new Engine(false);
|
||||||
var env = codeFrame.func.environment.fork();
|
var env = codeFrame.func.environment.fork();
|
||||||
|
|
||||||
ObjectValue global = env.global.obj,
|
ObjectValue global = env.global.obj,
|
||||||
@ -415,7 +409,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
env.global = new GlobalScope(local);
|
env.global = new GlobalScope(local);
|
||||||
|
|
||||||
var ctx = new Context(engine).pushEnv(env);
|
var ctx = new Context(engine).pushEnv(env);
|
||||||
var awaiter = engine.pushMsg(false, ctx, new Filename("temp", "exec"), "(" + code + ")", codeFrame.frame.thisArg, codeFrame.frame.args);
|
var awaiter = engine.pushMsg(false, ctx, new Filename("jscript", "eval"), code, codeFrame.frame.thisArg, codeFrame.frame.args);
|
||||||
|
|
||||||
engine.run(true);
|
engine.run(true);
|
||||||
|
|
||||||
@ -594,57 +588,46 @@ public class SimpleDebugger implements Debugger {
|
|||||||
}
|
}
|
||||||
@Override public void getProperties(V8Message msg) {
|
@Override public void getProperties(V8Message msg) {
|
||||||
var obj = idToObject.get(Integer.parseInt(msg.params.string("objectId")));
|
var obj = idToObject.get(Integer.parseInt(msg.params.string("objectId")));
|
||||||
var own = msg.params.bool("ownProperties");
|
|
||||||
var accessorPropertiesOnly = msg.params.bool("accessorPropertiesOnly", false);
|
|
||||||
var currOwn = true;
|
|
||||||
|
|
||||||
var res = new JSONList();
|
var res = new JSONList();
|
||||||
|
var ctx = objectToCtx.get(obj);
|
||||||
|
|
||||||
while (obj != emptyObject && obj != null) {
|
for (var key : obj.keys(true)) {
|
||||||
var ctx = objectToCtx.get(obj);
|
var propDesc = new JSONMap();
|
||||||
|
|
||||||
for (var key : obj.keys(true)) {
|
if (obj.properties.containsKey(key)) {
|
||||||
var propDesc = new JSONMap();
|
var prop = obj.properties.get(key);
|
||||||
|
|
||||||
if (obj.properties.containsKey(key)) {
|
propDesc.set("name", Values.toString(ctx, key));
|
||||||
var prop = obj.properties.get(key);
|
if (prop.getter != null) propDesc.set("get", serializeObj(ctx, prop.getter));
|
||||||
|
if (prop.setter != null) propDesc.set("set", serializeObj(ctx, prop.setter));
|
||||||
propDesc.set("name", Values.toString(ctx, key));
|
propDesc.set("enumerable", obj.memberEnumerable(key));
|
||||||
if (prop.getter != null) propDesc.set("get", serializeObj(ctx, prop.getter));
|
propDesc.set("configurable", obj.memberConfigurable(key));
|
||||||
if (prop.setter != null) propDesc.set("set", serializeObj(ctx, prop.setter));
|
propDesc.set("isOwn", true);
|
||||||
propDesc.set("enumerable", obj.memberEnumerable(key));
|
res.add(propDesc);
|
||||||
propDesc.set("configurable", obj.memberConfigurable(key));
|
|
||||||
propDesc.set("isOwn", currOwn);
|
|
||||||
res.add(propDesc);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
propDesc.set("name", Values.toString(ctx, key));
|
|
||||||
propDesc.set("value", serializeObj(ctx, obj.getMember(ctx, key)));
|
|
||||||
propDesc.set("writable", obj.memberWritable(key));
|
|
||||||
propDesc.set("enumerable", obj.memberEnumerable(key));
|
|
||||||
propDesc.set("configurable", obj.memberConfigurable(key));
|
|
||||||
propDesc.set("isOwn", currOwn);
|
|
||||||
res.add(propDesc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
obj = obj.getPrototype(ctx);
|
propDesc.set("name", Values.toString(ctx, key));
|
||||||
|
propDesc.set("value", serializeObj(ctx, obj.getMember(ctx, key)));
|
||||||
if (currOwn) {
|
propDesc.set("writable", obj.memberWritable(key));
|
||||||
var protoDesc = new JSONMap();
|
propDesc.set("enumerable", obj.memberEnumerable(key));
|
||||||
protoDesc.set("name", "__proto__");
|
propDesc.set("configurable", obj.memberConfigurable(key));
|
||||||
protoDesc.set("value", serializeObj(ctx, obj == null ? Values.NULL : obj));
|
propDesc.set("isOwn", true);
|
||||||
protoDesc.set("writable", true);
|
res.add(propDesc);
|
||||||
protoDesc.set("enumerable", false);
|
|
||||||
protoDesc.set("configurable", false);
|
|
||||||
protoDesc.set("isOwn", currOwn);
|
|
||||||
res.add(protoDesc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
currOwn = false;
|
|
||||||
if (true) break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var proto = obj.getPrototype(ctx);
|
||||||
|
|
||||||
|
var protoDesc = new JSONMap();
|
||||||
|
protoDesc.set("name", "__proto__");
|
||||||
|
protoDesc.set("value", serializeObj(ctx, proto == null ? Values.NULL : proto));
|
||||||
|
protoDesc.set("writable", true);
|
||||||
|
protoDesc.set("enumerable", false);
|
||||||
|
protoDesc.set("configurable", false);
|
||||||
|
protoDesc.set("isOwn", true);
|
||||||
|
res.add(protoDesc);
|
||||||
|
|
||||||
ws.send(msg.respond(new JSONMap().set("result", res)));
|
ws.send(msg.respond(new JSONMap().set("result", res)));
|
||||||
}
|
}
|
||||||
@Override public void callFunctionOn(V8Message msg) {
|
@Override public void callFunctionOn(V8Message msg) {
|
||||||
@ -667,36 +650,40 @@ public class SimpleDebugger implements Debugger {
|
|||||||
else src = src.substring(0, start) + src.substring(end + 1);
|
else src = src.substring(0, start) + src.substring(end + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (src) {
|
try {
|
||||||
case CHROME_GET_PROP_FUNC: {
|
switch (src) {
|
||||||
var path = JSON.parse(new Filename("tmp", "json"), (String)args.get(0)).list();
|
case CHROME_GET_PROP_FUNC: {
|
||||||
Object res = thisArg;
|
var path = JSON.parse(null, (String)args.get(0)).list();
|
||||||
for (var el : path) res = Values.getMember(ctx, res, JSON.toJs(el));
|
Object res = thisArg;
|
||||||
ws.send(msg.respond(new JSONMap().set("result", serializeObj(ctx, res))));
|
for (var el : path) res = Values.getMember(ctx, res, JSON.toJs(el));
|
||||||
return;
|
ws.send(msg.respond(new JSONMap().set("result", serializeObj(ctx, res))));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case VSCODE_STRINGIFY_VAL:
|
||||||
|
case VSCODE_STRINGIFY_PROPS:
|
||||||
|
case VSCODE_SHALLOW_COPY:
|
||||||
|
ws.send(msg.respond(new JSONMap().set("result", serializeObj(ctx, emptyObject))));
|
||||||
|
break;
|
||||||
|
case VSCODE_FLATTEN_ARRAY: {
|
||||||
|
ws.send(msg.respond(new JSONMap().set("result", serializeObj(ctx, thisArg))));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VSCODE_SYMBOL_REQUEST:
|
||||||
|
ws.send(msg.respond(new JSONMap().set("result", serializeObj(ctx, new ArrayValue(ctx)))));
|
||||||
|
break;
|
||||||
|
case VSCODE_CALL: {
|
||||||
|
var func = (FunctionValue)(args.size() < 1 ? null : args.get(0));
|
||||||
|
ws.send(msg.respond(new JSONMap().set("result", serializeObj(ctx, func.call(ctx, thisArg)))));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
var res = ctx.compile(new Filename("jscript", "eval"), src).call(ctx);
|
||||||
|
if (res instanceof FunctionValue) ((FunctionValue)res).call(ctx, thisArg, args);
|
||||||
|
ws.send(msg.respond(new JSONMap().set("result", serializeObj(ctx, res))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case VSCODE_STRINGIFY_VAL:
|
|
||||||
case VSCODE_STRINGIFY_PROPS:
|
|
||||||
case VSCODE_SHALLOW_COPY:
|
|
||||||
ws.send(msg.respond(new JSONMap().set("result", serializeObj(ctx, emptyObject))));
|
|
||||||
break;
|
|
||||||
case VSCODE_FLATTEN_ARRAY: {
|
|
||||||
ws.send(msg.respond(new JSONMap().set("result", serializeObj(ctx, thisArg))));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case VSCODE_SYMBOL_REQUEST:
|
|
||||||
ws.send(msg.respond(new JSONMap().set("result", serializeObj(ctx, new ArrayValue(ctx)))));
|
|
||||||
break;
|
|
||||||
case VSCODE_CALL: {
|
|
||||||
var func = (FunctionValue)(args.size() < 1 ? null : args.get(0));
|
|
||||||
try { ws.send(msg.respond(new JSONMap().set("result", serializeObj(ctx, func.call(ctx, thisArg))))); }
|
|
||||||
catch (EngineException e) { ws.send(msg.respond(new JSONMap().set("exceptionDetails", serializeException(ctx, e)))); }
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
ws.send(new V8Error("A non well-known function was used with callFunctionOn."));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
catch (EngineException e) { ws.send(msg.respond(new JSONMap().set("exceptionDetails", serializeException(ctx, e)))); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -708,8 +695,8 @@ public class SimpleDebugger implements Debugger {
|
|||||||
int id = nextId();
|
int id = nextId();
|
||||||
var src = new Source(id, filename, source, locations);
|
var src = new Source(id, filename, source, locations);
|
||||||
|
|
||||||
filenameToId.put(filename, id);
|
|
||||||
idToSource.put(id, src);
|
idToSource.put(id, src);
|
||||||
|
filenameToId.put(filename, id);
|
||||||
|
|
||||||
for (var bpcd : idToBptCand.values()) {
|
for (var bpcd : idToBptCand.values()) {
|
||||||
if (!bpcd.pattern.matcher(filename.toString()).matches()) continue;
|
if (!bpcd.pattern.matcher(filename.toString()).matches()) continue;
|
||||||
@ -801,27 +788,18 @@ public class SimpleDebugger implements Debugger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override public void connect() {
|
@Override public void connect() {
|
||||||
target.data.set(StackData.DEBUGGER, this);
|
if (!target.attachDebugger(this)) {
|
||||||
|
ws.send(new V8Error("A debugger is already attached to this engine."));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@Override public void disconnect() {
|
@Override public void disconnect() {
|
||||||
target.data.remove(StackData.DEBUGGER);
|
target.detachDebugger();
|
||||||
enabled = false;
|
enabled = false;
|
||||||
updateNotifier.next();
|
updateNotifier.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
private SimpleDebugger(WebSocket ws, Engine target) {
|
public SimpleDebugger(WebSocket ws, Engine target) {
|
||||||
this.ws = ws;
|
this.ws = ws;
|
||||||
this.target = target;
|
this.target = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SimpleDebugger get(WebSocket ws, Engine target) {
|
|
||||||
if (target.data.has(StackData.DEBUGGER)) {
|
|
||||||
ws.send(new V8Error("A debugger is already attached to this engine."));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var res = new SimpleDebugger(ws, target);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user