Compare commits

..

41 Commits

Author SHA1 Message Date
71b40240c0 feat: add Number.toFixed 2024-04-03 15:09:01 +03:00
a8775d212f fix: clean up extensions at some points 2024-04-03 14:52:29 +03:00
71872a8d64 fix 2024-04-03 14:25:14 +03:00
c707f880f7 fix: use Extensions instead of Environment 2024-04-03 14:21:23 +03:00
0d629a6e82 fix: use correct class instead of proxy 2024-04-03 12:27:15 +03:00
6eea342d04 fix: fuck 2024-04-02 18:24:43 +03:00
ece9cf68dc fix: correctly update proto chain 2024-04-02 18:19:05 +03:00
11ecd8c68f fix: exec debugger close logic on application exit 2024-04-02 18:05:49 +03:00
48bd304c6e fix: environment forks fixes 2024-04-02 18:05:20 +03:00
d8e46c3149 fix: clone environment correctly 2024-03-31 16:11:32 +03:00
5fc5eb08f8 fix: update breakpoints when removing bp 2024-03-30 12:52:44 +02:00
8acbc003c4 fix: properly resolve breakpoints 2024-03-30 12:13:04 +02:00
fda33112a7 fix: load maps when attaching debugger 2024-03-30 11:13:45 +02:00
67b2413d7c bump2 2024-03-30 10:36:55 +02:00
3a05416510 bump 2024-03-30 10:30:26 +02:00
c291328cc3 fix: detach debugger after close 2024-03-30 10:22:12 +02:00
7cb267b0d9 fix: some issues with debugger 2024-03-30 09:55:20 +02:00
4e31766665 fix: add new vscode debugger functions 2024-03-29 21:53:15 +02:00
b5b63c4342 fix: make global cache of native wrappers 2024-03-28 16:08:07 +02:00
18f70a0d58 fix: i hate wrappers 2024-03-28 15:10:21 +02:00
d38b600366 fix: some more wrapper issues 2024-03-28 14:52:49 +02:00
0ac7af2ea3 fix: take into account empty classes 2024-03-28 14:21:23 +02:00
5185c93663 fix: don't include non-exposing wrappers in proto chain
feat: allow adding custom wrappers
2024-03-28 00:57:09 +02:00
510422cab7 feat: implement logic for exposing non-static fields 2024-03-27 23:39:33 +02:00
79e1d1cfaf Merge branch 'master' of https://github.com/TopchetoEU/java-jscript 2024-03-27 23:08:25 +02:00
e0f3274a95 feat: add simple for-of loop (not intended for production usage) 2024-03-27 23:08:21 +02:00
ef5d29105f Update README.md 2024-03-10 02:17:18 +02:00
d8ea6557df fix: buildline expects tag to start with 'v' 2024-03-09 00:45:00 +02:00
5ba858545a fix: defer handles of async functions 2024-03-09 00:28:30 +02:00
446ecd8f2b fix: promise defers callback twice 2024-03-08 17:23:50 +02:00
fbf103439a bump 2024-03-08 16:55:46 +02:00
b30f94de8f refactor: move function pushMsg signatures in EventLoop 2024-03-08 16:53:47 +02:00
47b4dd3c15 refactor: rename code to runtime 2024-03-06 23:23:01 +02:00
0fb336373a fix: make fs calls synchronized 2024-03-06 12:50:57 +02:00
b33325a98d fix: clear buffer of line writer file 2024-03-05 17:10:06 +02:00
ccf75d6066 fix: don't use Context.NULL in global scope 2024-03-05 16:51:50 +02:00
662dcc1ac1 bump 2024-03-05 16:30:13 +02:00
3e6214659b fix: use new global API 2024-03-05 15:54:51 +02:00
7c6622c53d fix: separate scope records from scopes 2024-03-05 15:45:02 +02:00
70d5871091 fix: properly check permissions 2024-03-03 20:47:54 +02:00
7b9bbe576b feat: add std streams as global variables 2024-03-03 20:31:20 +02:00
101 changed files with 1649 additions and 1264 deletions

View File

@@ -3,7 +3,7 @@ name: "tagged-release"
on: on:
push: push:
tags: tags:
- "v*" - "*"
jobs: jobs:
tagged-release: tagged-release:

View File

@@ -23,7 +23,3 @@ engine.run(true);
// Get our result // Get our result
System.out.println(awaitable.await()); System.out.println(awaitable.await());
``` ```
## NOTE:
To setup the typescript bundle in your sources, run `node build.js init-ts`. This will download the latest version of typescript, minify it, and add it to your src folder. If you are going to work with the `node build.js debug|release` command, this is not a necessary step.

View File

@@ -1,4 +1,4 @@
project_group = me.topchetoeu project_group = me.topchetoeu
project_name = jscript project_name = jscript
project_version = 0.8.6-beta project_version = 0.9.27-beta
main_class = me.topchetoeu.jscript.utils.JScriptRepl main_class = me.topchetoeu.jscript.utils.JScriptRepl

View File

@@ -24,6 +24,11 @@ public class Buffer {
return n; return n;
} }
public void clear() {
data = new byte[128];
length = 0;
}
public void append(byte b) { public void append(byte b) {
write(length, new byte[] { b }); write(length, new byte[] { b });
} }

View File

