refactor: some minor fixes, rewrite README example

This commit is contained in:
TopchetoEU 2023-11-06 10:55:38 +02:00
parent f5d1287948
commit fdfa8d7713
Signed by: topchetoeu
GPG Key ID: 6531B8583E5F6ED4
7 changed files with 58 additions and 170152 deletions

View File

@ -4,31 +4,42 @@
**WARNING: Currently, this code is mostly undocumented. Proceed with caution and a psychiatrist.** **WARNING: Currently, this code is mostly undocumented. Proceed with caution and a psychiatrist.**
JScript is an engine, capable of running EcmaScript 5, written entirely in Java. This engine has been developed with the goal of being easy to integrate with your preexisting codebase, **THE GOAL OF THIS ENGINE IS NOT PERFORMANCE**. My crude experiments show that this engine is 50x-100x slower than V8, which, although bad, is acceptable for most simple scripting purposes. JScript is an engine, capable of running EcmaScript 5, written entirely in Java. This engine has been developed with the goal of being easy to integrate with your preexisting codebase, **THE GOAL OF THIS ENGINE IS NOT PERFORMANCE**. My crude experiments show that this engine is 50x-100x slower than V8, which, although bad, is acceptable for most simple scripting purposes. Note that although the codebase has a Main class, this isn't meant to be a standalone program, but instead a library for running JavaScript code.
## Example ## Example
The following will create a REPL using the engine as a backend. Not that this won't properly log errors. I recommend checking out the implementation in `Main.main`: The following will create a REPL using the engine as a backend. Not that this won't properly log errors. I recommend checking out the implementation in `Main.main`:
```java ```java
var engine = new PolyfillEngine(new File(".")); var engine = new Engine(true /* false if you dont want debugging */);
var in = new BufferedReader(new InputStreamReader(System.in)); var env = new Environment(null, null, null);
var debugger = new DebugServer();
// Create one target for the engine and start debugging server
debugger.targets.put("target", (socket, req) -> new SimpleDebugger(socket, engine));
debugger.start(new InetSocketAddress("127.0.0.1", 9229), true);
// Queue code to load internal libraries and start engine
engine.pushMsg(false, null, new Internals().getApplier(env));
engine.start(); engine.start();
while (true) { while (true) {
try { try {
var raw = in.readLine(); var raw = Reading.read();
if (raw == null) break;
var res = engine.pushMsg(false, engine.global(), Map.of(), "<stdio>", raw, null).await(); // Push a message to the engine with the raw REPL code
Values.printValue(engine.context(), res); var res = engine.pushMsg(
System.out.println(); false, new Context(engine).pushEnv(env),
new Filename("jscript", "repl.js"), raw, null
).await();
Values.printValue(null, res);
} }
catch (EngineException e) { catch (EngineException e) { Values.printError(e, ""); }
try { catch (SyntaxException ex) {
System.out.println("Uncaught " + e.toString(engine.context())); System.out.println("Syntax error:" + ex.msg);
}
catch (InterruptedException _e) { return; }
} }
catch (IOException | InterruptedException e) { return; } catch (IOException e) { }
} }
``` ```

View File

@ -8,12 +8,9 @@ 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.StackData;
import me.topchetoeu.jscript.engine.debug.DebugServer; import me.topchetoeu.jscript.engine.debug.DebugServer;
import me.topchetoeu.jscript.engine.debug.SimpleDebugger; import me.topchetoeu.jscript.engine.debug.SimpleDebugger;
import me.topchetoeu.jscript.engine.values.ArrayValue; import me.topchetoeu.jscript.engine.values.ArrayValue;
import me.topchetoeu.jscript.engine.values.NativeFunction;
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.events.Observer; import me.topchetoeu.jscript.events.Observer;
import me.topchetoeu.jscript.exceptions.EngineException; import me.topchetoeu.jscript.exceptions.EngineException;
@ -47,61 +44,42 @@ public class Main {
System.out.println(String.format("Running %s v%s by %s", Metadata.NAME, Metadata.VERSION, Metadata.AUTHOR)); System.out.println(String.format("Running %s v%s by %s", Metadata.NAME, Metadata.VERSION, Metadata.AUTHOR));
engine = new Engine(true); engine = new Engine(true);
env = new Environment(null, null, null);
var exited = new boolean[1]; var exited = new boolean[1];
var server = new DebugServer(); var server = new DebugServer();
server.targets.put("target", (ws, req) -> new SimpleDebugger(ws, engine)); server.targets.put("target", (ws, req) -> new SimpleDebugger(ws, engine));
env = Internals.apply(new Environment(null, null, null));
env.global.define("exit", _ctx -> {
exited[0] = true;
throw new InterruptException();
});
env.global.define("go", _ctx -> {
try {
var f = Path.of("do.js");
var func = _ctx.compile(new Filename("do", "do/" + j++ + ".js"), new String(Files.readAllBytes(f)));
return func.call(_ctx);
}
catch (IOException e) {
throw new EngineException("Couldn't open do.js");
}
});
engineTask = engine.start(); engineTask = engine.start();
debugTask = server.start(new InetSocketAddress("127.0.0.1", 9229), true); debugTask = server.start(new InetSocketAddress("127.0.0.1", 9229), true);
engine.pushMsg(false, null, new NativeFunction((ctx, thisArg, _a) -> {
new Internals().apply(env);
env.global.define("exit", _ctx -> {
exited[0] = true;
throw new InterruptException();
});
env.global.define("go", _ctx -> {
try {
var f = Path.of("do.js");
var func = _ctx.compile(new Filename("do", "do/" + j++ + ".js"), new String(Files.readAllBytes(f)));
return func.call(_ctx);
}
catch (IOException e) {
throw new EngineException("Couldn't open do.js");
}
});
// TODO: make better API
env.global.define(true, new NativeFunction("include", (_ctx, th, __args) -> {
try {
var currFilename = StackData.peekFrame(_ctx).function.loc().filename();
var loc = Path.of("").toAbsolutePath();
if (currFilename.protocol.equals("file")) loc = Path.of(currFilename.path).getParent();
var path = loc.resolve(Path.of(__args.length >= 1 ? Values.toString(_ctx, __args[0]) : ""));
var src = Files.readString(path);
var func = _ctx.compile(Filename.fromFile(path.toFile()), src);
var callArgs = new ArrayValue();
if (__args.length >= 2 && __args[1] instanceof ArrayValue) callArgs = (ArrayValue)__args[1];
return func.call(_ctx, null, callArgs);
}
catch (IOException e) { throw EngineException.ofError("IOError", "Couldn't open file."); }
}));
return null;
}), null).await();
try { try {
var tsEnv = env.child(); var tsEnv = Internals.apply(new Environment(null, null, null));
tsEnv.global.define(null, "module", false, new ObjectValue()); var bsEnv = Internals.apply(new Environment(null, null, null));
engine.pushMsg( engine.pushMsg(
false, new Context(engine).pushEnv(tsEnv), false, new Context(engine, tsEnv),
new Filename("jscript", "ts.js"), new Filename("jscript", "ts.js"),
Reading.resourceToString("js/ts.js"), null Reading.resourceToString("js/ts.js"), null
).await(); ).await();
System.out.println("Loaded typescript!"); System.out.println("Loaded typescript!");
var ctx = new Context(engine).pushEnv(env.child()); var ctx = new Context(engine, bsEnv);
engine.pushMsg( engine.pushMsg(
false, ctx, false, ctx,

View File

@ -24,9 +24,7 @@ public class CompoundStatement extends Statement {
public void compile(CompileTarget target, ScopeRecord scope, boolean pollute) { public void compile(CompileTarget target, ScopeRecord scope, boolean pollute) {
for (var stm : statements) { for (var stm : statements) {
if (stm instanceof FunctionStatement) { if (stm instanceof FunctionStatement) {
int start = target.size();
((FunctionStatement)stm).compile(target, scope, null, true); ((FunctionStatement)stm).compile(target, scope, null, true);
target.setDebug(start);
target.add(Instruction.discard()); target.add(Instruction.discard());
} }
} }

View File

@ -54,6 +54,11 @@ public class Context {
this.engine = engine; this.engine = engine;
} }
public Context(Engine engine) { public Context(Engine engine) {
this(engine, null); this(engine, (Data)null);
}
public Context(Engine engine, Environment env) {
this(engine, (Data)null);
this.pushEnv(env);
} }
} }

View File

@ -112,7 +112,6 @@ public class SimpleDebugger implements Debugger {
this.frame = frame; this.frame = frame;
this.func = frame.function; this.func = frame.function;
this.id = id; this.id = id;
this.local = new ObjectValue();
this.location = frame.function.loc(); this.location = frame.function.loc();
this.global = frame.function.environment.global.obj; this.global = frame.function.environment.global.obj;

File diff suppressed because one or more lines are too long

View File

@ -113,7 +113,7 @@ public class Internals {
return Double.POSITIVE_INFINITY; return Double.POSITIVE_INFINITY;
} }
public void apply(Environment env) { public static Environment apply(Environment env) {
var wp = env.wrappers; var wp = env.wrappers;
var glob = env.global = new GlobalScope(wp.getNamespace(Internals.class)); var glob = env.global = new GlobalScope(wp.getNamespace(Internals.class));
@ -157,6 +157,6 @@ public class Internals {
wp.getProto(ObjectLib.class).setPrototype(null, null); wp.getProto(ObjectLib.class).setPrototype(null, null);
env.regexConstructor = wp.getConstr(RegExpLib.class); env.regexConstructor = wp.getConstr(RegExpLib.class);
System.out.println("Loaded polyfills!"); return env;
} }
} }