@@ -5,7 +5,7 @@ import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import me.topchetoeu.jscript.core.exceptions.SyntaxException; import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
public class Instruction { public class Instruction {
public static enum Type { public static enum Type {

View File

@@ -1,6 +1,6 @@
package me.topchetoeu.jscript.common.events; package me.topchetoeu.jscript.common.events;
import me.topchetoeu.jscript.core.exceptions.InterruptException; import me.topchetoeu.jscript.runtime.exceptions.InterruptException;
public class Notifier { public class Notifier {
private boolean ok = false; private boolean ok = false;

View File

@@ -9,12 +9,12 @@ import me.topchetoeu.jscript.compilation.parsing.Operator;
import me.topchetoeu.jscript.compilation.parsing.ParseRes; import me.topchetoeu.jscript.compilation.parsing.ParseRes;
import me.topchetoeu.jscript.compilation.parsing.Parsing; import me.topchetoeu.jscript.compilation.parsing.Parsing;
import me.topchetoeu.jscript.compilation.parsing.Token; import me.topchetoeu.jscript.compilation.parsing.Token;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Extensions;
import me.topchetoeu.jscript.core.values.ArrayValue; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.core.exceptions.SyntaxException; import me.topchetoeu.jscript.runtime.values.Values;
public class JSON { public class JSON {
public static Object toJs(JSONElement val) { public static Object toJs(JSONElement val) {
@@ -32,7 +32,7 @@ public class JSON {
if (val.isNull()) return Values.NULL; if (val.isNull()) return Values.NULL;
return null; return null;
} }
private static JSONElement fromJs(Context ctx, Object val, HashSet<Object> prev) { private static JSONElement fromJs(Extensions ext, Object val, HashSet<Object> prev) {
if (val instanceof Boolean) return JSONElement.bool((boolean)val); if (val instanceof Boolean) return JSONElement.bool((boolean)val);
if (val instanceof Number) return JSONElement.number(((Number)val).doubleValue()); if (val instanceof Number) return JSONElement.number(((Number)val).doubleValue());
if (val instanceof String) return JSONElement.string((String)val); if (val instanceof String) return JSONElement.string((String)val);
@@ -44,7 +44,7 @@ public class JSON {
var res = new JSONList(); var res = new JSONList();
for (var el : ((ArrayValue)val).toArray()) { for (var el : ((ArrayValue)val).toArray()) {
var jsonEl = fromJs(ctx, el, prev); var jsonEl = fromJs(ext, el, prev);
if (jsonEl == null) jsonEl = JSONElement.NULL; if (jsonEl == null) jsonEl = JSONElement.NULL;
res.add(jsonEl); res.add(jsonEl);
} }
@@ -58,8 +58,8 @@ public class JSON {
var res = new JSONMap(); var res = new JSONMap();
for (var el : Values.getMembers(ctx, val, false, false)) { for (var el : Values.getMembers(ext, val, false, false)) {
var jsonEl = fromJs(ctx, Values.getMember(ctx, val, el), prev); var jsonEl = fromJs(ext, Values.getMember(ext, val, el), prev);
if (jsonEl == null) continue; if (jsonEl == null) continue;
if (el instanceof String || el instanceof Number) res.put(el.toString(), jsonEl); if (el instanceof String || el instanceof Number) res.put(el.toString(), jsonEl);
} }
@@ -70,8 +70,8 @@ public class JSON {
if (val == null) return null; if (val == null) return null;
return null; return null;
} }
public static JSONElement fromJs(Context ctx, Object val) { public static JSONElement fromJs(Extensions ext, Object val) {
return fromJs(ctx, val, new HashSet<>()); return fromJs(ext, val, new HashSet<>());
} }
public static ParseRes<String> parseIdentifier(List<Token> tokens, int i) { public static ParseRes<String> parseIdentifier(List<Token> tokens, int i) {

View File

@@ -14,7 +14,7 @@ import java.util.stream.Collectors;
import me.topchetoeu.jscript.common.Filename; import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.common.Location; import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Instruction.BreakpointType; import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.core.scope.LocalScopeRecord; import me.topchetoeu.jscript.compilation.scope.LocalScopeRecord;
import me.topchetoeu.jscript.utils.mapping.SourceMap; import me.topchetoeu.jscript.utils.mapping.SourceMap;
public class FunctionMap { public class FunctionMap {
@@ -104,7 +104,9 @@ public class FunctionMap {
var res = new ArrayList<Location>(candidates.size()); var res = new ArrayList<Location>(candidates.size());
for (var candidate : candidates.entrySet()) { for (var candidate : candidates.entrySet()) {
res.add(candidate.getValue().ceiling(new Location(line, column, candidate.getKey()))); var val = correctBreakpoint(new Location(line, column, candidate.getKey()));
if (val == null) continue;
res.add(val);
} }
return res; return res;

View File

@@ -10,7 +10,7 @@ import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Instruction.BreakpointType; import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.common.mapping.FunctionMap; import me.topchetoeu.jscript.common.mapping.FunctionMap;
import me.topchetoeu.jscript.common.mapping.FunctionMap.FunctionMapBuilder; import me.topchetoeu.jscript.common.mapping.FunctionMap.FunctionMapBuilder;
import me.topchetoeu.jscript.core.scope.LocalScopeRecord; import me.topchetoeu.jscript.compilation.scope.LocalScopeRecord;
public class CompileResult { public class CompileResult {
public final Vector<Instruction> instructions = new Vector<>(); public final Vector<Instruction> instructions = new Vector<>();

View File

@@ -1,7 +1,7 @@
package me.topchetoeu.jscript.compilation; package me.topchetoeu.jscript.compilation;
import me.topchetoeu.jscript.common.Instruction; import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.core.exceptions.SyntaxException; import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
public class ThrowSyntaxStatement extends Statement { public class ThrowSyntaxStatement extends Statement {
public final String name; public final String name;

View File

@@ -0,0 +1,73 @@
package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class ForOfStatement extends Statement {
public final String varName;
public final boolean isDeclaration;
public final Statement iterable, body;
public final String label;
public final Location varLocation;
@Override
public void declare(CompileResult target) {
body.declare(target);
if (isDeclaration) target.scope.define(varName);
}
@Override
public void compile(CompileResult target, boolean pollute) {
var key = target.scope.getKey(varName);
if (key instanceof String) target.add(Instruction.makeVar((String)key));
iterable.compile(target, true, BreakpointType.STEP_OVER);
target.add(Instruction.dup());
target.add(Instruction.loadVar("Symbol"));
target.add(Instruction.pushValue("iterator"));
target.add(Instruction.loadMember()).setLocation(iterable.loc());
target.add(Instruction.loadMember()).setLocation(iterable.loc());
target.add(Instruction.call(0)).setLocation(iterable.loc());
int start = target.size();
target.add(Instruction.dup());
target.add(Instruction.dup());
target.add(Instruction.pushValue("next"));
target.add(Instruction.loadMember()).setLocation(iterable.loc());
target.add(Instruction.call(0)).setLocation(iterable.loc());
target.add(Instruction.dup());
target.add(Instruction.pushValue("done"));
target.add(Instruction.loadMember()).setLocation(iterable.loc());
int mid = target.temp();
target.add(Instruction.pushValue("value"));
target.add(Instruction.loadMember()).setLocation(varLocation);
target.add(Instruction.storeVar(key)).setLocationAndDebug(iterable.loc(), BreakpointType.STEP_OVER);
body.compile(target, false, BreakpointType.STEP_OVER);
int end = target.size();
WhileStatement.replaceBreaks(target, label, mid + 1, end, start, end + 1);
target.add(Instruction.jmp(start - end));
target.add(Instruction.discard());
target.add(Instruction.discard());
target.set(mid, Instruction.jmpIf(end - mid + 1));
if (pollute) target.add(Instruction.pushUndefined());
}
public ForOfStatement(Location loc, Location varLocation, String label, boolean isDecl, String varName, Statement object, Statement body) {
super(loc);
this.varLocation = varLocation;
this.label = label;
this.isDeclaration = isDecl;
this.varName = varName;
this.iterable = object;
this.body = body;
}
}

View File

@@ -16,9 +16,9 @@ import me.topchetoeu.jscript.compilation.VariableDeclareStatement.Pair;
import me.topchetoeu.jscript.compilation.control.*; import me.topchetoeu.jscript.compilation.control.*;
import me.topchetoeu.jscript.compilation.control.SwitchStatement.SwitchCase; import me.topchetoeu.jscript.compilation.control.SwitchStatement.SwitchCase;
import me.topchetoeu.jscript.compilation.parsing.ParseRes.State; import me.topchetoeu.jscript.compilation.parsing.ParseRes.State;
import me.topchetoeu.jscript.compilation.scope.LocalScopeRecord;
import me.topchetoeu.jscript.compilation.values.*; import me.topchetoeu.jscript.compilation.values.*;
import me.topchetoeu.jscript.core.scope.LocalScopeRecord; import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
import me.topchetoeu.jscript.core.exceptions.SyntaxException;
// TODO: this has to be rewritten // TODO: this has to be rewritten
public class Parsing { public class Parsing {
@@ -1777,6 +1777,46 @@ public class Parsing {
return ParseRes.res(new ForInStatement(loc, nameLoc, labelRes.result, isDecl, nameRes.result, varVal, objRes.result, bodyRes.result), n); return ParseRes.res(new ForInStatement(loc, nameLoc, labelRes.result, isDecl, nameRes.result, varVal, objRes.result, bodyRes.result), n);
} }
public static ParseRes<ForOfStatement> parseForOf(Filename filename, List<Token> tokens, int i) {
var loc = getLoc(filename, tokens, i);
int n = 0;
var labelRes = parseLabel(tokens, i + n);
var isDecl = false;
n += labelRes.n;
if (!isIdentifier(tokens, i + n++, "for")) return ParseRes.failed();
if (!isOperator(tokens, i + n++, Operator.PAREN_OPEN)) return ParseRes.error(loc, "Expected a open paren after 'for'.");
if (isIdentifier(tokens, i + n, "var")) {
isDecl = true;
n++;
}
var nameRes = parseIdentifier(tokens, i + n);
if (!nameRes.isSuccess()) return ParseRes.error(loc, "Expected a variable name for 'for' loop.");
var nameLoc = getLoc(filename, tokens, i + n);
n += nameRes.n;
if (!isIdentifier(tokens, i + n++, "of")) {
if (nameRes.result.equals("const")) return ParseRes.error(loc, "'const' declarations are not supported.");
else if (nameRes.result.equals("let")) return ParseRes.error(loc, "'let' declarations are not supported.");
else return ParseRes.error(loc, "Expected 'of' keyword after variable declaration.");
}
var objRes = parseValue(filename, tokens, i + n, 0);
if (!objRes.isSuccess()) return ParseRes.error(loc, "Expected a value.", objRes);
n += objRes.n;
if (!isOperator(tokens, i + n++, Operator.PAREN_CLOSE)) return ParseRes.error(loc, "Expected a closing paren after for.");
var bodyRes = parseStatement(filename, tokens, i + n);
if (!bodyRes.isSuccess()) return ParseRes.error(loc, "Expected a for body.", bodyRes);
n += bodyRes.n;
return ParseRes.res(new ForOfStatement(loc, nameLoc, labelRes.result, isDecl, nameRes.result, objRes.result, bodyRes.result), n);
}
public static ParseRes<TryStatement> parseCatch(Filename filename, List<Token> tokens, int i) { public static ParseRes<TryStatement> parseCatch(Filename filename, List<Token> tokens, int i) {
var loc = getLoc(filename, tokens, i); var loc = getLoc(filename, tokens, i);
int n = 0; int n = 0;
@@ -1833,6 +1873,7 @@ public class Parsing {
parseSwitch(filename, tokens, i), parseSwitch(filename, tokens, i),
parseFor(filename, tokens, i), parseFor(filename, tokens, i),
parseForIn(filename, tokens, i), parseForIn(filename, tokens, i),
parseForOf(filename, tokens, i),
parseDoWhile(filename, tokens, i), parseDoWhile(filename, tokens, i),
parseCatch(filename, tokens, i), parseCatch(filename, tokens, i),
parseCompound(filename, tokens, i), parseCompound(filename, tokens, i),

View File

@@ -1,9 +1,7 @@
package me.topchetoeu.jscript.core.scope; package me.topchetoeu.jscript.compilation.scope;
import java.util.ArrayList; import java.util.ArrayList;
import me.topchetoeu.jscript.common.ScopeRecord;
public class LocalScopeRecord implements ScopeRecord { public class LocalScopeRecord implements ScopeRecord {
public final LocalScopeRecord parent; public final LocalScopeRecord parent;

View File

@@ -1,6 +1,4 @@
package me.topchetoeu.jscript.common; package me.topchetoeu.jscript.compilation.scope;
import me.topchetoeu.jscript.core.scope.LocalScopeRecord;
public interface ScopeRecord { public interface ScopeRecord {
public Object getKey(String name); public Object getKey(String name);

View File

@@ -7,7 +7,7 @@ import me.topchetoeu.jscript.common.Instruction.Type;
import me.topchetoeu.jscript.compilation.CompileResult; import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.CompoundStatement; import me.topchetoeu.jscript.compilation.CompoundStatement;
import me.topchetoeu.jscript.compilation.Statement; import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.core.exceptions.SyntaxException; import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
public class FunctionStatement extends Statement { public class FunctionStatement extends Statement {
public final CompoundStatement body; public final CompoundStatement body;

View File

@@ -1,109 +0,0 @@
package me.topchetoeu.jscript.core;
import java.util.Iterator;
import java.util.List;
import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.core.debug.DebugContext;
import me.topchetoeu.jscript.core.values.CodeFunction;
import me.topchetoeu.jscript.core.values.FunctionValue;
import me.topchetoeu.jscript.core.exceptions.EngineException;
import me.topchetoeu.jscript.core.scope.ValueVariable;
public class Context implements Extensions {
public static final Context NULL = new Context();
public final Context parent;
public final Environment environment;
public final Frame frame;
// public final Engine engine;
public final int stackSize;
@Override public <T> void add(Key<T> key, T obj) {
if (environment != null) environment.add(key, obj);
// else if (engine != null) engine.add(key, obj);
}
@Override public <T> T get(Key<T> key) {
if (environment != null && environment.has(key)) return environment.get(key);
// else if (engine != null && engine.has(key)) return engine.get(key);
return null;
}
@Override public boolean has(Key<?> key) {
return
environment != null && environment.has(key);
// engine != null && engine.has(key);
}
@Override public boolean remove(Key<?> key) {
var res = false;
if (environment != null) res |= environment.remove(key);
// else if (engine != null) res |= engine.remove(key);
return res;
}
@Override public Iterable<Key<?>> keys() {
if (environment == null) return List.of();
else return environment.keys();
// if (engine == null && environment == null) return List.of();
// if (engine == null) return environment.keys();
// if (environment == null) return engine.keys();
// return () -> Stream.concat(
// StreamSupport.stream(engine.keys().spliterator(), false),
// StreamSupport.stream(environment.keys().spliterator(), false)
// ).distinct().iterator();
}
public FunctionValue compile(Filename filename, String raw) {
DebugContext.get(this).onSource(filename, raw);
var result = new CodeFunction(environment, filename.toString(), Compiler.get(this).compile(filename, raw), new ValueVariable[0]);
return result;
}
public Context pushFrame(Frame frame) {
var res = new Context(this, frame.function.environment, frame, stackSize + 1);
return res;
}
public Iterable<Frame> frames() {
var self = this;
return () -> new Iterator<Frame>() {
private Context curr = self;
private void update() {
while (curr != null && curr.frame == null) curr = curr.parent;
}
@Override public boolean hasNext() {
update();
return curr != null;
}
@Override public Frame next() {
update();
var res = curr.frame;
curr = curr.parent;
return res;
}
};
}
private Context(Context parent, Environment environment, Frame frame, int stackSize) {
this.parent = parent;
this.environment = environment;
this.frame = frame;
this.stackSize = stackSize;
if (hasNotNull(Environment.MAX_STACK_COUNT) && stackSize > (int)get(Environment.MAX_STACK_COUNT)) {
throw EngineException.ofRange("Stack overflow!");
}
}
public Context() {
this(null, null, null, 0);
}
public Context(Environment env) {
this(null, env, null, 0);
}
}

View File

@@ -1,38 +0,0 @@
package me.topchetoeu.jscript.core;
public interface Extensions {
<T> T get(Key<T> key);
<T> void add(Key<T> key, T obj);
Iterable<Key<?>> keys();
boolean has(Key<?> key);
boolean remove(Key<?> key);
default void add(Key<Void> key) {
add(key, null);
}
default boolean hasNotNull(Key<?> key) {
return has(key) && get(key) != null;
}
default <T> T get(Key<T> key, T defaultVal) {
if (has(key)) return get(key);
else return defaultVal;
}
default <T> T init(Key<T> key, T val) {
if (has(key)) return get(key);
else {
add(key, val);
return val;
}
}
@SuppressWarnings("unchecked")
default void addAll(Extensions source) {
if (source == null) return;
for (var key : source.keys()) {
add((Key<Object>)key, (Object)source.get(key));
}
}
}

View File

@@ -1,5 +0,0 @@
package me.topchetoeu.jscript.core;
public class Key<T> {
}

View File

@@ -1,80 +0,0 @@
package me.topchetoeu.jscript.core.scope;
import java.util.HashSet;
import java.util.Set;
import me.topchetoeu.jscript.common.ScopeRecord;
import me.topchetoeu.jscript.core.Context;
import me.topchetoeu.jscript.core.values.FunctionValue;
import me.topchetoeu.jscript.core.values.NativeFunction;
import me.topchetoeu.jscript.core.values.ObjectValue;
import me.topchetoeu.jscript.core.values.Values;
import me.topchetoeu.jscript.core.exceptions.EngineException;
public class GlobalScope implements ScopeRecord {
public final ObjectValue obj;
public boolean has(Context ctx, String name) {
return Values.hasMember(null, obj, name, false);
}
public Object getKey(String name) {
return name;
}
public GlobalScope globalChild() {
var obj = new ObjectValue();
Values.setPrototype(null, obj, this.obj);
return new GlobalScope(obj);
}
public LocalScopeRecord child() {
return new LocalScopeRecord();
}
public Object define(String name) {
if (Values.hasMember(Context.NULL, obj, name, false)) return name;
obj.defineProperty(Context.NULL, name, null);
return name;
}
public void define(String name, Variable val) {
obj.defineProperty(Context.NULL, name,
new NativeFunction("get " + name, args -> val.get(args.ctx)),
new NativeFunction("set " + name, args -> { val.set(args.ctx, args.get(0)); return null; }),
true, true
);
}
public void define(Context ctx, String name, boolean readonly, Object val) {
obj.defineProperty(ctx, name, val, readonly, true, true);
}
public void define(String ...names) {
for (var n : names) define(n);
}
public void define(boolean readonly, FunctionValue val) {
define(null, val.name, readonly, val);
}
public Object get(Context ctx, String name) {
if (!Values.hasMember(ctx, obj, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
else return Values.getMember(ctx, obj, name);
}
public void set(Context ctx, String name, Object val) {
if (!Values.hasMember(ctx, obj, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
if (!Values.setMember(ctx, obj, name, val)) throw EngineException.ofSyntax("The global '" + name + "' is readonly.");
}
public Set<String> keys() {
var res = new HashSet<String>();
for (var key : keys()) {
if (key instanceof String) res.add((String)key);
}
return res;
}
public GlobalScope() {
this.obj = new ObjectValue();
}
public GlobalScope(ObjectValue val) {
this.obj = val;
}
}

View File

@@ -1,9 +0,0 @@
package me.topchetoeu.jscript.core.scope;
import me.topchetoeu.jscript.core.Context;
public interface Variable {
Object get(Context ctx);
default boolean readonly() { return true; }
default void set(Context ctx, Object val) { }
}

View File

@@ -1,32 +0,0 @@
package me.topchetoeu.jscript.core.values;
import me.topchetoeu.jscript.core.Context;
public class NativeWrapper extends ObjectValue {
private static final Object NATIVE_PROTO = new Object();
public final Object wrapped;
@Override
public ObjectValue getPrototype(Context ctx) {
if (prototype == NATIVE_PROTO) return ctx.environment.wrappers.getProto(wrapped.getClass());
else return super.getPrototype(ctx);
}
@Override
public String toString() {
return wrapped.toString();
}
@Override
public boolean equals(Object obj) {
return wrapped.equals(obj);
}
@Override
public int hashCode() {
return wrapped.hashCode();
}
public NativeWrapper(Object wrapped) {
this.wrapped = wrapped;
prototype = NATIVE_PROTO;
}
}

View File

@@ -3,11 +3,11 @@ package me.topchetoeu.jscript.lib;
import java.util.Iterator; import java.util.Iterator;
import java.util.Stack; import java.util.Stack;
import me.topchetoeu.jscript.core.values.ArrayValue; import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.core.values.FunctionValue; import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.core.values.NativeFunction; import me.topchetoeu.jscript.runtime.values.NativeFunction;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose; import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor; import me.topchetoeu.jscript.utils.interop.ExposeConstructor;

View File

@@ -1,13 +1,14 @@
package me.topchetoeu.jscript.lib; package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.core.Context;
import me.topchetoeu.jscript.core.Frame;
import me.topchetoeu.jscript.core.values.CodeFunction;
import me.topchetoeu.jscript.core.values.FunctionValue;
import me.topchetoeu.jscript.core.values.NativeFunction;
import me.topchetoeu.jscript.core.values.Values;
import me.topchetoeu.jscript.core.exceptions.EngineException;
import me.topchetoeu.jscript.lib.PromiseLib.Handle; import me.topchetoeu.jscript.lib.PromiseLib.Handle;
import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.runtime.Extensions;
import me.topchetoeu.jscript.runtime.Frame;
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.values.CodeFunction;
import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.runtime.values.NativeFunction;
import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.WrapperName; import me.topchetoeu.jscript.utils.interop.WrapperName;
@@ -54,7 +55,7 @@ public class AsyncFunctionLib extends FunctionValue {
public void onReject(EngineException err) { public void onReject(EngineException err) {
next(ctx, Values.NO_RETURN, err); next(ctx, Values.NO_RETURN, err);
} }
}); }.defer(ctx));
} }
} }
@@ -65,8 +66,9 @@ public class AsyncFunctionLib extends FunctionValue {
} }
@Override @Override
public Object call(Context ctx, Object thisArg, Object ...args) { public Object call(Extensions ext, Object thisArg, Object ...args) {
var handler = new AsyncHelper(); var handler = new AsyncHelper();
var ctx = Context.of(ext);
var newArgs = new Object[args.length + 1]; var newArgs = new Object[args.length + 1];
newArgs[0] = new NativeFunction("await", handler::await); newArgs[0] = new NativeFunction("await", handler::await);

View File

@@ -1,11 +1,12 @@
package me.topchetoeu.jscript.lib; package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.core.Frame; import me.topchetoeu.jscript.runtime.Extensions;
import me.topchetoeu.jscript.core.values.CodeFunction; import me.topchetoeu.jscript.runtime.Frame;
import me.topchetoeu.jscript.core.values.FunctionValue; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.core.values.NativeFunction; import me.topchetoeu.jscript.runtime.values.CodeFunction;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.runtime.values.NativeFunction;
import me.topchetoeu.jscript.utils.interop.WrapperName; import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("AsyncGeneratorFunction") @WrapperName("AsyncGeneratorFunction")
@@ -13,7 +14,7 @@ public class AsyncGeneratorFunctionLib extends FunctionValue {
public final CodeFunction func; public final CodeFunction func;
@Override @Override
public Object call(Context ctx, Object thisArg, Object ...args) { public Object call(Extensions ext, Object thisArg, Object ...args) {
var handler = new AsyncGeneratorLib(); var handler = new AsyncGeneratorLib();
var newArgs = new Object[args.length + 2]; var newArgs = new Object[args.length + 2];
@@ -21,7 +22,7 @@ public class AsyncGeneratorFunctionLib extends FunctionValue {
newArgs[1] = new NativeFunction("yield", handler::yield); newArgs[1] = new NativeFunction("yield", handler::yield);
System.arraycopy(args, 0, newArgs, 2, args.length); System.arraycopy(args, 0, newArgs, 2, args.length);
handler.frame = new Frame(ctx, thisArg, newArgs, func); handler.frame = new Frame(Context.of(ext), thisArg, newArgs, func);
return handler; return handler;
} }

View File

@@ -2,12 +2,12 @@ package me.topchetoeu.jscript.lib;
import java.util.Map; import java.util.Map;
import me.topchetoeu.jscript.core.Context;
import me.topchetoeu.jscript.core.Frame;
import me.topchetoeu.jscript.core.values.ObjectValue;
import me.topchetoeu.jscript.core.values.Values;
import me.topchetoeu.jscript.core.exceptions.EngineException;
import me.topchetoeu.jscript.lib.PromiseLib.Handle; import me.topchetoeu.jscript.lib.PromiseLib.Handle;
import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.runtime.Frame;
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose; import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.WrapperName; import me.topchetoeu.jscript.utils.interop.WrapperName;
@@ -62,7 +62,7 @@ public class AsyncGeneratorLib {
@Override public void onReject(EngineException err) { @Override public void onReject(EngineException err) {
next(ctx, Values.NO_RETURN, Values.NO_RETURN, err); next(ctx, Values.NO_RETURN, Values.NO_RETURN, err);
} }
}); }.defer(ctx));
} }
else if (state == 2) { else if (state == 2) {
var obj = new ObjectValue(); var obj = new ObjectValue();
@@ -101,7 +101,7 @@ public class AsyncGeneratorLib {
} }
@Expose public PromiseLib __throw(Arguments args) { @Expose public PromiseLib __throw(Arguments args) {
this.currPromise = new PromiseLib(); this.currPromise = new PromiseLib();
next(args.ctx, Values.NO_RETURN, Values.NO_RETURN, new EngineException(args.get(0)).setCtx(args.ctx)); next(args.ctx, Values.NO_RETURN, Values.NO_RETURN, new EngineException(args.get(0)).setExtensions(args.ctx));
return this.currPromise; return this.currPromise;
} }
} }

View File

@@ -1,7 +1,7 @@
package me.topchetoeu.jscript.lib; package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose; import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor; import me.topchetoeu.jscript.utils.interop.ExposeConstructor;

View File

@@ -2,7 +2,7 @@ package me.topchetoeu.jscript.lib;
import java.io.IOException; import java.io.IOException;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.filesystem.File; import me.topchetoeu.jscript.utils.filesystem.File;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose; import me.topchetoeu.jscript.utils.interop.Expose;

View File

@@ -4,9 +4,9 @@ import java.util.ArrayList;
import me.topchetoeu.jscript.common.Buffer; import me.topchetoeu.jscript.common.Buffer;
import me.topchetoeu.jscript.compilation.parsing.Parsing; import me.topchetoeu.jscript.compilation.parsing.Parsing;
import me.topchetoeu.jscript.core.values.ArrayValue; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose; import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeTarget; import me.topchetoeu.jscript.utils.interop.ExposeTarget;

View File

@@ -1,10 +1,10 @@
package me.topchetoeu.jscript.lib; package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.runtime.exceptions.ConvertException;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.core.values.ObjectValue.PlaceholderProto; import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.core.exceptions.ConvertException; import me.topchetoeu.jscript.runtime.values.ObjectValue.PlaceholderProto;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose; import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor; import me.topchetoeu.jscript.utils.interop.ExposeConstructor;

View File

@@ -1,7 +1,7 @@
package me.topchetoeu.jscript.lib; package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.core.values.ArrayValue; import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.filesystem.File; import me.topchetoeu.jscript.utils.filesystem.File;
import me.topchetoeu.jscript.utils.filesystem.FilesystemException; import me.topchetoeu.jscript.utils.filesystem.FilesystemException;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;

View File

@@ -4,10 +4,10 @@ import java.io.IOException;
import java.util.Iterator; import java.util.Iterator;
import java.util.Stack; import java.util.Stack;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.filesystem.ActionType; import me.topchetoeu.jscript.utils.filesystem.ActionType;
import me.topchetoeu.jscript.utils.filesystem.EntryType; import me.topchetoeu.jscript.utils.filesystem.EntryType;
import me.topchetoeu.jscript.utils.filesystem.ErrorReason; import me.topchetoeu.jscript.utils.filesystem.ErrorReason;

View File

@@ -1,9 +1,9 @@
package me.topchetoeu.jscript.lib; package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.core.values.ArrayValue; import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.core.values.CodeFunction; import me.topchetoeu.jscript.runtime.values.CodeFunction;
import me.topchetoeu.jscript.core.values.FunctionValue; import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.core.values.NativeFunction; import me.topchetoeu.jscript.runtime.values.NativeFunction;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose; import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeTarget; import me.topchetoeu.jscript.utils.interop.ExposeTarget;

View File

@@ -1,25 +1,26 @@
package me.topchetoeu.jscript.lib; package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.core.Frame; import me.topchetoeu.jscript.runtime.Extensions;
import me.topchetoeu.jscript.core.values.CodeFunction; import me.topchetoeu.jscript.runtime.Frame;
import me.topchetoeu.jscript.core.values.FunctionValue; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.core.values.NativeFunction; import me.topchetoeu.jscript.runtime.values.CodeFunction;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.runtime.values.NativeFunction;
import me.topchetoeu.jscript.utils.interop.WrapperName; import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("GeneratorFunction") @WrapperName("GeneratorFunction")
public class GeneratorFunctionLib extends FunctionValue { public class GeneratorFunctionLib extends FunctionValue {
public final CodeFunction func; public final CodeFunction func;
@Override public Object call(Context ctx, Object thisArg, Object ...args) { @Override public Object call(Extensions ext, Object thisArg, Object ...args) {
var handler = new GeneratorLib(); var handler = new GeneratorLib();
var newArgs = new Object[args.length + 1]; var newArgs = new Object[args.length + 1];
newArgs[0] = new NativeFunction("yield", handler::yield); newArgs[0] = new NativeFunction("yield", handler::yield);
System.arraycopy(args, 0, newArgs, 1, args.length); System.arraycopy(args, 0, newArgs, 1, args.length);
handler.frame = new Frame(ctx, thisArg, newArgs, func); handler.frame = new Frame(Context.of(ext), thisArg, newArgs, func);
return handler; return handler;
} }

View File

@@ -1,10 +1,10 @@
package me.topchetoeu.jscript.lib; package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.core.Frame; import me.topchetoeu.jscript.runtime.Frame;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose; import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.WrapperName; import me.topchetoeu.jscript.utils.interop.WrapperName;
@@ -59,7 +59,7 @@ public class GeneratorLib {
else return next(args.ctx, args.get(0), Values.NO_RETURN, null); else return next(args.ctx, args.get(0), Values.NO_RETURN, null);
} }
@Expose public ObjectValue __throw(Arguments args) { @Expose public ObjectValue __throw(Arguments args) {
return next(args.ctx, Values.NO_RETURN, Values.NO_RETURN, new EngineException(args.get(0)).setCtx(args.ctx)); return next(args.ctx, Values.NO_RETURN, Values.NO_RETURN, new EngineException(args.get(0)).setExtensions(args.ctx));
} }
@Expose public ObjectValue __return(Arguments args) { @Expose public ObjectValue __return(Arguments args) {
return next(args.ctx, Values.NO_RETURN, args.get(0), null); return next(args.ctx, Values.NO_RETURN, args.get(0), null);

View File

@@ -2,18 +2,22 @@ package me.topchetoeu.jscript.lib;
import java.util.HashMap; import java.util.HashMap;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.core.Environment; import me.topchetoeu.jscript.runtime.Environment;
import me.topchetoeu.jscript.core.EventLoop; import me.topchetoeu.jscript.runtime.EventLoop;
import me.topchetoeu.jscript.core.Key; import me.topchetoeu.jscript.runtime.Key;
import me.topchetoeu.jscript.core.scope.GlobalScope; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.core.values.FunctionValue; import me.topchetoeu.jscript.runtime.scope.GlobalScope;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.filesystem.Filesystem;
import me.topchetoeu.jscript.utils.filesystem.Mode;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose; import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeField; import me.topchetoeu.jscript.utils.interop.ExposeField;
import me.topchetoeu.jscript.utils.interop.ExposeTarget; import me.topchetoeu.jscript.utils.interop.ExposeTarget;
import me.topchetoeu.jscript.utils.interop.ExposeType;
import me.topchetoeu.jscript.utils.interop.NativeWrapperProvider;
import me.topchetoeu.jscript.utils.modules.ModuleRepo; import me.topchetoeu.jscript.utils.modules.ModuleRepo;
public class Internals { public class Internals {
@@ -48,7 +52,7 @@ public class Internals {
try { Thread.sleep(ms, ns); } try { Thread.sleep(ms, ns); }
catch (InterruptedException e) { return; } catch (InterruptedException e) { return; }
args.ctx.get(EventLoop.KEY).pushMsg(() -> func.call(new Context(args.ctx.environment), null, arguments), false); args.ctx.get(EventLoop.KEY).pushMsg(() -> func.call(new Context(args.ctx.extensions), null, arguments), false);
}); });
thread.start(); thread.start();
@@ -76,7 +80,7 @@ public class Internals {
} }
catch (InterruptedException e) { return; } catch (InterruptedException e) { return; }
args.ctx.get(EventLoop.KEY).pushMsg(() -> func.call(new Context(args.ctx.environment), null, arguments), false); args.ctx.get(EventLoop.KEY).pushMsg(() -> func.call(new Context(args.ctx.extensions), null, arguments), false);
} }
}); });
thread.start(); thread.start();
@@ -126,6 +130,19 @@ public class Internals {
return NumberLib.__isInfinite(args); return NumberLib.__isInfinite(args);
} }
@Expose(target = ExposeTarget.STATIC, type = ExposeType.GETTER)
public static FileLib __stdin(Arguments args) {
return new FileLib(Filesystem.get(args.ctx).open("std://in", Mode.READ));
}
@Expose(target = ExposeTarget.STATIC, type = ExposeType.GETTER)
public static FileLib __stdout(Arguments args) {
return new FileLib(Filesystem.get(args.ctx).open("std://out", Mode.READ));
}
@Expose(target = ExposeTarget.STATIC, type = ExposeType.GETTER)
public static FileLib __stderr(Arguments args) {
return new FileLib(Filesystem.get(args.ctx).open("std://err", Mode.READ));
}
@ExposeField(target = ExposeTarget.STATIC) @ExposeField(target = ExposeTarget.STATIC)
public static double __NaN = Double.NaN; public static double __NaN = Double.NaN;
@ExposeField(target = ExposeTarget.STATIC) @ExposeField(target = ExposeTarget.STATIC)
@@ -149,35 +166,35 @@ public class Internals {
} }
public static Environment apply(Environment env) { public static Environment apply(Environment env) {
var wp = env.wrappers; var wp = new NativeWrapperProvider();
var glob = env.global = new GlobalScope(wp.getNamespace(Internals.class)); var glob = new GlobalScope(wp.getNamespace(Internals.class));
glob.define(null, "Math", false, wp.getNamespace(MathLib.class)); glob.define(null, "Math", false, wp.getNamespace(MathLib.class));
glob.define(null, "JSON", false, wp.getNamespace(JSONLib.class)); glob.define(null, "JSON", false, wp.getNamespace(JSONLib.class));
glob.define(null, "Encoding", false, wp.getNamespace(EncodingLib.class)); glob.define(null, "Encoding", false, wp.getNamespace(EncodingLib.class));
glob.define(null, "Filesystem", false, wp.getNamespace(FilesystemLib.class)); glob.define(null, "Filesystem", false, wp.getNamespace(FilesystemLib.class));
glob.define(false, wp.getConstr(FileLib.class)); glob.define(null, false, wp.getConstr(FileLib.class));
glob.define(false, wp.getConstr(DateLib.class)); glob.define(null, false, wp.getConstr(DateLib.class));
glob.define(false, wp.getConstr(ObjectLib.class)); glob.define(null, false, wp.getConstr(ObjectLib.class));
glob.define(false, wp.getConstr(FunctionLib.class)); glob.define(null, false, wp.getConstr(FunctionLib.class));
glob.define(false, wp.getConstr(ArrayLib.class)); glob.define(null, false, wp.getConstr(ArrayLib.class));
glob.define(false, wp.getConstr(BooleanLib.class)); glob.define(null, false, wp.getConstr(BooleanLib.class));
glob.define(false, wp.getConstr(NumberLib.class)); glob.define(null, false, wp.getConstr(NumberLib.class));
glob.define(false, wp.getConstr(StringLib.class)); glob.define(null, false, wp.getConstr(StringLib.class));
glob.define(false, wp.getConstr(SymbolLib.class)); glob.define(null, false, wp.getConstr(SymbolLib.class));
glob.define(false, wp.getConstr(PromiseLib.class)); glob.define(null, false, wp.getConstr(PromiseLib.class));
glob.define(false, wp.getConstr(RegExpLib.class)); glob.define(null, false, wp.getConstr(RegExpLib.class));
glob.define(false, wp.getConstr(MapLib.class)); glob.define(null, false, wp.getConstr(MapLib.class));
glob.define(false, wp.getConstr(SetLib.class)); glob.define(null, false, wp.getConstr(SetLib.class));
glob.define(false, wp.getConstr(ErrorLib.class)); glob.define(null, false, wp.getConstr(ErrorLib.class));
glob.define(false, wp.getConstr(SyntaxErrorLib.class)); glob.define(null, false, wp.getConstr(SyntaxErrorLib.class));
glob.define(false, wp.getConstr(TypeErrorLib.class)); glob.define(null, false, wp.getConstr(TypeErrorLib.class));
glob.define(false, wp.getConstr(RangeErrorLib.class)); glob.define(null, false, wp.getConstr(RangeErrorLib.class));
env.add(Environment.OBJECT_PROTO, wp.getProto(ObjectLib.class)); env.add(Environment.OBJECT_PROTO, wp.getProto(ObjectLib.class));
env.add(Environment.FUNCTION_PROTO, wp.getProto(FunctionLib.class)); env.add(Environment.FUNCTION_PROTO, wp.getProto(FunctionLib.class));
@@ -193,8 +210,12 @@ public class Internals {
env.add(Environment.TYPE_ERR_PROTO, wp.getProto(TypeErrorLib.class)); env.add(Environment.TYPE_ERR_PROTO, wp.getProto(TypeErrorLib.class));
env.add(Environment.RANGE_ERR_PROTO, wp.getProto(RangeErrorLib.class)); env.add(Environment.RANGE_ERR_PROTO, wp.getProto(RangeErrorLib.class));
Values.setPrototype(Context.NULL, wp.getProto(ObjectLib.class), null);
env.add(Environment.REGEX_CONSTR, wp.getConstr(RegExpLib.class)); env.add(Environment.REGEX_CONSTR, wp.getConstr(RegExpLib.class));
Values.setPrototype(new Context(), wp.getProto(ObjectLib.class), null);
env.add(NativeWrapperProvider.KEY, wp);
env.add(GlobalScope.KEY, glob);
return env; return env;
} }

View File

@@ -1,8 +1,8 @@
package me.topchetoeu.jscript.lib; package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.common.json.JSON; import me.topchetoeu.jscript.common.json.JSON;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.core.exceptions.SyntaxException; import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose; import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeTarget; import me.topchetoeu.jscript.utils.interop.ExposeTarget;

View File

@@ -4,10 +4,10 @@ import java.util.ArrayList;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.core.values.ArrayValue; import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose; import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor; import me.topchetoeu.jscript.utils.interop.ExposeConstructor;

View File

@@ -1,7 +1,9 @@
package me.topchetoeu.jscript.lib; package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.core.values.ObjectValue; import java.text.NumberFormat;
import me.topchetoeu.jscript.core.values.Values;
import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose; import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor; import me.topchetoeu.jscript.utils.interop.ExposeConstructor;
@@ -85,6 +87,14 @@ public class NumberLib {
@Expose public static String __toString(Arguments args) { @Expose public static String __toString(Arguments args) {
return Values.toString(args.ctx, args.self); return Values.toString(args.ctx, args.self);
} }
@Expose public static String __toFixed(Arguments args) {
var digits = args.getInt(0, 0);
var nf = NumberFormat.getNumberInstance();
nf.setMaximumFractionDigits(digits);
return nf.format(args.getDouble(-1));
}
@Expose public static double __valueOf(Arguments args) { @Expose public static double __valueOf(Arguments args) {
if (Values.isWrapper(args.self, NumberLib.class)) return Values.wrapper(args.self, NumberLib.class).value; if (Values.isWrapper(args.self, NumberLib.class)) return Values.wrapper(args.self, NumberLib.class).value;
else return Values.toNumber(args.ctx, args.self); else return Values.toNumber(args.ctx, args.self);

View File

@@ -1,11 +1,11 @@
package me.topchetoeu.jscript.lib; package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.core.values.ArrayValue; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.core.values.FunctionValue; import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.core.values.Symbol; import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.values.Symbol;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose; import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor; import me.topchetoeu.jscript.utils.interop.ExposeConstructor;

View File

@@ -4,16 +4,16 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import me.topchetoeu.jscript.common.ResultRunnable; import me.topchetoeu.jscript.common.ResultRunnable;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.core.EventLoop; import me.topchetoeu.jscript.runtime.EventLoop;
import me.topchetoeu.jscript.core.Extensions; import me.topchetoeu.jscript.runtime.Extensions;
import me.topchetoeu.jscript.core.values.ArrayValue; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.core.values.FunctionValue; import me.topchetoeu.jscript.runtime.exceptions.InterruptException;
import me.topchetoeu.jscript.core.values.NativeFunction; import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.values.NativeFunction;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.core.exceptions.InterruptException; import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose; import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor; import me.topchetoeu.jscript.utils.interop.ExposeConstructor;
@@ -53,26 +53,29 @@ public class PromiseLib {
private Object val; private Object val;
private void resolveSynchronized(Context ctx, Object val, int newState) { private void resolveSynchronized(Context ctx, Object val, int newState) {
if (!ctx.hasNotNull(EventLoop.KEY)) throw EngineException.ofError("No event loop"); this.val = val;
this.state = newState;
ctx.get(EventLoop.KEY).pushMsg(() -> {
this.val = val; for (var handle : handles) {
this.state = newState; if (newState == STATE_FULFILLED) handle.onFulfil(val);
if (newState == STATE_REJECTED) {
for (var handle : handles) { handle.onReject((EngineException)val);
if (newState == STATE_FULFILLED) handle.onFulfil(val); handled = true;
if (newState == STATE_REJECTED) {
handle.onReject((EngineException)val);
handled = true;
}
} }
}
if (state == STATE_REJECTED && !handled) { if (state == STATE_REJECTED && !handled) {
Values.printError(((EngineException)val).setCtx(ctx), "(in promise)"); Values.printError(((EngineException)val).setExtensions(ctx), "(in promise)");
} }
handles = null; handles = null;
}, true);
// ctx.get(EventLoop.KEY).pushMsg(() -> {
// if (!ctx.hasNotNull(EventLoop.KEY)) throw EngineException.ofError("No event loop");
// handles = null;
// }, true);
} }
private synchronized void resolve(Context ctx, Object val, int newState) { private synchronized void resolve(Context ctx, Object val, int newState) {
@@ -204,7 +207,7 @@ public class PromiseLib {
} }
@Expose(value = "reject", target = ExposeTarget.STATIC) @Expose(value = "reject", target = ExposeTarget.STATIC)
public static PromiseLib __ofRejected(Arguments args) { public static PromiseLib __ofRejected(Arguments args) {
return ofRejected(args.ctx, new EngineException(args.get(0)).setCtx(args.ctx)); return ofRejected(args.ctx, new EngineException(args.get(0)).setExtensions(args.ctx));
} }
@Expose(target = ExposeTarget.STATIC) @Expose(target = ExposeTarget.STATIC)
@@ -212,7 +215,7 @@ public class PromiseLib {
if (!(args.get(0) instanceof ArrayValue)) throw EngineException.ofType("Expected argument for any to be an array."); if (!(args.get(0) instanceof ArrayValue)) throw EngineException.ofType("Expected argument for any to be an array.");
var promises = args.convert(0, ArrayValue.class); var promises = args.convert(0, ArrayValue.class);
if (promises.size() == 0) return ofRejected(args.ctx, EngineException.ofError("No promises passed to 'Promise.any'.").setCtx(args.ctx)); if (promises.size() == 0) return ofRejected(args.ctx, EngineException.ofError("No promises passed to 'Promise.any'.").setExtensions(args.ctx));
var n = new int[] { promises.size() }; var n = new int[] { promises.size() };
var res = new PromiseLib(); var res = new PromiseLib();
var errors = new ArrayValue(); var errors = new ArrayValue();
@@ -227,7 +230,7 @@ public class PromiseLib {
public void onReject(EngineException err) { public void onReject(EngineException err) {
errors.set(args.ctx, index, err.value); errors.set(args.ctx, index, err.value);
n[0]--; n[0]--;
if (n[0] <= 0) res.reject(args.ctx, new EngineException(errors).setCtx(args.ctx)); if (n[0] <= 0) res.reject(args.ctx, new EngineException(errors).setExtensions(args.ctx));
} }
}); });
} }
@@ -387,7 +390,7 @@ public class PromiseLib {
return null; return null;
}), }),
new NativeFunction(null, _args -> { new NativeFunction(null, _args -> {
res.reject(_args.ctx, new EngineException(_args.get(0)).setCtx(_args.ctx)); res.reject(_args.ctx, new EngineException(_args.get(0)).setExtensions(_args.ctx));
return null; return null;
}) })
); );

View File

@@ -1,7 +1,7 @@
package me.topchetoeu.jscript.lib; package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.core.values.ObjectValue.PlaceholderProto; import me.topchetoeu.jscript.runtime.values.ObjectValue.PlaceholderProto;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor; import me.topchetoeu.jscript.utils.interop.ExposeConstructor;
import me.topchetoeu.jscript.utils.interop.ExposeField; import me.topchetoeu.jscript.utils.interop.ExposeField;

View File

@@ -4,12 +4,12 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.core.values.ArrayValue; import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.core.values.FunctionValue; import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.core.values.NativeWrapper; import me.topchetoeu.jscript.runtime.values.NativeWrapper;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose; import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor; import me.topchetoeu.jscript.utils.interop.ExposeConstructor;

View File

@@ -4,10 +4,10 @@ import java.util.ArrayList;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.core.values.ArrayValue; import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose; import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor; import me.topchetoeu.jscript.utils.interop.ExposeConstructor;

View File

@@ -2,13 +2,13 @@ package me.topchetoeu.jscript.lib;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import me.topchetoeu.jscript.core.Environment; import me.topchetoeu.jscript.runtime.Environment;
import me.topchetoeu.jscript.core.values.ArrayValue; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.core.values.FunctionValue; import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.core.values.Symbol; import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.values.Symbol;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose; import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor; import me.topchetoeu.jscript.utils.interop.ExposeConstructor;

View File

@@ -3,10 +3,10 @@ package me.topchetoeu.jscript.lib;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.core.values.Symbol; import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.values.Symbol;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose; import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor; import me.topchetoeu.jscript.utils.interop.ExposeConstructor;

View File

@@ -1,7 +1,7 @@
package me.topchetoeu.jscript.lib; package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.core.values.ObjectValue.PlaceholderProto; import me.topchetoeu.jscript.runtime.values.ObjectValue.PlaceholderProto;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor; import me.topchetoeu.jscript.utils.interop.ExposeConstructor;
import me.topchetoeu.jscript.utils.interop.ExposeField; import me.topchetoeu.jscript.utils.interop.ExposeField;

View File

@@ -0,0 +1,18 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
public class ThrowableLib {
@Expose public static String __message(Arguments args) {
if (args.self instanceof Throwable) return ((Throwable)args.self).getMessage();
else return null;
}
@Expose public static String __name(Arguments args) {
return args.self.getClass().getSimpleName();
}
@Expose public static String __toString(Arguments args) {
return __name(args) + ": " + __message(args);
}
}

View File

@@ -1,7 +1,7 @@
package me.topchetoeu.jscript.lib; package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.core.values.ObjectValue.PlaceholderProto; import me.topchetoeu.jscript.runtime.values.ObjectValue.PlaceholderProto;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor; import me.topchetoeu.jscript.utils.interop.ExposeConstructor;
import me.topchetoeu.jscript.utils.interop.ExposeField; import me.topchetoeu.jscript.utils.interop.ExposeField;

View File

@@ -0,0 +1,5 @@
package me.topchetoeu.jscript.runtime;
public interface Childable {
Object child();
}

View File

@@ -1,10 +1,10 @@
package me.topchetoeu.jscript.core; package me.topchetoeu.jscript.runtime;
import me.topchetoeu.jscript.common.Filename; import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.common.FunctionBody; import me.topchetoeu.jscript.common.FunctionBody;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.core.scope.ValueVariable; import me.topchetoeu.jscript.runtime.scope.ValueVariable;
import me.topchetoeu.jscript.core.values.CodeFunction; import me.topchetoeu.jscript.runtime.values.CodeFunction;
public interface Compiler { public interface Compiler {
public Key<Compiler> KEY = new Key<>(); public Key<Compiler> KEY = new Key<>();

View File

@@ -0,0 +1,98 @@
package me.topchetoeu.jscript.runtime;
import java.util.Iterator;
import java.util.List;
import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.runtime.debug.DebugContext;
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.scope.ValueVariable;
import me.topchetoeu.jscript.runtime.values.CodeFunction;
import me.topchetoeu.jscript.runtime.values.FunctionValue;
public class Context implements Extensions {
public final Context parent;
public final Extensions extensions;
public final Frame frame;
public final int stackSize;
@Override public <T> void add(Key<T> key, T obj) {
if (extensions != null) extensions.add(key, obj);
}
@Override public <T> T get(Key<T> key) {
if (extensions != null && extensions.has(key)) return extensions.get(key);
return null;
}
@Override public boolean has(Key<?> key) {
return extensions != null && extensions.has(key);
}
@Override public boolean remove(Key<?> key) {
var res = false;
if (extensions != null) res |= extensions.remove(key);
return res;
}
@Override public Iterable<Key<?>> keys() {
if (extensions == null) return List.of();
else return extensions.keys();
}
public FunctionValue compile(Filename filename, String raw) {
DebugContext.get(this).onSource(filename, raw);
var result = new CodeFunction(extensions, filename.toString(), Compiler.get(this).compile(filename, raw), new ValueVariable[0]);
return result;
}
public Context pushFrame(Frame frame) {
var res = new Context(this, frame.function.extensions, frame, stackSize + 1);
return res;
}
public Iterable<Frame> frames() {
var self = this;
return () -> new Iterator<Frame>() {
private Context curr = self;
private void update() {
while (curr != null && curr.frame == null) curr = curr.parent;
}
@Override public boolean hasNext() {
update();
return curr != null;
}
@Override public Frame next() {
update();
var res = curr.frame;
curr = curr.parent;
return res;
}
};
}
private Context(Context parent, Extensions ext, Frame frame, int stackSize) {
this.parent = parent;
this.extensions = ext;
this.frame = frame;
this.stackSize = stackSize;
if (hasNotNull(Environment.MAX_STACK_COUNT) && stackSize > (int)get(Environment.MAX_STACK_COUNT)) {
throw EngineException.ofRange("Stack overflow!");
}
}
public Context() {
this(null, null, null, 0);
}
public Context(Extensions ext) {
this(null, clean(ext), null, 0);
}
public static Context of(Extensions ext) {
if (ext instanceof Context) return (Context)ext;
return new Context(ext);
}
public static Extensions clean(Extensions ext) {
if (ext instanceof Context) return ((Context)ext).extensions;
else return ext;
}
}

View File

@@ -0,0 +1,5 @@
package me.topchetoeu.jscript.runtime;
public interface Copyable {
Object copy();
}

View File

@@ -1,12 +1,10 @@
package me.topchetoeu.jscript.core; package me.topchetoeu.jscript.runtime;
import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.PriorityBlockingQueue;
import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.common.ResultRunnable; import me.topchetoeu.jscript.common.ResultRunnable;
import me.topchetoeu.jscript.common.events.DataNotifier; import me.topchetoeu.jscript.common.events.DataNotifier;
import me.topchetoeu.jscript.core.exceptions.InterruptException; import me.topchetoeu.jscript.runtime.exceptions.InterruptException;
import me.topchetoeu.jscript.core.values.FunctionValue;
public class Engine implements EventLoop { public class Engine implements EventLoop {
private static class Task<T> implements Comparable<Task<?>> { private static class Task<T> implements Comparable<Task<?>> {
@@ -78,18 +76,6 @@ public class Engine implements EventLoop {
return this.thread != null; return this.thread != null;
} }
public DataNotifier<Object> pushMsg(boolean micro, Environment env, FunctionValue func, Object thisArg, Object ...args) {
return pushMsg(() -> {
return func.call(new Context(env), thisArg, args);
}, micro);
}
public DataNotifier<Object> pushMsg(boolean micro, Environment env, Filename filename, String raw, Object thisArg, Object ...args) {
return pushMsg(() -> {
var ctx = new Context(env);
return ctx.compile(filename, raw).call(new Context(env), thisArg, args);
}, micro);
}
public Engine() { public Engine() {
} }
} }

View File

@@ -1,13 +1,11 @@
package me.topchetoeu.jscript.core; package me.topchetoeu.jscript.runtime;
import java.util.HashMap; import java.util.HashMap;
import me.topchetoeu.jscript.core.scope.GlobalScope; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.core.values.FunctionValue; import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.core.values.NativeFunction; import me.topchetoeu.jscript.runtime.values.NativeFunction;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.core.exceptions.EngineException;
import me.topchetoeu.jscript.utils.interop.NativeWrapperProvider;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class Environment implements Extensions { public class Environment implements Extensions {
@@ -31,9 +29,6 @@ public class Environment implements Extensions {
private HashMap<Key<?>, Object> data = new HashMap<>(); private HashMap<Key<?>, Object> data = new HashMap<>();
public GlobalScope global;
public WrapperProvider wrappers;
@Override public <T> void add(Key<T> key, T obj) { @Override public <T> void add(Key<T> key, T obj) {
data.put(key, obj); data.put(key, obj);
} }
@@ -56,37 +51,11 @@ public class Environment implements Extensions {
public static FunctionValue regexConstructor(Extensions ext) { public static FunctionValue regexConstructor(Extensions ext) {
return ext.init(REGEX_CONSTR, new NativeFunction("RegExp", args -> { return ext.init(REGEX_CONSTR, new NativeFunction("RegExp", args -> {
throw EngineException.ofError("Regular expressions not supported.").setCtx(args.ctx); throw EngineException.ofError("Regular expressions not supported.").setExtensions(args.ctx);
})); }));
} }
public Environment copy() {
var res = new Environment(null, global);
res.wrappers = wrappers.fork(res);
res.global = global;
res.data.putAll(data);
return res;
}
public Environment child() {
var res = copy();
res.global = res.global.globalChild();
return res;
}
public Context context() { public Context context() {
return new Context(this); return new Context(this);
} }
public Environment(WrapperProvider nativeConverter, GlobalScope global) {
if (nativeConverter == null) nativeConverter = new NativeWrapperProvider(this);
if (global == null) global = new GlobalScope();
this.wrappers = nativeConverter;
this.global = global;
}
public Environment() {
this(null, null);
}
} }

View File

@@ -1,8 +1,10 @@
package me.topchetoeu.jscript.core; package me.topchetoeu.jscript.runtime;
import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.common.ResultRunnable; import me.topchetoeu.jscript.common.ResultRunnable;
import me.topchetoeu.jscript.common.events.DataNotifier; import me.topchetoeu.jscript.common.events.DataNotifier;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.values.FunctionValue;
public interface EventLoop { public interface EventLoop {
public static final Key<EventLoop> KEY = new Key<>(); public static final Key<EventLoop> KEY = new Key<>();
@@ -20,4 +22,16 @@ public interface EventLoop {
public default DataNotifier<Void> pushMsg(Runnable runnable, boolean micro) { public default DataNotifier<Void> pushMsg(Runnable runnable, boolean micro) {
return pushMsg(() -> { runnable.run(); return null; }, micro); return pushMsg(() -> { runnable.run(); return null; }, micro);
} }
public default DataNotifier<Object> pushMsg(boolean micro, Extensions ext, FunctionValue func, Object thisArg, Object ...args) {
return pushMsg(() -> {
return func.call(Context.of(ext), thisArg, args);
}, micro);
}
public default DataNotifier<Object> pushMsg(boolean micro, Extensions ext, Filename filename, String raw, Object thisArg, Object ...args) {
return pushMsg(() -> {
var ctx = Context.of(ext);
return ctx.compile(filename, raw).call(Context.of(ext), thisArg, args);
}, micro);
}
} }

View File

@@ -0,0 +1,77 @@
package me.topchetoeu.jscript.runtime;
import java.util.List;
public interface Extensions extends Childable, Copyable {
public static Extensions EMPTY = new Extensions() {
@Override public <T> void add(Key<T> key, T obj) { }
@Override public boolean remove(Key<?> key) { return false; }
@Override public <T> T get(Key<T> key) { return null; }
@Override public boolean has(Key<?> key) { return false; }
@Override public Iterable<Key<?>> keys() { return List.of(); }
};
<T> T get(Key<T> key);
<T> void add(Key<T> key, T obj);
Iterable<Key<?>> keys();
boolean has(Key<?> key);
boolean remove(Key<?> key);
default void add(Key<Void> key) {
add(key, null);
}
default boolean hasNotNull(Key<?> key) {
return has(key) && get(key) != null;
}
default <T> T get(Key<T> key, T defaultVal) {
if (has(key)) return get(key);
else return defaultVal;
}
default <T> T init(Key<T> key, T val) {
if (has(key)) return get(key);
else {
add(key, val);
return val;
}
}
@SuppressWarnings("unchecked")
default void addAll(Extensions source) {
if (source == null) return;
for (var key : source.keys()) {
add((Key<Object>)key, (Object)source.get(key));
}
}
@Override
@SuppressWarnings("unchecked")
default Extensions copy() {
var res = new Environment();
for (var key : keys()) {
var val = get(key);
if (val instanceof Copyable) val = ((Copyable)val).copy();
res.add((Key<Object>)key, val);
}
return res;
}
@Override
@SuppressWarnings("unchecked")
default Extensions child() {
var res = new Environment();
for (var key : keys()) {
var val = get(key);
if (val instanceof Childable) val = ((Childable)val).child();
res.add((Key<Object>)key, val);
}
return res;
}
public static Extensions wrap(Extensions ext) {
if (ext == null) return EMPTY;
else return ext;
}
}

View File

@@ -1,19 +1,19 @@
package me.topchetoeu.jscript.core; package me.topchetoeu.jscript.runtime;
import java.util.List; import java.util.List;
import java.util.Stack; import java.util.Stack;
import me.topchetoeu.jscript.common.Instruction; import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.core.debug.DebugContext; import me.topchetoeu.jscript.runtime.debug.DebugContext;
import me.topchetoeu.jscript.core.scope.LocalScope; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.core.scope.ValueVariable; import me.topchetoeu.jscript.runtime.exceptions.InterruptException;
import me.topchetoeu.jscript.core.values.ArrayValue; import me.topchetoeu.jscript.runtime.scope.LocalScope;
import me.topchetoeu.jscript.core.values.CodeFunction; import me.topchetoeu.jscript.runtime.scope.ValueVariable;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.core.values.ScopeValue; import me.topchetoeu.jscript.runtime.values.CodeFunction;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.ScopeValue;
import me.topchetoeu.jscript.core.exceptions.InterruptException; import me.topchetoeu.jscript.runtime.values.Values;
public class Frame { public class Frame {
public static enum TryState { public static enum TryState {
@@ -294,13 +294,13 @@ public class Frame {
public ObjectValue getValStackScope() { public ObjectValue getValStackScope() {
return new ObjectValue() { return new ObjectValue() {
@Override @Override
protected Object getField(Context ctx, Object key) { protected Object getField(Extensions ext, Object key) {
var i = (int)Values.toNumber(ctx, key); var i = (int)Values.toNumber(ext, key);
if (i < 0 || i >= stackPtr) return null; if (i < 0 || i >= stackPtr) return null;
else return stack[i]; else return stack[i];
} }
@Override @Override
protected boolean hasField(Context ctx, Object key) { protected boolean hasField(Extensions ext, Object key) {
return true; return true;
} }
@Override @Override

View File

@@ -1,56 +1,57 @@
package me.topchetoeu.jscript.core; package me.topchetoeu.jscript.runtime;
import java.util.Collections; import java.util.Collections;
import me.topchetoeu.jscript.core.scope.ValueVariable;
import me.topchetoeu.jscript.core.values.ArrayValue;
import me.topchetoeu.jscript.core.values.CodeFunction;
import me.topchetoeu.jscript.core.values.FunctionValue;
import me.topchetoeu.jscript.core.values.ObjectValue;
import me.topchetoeu.jscript.core.values.Symbol;
import me.topchetoeu.jscript.core.values.Values;
import me.topchetoeu.jscript.common.Instruction; import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Operation; import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.scope.GlobalScope;
import me.topchetoeu.jscript.runtime.scope.ValueVariable;
import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.runtime.values.CodeFunction;
import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.runtime.values.Symbol;
import me.topchetoeu.jscript.runtime.values.Values;
public class InstructionRunner { public class InstructionRunner {
private static Object execReturn(Context ctx, Instruction instr, Frame frame) { private static Object execReturn(Extensions ext, Instruction instr, Frame frame) {
return frame.pop(); return frame.pop();
} }
private static Object execThrow(Context ctx, Instruction instr, Frame frame) { private static Object execThrow(Extensions ext, Instruction instr, Frame frame) {
throw new EngineException(frame.pop()); throw new EngineException(frame.pop());
} }
private static Object execThrowSyntax(Context ctx, Instruction instr, Frame frame) { private static Object execThrowSyntax(Extensions ext, Instruction instr, Frame frame) {
throw EngineException.ofSyntax((String)instr.get(0)); throw EngineException.ofSyntax((String)instr.get(0));
} }
private static Object execCall(Context ctx, Instruction instr, Frame frame) { private static Object execCall(Extensions ext, Instruction instr, Frame frame) {
var callArgs = frame.take(instr.get(0)); var callArgs = frame.take(instr.get(0));
var func = frame.pop(); var func = frame.pop();
var thisArg = frame.pop(); var thisArg = frame.pop();
frame.push(Values.call(ctx, func, thisArg, callArgs)); frame.push(Values.call(ext, func, thisArg, callArgs));
frame.codePtr++; frame.codePtr++;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execCallNew(Context ctx, Instruction instr, Frame frame) { private static Object execCallNew(Extensions ext, Instruction instr, Frame frame) {
var callArgs = frame.take(instr.get(0)); var callArgs = frame.take(instr.get(0));
var funcObj = frame.pop(); var funcObj = frame.pop();
frame.push(Values.callNew(ctx, funcObj, callArgs)); frame.push(Values.callNew(ext, funcObj, callArgs));
frame.codePtr++; frame.codePtr++;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execMakeVar(Context ctx, Instruction instr, Frame frame) { private static Object execMakeVar(Extensions ext, Instruction instr, Frame frame) {
var name = (String)instr.get(0); var name = (String)instr.get(0);
ctx.environment.global.define(name); GlobalScope.get(ext).define(ext, name);
frame.codePtr++; frame.codePtr++;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execDefProp(Context ctx, Instruction instr, Frame frame) { private static Object execDefProp(Extensions ext, Instruction instr, Frame frame) {
var setter = frame.pop(); var setter = frame.pop();
var getter = frame.pop(); var getter = frame.pop();
var name = frame.pop(); var name = frame.pop();
@@ -59,16 +60,16 @@ public class InstructionRunner {
if (getter != null && !(getter instanceof FunctionValue)) throw EngineException.ofType("Getter must be a function or undefined."); if (getter != null && !(getter instanceof FunctionValue)) throw EngineException.ofType("Getter must be a function or undefined.");
if (setter != null && !(setter instanceof FunctionValue)) throw EngineException.ofType("Setter must be a function or undefined."); if (setter != null && !(setter instanceof FunctionValue)) throw EngineException.ofType("Setter must be a function or undefined.");
if (!(obj instanceof ObjectValue)) throw EngineException.ofType("Property apply target must be an object."); if (!(obj instanceof ObjectValue)) throw EngineException.ofType("Property apply target must be an object.");
((ObjectValue)obj).defineProperty(ctx, name, (FunctionValue)getter, (FunctionValue)setter, false, false); ((ObjectValue)obj).defineProperty(ext, name, (FunctionValue)getter, (FunctionValue)setter, false, false);
frame.push(obj); frame.push(obj);
frame.codePtr++; frame.codePtr++;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execKeys(Context ctx, Instruction instr, Frame frame) { private static Object execKeys(Extensions ext, Instruction instr, Frame frame) {
var val = frame.pop(); var val = frame.pop();
var members = Values.getMembers(ctx, val, false, false); var members = Values.getMembers(ext, val, false, false);
Collections.reverse(members); Collections.reverse(members);
frame.push(null); frame.push(null);
@@ -76,7 +77,7 @@ public class InstructionRunner {
for (var el : members) { for (var el : members) {
if (el instanceof Symbol) continue; if (el instanceof Symbol) continue;
var obj = new ObjectValue(); var obj = new ObjectValue();
obj.defineProperty(ctx, "value", el); obj.defineProperty(ext, "value", el);
frame.push(obj); frame.push(obj);
} }
@@ -84,7 +85,7 @@ public class InstructionRunner {
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execTryStart(Context ctx, Instruction instr, Frame frame) { private static Object execTryStart(Extensions ext, Instruction instr, Frame frame) {
int start = frame.codePtr + 1; int start = frame.codePtr + 1;
int catchStart = (int)instr.get(0); int catchStart = (int)instr.get(0);
int finallyStart = (int)instr.get(1); int finallyStart = (int)instr.get(1);
@@ -95,12 +96,12 @@ public class InstructionRunner {
frame.codePtr++; frame.codePtr++;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execTryEnd(Context ctx, Instruction instr, Frame frame) { private static Object execTryEnd(Extensions ext, Instruction instr, Frame frame) {
frame.popTryFlag = true; frame.popTryFlag = true;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execDup(Context ctx, Instruction instr, Frame frame) { private static Object execDup(Extensions ext, Instruction instr, Frame frame) {
int count = instr.get(0); int count = instr.get(0);
for (var i = 0; i < count; i++) { for (var i = 0; i < count; i++) {
@@ -110,7 +111,7 @@ public class InstructionRunner {
frame.codePtr++; frame.codePtr++;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execLoadValue(Context ctx, Instruction instr, Frame frame) { private static Object execLoadValue(Extensions ext, Instruction instr, Frame frame) {
switch (instr.type) { switch (instr.type) {
case PUSH_UNDEFINED: frame.push(null); break; case PUSH_UNDEFINED: frame.push(null); break;
case PUSH_NULL: frame.push(Values.NULL); break; case PUSH_NULL: frame.push(Values.NULL); break;
@@ -120,33 +121,33 @@ public class InstructionRunner {
frame.codePtr++; frame.codePtr++;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execLoadVar(Context ctx, Instruction instr, Frame frame) { private static Object execLoadVar(Extensions ext, Instruction instr, Frame frame) {
var i = instr.get(0); var i = instr.get(0);
if (i instanceof String) frame.push(ctx.environment.global.get(ctx, (String)i)); if (i instanceof String) frame.push(GlobalScope.get(ext).get(ext, (String)i));
else frame.push(frame.scope.get((int)i).get(ctx)); else frame.push(frame.scope.get((int)i).get(ext));
frame.codePtr++; frame.codePtr++;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execLoadObj(Context ctx, Instruction instr, Frame frame) { private static Object execLoadObj(Extensions ext, Instruction instr, Frame frame) {
frame.push(new ObjectValue()); frame.push(new ObjectValue());
frame.codePtr++; frame.codePtr++;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execLoadGlob(Context ctx, Instruction instr, Frame frame) { private static Object execLoadGlob(Extensions ext, Instruction instr, Frame frame) {
frame.push(ctx.environment.global.obj); frame.push(GlobalScope.get(ext).obj);
frame.codePtr++; frame.codePtr++;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execLoadArr(Context ctx, Instruction instr, Frame frame) { private static Object execLoadArr(Extensions ext, Instruction instr, Frame frame) {
var res = new ArrayValue(); var res = new ArrayValue();
res.setSize(instr.get(0)); res.setSize(instr.get(0));
frame.push(res); frame.push(res);
frame.codePtr++; frame.codePtr++;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execLoadFunc(Context ctx, Instruction instr, Frame frame) { private static Object execLoadFunc(Extensions ext, Instruction instr, Frame frame) {
int id = instr.get(0); int id = instr.get(0);
var captures = new ValueVariable[instr.params.length - 1]; var captures = new ValueVariable[instr.params.length - 1];
@@ -154,19 +155,19 @@ public class InstructionRunner {
captures[i - 1] = frame.scope.get(instr.get(i)); captures[i - 1] = frame.scope.get(instr.get(i));
} }
var func = new CodeFunction(ctx.environment, "", frame.function.body.children[id], captures); var func = new CodeFunction(ext, "", frame.function.body.children[id], captures);
frame.push(func); frame.push(func);
frame.codePtr++; frame.codePtr++;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execLoadMember(Context ctx, Instruction instr, Frame frame) { private static Object execLoadMember(Extensions ext, Instruction instr, Frame frame) {
var key = frame.pop(); var key = frame.pop();
var obj = frame.pop(); var obj = frame.pop();
try { try {
frame.push(Values.getMember(ctx, obj, key)); frame.push(Values.getMember(ext, obj, key));
} }
catch (IllegalArgumentException e) { catch (IllegalArgumentException e) {
throw EngineException.ofType(e.getMessage()); throw EngineException.ofType(e.getMessage());
@@ -174,9 +175,9 @@ public class InstructionRunner {
frame.codePtr++; frame.codePtr++;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execLoadRegEx(Context ctx, Instruction instr, Frame frame) { private static Object execLoadRegEx(Extensions ext, Instruction instr, Frame frame) {
if (ctx.hasNotNull(Environment.REGEX_CONSTR)) { if (ext.hasNotNull(Environment.REGEX_CONSTR)) {
frame.push(Values.callNew(ctx, ctx.get(Environment.REGEX_CONSTR), instr.get(0), instr.get(1))); frame.push(Values.callNew(ext, ext.get(Environment.REGEX_CONSTR), instr.get(0), instr.get(1)));
} }
else { else {
throw EngineException.ofSyntax("Regex is not supported."); throw EngineException.ofSyntax("Regex is not supported.");
@@ -185,43 +186,43 @@ public class InstructionRunner {
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execDiscard(Context ctx, Instruction instr, Frame frame) { private static Object execDiscard(Extensions ext, Instruction instr, Frame frame) {
frame.pop(); frame.pop();
frame.codePtr++; frame.codePtr++;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execStoreMember(Context ctx, Instruction instr, Frame frame) { private static Object execStoreMember(Extensions ext, Instruction instr, Frame frame) {
var val = frame.pop(); var val = frame.pop();
var key = frame.pop(); var key = frame.pop();
var obj = frame.pop(); var obj = frame.pop();
if (!Values.setMember(ctx, obj, key, val)) throw EngineException.ofSyntax("Can't set member '" + key + "'."); if (!Values.setMember(ext, obj, key, val)) throw EngineException.ofSyntax("Can't set member '" + key + "'.");
if ((boolean)instr.get(0)) frame.push(val); if ((boolean)instr.get(0)) frame.push(val);
frame.codePtr++; frame.codePtr++;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execStoreVar(Context ctx, Instruction instr, Frame frame) { private static Object execStoreVar(Extensions ext, Instruction instr, Frame frame) {
var val = (boolean)instr.get(1) ? frame.peek() : frame.pop(); var val = (boolean)instr.get(1) ? frame.peek() : frame.pop();
var i = instr.get(0); var i = instr.get(0);
if (i instanceof String) ctx.environment.global.set(ctx, (String)i, val); if (i instanceof String) GlobalScope.get(ext).set(ext, (String)i, val);
else frame.scope.get((int)i).set(ctx, val); else frame.scope.get((int)i).set(ext, val);
frame.codePtr++; frame.codePtr++;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execStoreSelfFunc(Context ctx, Instruction instr, Frame frame) { private static Object execStoreSelfFunc(Extensions ext, Instruction instr, Frame frame) {
frame.scope.locals[(int)instr.get(0)].set(ctx, frame.function); frame.scope.locals[(int)instr.get(0)].set(ext, frame.function);
frame.codePtr++; frame.codePtr++;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execJmp(Context ctx, Instruction instr, Frame frame) { private static Object execJmp(Extensions ext, Instruction instr, Frame frame) {
frame.codePtr += (int)instr.get(0); frame.codePtr += (int)instr.get(0);
frame.jumpFlag = true; frame.jumpFlag = true;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execJmpIf(Context ctx, Instruction instr, Frame frame) { private static Object execJmpIf(Extensions ext, Instruction instr, Frame frame) {
if (Values.toBoolean(frame.pop())) { if (Values.toBoolean(frame.pop())) {
frame.codePtr += (int)instr.get(0); frame.codePtr += (int)instr.get(0);
frame.jumpFlag = true; frame.jumpFlag = true;
@@ -229,7 +230,7 @@ public class InstructionRunner {
else frame.codePtr ++; else frame.codePtr ++;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execJmpIfNot(Context ctx, Instruction instr, Frame frame) { private static Object execJmpIfNot(Extensions ext, Instruction instr, Frame frame) {
if (Values.not(frame.pop())) { if (Values.not(frame.pop())) {
frame.codePtr += (int)instr.get(0); frame.codePtr += (int)instr.get(0);
frame.jumpFlag = true; frame.jumpFlag = true;
@@ -238,13 +239,13 @@ public class InstructionRunner {
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execTypeof(Context ctx, Instruction instr, Frame frame) { private static Object execTypeof(Extensions ext, Instruction instr, Frame frame) {
String name = instr.get(0); String name = instr.get(0);
Object obj; Object obj;
if (name != null) { if (name != null) {
if (ctx.environment.global.has(ctx, name)) { if (GlobalScope.get(ext).has(ext, name)) {
obj = ctx.environment.global.get(ctx, name); obj = GlobalScope.get(ext).get(ext, name);
} }
else obj = null; else obj = null;
} }
@@ -255,73 +256,73 @@ public class InstructionRunner {
frame.codePtr++; frame.codePtr++;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execNop(Context ctx, Instruction instr, Frame frame) { private static Object execNop(Extensions ext, Instruction instr, Frame frame) {
frame.codePtr++; frame.codePtr++;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execDelete(Context ctx, Instruction instr, Frame frame) { private static Object execDelete(Extensions ext, Instruction instr, Frame frame) {
var key = frame.pop(); var key = frame.pop();
var val = frame.pop(); var val = frame.pop();
if (!Values.deleteMember(ctx, val, key)) throw EngineException.ofSyntax("Can't delete member '" + key + "'."); if (!Values.deleteMember(ext, val, key)) throw EngineException.ofSyntax("Can't delete member '" + key + "'.");
frame.codePtr++; frame.codePtr++;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
private static Object execOperation(Context ctx, Instruction instr, Frame frame) { private static Object execOperation(Extensions ext, Instruction instr, Frame frame) {
Operation op = instr.get(0); Operation op = instr.get(0);
var args = new Object[op.operands]; var args = new Object[op.operands];
for (var i = op.operands - 1; i >= 0; i--) args[i] = frame.pop(); for (var i = op.operands - 1; i >= 0; i--) args[i] = frame.pop();
frame.push(Values.operation(ctx, op, args)); frame.push(Values.operation(ext, op, args));
frame.codePtr++; frame.codePtr++;
return Values.NO_RETURN; return Values.NO_RETURN;
} }
public static Object exec(Context ctx, Instruction instr, Frame frame) { public static Object exec(Extensions ext, Instruction instr, Frame frame) {
switch (instr.type) { switch (instr.type) {
case NOP: return execNop(ctx, instr, frame); case NOP: return execNop(ext, instr, frame);
case RETURN: return execReturn(ctx, instr, frame); case RETURN: return execReturn(ext, instr, frame);
case THROW: return execThrow(ctx, instr, frame); case THROW: return execThrow(ext, instr, frame);
case THROW_SYNTAX: return execThrowSyntax(ctx, instr, frame); case THROW_SYNTAX: return execThrowSyntax(ext, instr, frame);
case CALL: return execCall(ctx, instr, frame); case CALL: return execCall(ext, instr, frame);
case CALL_NEW: return execCallNew(ctx, instr, frame); case CALL_NEW: return execCallNew(ext, instr, frame);
case TRY_START: return execTryStart(ctx, instr, frame); case TRY_START: return execTryStart(ext, instr, frame);
case TRY_END: return execTryEnd(ctx, instr, frame); case TRY_END: return execTryEnd(ext, instr, frame);
case DUP: return execDup(ctx, instr, frame); case DUP: return execDup(ext, instr, frame);
case PUSH_UNDEFINED: case PUSH_UNDEFINED:
case PUSH_NULL: case PUSH_NULL:
case PUSH_STRING: case PUSH_STRING:
case PUSH_NUMBER: case PUSH_NUMBER:
case PUSH_BOOL: case PUSH_BOOL:
return execLoadValue(ctx, instr, frame); return execLoadValue(ext, instr, frame);
case LOAD_VAR: return execLoadVar(ctx, instr, frame); case LOAD_VAR: return execLoadVar(ext, instr, frame);
case LOAD_OBJ: return execLoadObj(ctx, instr, frame); case LOAD_OBJ: return execLoadObj(ext, instr, frame);
case LOAD_ARR: return execLoadArr(ctx, instr, frame); case LOAD_ARR: return execLoadArr(ext, instr, frame);
case LOAD_FUNC: return execLoadFunc(ctx, instr, frame); case LOAD_FUNC: return execLoadFunc(ext, instr, frame);
case LOAD_MEMBER: return execLoadMember(ctx, instr, frame); case LOAD_MEMBER: return execLoadMember(ext, instr, frame);
case LOAD_REGEX: return execLoadRegEx(ctx, instr, frame); case LOAD_REGEX: return execLoadRegEx(ext, instr, frame);
case LOAD_GLOB: return execLoadGlob(ctx, instr, frame); case LOAD_GLOB: return execLoadGlob(ext, instr, frame);
case DISCARD: return execDiscard(ctx, instr, frame); case DISCARD: return execDiscard(ext, instr, frame);
case STORE_MEMBER: return execStoreMember(ctx, instr, frame); case STORE_MEMBER: return execStoreMember(ext, instr, frame);
case STORE_VAR: return execStoreVar(ctx, instr, frame); case STORE_VAR: return execStoreVar(ext, instr, frame);
case STORE_SELF_FUNC: return execStoreSelfFunc(ctx, instr, frame); case STORE_SELF_FUNC: return execStoreSelfFunc(ext, instr, frame);
case MAKE_VAR: return execMakeVar(ctx, instr, frame); case MAKE_VAR: return execMakeVar(ext, instr, frame);
case KEYS: return execKeys(ctx, instr, frame); case KEYS: return execKeys(ext, instr, frame);
case DEF_PROP: return execDefProp(ctx, instr, frame); case DEF_PROP: return execDefProp(ext, instr, frame);
case TYPEOF: return execTypeof(ctx, instr, frame); case TYPEOF: return execTypeof(ext, instr, frame);
case DELETE: return execDelete(ctx, instr, frame); case DELETE: return execDelete(ext, instr, frame);
case JMP: return execJmp(ctx, instr, frame); case JMP: return execJmp(ext, instr, frame);
case JMP_IF: return execJmpIf(ctx, instr, frame); case JMP_IF: return execJmpIf(ext, instr, frame);
case JMP_IFN: return execJmpIfNot(ctx, instr, frame); case JMP_IFN: return execJmpIfNot(ext, instr, frame);
case OPERATION: return execOperation(ctx, instr, frame); case OPERATION: return execOperation(ext, instr, frame);
default: throw EngineException.ofSyntax("Invalid instruction " + instr.type.name() + "."); default: throw EngineException.ofSyntax("Invalid instruction " + instr.type.name() + ".");
} }

View File

@@ -0,0 +1,5 @@
package me.topchetoeu.jscript.runtime;
public class Key<T> {
}

View File

@@ -1,7 +1,7 @@
package me.topchetoeu.jscript.core; package me.topchetoeu.jscript.runtime;
import me.topchetoeu.jscript.core.values.FunctionValue; import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.runtime.values.ObjectValue;
public interface WrapperProvider { public interface WrapperProvider {
public ObjectValue getProto(Class<?> obj); public ObjectValue getProto(Class<?> obj);

View File

@@ -1,4 +1,4 @@
package me.topchetoeu.jscript.core.debug; package me.topchetoeu.jscript.runtime.debug;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@@ -10,13 +10,13 @@ import me.topchetoeu.jscript.common.FunctionBody;
import me.topchetoeu.jscript.common.Instruction; import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location; import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.mapping.FunctionMap; import me.topchetoeu.jscript.common.mapping.FunctionMap;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.core.Extensions; import me.topchetoeu.jscript.runtime.Extensions;
import me.topchetoeu.jscript.core.Frame; import me.topchetoeu.jscript.runtime.Frame;
import me.topchetoeu.jscript.core.Key; import me.topchetoeu.jscript.runtime.Key;
import me.topchetoeu.jscript.core.values.CodeFunction; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.core.values.FunctionValue; import me.topchetoeu.jscript.runtime.values.CodeFunction;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.FunctionValue;
public class DebugContext { public class DebugContext {
public static final Key<DebugContext> KEY = new Key<>(); public static final Key<DebugContext> KEY = new Key<>();
@@ -32,10 +32,17 @@ public class DebugContext {
if (sources != null) { if (sources != null) {
for (var source : sources.entrySet()) debugger.onSourceLoad(source.getKey(), source.getValue()); for (var source : sources.entrySet()) debugger.onSourceLoad(source.getKey(), source.getValue());
} }
if (maps != null) {
for (var map : maps.entrySet()) debugger.onFunctionLoad(map.getKey(), map.getValue());
}
this.debugger = debugger; this.debugger = debugger;
return true; return true;
} }
public boolean detachDebugger(DebugHandler debugger) {
if (this.debugger != debugger) return false;
return detachDebugger();
}
public boolean detachDebugger() { public boolean detachDebugger() {
this.debugger = null; this.debugger = null;
return true; return true;

View File

@@ -1,12 +1,12 @@
package me.topchetoeu.jscript.core.debug; package me.topchetoeu.jscript.runtime.debug;
import me.topchetoeu.jscript.common.Filename; import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.common.FunctionBody; import me.topchetoeu.jscript.common.FunctionBody;
import me.topchetoeu.jscript.common.Instruction; import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.mapping.FunctionMap; import me.topchetoeu.jscript.common.mapping.FunctionMap;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.core.Frame; import me.topchetoeu.jscript.runtime.Frame;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
public interface DebugHandler { public interface DebugHandler {
/** /**

View File

@@ -1,4 +1,4 @@
package me.topchetoeu.jscript.core.exceptions; package me.topchetoeu.jscript.runtime.exceptions;
public class ConvertException extends RuntimeException { public class ConvertException extends RuntimeException {
public final String source, target; public final String source, target;

View File

@@ -1,23 +1,24 @@
package me.topchetoeu.jscript.core.exceptions; package me.topchetoeu.jscript.runtime.exceptions;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import me.topchetoeu.jscript.common.Location; import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.core.Environment; import me.topchetoeu.jscript.runtime.Environment;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.runtime.Extensions;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.core.values.ObjectValue.PlaceholderProto; import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.runtime.values.ObjectValue.PlaceholderProto;
public class EngineException extends RuntimeException { public class EngineException extends RuntimeException {
public static class StackElement { public static class StackElement {
public final Location location; public final Location location;
public final String name; public final String name;
public final Context ctx; public final Extensions ext;
public boolean visible() { public boolean visible() {
return ctx == null || !ctx.get(Environment.HIDE_STACK, false); return ext == null || !ext.get(Environment.HIDE_STACK, false);
} }
public String toString() { public String toString() {
var res = ""; var res = "";
@@ -29,12 +30,13 @@ public class EngineException extends RuntimeException {
return res.trim(); return res.trim();
} }
public StackElement(Context ctx, Location location, String name) { public StackElement(Extensions ext, Location location, String name) {
if (name != null) name = name.trim(); if (name != null) name = name.trim();
if (name.equals("")) name = null; if (name.equals("")) name = null;
if (ctx == null) this.ctx = null; if (ext == null) this.ext = null;
else this.ctx = new Context(ctx.environment); else this.ext = Context.clean(ext);
this.location = location; this.location = location;
this.name = name; this.name = name;
} }
@@ -42,13 +44,13 @@ public class EngineException extends RuntimeException {
public final Object value; public final Object value;
public EngineException cause; public EngineException cause;
public Environment env = null; public Extensions ext = null;
public final List<StackElement> stackTrace = new ArrayList<>(); public final List<StackElement> stackTrace = new ArrayList<>();
public EngineException add(Context ctx, String name, Location location) { public EngineException add(Extensions ext, String name, Location location) {
var el = new StackElement(ctx, location, name); var el = new StackElement(ext, location, name);
if (el.name == null && el.location == null) return this; if (el.name == null && el.location == null) return this;
setCtx(ctx); setExtensions(ext);
stackTrace.add(el); stackTrace.add(el);
return this; return this;
} }
@@ -56,15 +58,15 @@ public class EngineException extends RuntimeException {
this.cause = cause; this.cause = cause;
return this; return this;
} }
public EngineException setCtx(Context ctx) { public EngineException setExtensions(Extensions ext) {
if (this.env == null) this.env = ctx.environment; if (this.ext == null) this.ext = Context.clean(ext);
return this; return this;
} }
public String toString(Context ctx) { public String toString(Extensions ext) {
var ss = new StringBuilder(); var ss = new StringBuilder();
try { try {
ss.append(Values.toString(ctx, value)).append('\n'); ss.append(Values.toString(ext, value)).append('\n');
} }
catch (EngineException e) { catch (EngineException e) {
ss.append("[Error while stringifying]\n"); ss.append("[Error while stringifying]\n");
@@ -72,7 +74,7 @@ public class EngineException extends RuntimeException {
for (var line : stackTrace) { for (var line : stackTrace) {
if (line.visible()) ss.append(" ").append(line.toString()).append("\n"); if (line.visible()) ss.append(" ").append(line.toString()).append("\n");
} }
if (cause != null) ss.append("Caused by ").append(cause.toString(ctx)).append('\n'); if (cause != null) ss.append("Caused by ").append(cause.toString(ext)).append('\n');
ss.deleteCharAt(ss.length() - 1); ss.deleteCharAt(ss.length() - 1);
return ss.toString(); return ss.toString();
} }

View File

@@ -1,4 +1,4 @@
package me.topchetoeu.jscript.core.exceptions; package me.topchetoeu.jscript.runtime.exceptions;
public class InterruptException extends RuntimeException { public class InterruptException extends RuntimeException {
public InterruptException() { } public InterruptException() { }

View File

@@ -1,4 +1,4 @@
package me.topchetoeu.jscript.core.exceptions; package me.topchetoeu.jscript.runtime.exceptions;
import me.topchetoeu.jscript.common.Location; import me.topchetoeu.jscript.common.Location;

View File

@@ -0,0 +1,81 @@
package me.topchetoeu.jscript.runtime.scope;
import java.util.HashSet;
import java.util.Set;
import me.topchetoeu.jscript.runtime.Extensions;
import me.topchetoeu.jscript.runtime.Key;
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.runtime.values.NativeFunction;
import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.runtime.values.Values;
public class GlobalScope {
public static final Key<GlobalScope> KEY = new Key<>();
public final ObjectValue obj;
public boolean has(Extensions ext, String name) {
return Values.hasMember(ext, obj, name, false);
}
public GlobalScope globalChild() {
var obj = new ObjectValue();
Values.setPrototype(null, obj, this.obj);
return new GlobalScope(obj);
}
public Object define(Extensions ext, String name) {
if (Values.hasMember(ext, obj, name, false)) return name;
obj.defineProperty(ext, name, null);
return name;
}
public void define(Extensions ext, String name, Variable val) {
obj.defineProperty(ext, name,
new NativeFunction("get " + name, args -> val.get(args.ctx)),
new NativeFunction("set " + name, args -> { val.set(args.ctx, args.get(0)); return null; }),
true, true
);
}
public void define(Extensions ext, String name, boolean readonly, Object val) {
obj.defineProperty(ext, name, val, readonly, true, true);
}
public void define(Extensions ext, String ...names) {
for (var n : names) define(ext, n);
}
public void define(Extensions ext, boolean readonly, FunctionValue val) {
define(ext, val.name, readonly, val);
}
public Object get(Extensions ext, String name) {
if (!Values.hasMember(ext, obj, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
else return Values.getMember(ext, obj, name);
}
public void set(Extensions ext, String name, Object val) {
if (!Values.hasMember(ext, obj, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
if (!Values.setMember(ext, obj, name, val)) throw EngineException.ofSyntax("The global '" + name + "' is readonly.");
}
public Set<String> keys() {
var res = new HashSet<String>();
for (var key : keys()) {
if (key instanceof String) res.add((String)key);
}
return res;
}
public GlobalScope() {
this.obj = new ObjectValue();
}
public GlobalScope(ObjectValue val) {
this.obj = val;
}
public static GlobalScope get(Extensions ext) {
if (ext.has(KEY)) return ext.get(KEY);
else return new GlobalScope();
}
}

View File

@@ -1,4 +1,4 @@
package me.topchetoeu.jscript.core.scope; package me.topchetoeu.jscript.runtime.scope;
import java.util.ArrayList; import java.util.ArrayList;

View File

@@ -1,7 +1,7 @@
package me.topchetoeu.jscript.core.scope; package me.topchetoeu.jscript.runtime.scope;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Extensions;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.values.Values;
public class ValueVariable implements Variable { public class ValueVariable implements Variable {
public boolean readonly; public boolean readonly;
@@ -11,14 +11,14 @@ public class ValueVariable implements Variable {
public boolean readonly() { return readonly; } public boolean readonly() { return readonly; }
@Override @Override
public Object get(Context ctx) { public Object get(Extensions ext) {
return value; return value;
} }
@Override @Override
public void set(Context ctx, Object val) { public void set(Extensions ext, Object val) {
if (readonly) return; if (readonly) return;
this.value = Values.normalize(ctx, val); this.value = Values.normalize(ext, val);
} }
public ValueVariable(boolean readonly, Object val) { public ValueVariable(boolean readonly, Object val) {

View File

@@ -0,0 +1,9 @@
package me.topchetoeu.jscript.runtime.scope;
import me.topchetoeu.jscript.runtime.Extensions;
public interface Variable {
Object get(Extensions ext);
default boolean readonly() { return true; }
default void set(Extensions ext, Object val) { }
}

View File

@@ -1,4 +1,4 @@
package me.topchetoeu.jscript.core.values; package me.topchetoeu.jscript.runtime.values;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@@ -6,7 +6,7 @@ import java.util.Comparator;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Extensions;
// TODO: Make methods generic // TODO: Make methods generic
public class ArrayValue extends ObjectValue implements Iterable<Object> { public class ArrayValue extends ObjectValue implements Iterable<Object> {
@@ -41,12 +41,12 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
if (res == UNDEFINED) return null; if (res == UNDEFINED) return null;
else return res; else return res;
} }
public void set(Context ctx, int i, Object val) { public void set(Extensions ext, int i, Object val) {
if (i < 0) return; if (i < 0) return;
values = alloc(i); values = alloc(i);
val = Values.normalize(ctx, val); val = Values.normalize(ext, val);
if (val == null) val = UNDEFINED; if (val == null) val = UNDEFINED;
values[i] = val; values[i] = val;
if (i >= size) size = i + 1; if (i >= size) size = i + 1;
@@ -99,9 +99,9 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
} }
} }
public void copyFrom(Context ctx, Object[] arr, int sourceStart, int destStart, int count) { public void copyFrom(Extensions ext, Object[] arr, int sourceStart, int destStart, int count) {
for (var i = 0; i < count; i++) { for (var i = 0; i < count; i++) {
set(ctx, i + destStart, arr[i + sourceStart]); set(ext, i + destStart, arr[i + sourceStart]);
} }
} }
@@ -131,7 +131,7 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
} }
@Override @Override
protected Object getField(Context ctx, Object key) { protected Object getField(Extensions ext, Object key) {
if (key instanceof Number) { if (key instanceof Number) {
var i = ((Number)key).doubleValue(); var i = ((Number)key).doubleValue();
if (i >= 0 && i - Math.floor(i) == 0) { if (i >= 0 && i - Math.floor(i) == 0) {
@@ -139,22 +139,22 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
} }
} }
return super.getField(ctx, key); return super.getField(ext, key);
} }
@Override @Override
protected boolean setField(Context ctx, Object key, Object val) { protected boolean setField(Extensions ext, Object key, Object val) {
if (key instanceof Number) { if (key instanceof Number) {
var i = Values.number(key); var i = Values.number(key);
if (i >= 0 && i - Math.floor(i) == 0) { if (i >= 0 && i - Math.floor(i) == 0) {
set(ctx, (int)i, val); set(ext, (int)i, val);
return true; return true;
} }
} }
return super.setField(ctx, key, val); return super.setField(ext, key, val);
} }
@Override @Override
protected boolean hasField(Context ctx, Object key) { protected boolean hasField(Extensions ext, Object key) {
if (key instanceof Number) { if (key instanceof Number) {
var i = Values.number(key); var i = Values.number(key);
if (i >= 0 && i - Math.floor(i) == 0) { if (i >= 0 && i - Math.floor(i) == 0) {
@@ -162,10 +162,10 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
} }
} }
return super.hasField(ctx, key); return super.hasField(ext, key);
} }
@Override @Override
protected void deleteField(Context ctx, Object key) { protected void deleteField(Extensions ext, Object key) {
if (key instanceof Number) { if (key instanceof Number) {
var i = Values.number(key); var i = Values.number(key);
if (i >= 0 && i - Math.floor(i) == 0) { if (i >= 0 && i - Math.floor(i) == 0) {
@@ -174,7 +174,7 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
} }
} }
super.deleteField(ctx, key); super.deleteField(ext, key);
} }
@Override @Override
@@ -213,15 +213,15 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
values = new Object[cap]; values = new Object[cap];
size = 0; size = 0;
} }
public ArrayValue(Context ctx, Object ...values) { public ArrayValue(Extensions ext, Object ...values) {
this(); this();
this.values = new Object[values.length]; this.values = new Object[values.length];
size = values.length; size = values.length;
for (var i = 0; i < size; i++) this.values[i] = Values.normalize(ctx, values[i]); for (var i = 0; i < size; i++) this.values[i] = Values.normalize(ext, values[i]);
} }
public static ArrayValue of(Context ctx, Collection<?> values) { public static ArrayValue of(Extensions ext, Collection<?> values) {
return new ArrayValue(ctx, values.toArray(Object[]::new)); return new ArrayValue(ext, values.toArray(Object[]::new));
} }
} }

View File

@@ -1,15 +1,15 @@
package me.topchetoeu.jscript.core.values; package me.topchetoeu.jscript.runtime.values;
import me.topchetoeu.jscript.common.FunctionBody; import me.topchetoeu.jscript.common.FunctionBody;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.core.Environment; import me.topchetoeu.jscript.runtime.Extensions;
import me.topchetoeu.jscript.core.Frame; import me.topchetoeu.jscript.runtime.Frame;
import me.topchetoeu.jscript.core.scope.ValueVariable; import me.topchetoeu.jscript.runtime.scope.ValueVariable;
public class CodeFunction extends FunctionValue { public class CodeFunction extends FunctionValue {
public final FunctionBody body; public final FunctionBody body;
public final ValueVariable[] captures; public final ValueVariable[] captures;
public Environment environment; public Extensions extensions;
// public Location loc() { // public Location loc() {
// for (var instr : body.instructions) { // for (var instr : body.instructions) {
@@ -25,8 +25,8 @@ public class CodeFunction extends FunctionValue {
// } // }
@Override @Override
public Object call(Context ctx, Object thisArg, Object ...args) { public Object call(Extensions ext, Object thisArg, Object ...args) {
var frame = new Frame(ctx, thisArg, args, this); var frame = new Frame(Context.of(ext), thisArg, args, this);
frame.onPush(); frame.onPush();
@@ -41,10 +41,10 @@ public class CodeFunction extends FunctionValue {
} }
} }
public CodeFunction(Environment environment, String name, FunctionBody body, ValueVariable[] captures) { public CodeFunction(Extensions extensions, String name, FunctionBody body, ValueVariable[] captures) {
super(name, body.argsN); super(name, body.argsN);
this.captures = captures; this.captures = captures;
this.environment = environment; this.extensions = Context.clean(extensions);
this.body = body; this.body = body;
} }
} }

View File

@@ -1,4 +1,4 @@
package me.topchetoeu.jscript.core.values; package me.topchetoeu.jscript.runtime.values;
public enum ConvertHint { public enum ConvertHint {
TOSTRING, TOSTRING,

View File

@@ -1,8 +1,8 @@
package me.topchetoeu.jscript.core.values; package me.topchetoeu.jscript.runtime.values;
import java.util.List; import java.util.List;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Extensions;
public abstract class FunctionValue extends ObjectValue { public abstract class FunctionValue extends ObjectValue {
public String name = ""; public String name = "";
@@ -13,29 +13,29 @@ public abstract class FunctionValue extends ObjectValue {
return String.format("function %s(...)", name); return String.format("function %s(...)", name);
} }
public abstract Object call(Context ctx, Object thisArg, Object ...args); public abstract Object call(Extensions ext, Object thisArg, Object ...args);
public Object call(Context ctx) { public Object call(Extensions ext) {
return call(ctx, null); return call(ext, null);
} }
@Override @Override
protected Object getField(Context ctx, Object key) { protected Object getField(Extensions ext, Object key) {
if ("name".equals(key)) return name; if ("name".equals(key)) return name;
if ("length".equals(key)) return length; if ("length".equals(key)) return length;
return super.getField(ctx, key); return super.getField(ext, key);
} }
@Override @Override
protected boolean setField(Context ctx, Object key, Object val) { protected boolean setField(Extensions ext, Object key, Object val) {
if ("name".equals(key)) name = Values.toString(ctx, val); if ("name".equals(key)) name = Values.toString(ext, val);
else if ("length".equals(key)) length = (int)Values.toNumber(ctx, val); else if ("length".equals(key)) length = (int)Values.toNumber(ext, val);
else return super.setField(ctx, key, val); else return super.setField(ext, key, val);
return true; return true;
} }
@Override @Override
protected boolean hasField(Context ctx, Object key) { protected boolean hasField(Extensions ext, Object key) {
if ("name".equals(key)) return true; if ("name".equals(key)) return true;
if ("length".equals(key)) return true; if ("length".equals(key)) return true;
return super.hasField(ctx, key); return super.hasField(ext, key);
} }
@Override @Override

View File

@@ -1,6 +1,7 @@
package me.topchetoeu.jscript.core.values; package me.topchetoeu.jscript.runtime.values;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.runtime.Extensions;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
public class NativeFunction extends FunctionValue { public class NativeFunction extends FunctionValue {
@@ -11,8 +12,8 @@ public class NativeFunction extends FunctionValue {
public final NativeFunctionRunner action; public final NativeFunctionRunner action;
@Override @Override
public Object call(Context ctx, Object thisArg, Object ...args) { public Object call(Extensions ext, Object thisArg, Object ...args) {
return action.run(new Arguments(ctx, thisArg, args)); return action.run(new Arguments(Context.of(ext), thisArg, args));
} }
public NativeFunction(String name, NativeFunctionRunner action) { public NativeFunction(String name, NativeFunctionRunner action) {

View File

@@ -0,0 +1,58 @@
package me.topchetoeu.jscript.runtime.values;
import java.util.WeakHashMap;
import me.topchetoeu.jscript.runtime.Extensions;
import me.topchetoeu.jscript.runtime.Key;
import me.topchetoeu.jscript.utils.interop.NativeWrapperProvider;
public class NativeWrapper extends ObjectValue {
private static final Key<WeakHashMap<Object, NativeWrapper>> WRAPPERS = new Key<>();
private static final Object NATIVE_PROTO = new Object();
public final Object wrapped;
@Override
public ObjectValue getPrototype(Extensions ext) {
if (ext != null && prototype == NATIVE_PROTO) {
var clazz = wrapped.getClass();
var res = NativeWrapperProvider.get(ext).getProto(clazz);
if (res != null) return res;
}
return super.getPrototype(ext);
}
@Override
public String toString() {
return wrapped.toString();
}
@Override
public boolean equals(Object obj) {
return wrapped.equals(obj);
}
@Override
public int hashCode() {
return wrapped.hashCode();
}
private NativeWrapper(Object wrapped) {
this.wrapped = wrapped;
prototype = NATIVE_PROTO;
}
public static NativeWrapper of(Extensions exts, Object wrapped) {
if (exts == null) return new NativeWrapper(wrapped);
var wrappers = exts.get(WRAPPERS);
if (wrappers == null) {
wrappers = new WeakHashMap<>();
exts.add(WRAPPERS, wrappers);
}
if (wrappers.containsKey(wrapped)) return wrappers.get(wrapped);
var res = new NativeWrapper(wrapped);
wrappers.put(wrapped, res);
return res;
}
}

View File

@@ -1,4 +1,4 @@
package me.topchetoeu.jscript.core.values; package me.topchetoeu.jscript.runtime.values;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@@ -6,8 +6,8 @@ import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Environment;
import me.topchetoeu.jscript.core.Environment; import me.topchetoeu.jscript.runtime.Extensions;
public class ObjectValue { public class ObjectValue {
public static enum PlaceholderProto { public static enum PlaceholderProto {
@@ -54,10 +54,10 @@ public class ObjectValue {
public LinkedHashSet<Object> nonConfigurableSet = new LinkedHashSet<>(); public LinkedHashSet<Object> nonConfigurableSet = new LinkedHashSet<>();
public LinkedHashSet<Object> nonEnumerableSet = new LinkedHashSet<>(); public LinkedHashSet<Object> nonEnumerableSet = new LinkedHashSet<>();
private Property getProperty(Context ctx, Object key) { private Property getProperty(Extensions ext, Object key) {
if (properties.containsKey(key)) return properties.get(key); if (properties.containsKey(key)) return properties.get(key);
var proto = getPrototype(ctx); var proto = getPrototype(ext);
if (proto != null) return proto.getProperty(ctx, key); if (proto != null) return proto.getProperty(ext, key);
else return null; else return null;
} }
@@ -86,8 +86,8 @@ public class ObjectValue {
state = State.FROZEN; state = State.FROZEN;
} }
public final boolean defineProperty(Context ctx, Object key, Object val, boolean writable, boolean configurable, boolean enumerable) { public final boolean defineProperty(Extensions ext, Object key, Object val, boolean writable, boolean configurable, boolean enumerable) {
key = Values.normalize(ctx, key); val = Values.normalize(ctx, val); key = Values.normalize(ext, key); val = Values.normalize(ext, val);
boolean reconfigured = boolean reconfigured =
writable != memberWritable(key) || writable != memberWritable(key) ||
configurable != memberConfigurable(key) || configurable != memberConfigurable(key) ||
@@ -125,11 +125,11 @@ public class ObjectValue {
values.put(key, val); values.put(key, val);
return true; return true;
} }
public final boolean defineProperty(Context ctx, Object key, Object val) { public final boolean defineProperty(Extensions ext, Object key, Object val) {
return defineProperty(ctx, key, val, true, true, true); return defineProperty(ext, key, val, true, true, true);
} }
public final boolean defineProperty(Context ctx, Object key, FunctionValue getter, FunctionValue setter, boolean configurable, boolean enumerable) { public final boolean defineProperty(Extensions ext, Object key, FunctionValue getter, FunctionValue setter, boolean configurable, boolean enumerable) {
key = Values.normalize(ctx, key); key = Values.normalize(ext, key);
if ( if (
properties.containsKey(key) && properties.containsKey(key) &&
properties.get(key).getter == getter && properties.get(key).getter == getter &&
@@ -152,19 +152,19 @@ public class ObjectValue {
return true; return true;
} }
public ObjectValue getPrototype(Context ctx) { public ObjectValue getPrototype(Extensions ext) {
if (prototype instanceof ObjectValue || prototype == null) return (ObjectValue)prototype;
try { try {
if (prototype == OBJ_PROTO) return ctx.get(Environment.OBJECT_PROTO); if (prototype == ARR_PROTO) return ext.get(Environment.ARRAY_PROTO);
if (prototype == ARR_PROTO) return ctx.get(Environment.ARRAY_PROTO); if (prototype == FUNC_PROTO) return ext.get(Environment.FUNCTION_PROTO);
if (prototype == FUNC_PROTO) return ctx.get(Environment.FUNCTION_PROTO); if (prototype == ERR_PROTO) return ext.get(Environment.ERROR_PROTO);
if (prototype == ERR_PROTO) return ctx.get(Environment.ERROR_PROTO); if (prototype == RANGE_ERR_PROTO) return ext.get(Environment.RANGE_ERR_PROTO);
if (prototype == RANGE_ERR_PROTO) return ctx.get(Environment.RANGE_ERR_PROTO); if (prototype == SYNTAX_ERR_PROTO) return ext.get(Environment.SYNTAX_ERR_PROTO);
if (prototype == SYNTAX_ERR_PROTO) return ctx.get(Environment.SYNTAX_ERR_PROTO); if (prototype == TYPE_ERR_PROTO) return ext.get(Environment.TYPE_ERR_PROTO);
if (prototype == TYPE_ERR_PROTO) return ctx.get(Environment.TYPE_ERR_PROTO); return ext.get(Environment.OBJECT_PROTO);
} }
catch (NullPointerException e) { return null; } catch (NullPointerException e) { return null; }
return (ObjectValue)prototype;
} }
public final boolean setPrototype(PlaceholderProto val) { public final boolean setPrototype(PlaceholderProto val) {
if (!extensible()) return false; if (!extensible()) return false;
@@ -185,10 +185,10 @@ public class ObjectValue {
* A method, used to get the value of a field. If a property is bound to * A method, used to get the value of a field. If a property is bound to
* this key, but not a field, this method should return null. * this key, but not a field, this method should return null.
*/ */
protected Object getField(Context ctx, Object key) { protected Object getField(Extensions ext, Object key) {
if (values.containsKey(key)) return values.get(key); if (values.containsKey(key)) return values.get(key);
var proto = getPrototype(ctx); var proto = getPrototype(ext);
if (proto != null) return proto.getField(ctx, key); if (proto != null) return proto.getField(ext, key);
else return null; else return null;
} }
/** /**
@@ -196,9 +196,9 @@ public class ObjectValue {
* bound to this key, a new field should be created with the given value * bound to this key, a new field should be created with the given value
* @return Whether or not the operation was successful * @return Whether or not the operation was successful
*/ */
protected boolean setField(Context ctx, Object key, Object val) { protected boolean setField(Extensions ext, Object key, Object val) {
if (val instanceof FunctionValue && ((FunctionValue)val).name.equals("")) { if (val instanceof FunctionValue && ((FunctionValue)val).name.equals("")) {
((FunctionValue)val).name = Values.toString(ctx, key); ((FunctionValue)val).name = Values.toString(ext, key);
} }
values.put(key, val); values.put(key, val);
@@ -207,40 +207,40 @@ public class ObjectValue {
/** /**
* Deletes the field bound to the given key. * Deletes the field bound to the given key.
*/ */
protected void deleteField(Context ctx, Object key) { protected void deleteField(Extensions ext, Object key) {
values.remove(key); values.remove(key);
} }
/** /**
* Returns whether or not there is a field bound to the given key. * Returns whether or not there is a field bound to the given key.
* This must ignore properties * This must ignore properties
*/ */
protected boolean hasField(Context ctx, Object key) { protected boolean hasField(Extensions ext, Object key) {
return values.containsKey(key); return values.containsKey(key);
} }
public final Object getMember(Context ctx, Object key, Object thisArg) { public final Object getMember(Extensions ext, Object key, Object thisArg) {
key = Values.normalize(ctx, key); key = Values.normalize(ext, key);
if ("__proto__".equals(key)) { if ("__proto__".equals(key)) {
var res = getPrototype(ctx); var res = getPrototype(ext);
return res == null ? Values.NULL : res; return res == null ? Values.NULL : res;
} }
var prop = getProperty(ctx, key); var prop = getProperty(ext, key);
if (prop != null) { if (prop != null) {
if (prop.getter == null) return null; if (prop.getter == null) return null;
else return prop.getter.call(ctx, Values.normalize(ctx, thisArg)); else return prop.getter.call(ext, Values.normalize(ext, thisArg));
} }
else return getField(ctx, key); else return getField(ext, key);
} }
public final boolean setMember(Context ctx, Object key, Object val, Object thisArg, boolean onlyProps) { public final boolean setMember(Extensions ext, Object key, Object val, Object thisArg, boolean onlyProps) {
key = Values.normalize(ctx, key); val = Values.normalize(ctx, val); key = Values.normalize(ext, key); val = Values.normalize(ext, val);
var prop = getProperty(ctx, key); var prop = getProperty(ext, key);
if (prop != null) { if (prop != null) {
if (prop.setter == null) return false; if (prop.setter == null) return false;
prop.setter.call(ctx, Values.normalize(ctx, thisArg), val); prop.setter.call(ext, Values.normalize(ext, thisArg), val);
return true; return true;
} }
else if (onlyProps) return false; else if (onlyProps) return false;
@@ -249,32 +249,32 @@ public class ObjectValue {
values.put(key, val); values.put(key, val);
return true; return true;
} }
else if ("__proto__".equals(key)) return setPrototype(ctx, val); else if ("__proto__".equals(key)) return setPrototype(ext, val);
else if (nonWritableSet.contains(key)) return false; else if (nonWritableSet.contains(key)) return false;
else return setField(ctx, key, val); else return setField(ext, key, val);
} }
public final boolean hasMember(Context ctx, Object key, boolean own) { public final boolean hasMember(Extensions ext, Object key, boolean own) {
key = Values.normalize(ctx, key); key = Values.normalize(ext, key);
if (key != null && "__proto__".equals(key)) return true; if (key != null && "__proto__".equals(key)) return true;
if (hasField(ctx, key)) return true; if (hasField(ext, key)) return true;
if (properties.containsKey(key)) return true; if (properties.containsKey(key)) return true;
if (own) return false; if (own) return false;
var proto = getPrototype(ctx); var proto = getPrototype(ext);
return proto != null && proto.hasMember(ctx, key, own); return proto != null && proto.hasMember(ext, key, own);
} }
public final boolean deleteMember(Context ctx, Object key) { public final boolean deleteMember(Extensions ext, Object key) {
key = Values.normalize(ctx, key); key = Values.normalize(ext, key);
if (!memberConfigurable(key)) return false; if (!memberConfigurable(key)) return false;
properties.remove(key); properties.remove(key);
nonWritableSet.remove(key); nonWritableSet.remove(key);
nonEnumerableSet.remove(key); nonEnumerableSet.remove(key);
deleteField(ctx, key); deleteField(ext, key);
return true; return true;
} }
public final boolean setPrototype(Context ctx, Object val) { public final boolean setPrototype(Extensions ext, Object val) {
val = Values.normalize(ctx, val); val = Values.normalize(ext, val);
if (!extensible()) return false; if (!extensible()) return false;
if (val == null || val == Values.NULL) { if (val == null || val == Values.NULL) {
@@ -284,14 +284,14 @@ public class ObjectValue {
else if (val instanceof ObjectValue) { else if (val instanceof ObjectValue) {
var obj = (ObjectValue)val; var obj = (ObjectValue)val;
if (ctx != null) { if (ext != null) {
if (obj == ctx.get(Environment.OBJECT_PROTO)) prototype = OBJ_PROTO; if (obj == ext.get(Environment.OBJECT_PROTO)) prototype = OBJ_PROTO;
else if (obj == ctx.get(Environment.ARRAY_PROTO)) prototype = ARR_PROTO; else if (obj == ext.get(Environment.ARRAY_PROTO)) prototype = ARR_PROTO;
else if (obj == ctx.get(Environment.FUNCTION_PROTO)) prototype = FUNC_PROTO; else if (obj == ext.get(Environment.FUNCTION_PROTO)) prototype = FUNC_PROTO;
else if (obj == ctx.get(Environment.ERROR_PROTO)) prototype = ERR_PROTO; else if (obj == ext.get(Environment.ERROR_PROTO)) prototype = ERR_PROTO;
else if (obj == ctx.get(Environment.SYNTAX_ERR_PROTO)) prototype = SYNTAX_ERR_PROTO; else if (obj == ext.get(Environment.SYNTAX_ERR_PROTO)) prototype = SYNTAX_ERR_PROTO;
else if (obj == ctx.get(Environment.TYPE_ERR_PROTO)) prototype = TYPE_ERR_PROTO; else if (obj == ext.get(Environment.TYPE_ERR_PROTO)) prototype = TYPE_ERR_PROTO;
else if (obj == ctx.get(Environment.RANGE_ERR_PROTO)) prototype = RANGE_ERR_PROTO; else if (obj == ext.get(Environment.RANGE_ERR_PROTO)) prototype = RANGE_ERR_PROTO;
else prototype = obj; else prototype = obj;
} }
else prototype = obj; else prototype = obj;
@@ -301,22 +301,22 @@ public class ObjectValue {
return false; return false;
} }
public final ObjectValue getMemberDescriptor(Context ctx, Object key) { public final ObjectValue getMemberDescriptor(Extensions ext, Object key) {
key = Values.normalize(ctx, key); key = Values.normalize(ext, key);
var prop = properties.get(key); var prop = properties.get(key);
var res = new ObjectValue(); var res = new ObjectValue();
res.defineProperty(ctx, "configurable", memberConfigurable(key)); res.defineProperty(ext, "configurable", memberConfigurable(key));
res.defineProperty(ctx, "enumerable", memberEnumerable(key)); res.defineProperty(ext, "enumerable", memberEnumerable(key));
if (prop != null) { if (prop != null) {
res.defineProperty(ctx, "get", prop.getter); res.defineProperty(ext, "get", prop.getter);
res.defineProperty(ctx, "set", prop.setter); res.defineProperty(ext, "set", prop.setter);
} }
else if (hasField(ctx, key)) { else if (hasField(ext, key)) {
res.defineProperty(ctx, "value", values.get(key)); res.defineProperty(ext, "value", values.get(key));
res.defineProperty(ctx, "writable", memberWritable(key)); res.defineProperty(ext, "writable", memberWritable(key));
} }
else return null; else return null;
return res; return res;
@@ -337,10 +337,10 @@ public class ObjectValue {
return res; return res;
} }
public ObjectValue(Context ctx, Map<?, ?> values) { public ObjectValue(Extensions ext, Map<?, ?> values) {
this(PlaceholderProto.OBJECT); this(PlaceholderProto.OBJECT);
for (var el : values.entrySet()) { for (var el : values.entrySet()) {
defineProperty(ctx, el.getKey(), el.getValue()); defineProperty(ext, el.getKey(), el.getValue());
} }
} }
public ObjectValue(PlaceholderProto proto) { public ObjectValue(PlaceholderProto proto) {

View File

@@ -1,41 +1,41 @@
package me.topchetoeu.jscript.core.values; package me.topchetoeu.jscript.runtime.values;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Extensions;
import me.topchetoeu.jscript.core.scope.ValueVariable; import me.topchetoeu.jscript.runtime.scope.ValueVariable;
public class ScopeValue extends ObjectValue { public class ScopeValue extends ObjectValue {
public final ValueVariable[] variables; public final ValueVariable[] variables;
public final HashMap<String, Integer> names = new HashMap<>(); public final HashMap<String, Integer> names = new HashMap<>();
@Override @Override
protected Object getField(Context ctx, Object key) { protected Object getField(Extensions ext, Object key) {
if (names.containsKey(key)) return variables[names.get(key)].get(ctx); if (names.containsKey(key)) return variables[names.get(key)].get(ext);
return super.getField(ctx, key); return super.getField(ext, key);
} }
@Override @Override
protected boolean setField(Context ctx, Object key, Object val) { protected boolean setField(Extensions ext, Object key, Object val) {
if (names.containsKey(key)) { if (names.containsKey(key)) {
variables[names.get(key)].set(ctx, val); variables[names.get(key)].set(ext, val);
return true; return true;
} }
var proto = getPrototype(ctx); var proto = getPrototype(ext);
if (proto != null && proto.hasMember(ctx, key, false) && proto.setField(ctx, key, val)) return true; if (proto != null && proto.hasMember(ext, key, false) && proto.setField(ext, key, val)) return true;
return super.setField(ctx, key, val); return super.setField(ext, key, val);
} }
@Override @Override
protected void deleteField(Context ctx, Object key) { protected void deleteField(Extensions ext, Object key) {
if (names.containsKey(key)) return; if (names.containsKey(key)) return;
super.deleteField(ctx, key); super.deleteField(ext, key);
} }
@Override @Override
protected boolean hasField(Context ctx, Object key) { protected boolean hasField(Extensions ext, Object key) {
if (names.containsKey(key)) return true; if (names.containsKey(key)) return true;
return super.hasField(ctx, key); return super.hasField(ext, key);
} }
@Override @Override
public List<Object> keys(boolean includeNonEnumerable) { public List<Object> keys(boolean includeNonEnumerable) {

View File

@@ -1,4 +1,4 @@
package me.topchetoeu.jscript.core.values; package me.topchetoeu.jscript.runtime.values;
import java.util.HashMap; import java.util.HashMap;

View File

@@ -1,4 +1,4 @@
package me.topchetoeu.jscript.core.values; package me.topchetoeu.jscript.runtime.values;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.PrintStream; import java.io.PrintStream;
@@ -13,13 +13,14 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import me.topchetoeu.jscript.common.Operation; import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.core.Context;
import me.topchetoeu.jscript.core.Environment;
import me.topchetoeu.jscript.core.debug.DebugContext;
import me.topchetoeu.jscript.core.exceptions.ConvertException;
import me.topchetoeu.jscript.core.exceptions.EngineException;
import me.topchetoeu.jscript.core.exceptions.SyntaxException;
import me.topchetoeu.jscript.lib.PromiseLib; import me.topchetoeu.jscript.lib.PromiseLib;
import me.topchetoeu.jscript.runtime.Environment;
import me.topchetoeu.jscript.runtime.Extensions;
import me.topchetoeu.jscript.runtime.debug.DebugContext;
import me.topchetoeu.jscript.runtime.exceptions.ConvertException;
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
import me.topchetoeu.jscript.utils.interop.NativeWrapperProvider;
public class Values { public class Values {
public static enum CompareResult { public static enum CompareResult {
@@ -58,9 +59,8 @@ public class Values {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T> T wrapper(Object val, Class<T> clazz) { public static <T> T wrapper(Object val, Class<T> clazz) {
if (!isWrapper(val)) val = new NativeWrapper(val); if (isWrapper(val)) val = ((NativeWrapper)val).wrapped;
var res = (NativeWrapper)val; if (val != null && clazz.isInstance(val)) return (T)val;
if (res != null && clazz.isInstance(res.wrapped)) return (T)res.wrapped;
else return null; else return null;
} }
@@ -74,11 +74,11 @@ public class Values {
return "object"; return "object";
} }
private static Object tryCallConvertFunc(Context ctx, Object obj, String name) { private static Object tryCallConvertFunc(Extensions ext, Object obj, String name) {
var func = getMember(ctx, obj, name); var func = getMember(ext, obj, name);
if (func instanceof FunctionValue) { if (func instanceof FunctionValue) {
var res = Values.call(ctx, func, obj); var res = Values.call(ext, func, obj);
if (isPrimitive(res)) return res; if (isPrimitive(res)) return res;
} }
@@ -95,16 +95,16 @@ public class Values {
obj == NULL; obj == NULL;
} }
public static Object toPrimitive(Context ctx, Object obj, ConvertHint hint) { public static Object toPrimitive(Extensions ext, Object obj, ConvertHint hint) {
obj = normalize(ctx, obj); obj = normalize(ext, obj);
if (isPrimitive(obj)) return obj; if (isPrimitive(obj)) return obj;
var first = hint == ConvertHint.VALUEOF ? "valueOf" : "toString"; var first = hint == ConvertHint.VALUEOF ? "valueOf" : "toString";
var second = hint == ConvertHint.VALUEOF ? "toString" : "valueOf"; var second = hint == ConvertHint.VALUEOF ? "toString" : "valueOf";
if (ctx != null) { if (ext != null) {
try { return tryCallConvertFunc(ctx, obj, first); } try { return tryCallConvertFunc(ext, obj, first); }
catch (EngineException unused) { return tryCallConvertFunc(ctx, obj, second); } catch (EngineException unused) { return tryCallConvertFunc(ext, obj, second); }
} }
throw EngineException.ofType("Value couldn't be converted to a primitive."); throw EngineException.ofType("Value couldn't be converted to a primitive.");
@@ -116,8 +116,8 @@ public class Values {
if (obj instanceof Boolean) return (Boolean)obj; if (obj instanceof Boolean) return (Boolean)obj;
return true; return true;
} }
public static double toNumber(Context ctx, Object obj) { public static double toNumber(Extensions ext, Object obj) {
var val = toPrimitive(ctx, obj, ConvertHint.VALUEOF); var val = toPrimitive(ext, obj, ConvertHint.VALUEOF);
if (val instanceof Number) return number(val); if (val instanceof Number) return number(val);
if (val instanceof Boolean) return ((Boolean)val) ? 1 : 0; if (val instanceof Boolean) return ((Boolean)val) ? 1 : 0;
@@ -127,8 +127,8 @@ public class Values {
} }
return Double.NaN; return Double.NaN;
} }
public static String toString(Context ctx, Object obj) { public static String toString(Extensions ext, Object obj) {
var val = toPrimitive(ctx, obj, ConvertHint.VALUEOF); var val = toPrimitive(ext, obj, ConvertHint.VALUEOF);
if (val == null) return "undefined"; if (val == null) return "undefined";
if (val == NULL) return "null"; if (val == NULL) return "null";
@@ -147,63 +147,63 @@ public class Values {
return "Unknown value"; return "Unknown value";
} }
public static Object add(Context ctx, Object a, Object b) { public static Object add(Extensions ext, Object a, Object b) {
if (a instanceof String || b instanceof String) return toString(ctx, a) + toString(ctx, b); if (a instanceof String || b instanceof String) return toString(ext, a) + toString(ext, b);
else return toNumber(ctx, a) + toNumber(ctx, b); else return toNumber(ext, a) + toNumber(ext, b);
} }
public static double subtract(Context ctx, Object a, Object b) { public static double subtract(Extensions ext, Object a, Object b) {
return toNumber(ctx, a) - toNumber(ctx, b); return toNumber(ext, a) - toNumber(ext, b);
} }
public static double multiply(Context ctx, Object a, Object b) { public static double multiply(Extensions ext, Object a, Object b) {
return toNumber(ctx, a) * toNumber(ctx, b); return toNumber(ext, a) * toNumber(ext, b);
} }
public static double divide(Context ctx, Object a, Object b) { public static double divide(Extensions ext, Object a, Object b) {
return toNumber(ctx, a) / toNumber(ctx, b); return toNumber(ext, a) / toNumber(ext, b);
} }
public static double modulo(Context ctx, Object a, Object b) { public static double modulo(Extensions ext, Object a, Object b) {
return toNumber(ctx, a) % toNumber(ctx, b); return toNumber(ext, a) % toNumber(ext, b);
} }
public static double negative(Context ctx, Object obj) { public static double negative(Extensions ext, Object obj) {
return -toNumber(ctx, obj); return -toNumber(ext, obj);
} }
public static int and(Context ctx, Object a, Object b) { public static int and(Extensions ext, Object a, Object b) {
return (int)toNumber(ctx, a) & (int)toNumber(ctx, b); return (int)toNumber(ext, a) & (int)toNumber(ext, b);
} }
public static int or(Context ctx, Object a, Object b) { public static int or(Extensions ext, Object a, Object b) {
return (int)toNumber(ctx, a) | (int)toNumber(ctx, b); return (int)toNumber(ext, a) | (int)toNumber(ext, b);
} }
public static int xor(Context ctx, Object a, Object b) { public static int xor(Extensions ext, Object a, Object b) {
return (int)toNumber(ctx, a) ^ (int)toNumber(ctx, b); return (int)toNumber(ext, a) ^ (int)toNumber(ext, b);
} }
public static int bitwiseNot(Context ctx, Object obj) { public static int bitwiseNot(Extensions ext, Object obj) {
return ~(int)toNumber(ctx, obj); return ~(int)toNumber(ext, obj);
} }
public static int shiftLeft(Context ctx, Object a, Object b) { public static int shiftLeft(Extensions ext, Object a, Object b) {
return (int)toNumber(ctx, a) << (int)toNumber(ctx, b); return (int)toNumber(ext, a) << (int)toNumber(ext, b);
} }
public static int shiftRight(Context ctx, Object a, Object b) { public static int shiftRight(Extensions ext, Object a, Object b) {
return (int)toNumber(ctx, a) >> (int)toNumber(ctx, b); return (int)toNumber(ext, a) >> (int)toNumber(ext, b);
} }
public static long unsignedShiftRight(Context ctx, Object a, Object b) { public static long unsignedShiftRight(Extensions ext, Object a, Object b) {
long _a = (long)toNumber(ctx, a); long _a = (long)toNumber(ext, a);
long _b = (long)toNumber(ctx, b); long _b = (long)toNumber(ext, b);
if (_a < 0) _a += 0x100000000l; if (_a < 0) _a += 0x100000000l;
if (_b < 0) _b += 0x100000000l; if (_b < 0) _b += 0x100000000l;
return _a >>> _b; return _a >>> _b;
} }
public static CompareResult compare(Context ctx, Object a, Object b) { public static CompareResult compare(Extensions ext, Object a, Object b) {
a = toPrimitive(ctx, a, ConvertHint.VALUEOF); a = toPrimitive(ext, a, ConvertHint.VALUEOF);
b = toPrimitive(ctx, b, ConvertHint.VALUEOF); b = toPrimitive(ext, b, ConvertHint.VALUEOF);
if (a instanceof String && b instanceof String) CompareResult.from(((String)a).compareTo((String)b)); if (a instanceof String && b instanceof String) CompareResult.from(((String)a).compareTo((String)b));
var _a = toNumber(ctx, a); var _a = toNumber(ext, a);
var _b = toNumber(ctx, b); var _b = toNumber(ext, b);
if (Double.isNaN(_a) || Double.isNaN(_b)) return CompareResult.NOT_EQUAL; if (Double.isNaN(_a) || Double.isNaN(_b)) return CompareResult.NOT_EQUAL;
@@ -214,60 +214,60 @@ public class Values {
return !toBoolean(obj); return !toBoolean(obj);
} }
public static boolean isInstanceOf(Context ctx, Object obj, Object proto) { public static boolean isInstanceOf(Extensions ext, Object obj, Object proto) {
if (obj == null || obj == NULL || proto == null || proto == NULL) return false; if (obj == null || obj == NULL || proto == null || proto == NULL) return false;
var val = getPrototype(ctx, obj); var val = getPrototype(ext, obj);
while (val != null) { while (val != null) {
if (val.equals(proto)) return true; if (val.equals(proto)) return true;
val = val.getPrototype(ctx); val = val.getPrototype(ext);
} }
return false; return false;
} }
public static Object operation(Context ctx, Operation op, Object ...args) { public static Object operation(Extensions ext, Operation op, Object ...args) {
switch (op) { switch (op) {
case ADD: return add(ctx, args[0], args[1]); case ADD: return add(ext, args[0], args[1]);
case SUBTRACT: return subtract(ctx, args[0], args[1]); case SUBTRACT: return subtract(ext, args[0], args[1]);
case DIVIDE: return divide(ctx, args[0], args[1]); case DIVIDE: return divide(ext, args[0], args[1]);
case MULTIPLY: return multiply(ctx, args[0], args[1]); case MULTIPLY: return multiply(ext, args[0], args[1]);
case MODULO: return modulo(ctx, args[0], args[1]); case MODULO: return modulo(ext, args[0], args[1]);
case AND: return and(ctx, args[0], args[1]); case AND: return and(ext, args[0], args[1]);
case OR: return or(ctx, args[0], args[1]); case OR: return or(ext, args[0], args[1]);
case XOR: return xor(ctx, args[0], args[1]); case XOR: return xor(ext, args[0], args[1]);
case EQUALS: return strictEquals(ctx, args[0], args[1]); case EQUALS: return strictEquals(ext, args[0], args[1]);
case NOT_EQUALS: return !strictEquals(ctx, args[0], args[1]); case NOT_EQUALS: return !strictEquals(ext, args[0], args[1]);
case LOOSE_EQUALS: return looseEqual(ctx, args[0], args[1]); case LOOSE_EQUALS: return looseEqual(ext, args[0], args[1]);
case LOOSE_NOT_EQUALS: return !looseEqual(ctx, args[0], args[1]); case LOOSE_NOT_EQUALS: return !looseEqual(ext, args[0], args[1]);
case GREATER: return compare(ctx, args[0], args[1]).greater(); case GREATER: return compare(ext, args[0], args[1]).greater();
case GREATER_EQUALS: return compare(ctx, args[0], args[1]).greaterOrEqual(); case GREATER_EQUALS: return compare(ext, args[0], args[1]).greaterOrEqual();
case LESS: return compare(ctx, args[0], args[1]).less(); case LESS: return compare(ext, args[0], args[1]).less();
case LESS_EQUALS: return compare(ctx, args[0], args[1]).lessOrEqual(); case LESS_EQUALS: return compare(ext, args[0], args[1]).lessOrEqual();
case INVERSE: return bitwiseNot(ctx, args[0]); case INVERSE: return bitwiseNot(ext, args[0]);
case NOT: return not(args[0]); case NOT: return not(args[0]);
case POS: return toNumber(ctx, args[0]); case POS: return toNumber(ext, args[0]);
case NEG: return negative(ctx, args[0]); case NEG: return negative(ext, args[0]);
case SHIFT_LEFT: return shiftLeft(ctx, args[0], args[1]); case SHIFT_LEFT: return shiftLeft(ext, args[0], args[1]);
case SHIFT_RIGHT: return shiftRight(ctx, args[0], args[1]); case SHIFT_RIGHT: return shiftRight(ext, args[0], args[1]);
case USHIFT_RIGHT: return unsignedShiftRight(ctx, args[0], args[1]); case USHIFT_RIGHT: return unsignedShiftRight(ext, args[0], args[1]);
case IN: return hasMember(ctx, args[1], args[0], false); case IN: return hasMember(ext, args[1], args[0], false);
case INSTANCEOF: { case INSTANCEOF: {
var proto = getMember(ctx, args[1], "prototype"); var proto = getMember(ext, args[1], "prototype");
return isInstanceOf(ctx, args[0], proto); return isInstanceOf(ext, args[0], proto);
} }
default: return null; default: return null;
} }
} }
public static Object getMember(Context ctx, Object obj, Object key) { public static Object getMember(Extensions ctx, Object obj, Object key) {
obj = normalize(ctx, obj); key = normalize(ctx, key); obj = normalize(ctx, obj); key = normalize(ctx, key);
if (obj == null) throw new IllegalArgumentException("Tried to access member of undefined."); if (obj == null) throw new IllegalArgumentException("Tried to access member of undefined.");
if (obj == NULL) throw new IllegalArgumentException("Tried to access member of null."); if (obj == NULL) throw new IllegalArgumentException("Tried to access member of null.");
@@ -287,12 +287,12 @@ public class Values {
else if (key != null && "__proto__".equals(key)) return proto; else if (key != null && "__proto__".equals(key)) return proto;
else return proto.getMember(ctx, key, obj); else return proto.getMember(ctx, key, obj);
} }
public static Object getMemberPath(Context ctx, Object obj, Object ...path) { public static Object getMemberPath(Extensions ctx, Object obj, Object ...path) {
var res = obj; var res = obj;
for (var key : path) res = getMember(ctx, res, key); for (var key : path) res = getMember(ctx, res, key);
return res; return res;
} }
public static boolean setMember(Context ctx, Object obj, Object key, Object val) { public static boolean setMember(Extensions ctx, Object obj, Object key, Object val) {
obj = normalize(ctx, obj); key = normalize(ctx, key); val = normalize(ctx, val); obj = normalize(ctx, obj); key = normalize(ctx, key); val = normalize(ctx, val);
if (obj == null) throw EngineException.ofType("Tried to access member of undefined."); if (obj == null) throw EngineException.ofType("Tried to access member of undefined.");
if (obj == NULL) throw EngineException.ofType("Tried to access member of null."); if (obj == NULL) throw EngineException.ofType("Tried to access member of null.");
@@ -302,7 +302,7 @@ public class Values {
var proto = getPrototype(ctx, obj); var proto = getPrototype(ctx, obj);
return proto.setMember(ctx, key, val, obj, true); return proto.setMember(ctx, key, val, obj, true);
} }
public static boolean hasMember(Context ctx, Object obj, Object key, boolean own) { public static boolean hasMember(Extensions ctx, Object obj, Object key, boolean own) {
if (obj == null || obj == NULL) return false; if (obj == null || obj == NULL) return false;
obj = normalize(ctx, obj); key = normalize(ctx, key); obj = normalize(ctx, obj); key = normalize(ctx, key);
@@ -320,36 +320,36 @@ public class Values {
var proto = getPrototype(ctx, obj); var proto = getPrototype(ctx, obj);
return proto != null && proto.hasMember(ctx, key, own); return proto != null && proto.hasMember(ctx, key, own);
} }
public static boolean deleteMember(Context ctx, Object obj, Object key) { public static boolean deleteMember(Extensions ext, Object obj, Object key) {
if (obj == null || obj == NULL) return false; if (obj == null || obj == NULL) return false;
obj = normalize(ctx, obj); key = normalize(ctx, key); obj = normalize(ext, obj); key = normalize(ext, key);
if (obj instanceof ObjectValue) return ((ObjectValue)obj).deleteMember(ctx, key); if (obj instanceof ObjectValue) return ((ObjectValue)obj).deleteMember(ext, key);
else return false; else return false;
} }
public static ObjectValue getPrototype(Context ctx, Object obj) { public static ObjectValue getPrototype(Extensions ext, Object obj) {
if (obj == null || obj == NULL) return null; if (obj == null || obj == NULL) return null;
obj = normalize(ctx, obj); obj = normalize(ext, obj);
if (obj instanceof ObjectValue) return ((ObjectValue)obj).getPrototype(ctx); if (obj instanceof ObjectValue) return ((ObjectValue)obj).getPrototype(ext);
if (ctx == null) return null; if (ext == null) return null;
if (obj instanceof String) return ctx.get(Environment.STRING_PROTO); if (obj instanceof String) return ext.get(Environment.STRING_PROTO);
else if (obj instanceof Number) return ctx.get(Environment.NUMBER_PROTO); else if (obj instanceof Number) return ext.get(Environment.NUMBER_PROTO);
else if (obj instanceof Boolean) return ctx.get(Environment.BOOL_PROTO); else if (obj instanceof Boolean) return ext.get(Environment.BOOL_PROTO);
else if (obj instanceof Symbol) return ctx.get(Environment.SYMBOL_PROTO); else if (obj instanceof Symbol) return ext.get(Environment.SYMBOL_PROTO);
return null; return null;
} }
public static boolean setPrototype(Context ctx, Object obj, Object proto) { public static boolean setPrototype(Extensions ext, Object obj, Object proto) {
obj = normalize(ctx, obj); obj = normalize(ext, obj);
return obj instanceof ObjectValue && ((ObjectValue)obj).setPrototype(ctx, proto); return obj instanceof ObjectValue && ((ObjectValue)obj).setPrototype(ext, proto);
} }
public static void makePrototypeChain(Context ctx, Object... chain) { public static void makePrototypeChain(Extensions ext, Object... chain) {
for(var i = 1; i < chain.length; i++) { for(var i = 1; i < chain.length; i++) {
setPrototype(ctx, chain[i], chain[i - 1]); setPrototype(ext, chain[i], chain[i - 1]);
} }
} }
public static List<Object> getMembers(Context ctx, Object obj, boolean own, boolean includeNonEnumerable) { public static List<Object> getMembers(Extensions ext, Object obj, boolean own, boolean includeNonEnumerable) {
List<Object> res = new ArrayList<>(); List<Object> res = new ArrayList<>();
if (obj instanceof ObjectValue) res = ((ObjectValue)obj).keys(includeNonEnumerable); if (obj instanceof ObjectValue) res = ((ObjectValue)obj).keys(includeNonEnumerable);
@@ -358,26 +358,26 @@ public class Values {
} }
if (!own) { if (!own) {
var proto = getPrototype(ctx, obj); var proto = getPrototype(ext, obj);
while (proto != null) { while (proto != null) {
res.addAll(proto.keys(includeNonEnumerable)); res.addAll(proto.keys(includeNonEnumerable));
proto = getPrototype(ctx, proto); proto = getPrototype(ext, proto);
} }
} }
return res; return res;
} }
public static ObjectValue getMemberDescriptor(Context ctx, Object obj, Object key) { public static ObjectValue getMemberDescriptor(Extensions ext, Object obj, Object key) {
if (obj instanceof ObjectValue) return ((ObjectValue)obj).getMemberDescriptor(ctx, key); if (obj instanceof ObjectValue) return ((ObjectValue)obj).getMemberDescriptor(ext, key);
else if (obj instanceof String && key instanceof Number) { else if (obj instanceof String && key instanceof Number) {
var i = ((Number)key).intValue(); var i = ((Number)key).intValue();
var _i = ((Number)key).doubleValue(); var _i = ((Number)key).doubleValue();
if (i - _i != 0) return null; if (i - _i != 0) return null;
if (i < 0 || i >= ((String)obj).length()) return null; if (i < 0 || i >= ((String)obj).length()) return null;
return new ObjectValue(ctx, Map.of( return new ObjectValue(ext, Map.of(
"value", ((String)obj).charAt(i) + "", "value", ((String)obj).charAt(i) + "",
"writable", false, "writable", false,
"enumerable", true, "enumerable", true,
@@ -387,17 +387,17 @@ public class Values {
else return null; else return null;
} }
public static Object call(Context ctx, Object func, Object thisArg, Object ...args) { public static Object call(Extensions ext, Object func, Object thisArg, Object ...args) {
if (!(func instanceof FunctionValue)) throw EngineException.ofType("Tried to call a non-function value."); if (!(func instanceof FunctionValue)) throw EngineException.ofType("Tried to call a non-function value.");
return ((FunctionValue)func).call(ctx, thisArg, args); return ((FunctionValue)func).call(ext, thisArg, args);
} }
public static Object callNew(Context ctx, Object func, Object ...args) { public static Object callNew(Extensions ext, Object func, Object ...args) {
var res = new ObjectValue(); var res = new ObjectValue();
try { try {
var proto = Values.getMember(ctx, func, "prototype"); var proto = Values.getMember(ext, func, "prototype");
setPrototype(ctx, res, proto); setPrototype(ext, res, proto);
var ret = call(ctx, func, res, args); var ret = call(ext, func, res, args);
if (!isPrimitive(ret)) return ret; if (!isPrimitive(ret)) return ret;
return res; return res;
@@ -407,8 +407,9 @@ public class Values {
} }
} }
public static boolean strictEquals(Context ctx, Object a, Object b) { public static boolean strictEquals(Extensions ext, Object a, Object b) {
a = normalize(ctx, a); b = normalize(ctx, b); a = normalize(ext, a);
b = normalize(ext, b);
if (a == null || b == null) return a == null && b == null; if (a == null || b == null) return a == null && b == null;
if (isNan(a) || isNan(b)) return false; if (isNan(a) || isNan(b)) return false;
@@ -417,8 +418,8 @@ public class Values {
return a == b || a.equals(b); return a == b || a.equals(b);
} }
public static boolean looseEqual(Context ctx, Object a, Object b) { public static boolean looseEqual(Extensions ext, Object a, Object b) {
a = normalize(ctx, a); b = normalize(ctx, b); a = normalize(ext, a); b = normalize(ext, b);
// In loose equality, null is equivalent to undefined // In loose equality, null is equivalent to undefined
if (a == NULL) a = null; if (a == NULL) a = null;
@@ -429,19 +430,19 @@ public class Values {
if (!isPrimitive(a) && !isPrimitive(b)) return a == b; if (!isPrimitive(a) && !isPrimitive(b)) return a == b;
// Convert values to primitives // Convert values to primitives
a = toPrimitive(ctx, a, ConvertHint.VALUEOF); a = toPrimitive(ext, a, ConvertHint.VALUEOF);
b = toPrimitive(ctx, b, ConvertHint.VALUEOF); b = toPrimitive(ext, b, ConvertHint.VALUEOF);
// Compare symbols by reference // Compare symbols by reference
if (a instanceof Symbol || b instanceof Symbol) return a == b; if (a instanceof Symbol || b instanceof Symbol) return a == b;
if (a instanceof Boolean || b instanceof Boolean) return toBoolean(a) == toBoolean(b); if (a instanceof Boolean || b instanceof Boolean) return toBoolean(a) == toBoolean(b);
if (a instanceof Number || b instanceof Number) return strictEquals(ctx, toNumber(ctx, a), toNumber(ctx, b)); if (a instanceof Number || b instanceof Number) return strictEquals(ext, toNumber(ext, a), toNumber(ext, b));
// Default to strings // Default to strings
return toString(ctx, a).equals(toString(ctx, b)); return toString(ext, a).equals(toString(ext, b));
} }
public static Object normalize(Context ctx, Object val) { public static Object normalize(Extensions ext, Object val) {
if (val instanceof Number) return number(val); if (val instanceof Number) return number(val);
if (isPrimitive(val) || val instanceof ObjectValue) return val; if (isPrimitive(val) || val instanceof ObjectValue) return val;
if (val instanceof Character) return val + ""; if (val instanceof Character) return val + "";
@@ -450,7 +451,7 @@ public class Values {
var res = new ObjectValue(); var res = new ObjectValue();
for (var entry : ((Map<?, ?>)val).entrySet()) { for (var entry : ((Map<?, ?>)val).entrySet()) {
res.defineProperty(ctx, entry.getKey(), entry.getValue()); res.defineProperty(ext, entry.getKey(), entry.getValue());
} }
return res; return res;
@@ -460,22 +461,22 @@ public class Values {
var res = new ArrayValue(); var res = new ArrayValue();
for (var entry : ((Iterable<?>)val)) { for (var entry : ((Iterable<?>)val)) {
res.set(ctx, res.size(), entry); res.set(ext, res.size(), entry);
} }
return res; return res;
} }
if (val instanceof Class) { if (val instanceof Class) {
if (ctx == null) return null; if (ext == null) return null;
else return ctx.environment.wrappers.getConstr((Class<?>)val); else return NativeWrapperProvider.get(ext).getConstr((Class<?>)val);
} }
return new NativeWrapper(val); return NativeWrapper.of(ext, val);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T> T convert(Context ctx, Object obj, Class<T> clazz) { public static <T> T convert(Extensions ext, Object obj, Class<T> clazz) {
if (clazz == Void.class) return null; if (clazz == Void.class) return null;
if (obj instanceof NativeWrapper) { if (obj instanceof NativeWrapper) {
@@ -489,19 +490,19 @@ public class Values {
if (clazz.isAssignableFrom(ArrayList.class)) { if (clazz.isAssignableFrom(ArrayList.class)) {
var raw = ((ArrayValue)obj).toArray(); var raw = ((ArrayValue)obj).toArray();
var res = new ArrayList<>(); var res = new ArrayList<>();
for (var i = 0; i < raw.length; i++) res.add(convert(ctx, raw[i], Object.class)); for (var i = 0; i < raw.length; i++) res.add(convert(ext, raw[i], Object.class));
return (T)new ArrayList<>(res); return (T)new ArrayList<>(res);
} }
if (clazz.isAssignableFrom(HashSet.class)) { if (clazz.isAssignableFrom(HashSet.class)) {
var raw = ((ArrayValue)obj).toArray(); var raw = ((ArrayValue)obj).toArray();
var res = new HashSet<>(); var res = new HashSet<>();
for (var i = 0; i < raw.length; i++) res.add(convert(ctx, raw[i], Object.class)); for (var i = 0; i < raw.length; i++) res.add(convert(ext, raw[i], Object.class));
return (T)new HashSet<>(res); return (T)new HashSet<>(res);
} }
if (clazz.isArray()) { if (clazz.isArray()) {
var raw = ((ArrayValue)obj).toArray(); var raw = ((ArrayValue)obj).toArray();
Object res = Array.newInstance(clazz.getComponentType(), raw.length); Object res = Array.newInstance(clazz.getComponentType(), raw.length);
for (var i = 0; i < raw.length; i++) Array.set(res, i, convert(ctx, raw[i], Object.class)); for (var i = 0; i < raw.length; i++) Array.set(res, i, convert(ext, raw[i], Object.class));
return (T)res; return (T)res;
} }
} }
@@ -509,25 +510,25 @@ public class Values {
if (obj instanceof ObjectValue && clazz.isAssignableFrom(HashMap.class)) { if (obj instanceof ObjectValue && clazz.isAssignableFrom(HashMap.class)) {
var res = new HashMap<>(); var res = new HashMap<>();
for (var el : ((ObjectValue)obj).values.entrySet()) res.put( for (var el : ((ObjectValue)obj).values.entrySet()) res.put(
convert(ctx, el.getKey(), null), convert(ext, el.getKey(), null),
convert(ctx, el.getValue(), null) convert(ext, el.getValue(), null)
); );
return (T)res; return (T)res;
} }
if (clazz == String.class) return (T)toString(ctx, obj); if (clazz == String.class) return (T)toString(ext, obj);
if (clazz == Boolean.class || clazz == Boolean.TYPE) return (T)(Boolean)toBoolean(obj); if (clazz == Boolean.class || clazz == Boolean.TYPE) return (T)(Boolean)toBoolean(obj);
if (clazz == Byte.class || clazz == byte.class) return (T)(Byte)(byte)toNumber(ctx, obj); if (clazz == Byte.class || clazz == byte.class) return (T)(Byte)(byte)toNumber(ext, obj);
if (clazz == Integer.class || clazz == int.class) return (T)(Integer)(int)toNumber(ctx, obj); if (clazz == Integer.class || clazz == int.class) return (T)(Integer)(int)toNumber(ext, obj);
if (clazz == Long.class || clazz == long.class) return (T)(Long)(long)toNumber(ctx, obj); if (clazz == Long.class || clazz == long.class) return (T)(Long)(long)toNumber(ext, obj);
if (clazz == Short.class || clazz == short.class) return (T)(Short)(short)toNumber(ctx, obj); if (clazz == Short.class || clazz == short.class) return (T)(Short)(short)toNumber(ext, obj);
if (clazz == Float.class || clazz == float.class) return (T)(Float)(float)toNumber(ctx, obj); if (clazz == Float.class || clazz == float.class) return (T)(Float)(float)toNumber(ext, obj);
if (clazz == Double.class || clazz == double.class) return (T)(Double)toNumber(ctx, obj); if (clazz == Double.class || clazz == double.class) return (T)(Double)toNumber(ext, obj);
if (clazz == Character.class || clazz == char.class) { if (clazz == Character.class || clazz == char.class) {
if (obj instanceof Number) return (T)(Character)(char)number(obj); if (obj instanceof Number) return (T)(Character)(char)number(obj);
else { else {
var res = toString(ctx, obj); var res = toString(ext, obj);
if (res.length() == 0) throw new ConvertException("\"\"", "Character"); if (res.length() == 0) throw new ConvertException("\"\"", "Character");
else return (T)(Character)res.charAt(0); else return (T)(Character)res.charAt(0);
} }
@@ -536,23 +537,23 @@ public class Values {
if (obj == null) return null; if (obj == null) return null;
if (clazz.isInstance(obj)) return (T)obj; if (clazz.isInstance(obj)) return (T)obj;
if (clazz.isAssignableFrom(NativeWrapper.class)) { if (clazz.isAssignableFrom(NativeWrapper.class)) {
return (T)new NativeWrapper(obj); return (T)NativeWrapper.of(ext, obj);
} }
throw new ConvertException(type(obj), clazz.getSimpleName()); throw new ConvertException(type(obj), clazz.getSimpleName());
} }
public static Iterable<Object> fromJSIterator(Context ctx, Object obj) { public static Iterable<Object> fromJSIterator(Extensions ext, Object obj) {
return () -> { return () -> {
try { try {
var symbol = Symbol.get("Symbol.iterator"); var symbol = Symbol.get("Symbol.iterator");
var iteratorFunc = getMember(ctx, obj, symbol); var iteratorFunc = getMember(ext, obj, symbol);
if (!(iteratorFunc instanceof FunctionValue)) return Collections.emptyIterator(); if (!(iteratorFunc instanceof FunctionValue)) return Collections.emptyIterator();
var iterator = iteratorFunc instanceof FunctionValue ? var iterator = iteratorFunc instanceof FunctionValue ?
((FunctionValue)iteratorFunc).call(ctx, obj, obj) : ((FunctionValue)iteratorFunc).call(ext, obj, obj) :
iteratorFunc; iteratorFunc;
var nextFunc = getMember(ctx, call(ctx, iteratorFunc, obj), "next"); var nextFunc = getMember(ext, call(ext, iteratorFunc, obj), "next");
if (!(nextFunc instanceof FunctionValue)) return Collections.emptyIterator(); if (!(nextFunc instanceof FunctionValue)) return Collections.emptyIterator();
@@ -564,11 +565,11 @@ public class Values {
private void loadNext() { private void loadNext() {
if (next == null) value = null; if (next == null) value = null;
else if (consumed) { else if (consumed) {
var curr = next.call(ctx, iterator); var curr = next.call(ext, iterator);
if (curr == null) { next = null; value = null; } if (curr == null) { next = null; value = null; }
if (toBoolean(Values.getMember(ctx, curr, "done"))) { next = null; value = null; } if (toBoolean(Values.getMember(ext, curr, "done"))) { next = null; value = null; }
else { else {
this.value = Values.getMember(ctx, curr, "value"); this.value = Values.getMember(ext, curr, "value");
consumed = false; consumed = false;
} }
} }
@@ -595,17 +596,17 @@ public class Values {
}; };
} }
public static ObjectValue toJSIterator(Context ctx, Iterator<?> it) { public static ObjectValue toJSIterator(Extensions ext, Iterator<?> it) {
var res = new ObjectValue(); var res = new ObjectValue();
try { try {
var key = getMember(ctx, getMember(ctx, ctx.get(Environment.SYMBOL_PROTO), "constructor"), "iterator"); var key = getMember(ext, getMember(ext, ext.get(Environment.SYMBOL_PROTO), "constructor"), "iterator");
res.defineProperty(ctx, key, new NativeFunction("", args -> args.self)); res.defineProperty(ext, key, new NativeFunction("", args -> args.self));
} }
catch (IllegalArgumentException | NullPointerException e) { } catch (IllegalArgumentException | NullPointerException e) { }
res.defineProperty(ctx, "next", new NativeFunction("", args -> { res.defineProperty(ext, "next", new NativeFunction("", args -> {
if (!it.hasNext()) return new ObjectValue(ctx, Map.of("done", true)); if (!it.hasNext()) return new ObjectValue(ext, Map.of("done", true));
else { else {
var obj = new ObjectValue(); var obj = new ObjectValue();
obj.defineProperty(args.ctx, "value", it.next()); obj.defineProperty(args.ctx, "value", it.next());
@@ -616,22 +617,22 @@ public class Values {
return res; return res;
} }
public static ObjectValue toJSIterator(Context ctx, Iterable<?> it) { public static ObjectValue toJSIterator(Extensions ext, Iterable<?> it) {
return toJSIterator(ctx, it.iterator()); return toJSIterator(ext, it.iterator());
} }
public static ObjectValue toJSAsyncIterator(Context ctx, Iterator<?> it) { public static ObjectValue toJSAsyncIterator(Extensions ext, Iterator<?> it) {
var res = new ObjectValue(); var res = new ObjectValue();
try { try {
var key = getMemberPath(ctx, ctx.get(Environment.SYMBOL_PROTO), "constructor", "asyncIterator"); var key = getMemberPath(ext, ext.get(Environment.SYMBOL_PROTO), "constructor", "asyncIterator");
res.defineProperty(ctx, key, new NativeFunction("", args -> args.self)); res.defineProperty(ext, key, new NativeFunction("", args -> args.self));
} }
catch (IllegalArgumentException | NullPointerException e) { } catch (IllegalArgumentException | NullPointerException e) { }
res.defineProperty(ctx, "next", new NativeFunction("", args -> { res.defineProperty(ext, "next", new NativeFunction("", args -> {
return PromiseLib.await(args.ctx, () -> { return PromiseLib.await(args.ctx, () -> {
if (!it.hasNext()) return new ObjectValue(ctx, Map.of("done", true)); if (!it.hasNext()) return new ObjectValue(ext, Map.of("done", true));
else { else {
var obj = new ObjectValue(); var obj = new ObjectValue();
obj.defineProperty(args.ctx, "value", it.next()); obj.defineProperty(args.ctx, "value", it.next());
@@ -653,14 +654,14 @@ public class Values {
if (protoObj.values.size() + protoObj.properties.size() != 1) return false; if (protoObj.values.size() + protoObj.properties.size() != 1) return false;
return true; return true;
} }
private static String toReadable(Context ctx, Object val, HashSet<Object> passed, int tab) { private static String toReadable(Extensions ext, Object val, HashSet<Object> passed, int tab) {
if (tab == 0 && val instanceof String) return (String)val; if (tab == 0 && val instanceof String) return (String)val;
if (passed.contains(val)) return "[circular]"; if (passed.contains(val)) return "[circular]";
var printed = true; var printed = true;
var res = new StringBuilder(); var res = new StringBuilder();
var dbg = DebugContext.get(ctx); var dbg = DebugContext.get(ext);
if (val instanceof FunctionValue) { if (val instanceof FunctionValue) {
res.append(val.toString()); res.append(val.toString());
@@ -674,7 +675,7 @@ public class Values {
for (int i = 0; i < obj.size(); i++) { for (int i = 0; i < obj.size(); i++) {
if (i != 0) res.append(", "); if (i != 0) res.append(", ");
else res.append(" "); else res.append(" ");
if (obj.has(i)) res.append(toReadable(ctx, obj.get(i), passed, tab)); if (obj.has(i)) res.append(toReadable(ext, obj.get(i), passed, tab));
else res.append("<empty>"); else res.append("<empty>");
} }
res.append(" ] "); res.append(" ] ");
@@ -701,14 +702,14 @@ public class Values {
for (var el : obj.values.entrySet()) { for (var el : obj.values.entrySet()) {
for (int i = 0; i < tab + 1; i++) res.append(" "); for (int i = 0; i < tab + 1; i++) res.append(" ");
res.append(toReadable(ctx, el.getKey(), passed, tab + 1)); res.append(toReadable(ext, el.getKey(), passed, tab + 1));
res.append(": "); res.append(": ");
res.append(toReadable(ctx, el.getValue(), passed, tab + 1)); res.append(toReadable(ext, el.getValue(), passed, tab + 1));
res.append(",\n"); res.append(",\n");
} }
for (var el : obj.properties.entrySet()) { for (var el : obj.properties.entrySet()) {
for (int i = 0; i < tab + 1; i++) res.append(" "); for (int i = 0; i < tab + 1; i++) res.append(" ");
res.append(toReadable(ctx, el.getKey(), passed, tab + 1)); res.append(toReadable(ext, el.getKey(), passed, tab + 1));
res.append(": [prop],\n"); res.append(": [prop],\n");
} }
@@ -721,23 +722,23 @@ public class Values {
else if (val == null) return "undefined"; else if (val == null) return "undefined";
else if (val == Values.NULL) return "null"; else if (val == Values.NULL) return "null";
else if (val instanceof String) return "'" + val + "'"; else if (val instanceof String) return "'" + val + "'";
else return Values.toString(ctx, val); else return Values.toString(ext, val);
return res.toString(); return res.toString();
} }
public static String toReadable(Context ctx, Object val) { public static String toReadable(Extensions ext, Object val) {
return toReadable(ctx, val, new HashSet<>(), 0); return toReadable(ext, val, new HashSet<>(), 0);
} }
public static String errorToReadable(RuntimeException err, String prefix) { public static String errorToReadable(RuntimeException err, String prefix) {
prefix = prefix == null ? "Uncaught" : "Uncaught " + prefix; prefix = prefix == null ? "Uncaught" : "Uncaught " + prefix;
if (err instanceof EngineException) { if (err instanceof EngineException) {
var ee = ((EngineException)err); var ee = ((EngineException)err);
try { try {
return prefix + " " + ee.toString(new Context(ee.env)); return prefix + " " + ee.toString(ee.ext);
} }
catch (EngineException ex) { catch (EngineException ex) {
return prefix + " " + toReadable(new Context(ee.env), ee.value); return prefix + " " + toReadable(ee.ext, ee.value);
} }
} }
else if (err instanceof SyntaxException) { else if (err instanceof SyntaxException) {
@@ -751,8 +752,8 @@ public class Values {
return prefix + " internal error " + str.toString(); return prefix + " internal error " + str.toString();
} }
} }
public static void printValue(Context ctx, Object val) { public static void printValue(Extensions ext, Object val) {
System.out.print(toReadable(ctx, val)); System.out.print(toReadable(ext, val));
} }
public static void printError(RuntimeException err, String prefix) { public static void printError(RuntimeException err, String prefix) {
System.out.println(errorToReadable(err, prefix)); System.out.println(errorToReadable(err, prefix));

View File

@@ -4,9 +4,9 @@ import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.common.FunctionBody; import me.topchetoeu.jscript.common.FunctionBody;
import me.topchetoeu.jscript.compilation.CompileResult; import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.parsing.Parsing; import me.topchetoeu.jscript.compilation.parsing.Parsing;
import me.topchetoeu.jscript.core.Compiler; import me.topchetoeu.jscript.runtime.Compiler;
import me.topchetoeu.jscript.core.Extensions; import me.topchetoeu.jscript.runtime.Extensions;
import me.topchetoeu.jscript.core.debug.DebugContext; import me.topchetoeu.jscript.runtime.debug.DebugContext;
public class JSCompiler implements Compiler { public class JSCompiler implements Compiler {
public final Extensions ext; public final Extensions ext;

View File

@@ -8,18 +8,19 @@ import java.nio.file.Path;
import me.topchetoeu.jscript.common.Filename; import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.common.Metadata; import me.topchetoeu.jscript.common.Metadata;
import me.topchetoeu.jscript.common.Reading; import me.topchetoeu.jscript.common.Reading;
import me.topchetoeu.jscript.core.Compiler;
import me.topchetoeu.jscript.core.Context;
import me.topchetoeu.jscript.core.Engine;
import me.topchetoeu.jscript.core.Environment;
import me.topchetoeu.jscript.core.EventLoop;
import me.topchetoeu.jscript.core.debug.DebugContext;
import me.topchetoeu.jscript.core.values.NativeFunction;
import me.topchetoeu.jscript.core.values.Values;
import me.topchetoeu.jscript.core.exceptions.EngineException;
import me.topchetoeu.jscript.core.exceptions.InterruptException;
import me.topchetoeu.jscript.core.exceptions.SyntaxException;
import me.topchetoeu.jscript.lib.Internals; import me.topchetoeu.jscript.lib.Internals;
import me.topchetoeu.jscript.runtime.Compiler;
import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.runtime.Engine;
import me.topchetoeu.jscript.runtime.Environment;
import me.topchetoeu.jscript.runtime.EventLoop;
import me.topchetoeu.jscript.runtime.debug.DebugContext;
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.exceptions.InterruptException;
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
import me.topchetoeu.jscript.runtime.scope.GlobalScope;
import me.topchetoeu.jscript.runtime.values.NativeFunction;
import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.debug.DebugServer; import me.topchetoeu.jscript.utils.debug.DebugServer;
import me.topchetoeu.jscript.utils.debug.SimpleDebugger; import me.topchetoeu.jscript.utils.debug.SimpleDebugger;
import me.topchetoeu.jscript.utils.filesystem.Filesystem; import me.topchetoeu.jscript.utils.filesystem.Filesystem;
@@ -28,6 +29,7 @@ import me.topchetoeu.jscript.utils.filesystem.Mode;
import me.topchetoeu.jscript.utils.filesystem.PhysicalFilesystem; import me.topchetoeu.jscript.utils.filesystem.PhysicalFilesystem;
import me.topchetoeu.jscript.utils.filesystem.RootFilesystem; import me.topchetoeu.jscript.utils.filesystem.RootFilesystem;
import me.topchetoeu.jscript.utils.filesystem.STDFilesystem; import me.topchetoeu.jscript.utils.filesystem.STDFilesystem;
import me.topchetoeu.jscript.utils.interop.NativeWrapperProvider;
import me.topchetoeu.jscript.utils.modules.ModuleRepo; import me.topchetoeu.jscript.utils.modules.ModuleRepo;
import me.topchetoeu.jscript.utils.permissions.PermissionsManager; import me.topchetoeu.jscript.utils.permissions.PermissionsManager;
import me.topchetoeu.jscript.utils.permissions.PermissionsProvider; import me.topchetoeu.jscript.utils.permissions.PermissionsProvider;
@@ -87,10 +89,13 @@ public class JScriptRepl {
private static void initEnv() { private static void initEnv() {
environment = Internals.apply(environment); environment = Internals.apply(environment);
environment.global.define(false, new NativeFunction("exit", args -> { var wp = NativeWrapperProvider.get(environment);
var glob = GlobalScope.get(environment);
glob.define(null, false, new NativeFunction("exit", args -> {
throw new InterruptException(); throw new InterruptException();
})); }));
environment.global.define(false, new NativeFunction("go", args -> { glob.define(null, false, new NativeFunction("go", args -> {
try { try {
var f = Path.of("do.js"); var f = Path.of("do.js");
var func = args.ctx.compile(new Filename("do", "do/" + j++ + ".js"), new String(Files.readAllBytes(f))); var func = args.ctx.compile(new Filename("do", "do/" + j++ + ".js"), new String(Files.readAllBytes(f)));
@@ -100,7 +105,7 @@ public class JScriptRepl {
throw new EngineException("Couldn't open do.js"); throw new EngineException("Couldn't open do.js");
} }
})); }));
environment.global.define(false, new NativeFunction("log", args -> { glob.define(null, false, new NativeFunction("log", args -> {
for (var el : args.args) { for (var el : args.args) {
Values.printValue(args.ctx, el); Values.printValue(args.ctx, el);
} }
@@ -111,7 +116,7 @@ public class JScriptRepl {
var fs = new RootFilesystem(PermissionsProvider.get(environment)); var fs = new RootFilesystem(PermissionsProvider.get(environment));
fs.protocols.put("temp", new MemoryFilesystem(Mode.READ_WRITE)); fs.protocols.put("temp", new MemoryFilesystem(Mode.READ_WRITE));
fs.protocols.put("file", new PhysicalFilesystem(".")); fs.protocols.put("file", new PhysicalFilesystem("."));
fs.protocols.put("std", STDFilesystem.ofStd(System.in, System.out, System.err)); fs.protocols.put("std", new STDFilesystem(System.in, System.out, System.err));
environment.add(PermissionsProvider.KEY, PermissionsManager.ALL_PERMS); environment.add(PermissionsProvider.KEY, PermissionsManager.ALL_PERMS);
environment.add(Filesystem.KEY, fs); environment.add(Filesystem.KEY, fs);

View File

@@ -15,8 +15,8 @@ import me.topchetoeu.jscript.common.events.Notifier;
import me.topchetoeu.jscript.common.json.JSON; import me.topchetoeu.jscript.common.json.JSON;
import me.topchetoeu.jscript.common.json.JSONList; import me.topchetoeu.jscript.common.json.JSONList;
import me.topchetoeu.jscript.common.json.JSONMap; import me.topchetoeu.jscript.common.json.JSONMap;
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
import me.topchetoeu.jscript.utils.debug.WebSocketMessage.Type; import me.topchetoeu.jscript.utils.debug.WebSocketMessage.Type;
import me.topchetoeu.jscript.core.exceptions.SyntaxException;
public class DebugServer { public class DebugServer {
public static String browserDisplayName = Metadata.name() + "/" + Metadata.version(); public static String browserDisplayName = Metadata.name() + "/" + Metadata.version();
@@ -137,6 +137,13 @@ public class DebugServer {
} }
runAsync(() -> { runAsync(() -> {
var handle = new Thread(() -> {
System.out.println("test");
debugger.close();
});
Runtime.getRuntime().addShutdownHook(handle);
try { handle(ws, debugger); } try { handle(ws, debugger); }
catch (RuntimeException | IOException e) { catch (RuntimeException | IOException e) {
try { try {
@@ -145,7 +152,11 @@ public class DebugServer {
} }
catch (IOException e2) { /* Shit outta luck */ } catch (IOException e2) { /* Shit outta luck */ }
} }
finally { ws.close(); debugger.close(); } finally {
Runtime.getRuntime().removeShutdownHook(handle);
ws.close();
debugger.close();
}
}, "Debug Handler"); }, "Debug Handler");
} }
@@ -164,7 +175,6 @@ public class DebugServer {
var req = HttpRequest.read(socket); var req = HttpRequest.read(socket);
if (req == null) continue; if (req == null) continue;
switch (req.path) { switch (req.path) {
case "/json/version": case "/json/version":
send(req, "{\"Browser\":\"" + browserDisplayName + "\",\"Protocol-Version\":\"1.1\"}"); send(req, "{\"Browser\":\"" + browserDisplayName + "\",\"Protocol-Version\":\"1.1\"}");

View File

@@ -1,8 +1,9 @@
package me.topchetoeu.jscript.utils.debug; package me.topchetoeu.jscript.utils.debug;
import me.topchetoeu.jscript.core.debug.DebugHandler;
import java.io.IOException; import java.io.IOException;
import me.topchetoeu.jscript.runtime.debug.DebugHandler;
public interface Debugger extends DebugHandler { public interface Debugger extends DebugHandler {
void close(); void close();

View File

@@ -23,25 +23,29 @@ import me.topchetoeu.jscript.common.json.JSONList;
import me.topchetoeu.jscript.common.json.JSONMap; import me.topchetoeu.jscript.common.json.JSONMap;
import me.topchetoeu.jscript.common.mapping.FunctionMap; import me.topchetoeu.jscript.common.mapping.FunctionMap;
import me.topchetoeu.jscript.compilation.parsing.Parsing; import me.topchetoeu.jscript.compilation.parsing.Parsing;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.core.Engine; import me.topchetoeu.jscript.runtime.Engine;
import me.topchetoeu.jscript.core.Environment; import me.topchetoeu.jscript.runtime.Environment;
import me.topchetoeu.jscript.core.EventLoop; import me.topchetoeu.jscript.runtime.EventLoop;
import me.topchetoeu.jscript.core.Frame; import me.topchetoeu.jscript.runtime.Extensions;
import me.topchetoeu.jscript.core.debug.DebugContext; import me.topchetoeu.jscript.runtime.Frame;
import me.topchetoeu.jscript.core.scope.GlobalScope; import me.topchetoeu.jscript.runtime.debug.DebugContext;
import me.topchetoeu.jscript.core.values.ArrayValue; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.core.values.FunctionValue; import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.runtime.scope.GlobalScope;
import me.topchetoeu.jscript.core.values.Symbol; import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.runtime.values.Symbol;
import me.topchetoeu.jscript.runtime.values.Values;
// very simple indeed // very simple indeed
public class SimpleDebugger implements Debugger { public class SimpleDebugger implements Debugger {
public static final Set<String> VSCODE_EMPTY = Set.of( public static final Set<String> VSCODE_EMPTY = Set.of(
"function(...runtimeArgs){\n let t = 1024; let e = null;\n if(e)try{let r=\"<<default preview>>\",i=e.call(this,r);if(i!==r)return String(i)}catch(r){return`<<indescribable>>${JSON.stringify([String(r),\"object\"])}`}if(typeof this==\"object\"&&this){let r;for(let i of[Symbol.for(\"debug.description\"),Symbol.for(\"nodejs.util.inspect.custom\")])try{r=this[i]();break}catch{}if(!r&&!String(this.toString).includes(\"[native code]\")&&(r=String(this)),r&&!r.startsWith(\"[object \"))return r.length>=t?r.slice(0,t)+\"\\u2026\":r}\n ;\n\n}", "function(...runtimeArgs){\n let t = 1024; let e = null;\n if(e)try{let r=\"<<default preview>>\",i=e.call(this,r);if(i!==r)return String(i)}catch(r){return`<<indescribable>>${JSON.stringify([String(r),\"object\"])}`}if(typeof this==\"object\"&&this){let r;for(let i of[Symbol.for(\"debug.description\"),Symbol.for(\"nodejs.util.inspect.custom\")])try{r=this[i]();break}catch{}if(!r&&!String(this.toString).includes(\"[native code]\")&&(r=String(this)),r&&!r.startsWith(\"[object \"))return r.length>=t?r.slice(0,t)+\"\\u2026\":r}\n ;\n\n}",
"function(...runtimeArgs){\n let r = 1024; let e = null;\n if(e)try{let t=\"<<default preview>>\",n=e.call(this,t);if(n!==t)return String(n)}catch(t){return`<<indescribable>>${JSON.stringify([String(t),\"object\"])}`}if(typeof this==\"object\"&&this){let t;for(let n of[Symbol.for(\"debug.description\"),Symbol.for(\"nodejs.util.inspect.custom\")])if(typeof this[n]==\"function\")try{t=this[n]();break}catch{}if(!t&&!String(this.toString).includes(\"[native code]\")&&(t=String(this)),t&&!t.startsWith(\"[object\"))return t.length>=r?t.slice(0,r)+\"\\u2026\":t};}",
"function(...runtimeArgs){\n let t = 1024; let e = null;\n let r={},i=\"<<default preview>>\";if(typeof this!=\"object\"||!this)return r;for(let[n,s]of Object.entries(this)){if(e)try{let o=e.call(s,i);if(o!==i){r[n]=String(o);continue}}catch(o){r[n]=`<<indescribable>>${JSON.stringify([String(o),n])}`;continue}if(typeof s==\"object\"&&s){let o;for(let a of runtimeArgs[0])try{o=s[a]();break}catch{}!o&&!String(s.toString).includes(\"[native code]\")&&(o=String(s)),o&&!o.startsWith(\"[object \")&&(r[n]=o.length>=t?o.slice(0,t)+\"\\u2026\":o)}}return r\n ;\n\n}", "function(...runtimeArgs){\n let t = 1024; let e = null;\n let r={},i=\"<<default preview>>\";if(typeof this!=\"object\"||!this)return r;for(let[n,s]of Object.entries(this)){if(e)try{let o=e.call(s,i);if(o!==i){r[n]=String(o);continue}}catch(o){r[n]=`<<indescribable>>${JSON.stringify([String(o),n])}`;continue}if(typeof s==\"object\"&&s){let o;for(let a of runtimeArgs[0])try{o=s[a]();break}catch{}!o&&!String(s.toString).includes(\"[native code]\")&&(o=String(s)),o&&!o.startsWith(\"[object \")&&(r[n]=o.length>=t?o.slice(0,t)+\"\\u2026\":o)}}return r\n ;\n\n}",
"function(...runtimeArgs){\n let r = 1024; let e = null;\n let t={},n=\"<<default preview>>\";if(typeof this!=\"object\"||!this)return t;for(let[i,o]of Object.entries(this)){if(e)try{let s=e.call(o,n);if(s!==n){t[i]=String(s);continue}}catch(s){t[i]=`<<indescribable>>${JSON.stringify([String(s),i])}`;continue}if(typeof o==\"object\"&&o){let s;for(let a of runtimeArgs[0])if(typeof o[a]==\"function\")try{s=o[a]();break}catch{}!s&&!String(o.toString).includes(\"[native code]\")&&(s=String(o)),s&&!s.startsWith(\"[object \")&&(t[i]=s.length>=r?s.slice(0,r)+\"\\u2026\":s)}}return t\n ;\n\n}",
"function(){let t={__proto__:this.__proto__\n},e=Object.getOwnPropertyNames(this);for(let r=0;r<e.length;++r){let i=e[r],n=i>>>0;if(String(n>>>0)===i&&n>>>0!==4294967295)continue;let s=Object.getOwnPropertyDescriptor(this,i);s&&Object.defineProperty(t,i,s)}return t}", "function(){let t={__proto__:this.__proto__\n},e=Object.getOwnPropertyNames(this);for(let r=0;r<e.length;++r){let i=e[r],n=i>>>0;if(String(n>>>0)===i&&n>>>0!==4294967295)continue;let s=Object.getOwnPropertyDescriptor(this,i);s&&Object.defineProperty(t,i,s)}return t}",
"function(){return[Symbol.for(\"debug.description\"),Symbol.for(\"nodejs.util.inspect.custom\")]\n}" "function(){return[Symbol.for(\"debug.description\"),Symbol.for(\"nodejs.util.inspect.custom\")]\n}"
); );
@@ -50,6 +54,7 @@ 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}";
public static final String CHROME_GET_PROP_FUNC_2 = "function invokeGetter(getter) { return Reflect.apply(getter, this, []);}";
public static final String VSCODE_CALL = "function(t){return t.call(this)\n}"; public static final String VSCODE_CALL = "function(t){return t.call(this)\n}";
public static final String VSCODE_AUTOCOMPLETE = "function(t,e,r){let n=r?\"variable\":\"property\",i=(l,p,f)=>{if(p!==\"function\")return n;if(l===\"constructor\")return\"class\";let m=String(f);return m.startsWith(\"class \")||m.includes(\"[native code]\")&&/^[A-Z]/.test(l)?\"class\":r?\"function\":\"method\"\n},o=l=>{switch(typeof l){case\"number\":case\"boolean\":return`${l}`;case\"object\":return l===null?\"null\":l.constructor.name||\"object\";case\"function\":return`fn(${new Array(l.length).fill(\"?\").join(\", \")})`;default:return typeof l}},s=[],a=new Set,u=\"~\",c=t===void 0?this:t;for(;c!=null;c=c.__proto__){u+=\"~\";let l=Object.getOwnPropertyNames(c).filter(p=>p.startsWith(e)&&!p.match(/^\\d+$/));for(let p of l){if(a.has(p))continue;a.add(p);let f=Object.getOwnPropertyDescriptor(c,p),m=n,h;try{let H=c[p];m=i(p,typeof f?.value,H),h=o(H)}catch{}s.push({label:p,sortText:u+p.replace(/^_+/,H=>\"{\".repeat(H.length)),type:m,detail:h})}r=!1}return{result:s,isArray:this instanceof Array}}"; public static final String VSCODE_AUTOCOMPLETE = "function(t,e,r){let n=r?\"variable\":\"property\",i=(l,p,f)=>{if(p!==\"function\")return n;if(l===\"constructor\")return\"class\";let m=String(f);return m.startsWith(\"class \")||m.includes(\"[native code]\")&&/^[A-Z]/.test(l)?\"class\":r?\"function\":\"method\"\n},o=l=>{switch(typeof l){case\"number\":case\"boolean\":return`${l}`;case\"object\":return l===null?\"null\":l.constructor.name||\"object\";case\"function\":return`fn(${new Array(l.length).fill(\"?\").join(\", \")})`;default:return typeof l}},s=[],a=new Set,u=\"~\",c=t===void 0?this:t;for(;c!=null;c=c.__proto__){u+=\"~\";let l=Object.getOwnPropertyNames(c).filter(p=>p.startsWith(e)&&!p.match(/^\\d+$/));for(let p of l){if(a.has(p))continue;a.add(p);let f=Object.getOwnPropertyDescriptor(c,p),m=n,h;try{let H=c[p];m=i(p,typeof f?.value,H),h=o(H)}catch{}s.push({label:p,sortText:u+p.replace(/^_+/,H=>\"{\".repeat(H.length)),type:m,detail:h})}r=!1}return{result:s,isArray:this instanceof Array}}";
@@ -83,7 +88,9 @@ public class SimpleDebugger implements Debugger {
public final String condition; public final String condition;
public final Pattern pattern; public final Pattern pattern;
public final int line, start; public final int line, start;
public final WeakHashMap<FunctionBody, Set<Location>> resolvedLocations = new WeakHashMap<>(); public final long locNum;
public final HashMap<Filename, Location> resolvedLocations = new HashMap<>();
public final HashMap<Filename, Long> resolvedDistances = new HashMap<>();
public Breakpoint(int id, Pattern pattern, int line, int start, String condition) { public Breakpoint(int id, Pattern pattern, int line, int start, String condition) {
this.id = id; this.id = id;
@@ -91,18 +98,28 @@ public class SimpleDebugger implements Debugger {
this.pattern = pattern; this.pattern = pattern;
this.line = line; this.line = line;
this.start = start; this.start = start;
this.locNum = start | ((long)line << 32);
if (condition != null && condition.trim().equals("")) condition = null; if (condition != null && condition.trim().equals("")) condition = null;
} }
// TODO: Figure out how to unload a breakpoint // TODO: Figure out how to unload a breakpoint
// TODO: Do location resolution with function boundaries
public void addFunc(FunctionBody body, FunctionMap map) { public void addFunc(FunctionBody body, FunctionMap map) {
try { try {
for (var loc : map.correctBreakpoint(pattern, line, start)) { for (var loc : map.correctBreakpoint(pattern, line, start)) {
if (!resolvedLocations.containsKey(body)) resolvedLocations.put(body, new HashSet<>()); var currNum = loc.start() + ((long)loc.line() << 32);
var set = resolvedLocations.get(body); long currDist = 0;
set.add(loc); if (currNum > locNum) currDist = currNum - locNum;
else currDist = locNum - currNum;
if ( currDist > resolvedDistances.getOrDefault(loc.filename(), Long.MAX_VALUE)) continue;
resolvedLocations.put(loc.filename(), loc);
resolvedDistances.put(loc.filename(), currDist);
}
for (var loc : resolvedLocations.values()) {
ws.send(new V8Event("Debugger.breakpointResolved", new JSONMap() ws.send(new V8Event("Debugger.breakpointResolved", new JSONMap()
.set("breakpointId", id) .set("breakpointId", id)
.set("location", serializeLocation(loc)) .set("location", serializeLocation(loc))
@@ -133,7 +150,7 @@ public class SimpleDebugger implements Debugger {
this.frame = frame; this.frame = frame;
this.id = id; this.id = id;
this.global = frame.function.environment.global.obj; this.global = GlobalScope.get(frame.ctx).obj;
this.local = frame.getLocalScope(); this.local = frame.getLocalScope();
this.capture = frame.getCaptureScope(); this.capture = frame.getCaptureScope();
Values.makePrototypeChain(frame.ctx, global, capture, local); Values.makePrototypeChain(frame.ctx, global, capture, local);
@@ -156,19 +173,19 @@ public class SimpleDebugger implements Debugger {
.add(new JSONMap() .add(new JSONMap()
.set("type", "global") .set("type", "global")
.set("name", "Global Scope") .set("name", "Global Scope")
.set("object", serializeObj(frame.ctx, global)) .set("object", serializeObj(frame.ctx.extensions, global))
) )
.add(new JSONMap() .add(new JSONMap()
.set("type", "other") .set("type", "other")
.set("name", "Value Stack") .set("name", "Value Stack")
.set("object", serializeObj(frame.ctx, valstack)) .set("object", serializeObj(frame.ctx.extensions, valstack))
) )
); );
} }
} }
private class ObjRef { private class ObjRef {
public final ObjectValue obj; public final ObjectValue obj;
public final Context ctx; public final Extensions ext;
public final HashSet<String> heldGroups = new HashSet<>(); public final HashSet<String> heldGroups = new HashSet<>();
public boolean held = true; public boolean held = true;
@@ -176,19 +193,19 @@ public class SimpleDebugger implements Debugger {
return !held && heldGroups.size() == 0; return !held && heldGroups.size() == 0;
} }
public ObjRef(Context ctx, ObjectValue obj) { public ObjRef(Extensions ext, ObjectValue obj) {
this.ctx = ctx; this.ext = ext;
this.obj = obj; this.obj = obj;
} }
} }
private static class RunResult { private static class RunResult {
public final Context ctx; public final Extensions ext;
public final Object result; public final Object result;
public final EngineException error; public final EngineException error;
public RunResult(Context ctx, Object result, EngineException error) { public RunResult(Extensions ext, Object result, EngineException error) {
this.ctx = ctx; this.ext = ext;
this.result = result; this.result = result;
this.error = error; this.error = error;
} }
@@ -202,8 +219,9 @@ public class SimpleDebugger implements Debugger {
private ObjectValue emptyObject = new ObjectValue(); private ObjectValue emptyObject = new ObjectValue();
private WeakHashMap<DebugContext, DebugContext> contexts = new WeakHashMap<>();
private WeakHashMap<FunctionBody, FunctionMap> mappings = new WeakHashMap<>(); private WeakHashMap<FunctionBody, FunctionMap> mappings = new WeakHashMap<>();
private WeakHashMap<FunctionBody, HashMap<Location, Breakpoint>> bpLocs = new WeakHashMap<>(); private HashMap<Location, HashSet<Breakpoint>> bpLocs = new HashMap<>();
private HashMap<Integer, Breakpoint> idToBreakpoint = new HashMap<>(); private HashMap<Integer, Breakpoint> idToBreakpoint = new HashMap<>();
@@ -226,6 +244,8 @@ public class SimpleDebugger implements Debugger {
private int stepOutPtr = 0; private int stepOutPtr = 0;
private boolean compare(String src, String target) { private boolean compare(String src, String target) {
src = src.replaceAll("\\s", "");
target = target.replaceAll("\\s", "");
if (src.length() != target.length()) return false; if (src.length() != target.length()) return false;
var diff = 0; var diff = 0;
var all = 0; var all = 0;
@@ -291,13 +311,11 @@ public class SimpleDebugger implements Debugger {
bpLocs.clear(); bpLocs.clear();
for (var bp : idToBreakpoint.values()) { for (var bp : idToBreakpoint.values()) {
for (var el : bp.resolvedLocations.entrySet()) { for (var loc : bp.resolvedLocations.values()) {
if (!bpLocs.containsKey(el.getKey())) bpLocs.put(el.getKey(), new HashMap<>()); bpLocs.putIfAbsent(loc, new HashSet<>());
var map = bpLocs.get(el.getKey()); var set = bpLocs.get(loc);
for (var loc : el.getValue()) { set.add(bp);
map.put(loc, bp);
}
} }
} }
} }
@@ -321,22 +339,10 @@ public class SimpleDebugger implements Debugger {
.set("columnNumber", loc.start() - 1); .set("columnNumber", loc.start() - 1);
} }
private Integer objectId(Context ctx, ObjectValue obj) { private JSONMap serializeObj(Extensions env, Object val, boolean byValue) {
if (objectToId.containsKey(obj)) return objectToId.get(obj);
else {
int id = nextId();
var ref = new ObjRef(ctx, obj);
objectToId.put(obj, id);
idToObject.put(id, ref);
return id;
}
}
private JSONMap serializeObj(Context ctx, Object val, boolean byValue) {
val = Values.normalize(null, val); val = Values.normalize(null, val);
var newCtx = new Context(); env = sanitizeEnvironment(env);
newCtx.addAll(ctx); var ctx = Context.of(env);
newCtx.add(DebugContext.IGNORE);
ctx = newCtx;
if (val == Values.NULL) { if (val == Values.NULL) {
return new JSONMap() return new JSONMap()
@@ -348,7 +354,16 @@ public class SimpleDebugger implements Debugger {
if (val instanceof ObjectValue) { if (val instanceof ObjectValue) {
var obj = (ObjectValue)val; var obj = (ObjectValue)val;
var id = objectId(ctx, obj); int id;
if (objectToId.containsKey(obj)) id = objectToId.get(obj);
else {
id = nextId();
var ref = new ObjRef(env, obj);
objectToId.put(obj, id);
idToObject.put(id, ref);
}
var type = "object"; var type = "object";
String subtype = null; String subtype = null;
String className = null; String className = null;
@@ -366,6 +381,7 @@ public class SimpleDebugger implements Debugger {
if (subtype != null) res.set("subtype", subtype); if (subtype != null) res.set("subtype", subtype);
if (className != null) { if (className != null) {
res.set("className", className); res.set("className", className);
res.set("description", className);
} }
if (obj instanceof ArrayValue) res.set("description", "Array(" + ((ArrayValue)obj).size() + ")"); if (obj instanceof ArrayValue) res.set("description", "Array(" + ((ArrayValue)obj).size() + ")");
@@ -376,16 +392,16 @@ public class SimpleDebugger implements Debugger {
try { try {
defaultToString = defaultToString =
Values.getMember(ctx, obj, "toString") == Values.getMember(ctx, obj, "toString") ==
Values.getMember(ctx, ctx.get(Environment.OBJECT_PROTO), "toString"); Values.getMember(ctx, env.get(Environment.OBJECT_PROTO), "toString");
} }
catch (Exception e) { } catch (Exception e) { }
try { res.set("description", className + (defaultToString ? "" : " { " + Values.toString(ctx, obj) + " }")); } try { res.set("description", className + (defaultToString ? "" : " { " + Values.toString(ctx, obj) + " }")); }
catch (EngineException e) { res.set("description", className); } catch (EngineException e) { }
} }
if (byValue) try { res.put("value", JSON.fromJs(ctx, obj)); } if (byValue) try { res.put("value", JSON.fromJs(env, obj)); }
catch (Exception e) { } catch (Exception e) { }
return res; return res;
@@ -411,8 +427,8 @@ public class SimpleDebugger implements Debugger {
throw new IllegalArgumentException("Unexpected JS object."); throw new IllegalArgumentException("Unexpected JS object.");
} }
private JSONMap serializeObj(Context ctx, Object val) { private JSONMap serializeObj(Extensions ext, Object val) {
return serializeObj(ctx, val, false); return serializeObj(ext, val, false);
} }
private void addObjectGroup(String name, Object val) { private void addObjectGroup(String name, Object val) {
if (val instanceof ObjectValue) { if (val instanceof ObjectValue) {
@@ -451,11 +467,11 @@ public class SimpleDebugger implements Debugger {
else return JSON.toJs(res); else return JSON.toJs(res);
} }
private JSONMap serializeException(Context ctx, EngineException err) { private JSONMap serializeException(Extensions ext, EngineException err) {
String text = null; String text = null;
try { try {
text = Values.toString(ctx, err.value); text = Values.toString(Context.of(ext), err.value);
} }
catch (EngineException e) { catch (EngineException e) {
text = "[error while stringifying]"; text = "[error while stringifying]";
@@ -463,7 +479,7 @@ public class SimpleDebugger implements Debugger {
var res = new JSONMap() var res = new JSONMap()
.set("exceptionId", nextId()) .set("exceptionId", nextId())
.set("exception", serializeObj(ctx, err.value)) .set("exception", serializeObj(ext, err.value))
.set("text", text); .set("text", text);
return res; return res;
@@ -524,30 +540,43 @@ public class SimpleDebugger implements Debugger {
} }
} }
private Extensions sanitizeEnvironment(Extensions ext) {
var res = ext.child();
res.remove(EventLoop.KEY);
res.remove(DebugContext.KEY);
res.add(DebugContext.IGNORE);
return res;
}
private RunResult run(DebugFrame codeFrame, String code) { private RunResult run(DebugFrame codeFrame, String code) {
if (codeFrame == null) return new RunResult(null, code, new EngineException("Invalid code frame!")); if (codeFrame == null) return new RunResult(null, code, new EngineException("Invalid code frame!"));
var engine = new Engine(); var engine = new Engine();
var env = codeFrame.frame.function.environment.copy(); var env = codeFrame.frame.ctx.extensions.copy();
env.global = new GlobalScope(codeFrame.local);
env.remove(EventLoop.KEY);
env.remove(DebugContext.KEY); env.remove(DebugContext.KEY);
env.remove(EventLoop.KEY);
env.remove(GlobalScope.KEY);
env.add(EventLoop.KEY, engine); env.add(EventLoop.KEY, engine);
env.add(GlobalScope.KEY, new GlobalScope(codeFrame.local));
var ctx = new Context(env); var awaiter = engine.pushMsg(false, env, new Filename("jscript", "eval"), code, codeFrame.frame.thisArg, codeFrame.frame.args);
var awaiter = engine.pushMsg(false, ctx.environment, new Filename("jscript", "eval"), code, codeFrame.frame.thisArg, codeFrame.frame.args);
engine.run(true); try {
engine.run(true);
try { return new RunResult(ctx, awaiter.await(), null); } return new RunResult(env, awaiter.await(), null);
catch (EngineException e) { return new RunResult(ctx, null, e); } }
catch (EngineException e) { return new RunResult(env, null, e); }
catch (SyntaxException e) { return new RunResult(env, null, EngineException.ofSyntax(e.toString())); }
} }
private ObjectValue vscodeAutoSuggest(Context ctx, Object target, String query, boolean variable) { private ObjectValue vscodeAutoSuggest(Extensions ext, Object target, String query, boolean variable) {
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.global; var ctx = Context.of(ext);
if (target == null) target = GlobalScope.get(ext);
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)) {
@@ -602,7 +631,7 @@ public class SimpleDebugger implements Debugger {
desc.defineProperty(ctx, "type", Values.type(val)); desc.defineProperty(ctx, "type", Values.type(val));
break; break;
} }
res.set(ctx, res.size(), desc); res.set(ctx, res.size(), desc);
} }
@@ -630,15 +659,18 @@ public class SimpleDebugger implements Debugger {
ws.send(msg.respond()); ws.send(msg.respond());
} }
@Override public synchronized void close() { @Override public synchronized void close() {
if (state != State.RESUMED) {
resume(State.RESUMED);
}
enabled = false; enabled = false;
execptionType = CatchType.NONE; execptionType = CatchType.NONE;
state = State.RESUMED; state = State.RESUMED;
// idToBptCand.clear(); mappings.clear();
bpLocs.clear();
idToBreakpoint.clear(); idToBreakpoint.clear();
// locToBreakpoint.clear();
// tmpBreakpts.clear();
filenameToId.clear(); filenameToId.clear();
idToSource.clear(); idToSource.clear();
@@ -656,6 +688,9 @@ public class SimpleDebugger implements Debugger {
stepOutFrame = currFrame = null; stepOutFrame = currFrame = null;
stepOutPtr = 0; stepOutPtr = 0;
for (var ctx : contexts.keySet()) ctx.detachDebugger(this);
contexts.clear();
updateNotifier.next(); updateNotifier.next();
} }
@@ -709,16 +744,15 @@ public class SimpleDebugger implements Debugger {
var bpt = new Breakpoint(nextId(), regex, line, col, cond); var bpt = new Breakpoint(nextId(), regex, line, col, cond);
idToBreakpoint.put(bpt.id, bpt); idToBreakpoint.put(bpt.id, bpt);
var locs = new JSONList();
for (var el : mappings.entrySet()) { for (var el : mappings.entrySet()) {
bpt.addFunc(el.getKey(), el.getValue()); bpt.addFunc(el.getKey(), el.getValue());
} }
for (var el : bpt.resolvedLocations.values()) { var locs = new JSONList();
for (var loc : el) {
locs.add(serializeLocation(loc)); for (var loc : bpt.resolvedLocations.values()) {
} locs.add(serializeLocation(loc));
} }
ws.send(msg.respond(new JSONMap() ws.send(msg.respond(new JSONMap()
@@ -730,6 +764,7 @@ public class SimpleDebugger implements Debugger {
var id = Integer.parseInt(msg.params.string("breakpointId")); var id = Integer.parseInt(msg.params.string("breakpointId"));
idToBreakpoint.remove(id); idToBreakpoint.remove(id);
updateBreakpoints();
ws.send(msg.respond()); ws.send(msg.respond());
} }
@Override public synchronized void continueToLocation(V8Message msg) throws IOException { @Override public synchronized void continueToLocation(V8Message msg) throws IOException {
@@ -794,8 +829,8 @@ public class SimpleDebugger implements Debugger {
if (group != null) addObjectGroup(group, res.result); if (group != null) addObjectGroup(group, res.result);
if (res.error != null) ws.send(msg.respond(new JSONMap().set("exceptionDetails", serializeException(res.ctx, res.error)))); if (res.error != null) ws.send(msg.respond(new JSONMap().set("exceptionDetails", serializeException(res.ext, res.error))));
else ws.send(msg.respond(new JSONMap().set("result", serializeObj(res.ctx, res.result)))); else ws.send(msg.respond(new JSONMap().set("result", serializeObj(res.ext, res.result))));
} }
@Override public synchronized void releaseObjectGroup(V8Message msg) throws IOException { @Override public synchronized void releaseObjectGroup(V8Message msg) throws IOException {
@@ -818,46 +853,54 @@ public class SimpleDebugger implements Debugger {
@Override public synchronized void getProperties(V8Message msg) throws IOException { @Override public synchronized void getProperties(V8Message msg) throws IOException {
var ref = idToObject.get(Integer.parseInt(msg.params.string("objectId"))); var ref = idToObject.get(Integer.parseInt(msg.params.string("objectId")));
var obj = ref.obj; var obj = ref.obj;
var ext = ref.ext;
var ctx = Context.of(ext);
var res = new JSONList(); var res = new JSONList();
var ctx = ref.ctx; var own = true;
if (obj != emptyObject && obj != null) { if (obj != emptyObject && obj != null) {
for (var key : obj.keys(true)) { while (obj != null) {
var propDesc = new JSONMap(); for (var key : obj.keys(true)) {
var propDesc = new JSONMap();
if (obj.properties.containsKey(key)) { if (obj.properties.containsKey(key)) {
var prop = obj.properties.get(key); var prop = obj.properties.get(key);
propDesc.set("name", Values.toString(ctx, key)); propDesc.set("name", Values.toString(ctx, key));
if (prop.getter != null) propDesc.set("get", serializeObj(ctx, prop.getter)); if (prop.getter != null) propDesc.set("get", serializeObj(ext, prop.getter));
if (prop.setter != null) propDesc.set("set", serializeObj(ctx, prop.setter)); if (prop.setter != null) propDesc.set("set", serializeObj(ext, prop.setter));
propDesc.set("enumerable", obj.memberEnumerable(key)); propDesc.set("enumerable", obj.memberEnumerable(key));
propDesc.set("configurable", obj.memberConfigurable(key)); propDesc.set("configurable", obj.memberConfigurable(key));
propDesc.set("isOwn", true); propDesc.set("isOwn", true);
res.add(propDesc); res.add(propDesc);
}
else {
propDesc.set("name", Values.toString(ctx, key));
propDesc.set("value", serializeObj(ext, Values.getMember(ctx, obj, key)));
propDesc.set("writable", obj.memberWritable(key));
propDesc.set("enumerable", obj.memberEnumerable(key));
propDesc.set("configurable", obj.memberConfigurable(key));
propDesc.set("isOwn", own);
res.add(propDesc);
}
} }
else {
propDesc.set("name", Values.toString(ctx, key)); var proto = Values.getPrototype(ctx, obj);
propDesc.set("value", serializeObj(ctx, Values.getMember(ctx, obj, key)));
propDesc.set("writable", obj.memberWritable(key)); if (own) {
propDesc.set("enumerable", obj.memberEnumerable(key)); var protoDesc = new JSONMap();
propDesc.set("configurable", obj.memberConfigurable(key)); protoDesc.set("name", "__proto__");
propDesc.set("isOwn", true); protoDesc.set("value", serializeObj(ext, proto == null ? Values.NULL : proto));
res.add(propDesc); protoDesc.set("writable", true);
protoDesc.set("enumerable", false);
protoDesc.set("configurable", false);
protoDesc.set("isOwn", own);
res.add(protoDesc);
} }
obj = proto;
own = false;
} }
var proto = Values.getPrototype(ctx, obj);
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)));
@@ -874,7 +917,8 @@ public class SimpleDebugger implements Debugger {
var thisArgRef = idToObject.get(Integer.parseInt(msg.params.string("objectId"))); var thisArgRef = idToObject.get(Integer.parseInt(msg.params.string("objectId")));
var thisArg = thisArgRef.obj; var thisArg = thisArgRef.obj;
var ctx = thisArgRef.ctx; var ext = thisArgRef.ext;
var ctx = Context.of(ext);
while (true) { while (true) {
var start = src.lastIndexOf("//# sourceURL="); var start = src.lastIndexOf("//# sourceURL=");
@@ -892,22 +936,25 @@ public class SimpleDebugger implements Debugger {
res = thisArg; res = thisArg;
for (var el : JSON.parse(null, (String)args.get(0)).list()) res = Values.getMember(ctx, res, JSON.toJs(el)); for (var el : JSON.parse(null, (String)args.get(0)).list()) res = Values.getMember(ctx, res, JSON.toJs(el));
} }
else if (compare(src, CHROME_GET_PROP_FUNC_2)) {
res = Values.call(ctx, args.get(0), thisArg);
}
else if (compare(src, VSCODE_CALL)) { else if (compare(src, VSCODE_CALL)) {
var func = (FunctionValue)(args.size() < 1 ? null : args.get(0)); var func = (FunctionValue)(args.size() < 1 ? null : args.get(0));
ws.send(msg.respond(new JSONMap().set("result", serializeObj(ctx, func.call(ctx, thisArg))))); ws.send(msg.respond(new JSONMap().set("result", serializeObj(ext, func.call(ctx, thisArg)))));
} }
else if (compare(src, VSCODE_AUTOCOMPLETE)) { else if (compare(src, VSCODE_AUTOCOMPLETE)) {
var target = args.get(0); var target = args.get(0);
if (target == null) target = thisArg; if (target == null) target = thisArg;
res = vscodeAutoSuggest(ctx, target, Values.toString(ctx, args.get(1)), Values.toBoolean(args.get(2))); res = vscodeAutoSuggest(ext, target, Values.toString(ctx, args.get(1)), Values.toBoolean(args.get(2)));
} }
else { else {
ws.send(new V8Error("Please use well-known functions with callFunctionOn")); ws.send(new V8Error("Please use well-known functions with callFunctionOn"));
return; return;
} }
ws.send(msg.respond(new JSONMap().set("result", serializeObj(ctx, res, byValue)))); ws.send(msg.respond(new JSONMap().set("result", serializeObj(ext, res, byValue))));
} }
catch (EngineException e) { ws.send(msg.respond(new JSONMap().set("exceptionDetails", serializeException(ctx, e)))); } catch (EngineException e) { ws.send(msg.respond(new JSONMap().set("exceptionDetails", serializeException(ext, e)))); }
} }
@Override public synchronized void runtimeEnable(V8Message msg) throws IOException { @Override public synchronized void runtimeEnable(V8Message msg) throws IOException {
@@ -958,10 +1005,11 @@ public class SimpleDebugger implements Debugger {
) { ) {
pauseDebug(ctx, null); pauseDebug(ctx, null);
} }
else if (isBreakpointable && bpLocs.getOrDefault(cf.function.body, new HashMap<>()).containsKey(loc)) { else if (isBreakpointable && bpLocs.containsKey(loc)) {
var bp = bpLocs.get(cf.function.body).get(loc); for (var bp : bpLocs.get(loc)) {
var ok = bp.condition == null ? true : Values.toBoolean(run(currFrame, bp.condition).result); var ok = bp.condition == null ? true : Values.toBoolean(run(currFrame, bp.condition).result);
if (ok) pauseDebug(ctx, bp); if (ok) pauseDebug(ctx, bp);
}
} }
// else if (isBreakpointable && tmpBreakpts.remove(loc)) pauseDebug(ctx, null); // else if (isBreakpointable && tmpBreakpts.remove(loc)) pauseDebug(ctx, null);
else if (isBreakpointable && pendingPause) { else if (isBreakpointable && pendingPause) {
@@ -1033,6 +1081,7 @@ public class SimpleDebugger implements Debugger {
public SimpleDebugger attach(DebugContext ctx) { public SimpleDebugger attach(DebugContext ctx) {
ctx.attachDebugger(this); ctx.attachDebugger(this);
contexts.put(ctx, ctx);
return this; return this;
} }

View File

@@ -13,7 +13,7 @@ public abstract class BaseFile<T> implements File {
protected abstract long onSeek(long offset, int pos); protected abstract long onSeek(long offset, int pos);
protected abstract boolean onClose(); protected abstract boolean onClose();
@Override public int read(byte[] buff) { @Override public synchronized int read(byte[] buff) {
try { try {
if (handle == null) throw new FilesystemException(ErrorReason.CLOSED); if (handle == null) throw new FilesystemException(ErrorReason.CLOSED);
if (!mode.readable) throw new FilesystemException(ErrorReason.NO_PERMISSION, "File not open for reading."); if (!mode.readable) throw new FilesystemException(ErrorReason.NO_PERMISSION, "File not open for reading.");
@@ -21,7 +21,7 @@ public abstract class BaseFile<T> implements File {
} }
catch (FilesystemException e) { throw e.setAction(ActionType.READ); } catch (FilesystemException e) { throw e.setAction(ActionType.READ); }
} }
@Override public void write(byte[] buff) { @Override public synchronized void write(byte[] buff) {
try { try {
if (handle == null) throw new FilesystemException(ErrorReason.CLOSED); if (handle == null) throw new FilesystemException(ErrorReason.CLOSED);
if (!mode.writable) throw new FilesystemException(ErrorReason.NO_PERMISSION, "File not open for writting."); if (!mode.writable) throw new FilesystemException(ErrorReason.NO_PERMISSION, "File not open for writting.");
@@ -29,7 +29,7 @@ public abstract class BaseFile<T> implements File {
} }
catch (FilesystemException e) { throw e.setAction(ActionType.WRITE); } catch (FilesystemException e) { throw e.setAction(ActionType.WRITE); }
} }
@Override public long seek(long offset, int pos) { @Override public synchronized long seek(long offset, int pos) {
try { try {
if (handle == null) throw new FilesystemException(ErrorReason.CLOSED); if (handle == null) throw new FilesystemException(ErrorReason.CLOSED);
if (!mode.writable) throw new FilesystemException(ErrorReason.NO_PERMISSION, "File not open for seeking."); if (!mode.writable) throw new FilesystemException(ErrorReason.NO_PERMISSION, "File not open for seeking.");
@@ -37,7 +37,7 @@ public abstract class BaseFile<T> implements File {
} }
catch (FilesystemException e) { throw e.setAction(ActionType.SEEK); } catch (FilesystemException e) { throw e.setAction(ActionType.SEEK); }
} }
@Override public boolean close() { @Override public synchronized boolean close() {
if (handle != null) { if (handle != null) {
try { try {
var res = onClose(); var res = onClose();

View File

@@ -66,7 +66,7 @@ public interface File {
public static File ofStream(InputStream str) { public static File ofStream(InputStream str) {
return new File() { return new File() {
@Override public int read(byte[] buff) { @Override public synchronized int read(byte[] buff) {
try { try {
try { return str.read(buff); } try { return str.read(buff); }
catch (NullPointerException e) { throw new FilesystemException(ErrorReason.ILLEGAL_ARGS, e.getMessage()); } catch (NullPointerException e) { throw new FilesystemException(ErrorReason.ILLEGAL_ARGS, e.getMessage()); }
@@ -78,7 +78,7 @@ public interface File {
} }
public static File ofStream(OutputStream str) { public static File ofStream(OutputStream str) {
return new File() { return new File() {
@Override public void write(byte[] buff) { @Override public synchronized void write(byte[] buff) {
try { try {
try { str.write(buff); } try { str.write(buff); }
catch (NullPointerException e) {throw new FilesystemException(ErrorReason.ILLEGAL_ARGS, e.getMessage()); } catch (NullPointerException e) {throw new FilesystemException(ErrorReason.ILLEGAL_ARGS, e.getMessage()); }
@@ -91,7 +91,7 @@ public interface File {
public static File ofLineWriter(LineWriter writer) { public static File ofLineWriter(LineWriter writer) {
var buff = new Buffer(); var buff = new Buffer();
return new File() { return new File() {
@Override public void write(byte[] val) { @Override public synchronized void write(byte[] val) {
try { try {
if (val == null) throw new FilesystemException(ErrorReason.ILLEGAL_ARGS, "Given buffer is null."); if (val == null) throw new FilesystemException(ErrorReason.ILLEGAL_ARGS, "Given buffer is null.");
@@ -99,6 +99,7 @@ public interface File {
if (b == '\n') { if (b == '\n') {
try { try {
writer.writeLine(new String(buff.data())); writer.writeLine(new String(buff.data()));
buff.clear();
} }
catch (IOException e) { catch (IOException e) {
throw new FilesystemException(ErrorReason.UNKNOWN, e.getMessage()); throw new FilesystemException(ErrorReason.UNKNOWN, e.getMessage());
@@ -117,7 +118,7 @@ public interface File {
private byte[] prev = new byte[0]; private byte[] prev = new byte[0];
@Override @Override
public int read(byte[] buff) { public synchronized int read(byte[] buff) {
try { try {
if (buff == null) throw new FilesystemException(ErrorReason.ILLEGAL_ARGS, "Given buffer is null."); if (buff == null) throw new FilesystemException(ErrorReason.ILLEGAL_ARGS, "Given buffer is null.");
var ptr = 0; var ptr = 0;

View File

@@ -1,7 +1,7 @@
package me.topchetoeu.jscript.utils.filesystem; package me.topchetoeu.jscript.utils.filesystem;
import me.topchetoeu.jscript.core.Extensions; import me.topchetoeu.jscript.runtime.Extensions;
import me.topchetoeu.jscript.core.Key; import me.topchetoeu.jscript.runtime.Key;
public interface Filesystem { public interface Filesystem {
public static final Key<Filesystem> KEY = new Key<>(); public static final Key<Filesystem> KEY = new Key<>();

View File

@@ -2,8 +2,8 @@ package me.topchetoeu.jscript.utils.filesystem;
import java.util.ArrayList; import java.util.ArrayList;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.Values;
public class FilesystemException extends RuntimeException { public class FilesystemException extends RuntimeException {
public final ErrorReason reason; public final ErrorReason reason;

View File

@@ -20,7 +20,7 @@ public class MemoryFilesystem implements Filesystem {
@Override public String normalize(String... path) { @Override public String normalize(String... path) {
return Paths.normalize(path); return Paths.normalize(path);
} }
@Override public File open(String _path, Mode perms) { @Override public synchronized File open(String _path, Mode perms) {
try { try {
var path = realPath(_path); var path = realPath(_path);
var pcount = path.getNameCount(); var pcount = path.getNameCount();
@@ -47,7 +47,7 @@ public class MemoryFilesystem implements Filesystem {
} }
catch (FilesystemException e) { throw e.setPath(_path).setAction(ActionType.OPEN); } catch (FilesystemException e) { throw e.setPath(_path).setAction(ActionType.OPEN); }
} }
@Override public boolean create(String _path, EntryType type) { @Override public synchronized boolean create(String _path, EntryType type) {
try { try {
var path = realPath(_path); var path = realPath(_path);
@@ -69,14 +69,14 @@ public class MemoryFilesystem implements Filesystem {
} }
catch (FilesystemException e) { throw e.setPath(_path).setAction(ActionType.CREATE); } catch (FilesystemException e) { throw e.setPath(_path).setAction(ActionType.CREATE); }
} }
@Override public FileStat stat(String _path) { @Override public synchronized FileStat stat(String _path) {
var path = realPath(_path); var path = realPath(_path);
if (files.containsKey(path)) return new FileStat(mode, EntryType.FILE); if (files.containsKey(path)) return new FileStat(mode, EntryType.FILE);
else if (folders.contains(path)) return new FileStat(mode, EntryType.FOLDER); else if (folders.contains(path)) return new FileStat(mode, EntryType.FOLDER);
else return new FileStat(Mode.NONE, EntryType.NONE); else return new FileStat(Mode.NONE, EntryType.NONE);
} }
@Override public void close() throws FilesystemException { @Override public synchronized void close() throws FilesystemException {
handles.close(); handles.close();
} }

View File

@@ -24,7 +24,7 @@ public class PhysicalFilesystem implements Filesystem {
@Override public String normalize(String... paths) { @Override public String normalize(String... paths) {
return Paths.normalize(paths); return Paths.normalize(paths);
} }
@Override public File open(String _path, Mode perms) { @Override public synchronized File open(String _path, Mode perms) {
try { try {
var path = realPath(normalize(_path)); var path = realPath(normalize(_path));
checkMode(path, perms); checkMode(path, perms);
@@ -39,7 +39,7 @@ public class PhysicalFilesystem implements Filesystem {
} }
catch (FilesystemException e) { throw e.setAction(ActionType.OPEN).setPath(_path); } catch (FilesystemException e) { throw e.setAction(ActionType.OPEN).setPath(_path); }
} }
@Override public boolean create(String _path, EntryType type) { @Override public synchronized boolean create(String _path, EntryType type) {
try { try {
var path = realPath(_path); var path = realPath(_path);
@@ -63,7 +63,7 @@ public class PhysicalFilesystem implements Filesystem {
return true; return true;
} }
@Override public FileStat stat(String _path) { @Override public synchronized FileStat stat(String _path) {
var path = realPath(_path); var path = realPath(_path);
if (!Files.exists(path)) return new FileStat(Mode.NONE, EntryType.NONE); if (!Files.exists(path)) return new FileStat(Mode.NONE, EntryType.NONE);
@@ -82,7 +82,7 @@ public class PhysicalFilesystem implements Filesystem {
Files.isDirectory(path) ? EntryType.FOLDER : EntryType.FILE Files.isDirectory(path) ? EntryType.FOLDER : EntryType.FILE
); );
} }
@Override public void close() throws FilesystemException { @Override public synchronized void close() throws FilesystemException {
try { try {
handles.close(); handles.close();
} }

View File

@@ -5,17 +5,21 @@ import java.util.Map;
import me.topchetoeu.jscript.common.Filename; import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.utils.permissions.Matcher; import me.topchetoeu.jscript.utils.permissions.Matcher;
import me.topchetoeu.jscript.utils.permissions.Permission;
import me.topchetoeu.jscript.utils.permissions.PermissionsProvider; import me.topchetoeu.jscript.utils.permissions.PermissionsProvider;
public class RootFilesystem implements Filesystem { public class RootFilesystem implements Filesystem {
public final Map<String, Filesystem> protocols = new HashMap<>(); public final Map<String, Filesystem> protocols = new HashMap<>();
public final PermissionsProvider perms; public final PermissionsProvider perms;
public static final Permission PERM_READ = new Permission("jscript.file.read", Matcher.fileWildcard());
public static final Permission PERM_WRITE = new Permission("jscript.file.read", Matcher.fileWildcard());
private boolean canRead(String _path) { private boolean canRead(String _path) {
return perms.hasPermission("jscript.file.read:" + _path, Matcher.fileWildcard()); return perms.hasPermission(PERM_READ, _path);
} }
private boolean canWrite(String _path) { private boolean canWrite(String _path) {
return perms.hasPermission("jscript.file.write:" + _path, Matcher.fileWildcard()); return perms.hasPermission(PERM_WRITE, _path);
} }
private void modeAllowed(String _path, Mode mode) throws FilesystemException { private void modeAllowed(String _path, Mode mode) throws FilesystemException {
@@ -49,7 +53,7 @@ public class RootFilesystem implements Filesystem {
else return filename.protocol + "://" + protocol.normalize(paths); else return filename.protocol + "://" + protocol.normalize(paths);
} }
} }
@Override public File open(String path, Mode perms) throws FilesystemException { @Override public synchronized File open(String path, Mode perms) throws FilesystemException {
try { try {
var filename = Filename.parse(path); var filename = Filename.parse(path);
var protocol = getProtocol(filename); var protocol = getProtocol(filename);
@@ -59,7 +63,7 @@ public class RootFilesystem implements Filesystem {
} }
catch (FilesystemException e) { throw e.setPath(path).setAction(ActionType.OPEN); } catch (FilesystemException e) { throw e.setPath(path).setAction(ActionType.OPEN); }
} }
@Override public boolean create(String path, EntryType type) throws FilesystemException { @Override public synchronized boolean create(String path, EntryType type) throws FilesystemException {
try { try {
var filename = Filename.parse(path); var filename = Filename.parse(path);
var protocol = getProtocol(filename); var protocol = getProtocol(filename);
@@ -69,7 +73,7 @@ public class RootFilesystem implements Filesystem {
} }
catch (FilesystemException e) { throw e.setPath(path).setAction(ActionType.CREATE); } catch (FilesystemException e) { throw e.setPath(path).setAction(ActionType.CREATE); }
} }
@Override public FileStat stat(String path) throws FilesystemException { @Override public synchronized FileStat stat(String path) throws FilesystemException {
try { try {
var filename = Filename.parse(path); var filename = Filename.parse(path);
var protocol = getProtocol(filename); var protocol = getProtocol(filename);
@@ -78,7 +82,7 @@ public class RootFilesystem implements Filesystem {
} }
catch (FilesystemException e) { throw e.setPath(path).setAction(ActionType.STAT); } catch (FilesystemException e) { throw e.setPath(path).setAction(ActionType.STAT); }
} }
@Override public void close() throws FilesystemException { @Override public synchronized void close() throws FilesystemException {
try { try {
for (var protocol : protocols.values()) { for (var protocol : protocols.values()) {
protocol.close(); protocol.close();

View File

@@ -2,41 +2,51 @@ package me.topchetoeu.jscript.utils.filesystem;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.HashMap;
public class STDFilesystem implements Filesystem { public class STDFilesystem implements Filesystem {
private final HashMap<String, File> handles = new HashMap<>(); private File in;
private File out;
private File err;
@Override @Override
public String normalize(String... path) { public String normalize(String... path) {
var res = Paths.normalize(path); var res = Paths.normalize(path);
while (res.startsWith("/")) res = res.substring(1); while (res.startsWith("/")) res = res.substring(1);
while (res.endsWith("/")) res = res.substring(0, res.length() - 1);
return res; return res;
} }
@Override public File open(String path, Mode mode) { @Override public synchronized File open(String path, Mode mode) {
path = normalize(path); path = normalize(path);
if (handles.containsKey(path)) return handles.get(path); if (in != null && path.equals("in")) return in;
else if (out != null && path.equals("out")) return out;
else if (err != null && path.equals("err")) return err;
else throw new FilesystemException(ErrorReason.DOESNT_EXIST).setAction(ActionType.OPEN).setPath(path); else throw new FilesystemException(ErrorReason.DOESNT_EXIST).setAction(ActionType.OPEN).setPath(path);
} }
@Override public FileStat stat(String path) { @Override public synchronized FileStat stat(String path) {
path = normalize(path); path = normalize(path);
if (handles.containsKey(path)) return new FileStat(Mode.READ_WRITE, EntryType.FILE); if (path.equals("in") || path.equals("out") || path.equals("err")) return new FileStat(Mode.READ_WRITE, EntryType.FILE);
else return new FileStat(Mode.NONE, EntryType.NONE); else return new FileStat(Mode.NONE, EntryType.NONE);
} }
@Override public void close() { @Override public synchronized void close() {
handles.clear(); in = out = err = null;
} }
public STDFilesystem add(String name, File handle) { public STDFilesystem(File in, File out, File err) {
this.handles.put(name, handle); this.in = in;
return this; this.out = out;
this.err = err;
} }
public STDFilesystem(InputStream in, OutputStream out, OutputStream err) {
public static STDFilesystem ofStd(InputStream in, OutputStream out, OutputStream err) { if (in != null) this.in = File.ofStream(in);
return new STDFilesystem() if (out != null) this.out = File.ofStream(out);
.add("in", File.ofStream(in)) if (err != null) this.err = File.ofStream(err);
.add("out", File.ofStream(out)) }
.add("err", File.ofStream(err)); public STDFilesystem(LineReader in, LineWriter out) {
if (in != null) this.in = File.ofLineReader(in);
if (out != null) {
this.out = File.ofLineWriter(out);
this.err = File.ofLineWriter(out);
}
} }
} }

View File

@@ -2,15 +2,33 @@ package me.topchetoeu.jscript.utils.interop;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.core.values.NativeWrapper; import me.topchetoeu.jscript.runtime.Extensions;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.Key;
import me.topchetoeu.jscript.runtime.values.NativeWrapper;
import me.topchetoeu.jscript.runtime.values.Values;
public class Arguments { public class Arguments implements Extensions {
public final Object self; public final Object self;
public final Object[] args; public final Object[] args;
public final Context ctx; public final Context ctx;
@Override public <T> void add(Key<T> key, T obj) {
ctx.add(key, obj);
}
@Override public <T> T get(Key<T> key) {
return ctx.get(key);
}
@Override public boolean has(Key<?> key) {
return ctx.has(key);
}
@Override public boolean remove(Key<?> key) {
return ctx.remove(key);
}
@Override public Iterable<Key<?>> keys() {
return ctx.keys();
}
public int n() { public int n() {
return args.length; return args.length;
} }

View File

@@ -1,7 +1,6 @@
package me.topchetoeu.jscript.utils.interop; package me.topchetoeu.jscript.utils.interop;
public enum ExposeType { public enum ExposeType {
INIT,
METHOD, METHOD,
GETTER, GETTER,
SETTER, SETTER,

View File

@@ -10,22 +10,27 @@ import java.util.HashSet;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import me.topchetoeu.jscript.common.Location; import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.core.Environment; import me.topchetoeu.jscript.runtime.Copyable;
import me.topchetoeu.jscript.core.WrapperProvider; import me.topchetoeu.jscript.runtime.Extensions;
import me.topchetoeu.jscript.core.values.FunctionValue; import me.topchetoeu.jscript.runtime.Key;
import me.topchetoeu.jscript.core.values.NativeFunction; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.runtime.exceptions.InterruptException;
import me.topchetoeu.jscript.core.values.Symbol; import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.runtime.values.NativeFunction;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.core.exceptions.InterruptException; import me.topchetoeu.jscript.runtime.values.Symbol;
import me.topchetoeu.jscript.runtime.values.Values;
public class NativeWrapperProvider implements Copyable {
public static final Key<NativeWrapperProvider> KEY = new Key<>();
public class NativeWrapperProvider implements WrapperProvider {
private final HashMap<Class<?>, FunctionValue> constructors = new HashMap<>(); private final HashMap<Class<?>, FunctionValue> constructors = new HashMap<>();
private final HashMap<Class<?>, ObjectValue> prototypes = new HashMap<>(); private final HashMap<Class<?>, ObjectValue> prototypes = new HashMap<>();
private final HashMap<Class<?>, ObjectValue> namespaces = new HashMap<>(); private final HashMap<Class<?>, ObjectValue> namespaces = new HashMap<>();
private final Environment env; private final HashMap<Class<?>, Class<?>> classToProxy = new HashMap<>();
private final HashMap<Class<?>, Class<?>> proxyToClass = new HashMap<>();
private final HashSet<Class<?>> ignore = new HashSet<>();
private static Object call(Context ctx, String name, Method method, Object thisArg, Object... args) { private static Object call(Context ctx, String name, Method method, Object thisArg, Object... args) {
try { try {
@@ -106,11 +111,12 @@ public class NativeWrapperProvider implements WrapperProvider {
else return name; else return name;
} }
private static void apply(ObjectValue obj, Environment env, ExposeTarget target, Class<?> clazz) { private static boolean apply(ObjectValue obj, ExposeTarget target, Class<?> clazz) {
var getters = new HashMap<Object, FunctionValue>(); var getters = new HashMap<Object, FunctionValue>();
var setters = new HashMap<Object, FunctionValue>(); var setters = new HashMap<Object, FunctionValue>();
var props = new HashSet<Object>(); var props = new HashSet<Object>();
var nonProps = new HashSet<Object>(); var nonProps = new HashSet<Object>();
var any = false;
for (var method : clazz.getDeclaredMethods()) { for (var method : clazz.getDeclaredMethods()) {
for (var annotation : method.getAnnotationsByType(Expose.class)) { for (var annotation : method.getAnnotationsByType(Expose.class)) {
@@ -120,15 +126,9 @@ public class NativeWrapperProvider implements WrapperProvider {
var name = getName(method, annotation.value()); var name = getName(method, annotation.value());
var key = getKey(name); var key = getKey(name);
var repeat = false; var repeat = false;
any = true;
switch (annotation.type()) { switch (annotation.type()) {
case INIT:
checkSignature(method, true,
target == ExposeTarget.CONSTRUCTOR ? FunctionValue.class : ObjectValue.class,
Environment.class
);
call(null, null, method, obj, null, env);
break;
case METHOD: case METHOD:
if (props.contains(key) || nonProps.contains(key)) repeat = true; if (props.contains(key) || nonProps.contains(key)) repeat = true;
else { else {
@@ -168,11 +168,17 @@ public class NativeWrapperProvider implements WrapperProvider {
var name = getName(method, annotation.value()); var name = getName(method, annotation.value());
var key = getKey(name); var key = getKey(name);
var repeat = false; var repeat = false;
any = true;
if (props.contains(key) || nonProps.contains(key)) repeat = true; if (props.contains(key) || nonProps.contains(key)) repeat = true;
else { else {
checkSignature(method, true, Environment.class); checkSignature(method, true);
obj.defineProperty(null, key, call(new Context(env), name, method, null, env), true, true, false); try {
obj.defineProperty(null, key, method.invoke(null), true, true, false);
}
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new RuntimeException(e);
}
nonProps.add(key); nonProps.add(key);
} }
@@ -191,11 +197,29 @@ public class NativeWrapperProvider implements WrapperProvider {
var name = getName(field, annotation.value()); var name = getName(field, annotation.value());
var key = getKey(name); var key = getKey(name);
var repeat = false; var repeat = false;
any = true;
if (props.contains(key) || nonProps.contains(key)) repeat = true; if (props.contains(key) || nonProps.contains(key)) repeat = true;
else { else {
try { try {
obj.defineProperty(null, key, Values.normalize(new Context(env), field.get(null)), true, true, false); if (Modifier.isStatic(field.getModifiers())) {
obj.defineProperty(null, key, Values.normalize(null, field.get(null)), true, true, false);
}
else {
obj.defineProperty(
null, key,
new NativeFunction("get " + key, args -> {
try { return field.get(args.self(clazz)); }
catch (IllegalAccessException e) { e.printStackTrace(); return null; }
}),
Modifier.isFinal(field.getModifiers()) ? null : new NativeFunction("get " + key, args -> {
try { field.set(args.self(clazz), args.convert(0, field.getType())); }
catch (IllegalAccessException e) { e.printStackTrace(); }
return null;
}),
true, false
);
}
nonProps.add(key); nonProps.add(key);
} }
catch (IllegalArgumentException | IllegalAccessException e) { } catch (IllegalArgumentException | IllegalAccessException e) { }
@@ -210,9 +234,11 @@ public class NativeWrapperProvider implements WrapperProvider {
} }
for (var key : props) obj.defineProperty(null, key, getters.get(key), setters.get(key), true, false); for (var key : props) obj.defineProperty(null, key, getters.get(key), setters.get(key), true, false);
return any;
} }
private static Method getConstructor(Environment env, Class<?> clazz) { private static Method getConstructor(Class<?> clazz) {
for (var method : clazz.getDeclaredMethods()) { for (var method : clazz.getDeclaredMethods()) {
if (!method.isAnnotationPresent(ExposeConstructor.class)) continue; if (!method.isAnnotationPresent(ExposeConstructor.class)) continue;
checkSignature(method, true, Arguments.class); checkSignature(method, true, Arguments.class);
@@ -228,10 +254,10 @@ public class NativeWrapperProvider implements WrapperProvider {
* All accessors and methods will expect the this argument to be a native wrapper of the given class type. * All accessors and methods will expect the this argument to be a native wrapper of the given class type.
* @param clazz The class for which a prototype should be generated * @param clazz The class for which a prototype should be generated
*/ */
public static ObjectValue makeProto(Environment env, Class<?> clazz) { public static ObjectValue makeProto(Class<?> clazz) {
var res = new ObjectValue(); var res = new ObjectValue();
res.defineProperty(null, Symbol.get("Symbol.typeName"), getName(clazz)); res.defineProperty(null, Symbol.get("Symbol.typeName"), getName(clazz));
apply(res, env, ExposeTarget.PROTOTYPE, clazz); if (!apply(res, ExposeTarget.PROTOTYPE, clazz)) return null;
return res; return res;
} }
/** /**
@@ -240,14 +266,14 @@ public class NativeWrapperProvider implements WrapperProvider {
* When the function gets called, the underlying constructor will get called, unless the constructor is inaccessible. * When the function gets called, the underlying constructor will get called, unless the constructor is inaccessible.
* @param clazz The class for which a constructor should be generated * @param clazz The class for which a constructor should be generated
*/ */
public static FunctionValue makeConstructor(Environment ctx, Class<?> clazz) { public static FunctionValue makeConstructor(Class<?> clazz) {
var constr = getConstructor(ctx, clazz); var constr = getConstructor(clazz);
FunctionValue res = constr == null ? FunctionValue res = constr == null ?
new NativeFunction(getName(clazz), args -> { throw EngineException.ofError("This constructor is not invokable."); }) : new NativeFunction(getName(clazz), args -> { throw EngineException.ofError("This constructor is not invokable."); }) :
create(getName(clazz), constr); create(getName(clazz), constr);
apply(res, ctx, ExposeTarget.CONSTRUCTOR, clazz); apply(res, ExposeTarget.CONSTRUCTOR, clazz);
return res; return res;
} }
@@ -257,15 +283,34 @@ public class NativeWrapperProvider implements WrapperProvider {
* This method behaves almost like {@link NativeWrapperProvider#makeConstructor}, but will return an object instead. * This method behaves almost like {@link NativeWrapperProvider#makeConstructor}, but will return an object instead.
* @param clazz The class for which a constructor should be generated * @param clazz The class for which a constructor should be generated
*/ */
public static ObjectValue makeNamespace(Environment ctx, Class<?> clazz) { public static ObjectValue makeNamespace(Class<?> clazz) {
var res = new ObjectValue(); var res = new ObjectValue();
res.defineProperty(null, Symbol.get("Symbol.typeName"), getName(clazz)); res.defineProperty(null, Symbol.get("Symbol.typeName"), getName(clazz));
apply(res, ctx, ExposeTarget.NAMESPACE, clazz); if (!apply(res, ExposeTarget.NAMESPACE, clazz)) return null;
return res; return res;
} }
private void updateProtoChain(Class<?> clazz, ObjectValue proto, FunctionValue constr) {
var parent = clazz;
while (true) {
parent = parent.getSuperclass();
if (parent == null) break;
var parentProto = getProto(parent);
var parentConstr = getConstr(parent);
if (parentProto != null && parentConstr != null) {
Values.setPrototype(Extensions.EMPTY, proto, parentProto);
Values.setPrototype(Extensions.EMPTY, constr, parentConstr);
return;
}
}
}
private void initType(Class<?> clazz, FunctionValue constr, ObjectValue proto) { private void initType(Class<?> clazz, FunctionValue constr, ObjectValue proto) {
if (constr != null && proto != null) return; if (constr != null && proto != null || ignore.contains(clazz)) return;
// i vomit // i vomit
if ( if (
clazz == Object.class || clazz == Object.class ||
@@ -281,8 +326,10 @@ public class NativeWrapperProvider implements WrapperProvider {
clazz.isSynthetic() clazz.isSynthetic()
) return; ) return;
if (constr == null) constr = makeConstructor(env, clazz); if (constr == null) constr = makeConstructor(clazz);
if (proto == null) proto = makeProto(env, clazz); if (proto == null) proto = makeProto(clazz);
if (constr == null || proto == null) return;
proto.defineProperty(null, "constructor", constr, true, false, false); proto.defineProperty(null, "constructor", constr, true, false, false);
constr.defineProperty(null, "prototype", proto, true, false, false); constr.defineProperty(null, "prototype", proto, true, false, false);
@@ -290,59 +337,85 @@ public class NativeWrapperProvider implements WrapperProvider {
prototypes.put(clazz, proto); prototypes.put(clazz, proto);
constructors.put(clazz, constr); constructors.put(clazz, constr);
var parent = clazz.getSuperclass(); updateProtoChain(clazz, proto, constr);
if (parent == null) return;
var parentProto = getProto(parent);
var parentConstr = getConstr(parent);
if (parentProto != null) Values.setPrototype(Context.NULL, proto, parentProto);
if (parentConstr != null) Values.setPrototype(Context.NULL, constr, parentConstr);
} }
public ObjectValue getProto(Class<?> clazz) { public ObjectValue getProto(Class<?> clazz) {
if (proxyToClass.containsKey(clazz)) return getProto(proxyToClass.get(clazz));
initType(clazz, constructors.get(clazz), prototypes.get(clazz)); initType(clazz, constructors.get(clazz), prototypes.get(clazz));
return prototypes.get(clazz); while (clazz != null) {
var res = prototypes.get(clazz);
if (res != null) return res;
clazz = clazz.getSuperclass();
}
return null;
} }
public ObjectValue getNamespace(Class<?> clazz) { public ObjectValue getNamespace(Class<?> clazz) {
if (!namespaces.containsKey(clazz)) namespaces.put(clazz, makeNamespace(env, clazz)); if (proxyToClass.containsKey(clazz)) return getNamespace(proxyToClass.get(clazz));
return namespaces.get(clazz);
if (!namespaces.containsKey(clazz)) namespaces.put(clazz, makeNamespace(clazz));
while (clazz != null) {
var res = namespaces.get(clazz);
if (res != null) return res;
clazz = clazz.getSuperclass();
}
return null;
} }
public FunctionValue getConstr(Class<?> clazz) { public FunctionValue getConstr(Class<?> clazz) {
if (proxyToClass.containsKey(clazz)) return getConstr(proxyToClass.get(clazz));
initType(clazz, constructors.get(clazz), prototypes.get(clazz)); initType(clazz, constructors.get(clazz), prototypes.get(clazz));
return constructors.get(clazz); while (clazz != null) {
var res = constructors.get(clazz);
if (res != null) return res;
clazz = clazz.getSuperclass();
}
return null;
} }
@Override public WrapperProvider fork(Environment env) { public NativeWrapperProvider copy() {
return new NativeWrapperProvider(env); var res = new NativeWrapperProvider();
for (var pair : classToProxy.entrySet()) {
res.set(pair.getKey(), pair.getValue());
}
return this;
} }
public void setProto(Class<?> clazz, ObjectValue value) { public void set(Class<?> clazz, Class<?> wrapper) {
prototypes.put(clazz, value); if (clazz == null) return;
} if (wrapper == null) wrapper = clazz;
public void setConstr(Class<?> clazz, FunctionValue value) { if (classToProxy.get(clazz) == wrapper) return;
constructors.put(clazz, value);
}
private void initError() { classToProxy.remove(wrapper);
var proto = new ObjectValue(); proxyToClass.remove(clazz);
proto.defineProperty(null, "message", new NativeFunction("message", args -> {
if (args.self instanceof Throwable) return ((Throwable)args.self).getMessage(); classToProxy.put(clazz, wrapper);
else return null; proxyToClass.put(wrapper, clazz);
}));
proto.defineProperty(null, "name", new NativeFunction("name", args -> getName(args.self.getClass()))); ignore.remove(clazz);
proto.defineProperty(null, "toString", new NativeFunction("toString", args -> args.self.toString()));
var proto = makeProto(wrapper);
var constr = makeConstructor(wrapper);
prototypes.put(clazz, proto);
constructors.put(clazz, constr);
var constr = makeConstructor(null, Throwable.class);
proto.defineProperty(null, "constructor", constr, true, false, false); proto.defineProperty(null, "constructor", constr, true, false, false);
constr.defineProperty(null, "prototype", proto, true, false, false); constr.defineProperty(null, "prototype", proto, true, false, false);
setProto(Throwable.class, proto); for (var el : prototypes.keySet()) {
setConstr(Throwable.class, constr); if (clazz.isAssignableFrom(el)) {
updateProtoChain(el, getProto(el), getConstr(el));
}
}
} }
public NativeWrapperProvider(Environment env) { public NativeWrapperProvider() { }
this.env = env;
initError(); public static NativeWrapperProvider get(Extensions ext) {
return ext.get(KEY);
} }
} }

View File

@@ -1,6 +1,6 @@
package me.topchetoeu.jscript.utils.modules; package me.topchetoeu.jscript.utils.modules;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Context;
public abstract class Module { public abstract class Module {
private Object value; private Object value;

View File

@@ -3,9 +3,9 @@ package me.topchetoeu.jscript.utils.modules;
import java.util.HashMap; import java.util.HashMap;
import me.topchetoeu.jscript.common.Filename; import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.core.Extensions; import me.topchetoeu.jscript.runtime.Extensions;
import me.topchetoeu.jscript.core.Key; import me.topchetoeu.jscript.runtime.Key;
import me.topchetoeu.jscript.utils.filesystem.Filesystem; import me.topchetoeu.jscript.utils.filesystem.Filesystem;
import me.topchetoeu.jscript.utils.filesystem.Mode; import me.topchetoeu.jscript.utils.filesystem.Mode;
@@ -25,7 +25,7 @@ public interface ModuleRepo {
if (modules.containsKey(name)) return modules.get(name); if (modules.containsKey(name)) return modules.get(name);
var env = ctx.environment.child(); var env = ctx.extensions.child();
env.add(CWD, fs.normalize(name, "..")); env.add(CWD, fs.normalize(name, ".."));
var mod = new SourceModule(filename, src, env); var mod = new SourceModule(filename, src, env);

View File

@@ -2,8 +2,8 @@ package me.topchetoeu.jscript.utils.modules;
import java.util.HashMap; import java.util.HashMap;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
public class RootModuleRepo implements ModuleRepo { public class RootModuleRepo implements ModuleRepo {
public final HashMap<String, ModuleRepo> repos = new HashMap<>(); public final HashMap<String, ModuleRepo> repos = new HashMap<>();

View File

@@ -1,23 +1,23 @@
package me.topchetoeu.jscript.utils.modules; package me.topchetoeu.jscript.utils.modules;
import me.topchetoeu.jscript.common.Filename; import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.core.Environment; import me.topchetoeu.jscript.runtime.Extensions;
public class SourceModule extends Module { public class SourceModule extends Module {
public final Filename filename; public final Filename filename;
public final String source; public final String source;
public final Environment env; public final Extensions ext;
@Override @Override
protected Object onLoad(Context ctx) { protected Object onLoad(Context ctx) {
var res = new Context(env).compile(filename, source); var res = new Context(ext).compile(filename, source);
return res.call(ctx); return res.call(ctx);
} }
public SourceModule(Filename filename, String source, Environment env) { public SourceModule(Filename filename, String source, Extensions ext) {
this.filename = filename; this.filename = filename;
this.source = source; this.source = source;
this.env = env; this.ext = ext;
} }
} }

Some files were not shown because too many files have changed in this diff Show More