refactor: fully separate event loop from context

This commit is contained in:
TopchetoEU 2024-02-29 00:23:14 +02:00
parent 52489ad3a8
commit 49dd725669
Signed by: topchetoeu
GPG Key ID: 6531B8583E5F6ED4
79 changed files with 526 additions and 519 deletions

View File

@ -1,4 +1,4 @@
package me.topchetoeu.jscript.compilation;
package me.topchetoeu.jscript.common;
public class FunctionBody {
public final FunctionBody[] children;

View File

@ -1,11 +1,10 @@
package me.topchetoeu.jscript.compilation;
package me.topchetoeu.jscript.common;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.HashMap;
import me.topchetoeu.jscript.core.Operation;
import me.topchetoeu.jscript.core.exceptions.SyntaxException;
public class Instruction {

View File

@ -1,7 +1,9 @@
package me.topchetoeu.jscript.common;
import java.util.ArrayList;
public class Location implements Comparable<Location> {
public static final Location INTERNAL = new Location(0, 0, new Filename("jscript", "native"));
public static final Location INTERNAL = new Location(-1, -1, new Filename("jscript", "native"));
private int line;
private int start;
private Filename filename;
@ -12,7 +14,13 @@ public class Location implements Comparable<Location> {
@Override
public String toString() {
return filename.toString() + ":" + line + ":" + start;
var res = new ArrayList<String>();
if (filename != null) res.add(filename.toString());
if (line >= 0) res.add(line + "");
if (start >= 0) res.add(start + "");
return String.join(":", res);
}
public Location add(int n, boolean clone) {

View File

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

View File

@ -13,11 +13,6 @@ public class Reading {
return reader.readLine();
}
/**
* Reads the given stream to a string
* @param in
* @return
*/
public static String streamToString(InputStream in) {
try {
return new String(in.readAllBytes());

View File

@ -1,4 +1,4 @@
package me.topchetoeu.jscript.compilation.mapping;
package me.topchetoeu.jscript.common.mapping;
public enum ConvertType {
Exact,

View File

@ -1,4 +1,4 @@
package me.topchetoeu.jscript.compilation.mapping;
package me.topchetoeu.jscript.common.mapping;
import java.util.ArrayList;
import java.util.Collections;
@ -9,8 +9,9 @@ import java.util.TreeMap;
import java.util.TreeSet;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.core.scope.LocalScopeRecord;
import me.topchetoeu.jscript.utils.mapping.SourceMap;
public class FunctionMap {
public static class FunctionMapBuilder {
@ -22,10 +23,12 @@ public class FunctionMap {
}
public FunctionMapBuilder setDebug(Location loc, BreakpointType type) {
if (loc == null || type == null || type == BreakpointType.NONE) return this;
breakpoints.put(loc, type);
return this;
}
public FunctionMapBuilder setLocation(int i, Location loc) {
if (loc == null || i < 0) return this;
sourceMap.put(i, loc);
return this;
}
@ -36,9 +39,11 @@ public class FunctionMap {
}
public Location first() {
if (sourceMap.size() == 0) return null;
return sourceMap.firstEntry().getValue();
}
public Location last() {
if (sourceMap.size() == 0) return null;
return sourceMap.lastEntry().getValue();
}
@ -68,7 +73,9 @@ public class FunctionMap {
public Location toLocation(int pc, boolean approxiamte) {
var res = pcToLoc.get(pc);
if (!approxiamte || res != null) return res;
return pcToLoc.headMap(pc, true).lastEntry().getValue();
var entry = pcToLoc.headMap(pc, true).lastEntry();
if (entry == null) return null;
else return entry.getValue();
}
public Location toLocation(int pc) {
return toLocation(pc, false);
@ -85,9 +92,11 @@ public class FunctionMap {
}
public Location start() {
if (pcToLoc.size() == 0) return null;
return pcToLoc.firstEntry().getValue();
}
public Location end() {
if (pcToLoc.size() == 0) return null;
return pcToLoc.lastEntry().getValue();
}
@ -126,6 +135,9 @@ public class FunctionMap {
if (b != null) pcToLoc.remove(b);
if (a != null) locToPc.remove(a);
pcToLoc.put(pc, loc);
locToPc.put(loc, pc);
}
for (var el : breakpoints.entrySet()) {
if (el.getValue() == null || el.getValue() == BreakpointType.NONE) continue;

View File

@ -1,7 +1,7 @@
package me.topchetoeu.jscript.compilation;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.core.Operation;
import me.topchetoeu.jscript.common.Operation;
public abstract class AssignableStatement extends Statement {
public abstract Statement toAssign(Statement val, Operation operation);

View File

@ -4,10 +4,12 @@ import java.util.List;
import java.util.LinkedList;
import java.util.Vector;
import me.topchetoeu.jscript.common.FunctionBody;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.mapping.FunctionMap;
import me.topchetoeu.jscript.compilation.mapping.FunctionMap.FunctionMapBuilder;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.common.mapping.FunctionMap;
import me.topchetoeu.jscript.common.mapping.FunctionMap.FunctionMapBuilder;
import me.topchetoeu.jscript.core.scope.LocalScopeRecord;
public class CompileResult {
@ -59,6 +61,9 @@ public class CompileResult {
return child;
}
public FunctionMap map() {
return map.build(scope);
}
public FunctionBody body() {
var builtChildren = new FunctionBody[children.size()];
@ -67,10 +72,6 @@ public class CompileResult {
return new FunctionBody(scope.localsCount(), length, instructions.toArray(Instruction[]::new), builtChildren);
}
public FunctionMap map() {
return map.build();
}
public CompileResult(LocalScopeRecord scope) {
this.scope = scope;
}

View File

@ -3,8 +3,9 @@ package me.topchetoeu.jscript.compilation;
import java.util.List;
import java.util.Vector;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.values.FunctionStatement;
public class CompoundStatement extends Statement {

View File

@ -1,7 +1,7 @@
package me.topchetoeu.jscript.compilation;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
public abstract class Statement {
private Location _loc;

View File

@ -1,5 +1,6 @@
package me.topchetoeu.jscript.compilation;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.core.exceptions.SyntaxException;
public class ThrowSyntaxStatement extends Statement {

View File

@ -2,8 +2,9 @@ package me.topchetoeu.jscript.compilation;
import java.util.List;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.values.FunctionStatement;
public class VariableDeclareStatement extends Statement {

View File

@ -1,8 +1,8 @@
package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
public class BreakStatement extends Statement {

View File

@ -1,8 +1,8 @@
package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
public class ContinueStatement extends Statement {

View File

@ -1,8 +1,8 @@
package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
public class DebugStatement extends Statement {

View File

@ -1,8 +1,8 @@
package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
public class DeleteStatement extends Statement {

View File

@ -1,10 +1,10 @@
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.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
public class DoWhileStatement extends Statement {
public final Statement condition, body;

View File

@ -1,11 +1,11 @@
package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
import me.topchetoeu.jscript.core.Operation;
public class ForInStatement extends Statement {
public final String varName;

View File

@ -1,10 +1,10 @@
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.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
public class ForStatement extends Statement {
public final Statement declaration, assignment, condition, body;

View File

@ -1,10 +1,10 @@
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.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
public class IfStatement extends Statement {
public final Statement condition, body, elseBody;
@ -31,7 +31,7 @@ public class IfStatement extends Statement {
elseBody.compile(target, pollute, breakpoint);
int end = target.size();
target.set(start, Instruction.jmpIfNot(mid - start - 1));
target.set(start, Instruction.jmpIfNot(mid - start + 1));
target.set(mid, Instruction.jmp(end - mid));
}
}

View File

@ -1,8 +1,8 @@
package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
public class ReturnStatement extends Statement {

View File

@ -2,13 +2,13 @@ package me.topchetoeu.jscript.compilation.control;
import java.util.HashMap;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.common.Instruction.Type;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.Instruction.Type;
import me.topchetoeu.jscript.core.Operation;
public class SwitchStatement extends Statement {
public static class SwitchCase {

View File

@ -1,8 +1,8 @@
package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
public class ThrowStatement extends Statement {

View File

@ -1,10 +1,10 @@
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.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
public class TryStatement extends Statement {
public final Statement tryBody;

View File

@ -1,11 +1,11 @@
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.common.Instruction.Type;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.Instruction.Type;
public class WhileStatement extends Statement {
public final Statement condition, body;

View File

@ -3,7 +3,7 @@ package me.topchetoeu.jscript.compilation.parsing;
import java.util.HashMap;
import java.util.Map;
import me.topchetoeu.jscript.core.Operation;
import me.topchetoeu.jscript.common.Operation;
public enum Operator {
MULTIPLY("*", Operation.MULTIPLY, 13),

View File

@ -8,14 +8,15 @@ import java.util.LinkedHashMap;
import java.util.List;
import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.compilation.*;
import me.topchetoeu.jscript.compilation.VariableDeclareStatement.Pair;
import me.topchetoeu.jscript.compilation.control.*;
import me.topchetoeu.jscript.compilation.control.SwitchStatement.SwitchCase;
import me.topchetoeu.jscript.compilation.parsing.ParseRes.State;
import me.topchetoeu.jscript.compilation.values.*;
import me.topchetoeu.jscript.core.Operation;
import me.topchetoeu.jscript.core.scope.LocalScopeRecord;
import me.topchetoeu.jscript.core.exceptions.SyntaxException;
@ -400,6 +401,10 @@ public class Parsing {
return -1;
}
private static boolean inBounds(List<Token> tokens, int i) {
return i >= 0 && i < tokens.size();
}
private static String parseString(Location loc, String literal) {
var res = new StringBuilder();
@ -605,49 +610,41 @@ public class Parsing {
}
public static ParseRes<String> parseIdentifier(List<Token> tokens, int i) {
try {
if (inBounds(tokens, i)) {
if (tokens.get(i).isIdentifier()) {
return ParseRes.res(tokens.get(i).identifier(), 1);
}
else return ParseRes.failed();
}
catch (IndexOutOfBoundsException e) {
return ParseRes.failed();
}
else return ParseRes.failed();
}
public static ParseRes<Operator> parseOperator(List<Token> tokens, int i) {
try {
if (inBounds(tokens, i)) {
if (tokens.get(i).isOperator()) {
return ParseRes.res(tokens.get(i).operator(), 1);
}
else return ParseRes.failed();
}
catch (IndexOutOfBoundsException e) {
return ParseRes.failed();
}
else return ParseRes.failed();
}
public static boolean isIdentifier(List<Token> tokens, int i, String lit) {
try {
if (inBounds(tokens, i)) {
if (tokens.get(i).isIdentifier(lit)) {
return true;
}
else return false;
}
catch (IndexOutOfBoundsException e) {
return false;
}
else return false;
}
public static boolean isOperator(List<Token> tokens, int i, Operator op) {
try {
if (inBounds(tokens, i)) {
if (tokens.get(i).isOperator(op)) {
return true;
}
else return false;
}
catch (IndexOutOfBoundsException e) {
return false;
}
else return false;
}
public static boolean isStatementEnd(List<Token> tokens, int i) {
if (isOperator(tokens, i, Operator.SEMICOLON)) return true;
@ -662,32 +659,27 @@ public class Parsing {
public static ParseRes<ConstantStatement> parseString(Filename filename, List<Token> tokens, int i) {
var loc = getLoc(filename, tokens, i);
try {
if (inBounds(tokens, i)) {
if (tokens.get(i).isString()) {
return ParseRes.res(new ConstantStatement(loc, tokens.get(i).string()), 1);
}
else return ParseRes.failed();
}
catch (IndexOutOfBoundsException e) {
return ParseRes.failed();
}
else return ParseRes.failed();
}
public static ParseRes<ConstantStatement> parseNumber(Filename filename, List<Token> tokens, int i) {
var loc = getLoc(filename, tokens, i);
try {
if (inBounds(tokens, i)) {
if (tokens.get(i).isNumber()) {
return ParseRes.res(new ConstantStatement(loc, tokens.get(i).number()), 1);
}
else return ParseRes.failed();
}
catch (IndexOutOfBoundsException e) {
return ParseRes.failed();
}
else return ParseRes.failed();
}
public static ParseRes<RegexStatement> parseRegex(Filename filename, List<Token> tokens, int i) {
var loc = getLoc(filename, tokens, i);
try {
if (inBounds(tokens, i)) {
if (tokens.get(i).isRegex()) {
var val = tokens.get(i).regex();
var index = val.lastIndexOf('/');
@ -697,9 +689,7 @@ public class Parsing {
}
else return ParseRes.failed();
}
catch (IndexOutOfBoundsException e) {
return ParseRes.failed();
}
return ParseRes.failed();
}
public static ParseRes<ArrayStatement> parseArray(Filename filename, List<Token> tokens, int i) {
@ -776,15 +766,13 @@ public class Parsing {
public static ParseRes<String> parsePropName(Filename filename, List<Token> tokens, int i) {
var loc = getLoc(filename, tokens, i);
try {
if (inBounds(tokens, i)) {
var token = tokens.get(i);
if (token.isNumber() || token.isIdentifier() || token.isString()) return ParseRes.res(token.rawValue, 1);
else return ParseRes.error(loc, "Expected identifier, string or number literal.");
}
catch (IndexOutOfBoundsException e) {
return ParseRes.failed();
}
else return ParseRes.failed();
}
public static ParseRes<ObjProp> parseObjectProp(Filename filename, List<Token> tokens, int i) {
var loc = getLoc(filename, tokens, i);
@ -1900,7 +1888,6 @@ public class Parsing {
return target;
}
public static CompileResult compile(Filename filename, String raw) {
try { return compile(parse(filename, raw)); }
catch (SyntaxException e) { return compile(new ThrowSyntaxStatement(e)); }
return compile(parse(filename, raw));
}
}

View File

@ -1,8 +1,8 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
public class ArrayStatement extends Statement {

View File

@ -1,10 +1,10 @@
package me.topchetoeu.jscript.compilation.values;
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.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
public class CallStatement extends Statement {
public final Statement func;
@ -24,8 +24,8 @@ public class CallStatement extends Statement {
for (var arg : args) arg.compile(target, true);
if (isNew) target.add(Instruction.callNew(args.length));
else target.add(Instruction.call(args.length)).setDebug(loc(), type);
if (isNew) target.add(Instruction.callNew(args.length)).setLocationAndDebug(loc(), type);
else target.add(Instruction.call(args.length)).setLocationAndDebug(loc(), type);
if (!pollute) target.add(Instruction.discard());
}

View File

@ -1,11 +1,11 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.compilation.AssignableStatement;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.core.Operation;
public class ChangeStatement extends Statement {
public final AssignableStatement value;

View File

@ -1,8 +1,8 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
public class ConstantStatement extends Statement {

View File

@ -1,8 +1,8 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
public class DiscardStatement extends Statement {

View File

@ -1,12 +1,12 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.common.Instruction.Type;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.CompoundStatement;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.Instruction.Type;
import me.topchetoeu.jscript.core.exceptions.SyntaxException;
public class FunctionStatement extends Statement {

View File

@ -1,8 +1,8 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
public class GlobalThisStatement extends Statement {

View File

@ -1,11 +1,11 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
import me.topchetoeu.jscript.core.Operation;
public class IndexAssignStatement extends Statement {
public final Statement object;

View File

@ -1,12 +1,12 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.AssignableStatement;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
import me.topchetoeu.jscript.core.Operation;
public class IndexStatement extends AssignableStatement {
public final Statement object;

View File

@ -1,8 +1,8 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
public class LazyAndStatement extends Statement {

View File

@ -1,8 +1,8 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
public class LazyOrStatement extends Statement {

View File

@ -3,9 +3,9 @@ package me.topchetoeu.jscript.compilation.values;
import java.util.ArrayList;
import java.util.Map;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
public class ObjectStatement extends Statement {

View File

@ -1,10 +1,10 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.core.Operation;
public class OperationStatement extends Statement {
public final Statement[] args;

View File

@ -1,8 +1,8 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
public class RegexStatement extends Statement {

View File

@ -1,8 +1,8 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
public class TypeofStatement extends Statement {

View File

@ -1,10 +1,10 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.core.Operation;
public class VariableAssignStatement extends Statement {
public final String name;

View File

@ -1,8 +1,8 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
public class VariableIndexStatement extends Statement {

View File

@ -1,11 +1,11 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.compilation.AssignableStatement;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.core.Operation;
public class VariableStatement extends AssignableStatement {
public final String name;

View File

@ -1,8 +1,17 @@
package me.topchetoeu.jscript.core;
import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.compilation.FunctionBody;
import me.topchetoeu.jscript.common.FunctionBody;
import me.topchetoeu.jscript.core.exceptions.EngineException;
public interface Compiler {
public Key<Compiler> KEY = new Key<>();
public FunctionBody compile(Filename filename, String source);
public static Compiler get(Extensions ext) {
return ext.get(KEY, (filename, src) -> {
throw EngineException.ofError("No compiler attached to engine.");
});
}
}

View File

@ -1,90 +1,66 @@
package me.topchetoeu.jscript.core;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
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.values.Symbol;
import me.topchetoeu.jscript.core.exceptions.EngineException;
import me.topchetoeu.jscript.lib.EnvironmentLib;
import me.topchetoeu.jscript.core.scope.ValueVariable;
public class Context implements Extensions {
public static final Context NULL = new Context(null);
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 Engine engine;
public final int stackSize;
@Override public <T> void add(Symbol key, T obj) {
@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);
// else if (engine != null) engine.add(key, obj);
}
@Override public <T> T get(Symbol key) {
@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);
// else if (engine != null && engine.has(key)) return engine.get(key);
return null;
}
@Override public boolean has(Symbol key) {
@Override public boolean has(Key<?> key) {
return
environment != null && environment.has(key) ||
engine != null && engine.has(key);
environment != null && environment.has(key);
// engine != null && engine.has(key);
}
@Override public boolean remove(Symbol 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);
// else if (engine != null) res |= engine.remove(key);
return res;
}
@Override public Iterable<Symbol> keys() {
if (engine == null && environment == null) return List.of();
if (engine == null) return environment.keys();
if (environment == null) return engine.keys();
@Override public Iterable<Key<?>> keys() {
return environment.keys();
return () -> Stream.concat(
StreamSupport.stream(engine.keys().spliterator(), false),
StreamSupport.stream(environment.keys().spliterator(), false)
).distinct().iterator();
// 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) {
var env = environment;
var result = Environment.compileFunc(this).call(this, null, raw, filename.toString(), new EnvironmentLib(env));
DebugContext.get(this).onSource(filename, raw);
return (FunctionValue)result;
// var rawMapChain = ((ArrayValue)Values.getMember(this, result, "mapChain")).toArray();
// var breakpoints = new TreeSet<>(
// Arrays.stream(((ArrayValue)Values.getMember(this, result, "breakpoints")).toArray())
// .map(v -> Location.parse(Values.toString(this, v)))
// .collect(Collectors.toList())
// );
// var maps = new SourceMap[rawMapChain.length];
// for (var i = 0; i < maps.length; i++) maps[i] = SourceMap.parse(Values.toString(this, (String)rawMapChain[i]));
// var map = SourceMap.chain(maps);
// if (map != null) {
// var newBreakpoints = new TreeSet<Location>();
// for (var bp : breakpoints) {
// bp = map.toCompiled(bp);
// if (bp != null) newBreakpoints.add(bp);
// }
// breakpoints = newBreakpoints;
// }
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, engine, stackSize + 1);
var res = new Context(this, frame.function.environment, frame, stackSize + 1);
return res;
}
@ -111,11 +87,10 @@ public class Context implements Extensions {
}
private Context(Context parent, Environment environment, Frame frame, Engine engine, int stackSize) {
private Context(Context parent, Environment environment, Frame frame, int stackSize) {
this.parent = parent;
this.environment = environment;
this.frame = frame;
this.engine = engine;
this.stackSize = stackSize;
if (hasNotNull(Environment.MAX_STACK_COUNT) && stackSize > (int)get(Environment.MAX_STACK_COUNT)) {
@ -123,10 +98,10 @@ public class Context implements Extensions {
}
}
public Context(Engine engine) {
this(null, null, null, engine, 0);
public Context() {
this(null, null, null, 0);
}
public Context(Engine engine, Environment env) {
this(null, env, null, engine, 0);
public Context(Environment env) {
this(null, env, null, 0);
}
}

View File

@ -1,54 +1,92 @@
package me.topchetoeu.jscript.core;
import java.util.HashMap;
import java.util.concurrent.PriorityBlockingQueue;
import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.common.ResultRunnable;
import me.topchetoeu.jscript.common.events.DataNotifier;
import me.topchetoeu.jscript.compilation.FunctionBody;
import me.topchetoeu.jscript.core.exceptions.InterruptException;
import me.topchetoeu.jscript.core.values.FunctionValue;
import me.topchetoeu.jscript.core.values.Symbol;
public class Engine extends EventLoop implements Extensions {
public static final HashMap<Integer, FunctionBody> functions = new HashMap<>();
public class Engine implements EventLoop {
private static class Task<T> implements Comparable<Task<?>> {
public final ResultRunnable<?> runnable;
public final DataNotifier<T> notifier = new DataNotifier<>();
public final boolean micro;
private final Environment env = new Environment();
public Task(ResultRunnable<T> runnable, boolean micro) {
this.runnable = runnable;
this.micro = micro;
}
@Override
public <T> void add(Symbol key, T obj) {
this.env.add(key, obj);
}
@Override
public <T> T get(Symbol key) {
return this.env.get(key);
}
@Override
public boolean has(Symbol key) {
return this.env.has(key);
}
@Override
public boolean remove(Symbol key) {
return this.env.remove(key);
}
@Override
public Iterable<Symbol> keys() {
return env.keys();
@Override
public int compareTo(Task<?> other) {
return Integer.compare(this.micro ? 0 : 1, other.micro ? 0 : 1);
}
}
public Engine copy() {
var res = new Engine();
res.env.addAll(env);
return res;
private PriorityBlockingQueue<Task<?>> tasks = new PriorityBlockingQueue<>();
private Thread thread;
@Override
public <T> DataNotifier<T> pushMsg(ResultRunnable<T> runnable, boolean micro) {
var msg = new Task<T>(runnable, micro);
tasks.add(msg);
return msg.notifier;
}
@SuppressWarnings("unchecked")
public void run(boolean untilEmpty) {
while (!untilEmpty || !tasks.isEmpty()) {
try {
var task = tasks.take();
try {
((Task<Object>)task).notifier.next(task.runnable.run());
}
catch (RuntimeException e) {
if (e instanceof InterruptException) throw e;
task.notifier.error(e);
}
}
catch (InterruptedException | InterruptException e) {
for (var msg : tasks) msg.notifier.error(new InterruptException(e));
break;
}
}
}
public Thread thread() {
return thread;
}
public Thread start() {
if (thread == null) {
thread = new Thread(() -> run(false), "Event loop #" + hashCode());
thread.start();
}
return thread;
}
public void stop() {
if (thread != null) thread.interrupt();
thread = null;
}
public boolean inLoopThread() {
return Thread.currentThread() == thread;
}
public boolean isRunning() {
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(this, env), thisArg, args);
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(this, env);
return ctx.compile(filename, raw).call(new Context(this, env), thisArg, args);
var ctx = new Context(env);
return ctx.compile(filename, raw).call(new Context(env), thisArg, args);
}, micro);
}

View File

@ -5,77 +5,57 @@ import java.util.HashMap;
import me.topchetoeu.jscript.core.scope.GlobalScope;
import me.topchetoeu.jscript.core.values.FunctionValue;
import me.topchetoeu.jscript.core.values.NativeFunction;
import me.topchetoeu.jscript.core.values.Symbol;
import me.topchetoeu.jscript.core.values.ObjectValue;
import me.topchetoeu.jscript.core.exceptions.EngineException;
import me.topchetoeu.jscript.utils.interop.NativeWrapperProvider;
@SuppressWarnings("unchecked")
public class Environment implements Extensions {
public static final Key<Compiler> COMPILE_FUNC = new Key<>();
public static final HashMap<String, Symbol> symbols = new HashMap<>();
public static final Key<FunctionValue> REGEX_CONSTR = new Key<>();
public static final Key<Integer> MAX_STACK_COUNT = new Key<>();
public static final Key<Boolean> HIDE_STACK = new Key<>();
public static final Symbol COMPILE_FUNC = Symbol.get("Environment.compile");
public static final Key<ObjectValue> OBJECT_PROTO = new Key<>();
public static final Key<ObjectValue> FUNCTION_PROTO = new Key<>();
public static final Key<ObjectValue> ARRAY_PROTO = new Key<>();
public static final Key<ObjectValue> BOOL_PROTO = new Key<>();
public static final Key<ObjectValue> NUMBER_PROTO = new Key<>();
public static final Key<ObjectValue> STRING_PROTO = new Key<>();
public static final Key<ObjectValue> SYMBOL_PROTO = new Key<>();
public static final Key<ObjectValue> ERROR_PROTO = new Key<>();
public static final Key<ObjectValue> SYNTAX_ERR_PROTO = new Key<>();
public static final Key<ObjectValue> TYPE_ERR_PROTO = new Key<>();
public static final Key<ObjectValue> RANGE_ERR_PROTO = new Key<>();
public static final Symbol REGEX_CONSTR = Symbol.get("Environment.regexConstructor");
public static final Symbol STACK = Symbol.get("Environment.stack");
public static final Symbol MAX_STACK_COUNT = Symbol.get("Environment.maxStackCount");
public static final Symbol HIDE_STACK = Symbol.get("Environment.hideStack");
public static final Symbol OBJECT_PROTO = Symbol.get("Environment.objectPrototype");
public static final Symbol FUNCTION_PROTO = Symbol.get("Environment.functionPrototype");
public static final Symbol ARRAY_PROTO = Symbol.get("Environment.arrayPrototype");
public static final Symbol BOOL_PROTO = Symbol.get("Environment.boolPrototype");
public static final Symbol NUMBER_PROTO = Symbol.get("Environment.numberPrototype");
public static final Symbol STRING_PROTO = Symbol.get("Environment.stringPrototype");
public static final Symbol SYMBOL_PROTO = Symbol.get("Environment.symbolPrototype");
public static final Symbol ERROR_PROTO = Symbol.get("Environment.errorPrototype");
public static final Symbol SYNTAX_ERR_PROTO = Symbol.get("Environment.syntaxErrorPrototype");
public static final Symbol TYPE_ERR_PROTO = Symbol.get("Environment.typeErrorPrototype");
public static final Symbol RANGE_ERR_PROTO = Symbol.get("Environment.rangeErrorPrototype");
private HashMap<Symbol, Object> data = new HashMap<>();
private HashMap<Key<?>, Object> data = new HashMap<>();
public GlobalScope global;
public WrapperProvider wrappers;
@Override public <T> void add(Symbol key, T obj) {
@Override public <T> void add(Key<T> key, T obj) {
data.put(key, obj);
}
@Override public <T> T get(Symbol key) {
@Override public <T> T get(Key<T> key) {
return (T)data.get(key);
}
@Override public boolean remove(Symbol key) {
@Override public boolean remove(Key<?> key) {
if (data.containsKey(key)) {
data.remove(key);
return true;
}
return false;
}
@Override public boolean has(Symbol key) {
@Override public boolean has(Key<?> key) {
return data.containsKey(key);
}
@Override public Iterable<Symbol> keys() {
@Override public Iterable<Key<?>> keys() {
return data.keySet();
}
public static FunctionValue compileFunc(Extensions ext) {
return ext.init(COMPILE_FUNC, new NativeFunction("compile", args -> {
// var source = args.getString(0);
// var filename = args.getString(1);
// var target = Parsing.compile(Filename.parse(filename), source);
// var res = new ObjectValue();
// res.defineProperty(args.ctx, "function", target.body());
// res.defineProperty(args.ctx, "map", target.map());
// return res;
throw EngineException.ofError("No compiler attached to engine.");
}));
}
public static FunctionValue regexConstructor(Extensions ext) {
return ext.init(COMPILE_FUNC, new NativeFunction("RegExp", args -> {
return ext.init(REGEX_CONSTR, new NativeFunction("RegExp", args -> {
throw EngineException.ofError("Regular expressions not supported.").setCtx(args.ctx);
}));
}
@ -95,8 +75,8 @@ public class Environment implements Extensions {
return res;
}
public Context context(Engine engine) {
return new Context(engine, this);
public Context context() {
return new Context(this);
}
public Environment(WrapperProvider nativeConverter, GlobalScope global) {

View File

@ -1,80 +1,23 @@
package me.topchetoeu.jscript.core;
import java.util.concurrent.PriorityBlockingQueue;
import me.topchetoeu.jscript.common.ResultRunnable;
import me.topchetoeu.jscript.common.events.DataNotifier;
import me.topchetoeu.jscript.core.exceptions.InterruptException;
import me.topchetoeu.jscript.core.exceptions.EngineException;
public class EventLoop {
private static class Task implements Comparable<Task> {
public final ResultRunnable<?> runnable;
public final DataNotifier<Object> notifier = new DataNotifier<>();
public final boolean micro;
public interface EventLoop {
public static final Key<EventLoop> KEY = new Key<>();
public Task(ResultRunnable<?> runnable, boolean micro) {
this.runnable = runnable;
this.micro = micro;
}
@Override
public int compareTo(Task other) {
return Integer.compare(this.micro ? 0 : 1, other.micro ? 0 : 1);
}
public static EventLoop get(Extensions ext) {
if (ext.hasNotNull(KEY)) return ext.get(KEY);
else return new EventLoop() {
@Override public <T> DataNotifier<T> pushMsg(ResultRunnable<T> runnable, boolean micro) {
throw EngineException.ofError("No event loop attached to environment.");
}
};
}
private PriorityBlockingQueue<Task> tasks = new PriorityBlockingQueue<>();
private Thread thread;
@SuppressWarnings("unchecked")
public <T> DataNotifier<T> pushMsg(ResultRunnable<T> runnable, boolean micro) {
var msg = new Task(runnable, micro);
tasks.add(msg);
return (DataNotifier<T>)msg.notifier;
}
public DataNotifier<Void> pushMsg(Runnable runnable, boolean micro) {
public <T> DataNotifier<T> pushMsg(ResultRunnable<T> runnable, boolean micro);
public default DataNotifier<Void> pushMsg(Runnable runnable, boolean micro) {
return pushMsg(() -> { runnable.run(); return null; }, micro);
}
public void run(boolean untilEmpty) {
while (!untilEmpty || !tasks.isEmpty()) {
try {
var task = tasks.take();
try {
task.notifier.next(task.runnable.run());
}
catch (RuntimeException e) {
if (e instanceof InterruptException) throw e;
task.notifier.error(e);
}
}
catch (InterruptedException | InterruptException e) {
for (var msg : tasks) msg.notifier.error(new InterruptException(e));
break;
}
}
}
public Thread thread() {
return thread;
}
public Thread start() {
if (thread == null) {
thread = new Thread(() -> run(false), "Event loop #" + hashCode());
thread.start();
}
return thread;
}
public void stop() {
if (thread != null) thread.interrupt();
thread = null;
}
public boolean inLoopThread() {
return Thread.currentThread() == thread;
}
public boolean isRunning() {
return this.thread != null;
}
}

View File

@ -1,34 +1,33 @@
package me.topchetoeu.jscript.core;
import me.topchetoeu.jscript.core.values.Symbol;
public interface Extensions {
<T> T get(Symbol key);
<T> void add(Symbol key, T obj);
Iterable<Symbol> keys();
<T> T get(Key<T> key);
<T> void add(Key<T> key, T obj);
Iterable<Key<?>> keys();
boolean has(Symbol key);
boolean remove(Symbol key);
boolean has(Key<?> key);
boolean remove(Key<?> key);
default boolean hasNotNull(Symbol key) {
default boolean hasNotNull(Key<?> key) {
return has(key) && get(key) != null;
}
default <T> T get(Symbol key, T defaultVal) {
default <T> T get(Key<T> key, T defaultVal) {
if (has(key)) return get(key);
else return defaultVal;
}
default <T> T init(Symbol key, T val) {
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) {
for (var key : source.keys()) {
add(key, source.get(key));
add((Key<Object>)key, (Object)source.get(key));
}
}
}

View File

@ -3,7 +3,7 @@ package me.topchetoeu.jscript.core;
import java.util.List;
import java.util.Stack;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.core.debug.DebugContext;
import me.topchetoeu.jscript.core.scope.LocalScope;
import me.topchetoeu.jscript.core.scope.ValueVariable;
@ -159,7 +159,7 @@ public class Frame {
returnValue = InstructionRunner.exec(ctx, instr, this);
}
catch (EngineException e) {
error = e.add(ctx, function.name, DebugContext.get(ctx).getMap(function).toLocation(codePtr, true));
error = e.add(ctx, function.name, DebugContext.get(ctx).getMapOrEmpty(function).toLocation(codePtr, true));
}
}
}

View File

@ -2,7 +2,6 @@ package me.topchetoeu.jscript.core;
import java.util.Collections;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.core.scope.ValueVariable;
import me.topchetoeu.jscript.core.values.ArrayValue;
import me.topchetoeu.jscript.core.values.CodeFunction;
@ -10,6 +9,8 @@ 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.Operation;
import me.topchetoeu.jscript.core.exceptions.EngineException;
public class InstructionRunner {

View File

@ -6,31 +6,31 @@ import java.util.List;
import java.util.WeakHashMap;
import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.common.FunctionBody;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.FunctionBody;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.mapping.FunctionMap;
import me.topchetoeu.jscript.common.mapping.FunctionMap;
import me.topchetoeu.jscript.core.Context;
import me.topchetoeu.jscript.core.Extensions;
import me.topchetoeu.jscript.core.Frame;
import me.topchetoeu.jscript.core.Key;
import me.topchetoeu.jscript.core.values.CodeFunction;
import me.topchetoeu.jscript.core.values.FunctionValue;
import me.topchetoeu.jscript.core.values.Symbol;
import me.topchetoeu.jscript.core.exceptions.EngineException;
public class DebugContext implements DebugController {
public static final Symbol ENV_KEY = Symbol.get("Engine.debug");
public static final Symbol IGNORE = Symbol.get("Engine.ignoreDebug");
public class DebugContext {
public static final Key<DebugContext> KEY = new Key<>();
public static final Key<Void> IGNORE = new Key<>();
private HashMap<Filename, String> sources;
private WeakHashMap<FunctionBody, FunctionMap> maps;
private DebugController debugger;
private DebugHandler debugger;
public boolean attachDebugger(DebugController debugger) {
public boolean attachDebugger(DebugHandler debugger) {
if (this.debugger != null) return false;
if (sources != null) {
for (var source : sources.entrySet()) debugger.onSource(source.getKey(), source.getValue());
for (var source : sources.entrySet()) debugger.onSourceLoad(source.getKey(), source.getValue());
}
this.debugger = debugger;
@ -41,8 +41,8 @@ public class DebugContext implements DebugController {
return true;
}
public DebugController debugger() {
if (debugger == null) return DebugController.empty();
public DebugHandler debugger() {
if (debugger == null) return DebugHandler.empty();
else return debugger;
}
@ -61,24 +61,27 @@ public class DebugContext implements DebugController {
else return res;
}
public FunctionMap getMapOrEmpty(FunctionValue func) {
if (maps == null || !(func instanceof CodeFunction)) return null;
if (maps == null || !(func instanceof CodeFunction)) return FunctionMap.EMPTY;
return getMapOrEmpty(((CodeFunction)func).body);
}
@Override public void onFramePop(Context ctx, Frame frame) {
public void onFramePop(Context ctx, Frame frame) {
if (debugger != null) debugger.onFramePop(ctx, frame);
}
@Override public void onFramePush(Context ctx, Frame frame) {
public void onFramePush(Context ctx, Frame frame) {
if (debugger != null) debugger.onFramePush(ctx, frame);
}
@Override public boolean onInstruction(Context ctx, Frame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught) {
public boolean onInstruction(Context ctx, Frame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught) {
if (debugger != null) return debugger.onInstruction(ctx, frame, instruction, returnVal, error, caught);
else return false;
}
@Override public void onSource(Filename filename, String source) {
if (debugger != null) debugger.onSource(filename, source);
public void onSource(Filename filename, String source) {
if (debugger != null) debugger.onSourceLoad(filename, source);
if (sources != null) sources.put(filename, source);
}
public void onFunctionLoad(FunctionBody func, FunctionMap map) {
if (maps != null) maps.put(func, map);
}
private DebugContext(boolean enabled) {
if (enabled) {
@ -92,10 +95,10 @@ public class DebugContext implements DebugController {
}
public static boolean enabled(Extensions exts) {
return exts.hasNotNull(ENV_KEY) && !exts.has(IGNORE);
return exts != null && exts.hasNotNull(KEY) && !exts.has(IGNORE);
}
public static DebugContext get(Extensions exts) {
if (enabled(exts)) return exts.get(ENV_KEY);
if (enabled(exts)) return exts.get(KEY);
else return new DebugContext(false);
}
@ -106,7 +109,7 @@ public class DebugContext implements DebugController {
for (var el : ctx.frames()) {
var name = el.function.name;
var map = dbgCtx.getMap(el.function);
var map = dbgCtx.getMapOrEmpty(el.function);
Location loc = null;
if (map != null) {

View File

@ -1,12 +1,14 @@
package me.topchetoeu.jscript.core.debug;
import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.common.FunctionBody;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.mapping.FunctionMap;
import me.topchetoeu.jscript.core.Context;
import me.topchetoeu.jscript.core.Frame;
import me.topchetoeu.jscript.core.exceptions.EngineException;
public interface DebugController {
public interface DebugHandler {
/**
* Called when a script has been loaded
* @param filename The name of the source
@ -14,7 +16,21 @@ public interface DebugController {
* @param breakpoints A set of all the breakpointable locations in this source
* @param map The source map associated with this file. null if this source map isn't mapped
*/
void onSource(Filename filename, String source);
void onSourceLoad(Filename filename, String source);
/**
* Called when a function body has been loaded
* @param body The body loaded
* @param map The map of the function
*/
void onFunctionLoad(FunctionBody body, FunctionMap map);
// /**
// * Called when a function body has been loaded
// * @param body The body loaded
// * @param map The map of the function
// */
// void onFunctionUnload(FunctionBody body, FunctionMap map);
/**
* Called immediatly before an instruction is executed, as well as after an instruction, if it has threw or returned.
@ -44,14 +60,15 @@ public interface DebugController {
*/
void onFramePop(Context ctx, Frame frame);
public static DebugController empty() {
return new DebugController () {
public static DebugHandler empty() {
return new DebugHandler () {
@Override public void onFramePop(Context ctx, Frame frame) { }
@Override public void onFramePush(Context ctx, Frame frame) { }
@Override public boolean onInstruction(Context ctx, Frame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught) {
return false;
}
@Override public void onSource(Filename filename, String source) { }
@Override public void onSourceLoad(Filename filename, String source) { }
@Override public void onFunctionLoad(FunctionBody body, FunctionMap map) { }
};
}
}

View File

@ -5,7 +5,6 @@ import java.util.List;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.core.Context;
import me.topchetoeu.jscript.core.Engine;
import me.topchetoeu.jscript.core.Environment;
import me.topchetoeu.jscript.core.values.ObjectValue;
import me.topchetoeu.jscript.core.values.Values;
@ -35,7 +34,7 @@ public class EngineException extends RuntimeException {
if (name.equals("")) name = null;
if (ctx == null) this.ctx = null;
else this.ctx = new Context(ctx.engine, ctx.environment);
else this.ctx = new Context(ctx.environment);
this.location = location;
this.name = name;
}
@ -44,7 +43,6 @@ public class EngineException extends RuntimeException {
public final Object value;
public EngineException cause;
public Environment env = null;
public Engine engine = null;
public final List<StackElement> stackTrace = new ArrayList<>();
public EngineException add(Context ctx, String name, Location location) {
@ -60,7 +58,6 @@ public class EngineException extends RuntimeException {
}
public EngineException setCtx(Context ctx) {
if (this.env == null) this.env = ctx.environment;
if (this.engine == null) this.engine = ctx.engine;
return this;
}

View File

@ -1,6 +1,6 @@
package me.topchetoeu.jscript.core.values;
import me.topchetoeu.jscript.compilation.FunctionBody;
import me.topchetoeu.jscript.common.FunctionBody;
import me.topchetoeu.jscript.core.Context;
import me.topchetoeu.jscript.core.Environment;
import me.topchetoeu.jscript.core.Frame;

View File

@ -12,9 +12,9 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.core.Context;
import me.topchetoeu.jscript.core.Environment;
import me.topchetoeu.jscript.core.Operation;
import me.topchetoeu.jscript.core.debug.DebugContext;
import me.topchetoeu.jscript.core.exceptions.ConvertException;
import me.topchetoeu.jscript.core.exceptions.EngineException;
@ -664,7 +664,7 @@ public class Values {
if (val instanceof FunctionValue) {
res.append(val.toString());
var loc = val instanceof CodeFunction ? dbg.getMap((CodeFunction)val).start() : null;
var loc = val instanceof CodeFunction ? dbg.getMapOrEmpty((CodeFunction)val).start() : null;
if (loc != null) res.append(" @ " + loc);
}
@ -734,10 +734,10 @@ public class Values {
if (err instanceof EngineException) {
var ee = ((EngineException)err);
try {
return prefix + " " + ee.toString(new Context(ee.engine, ee.env));
return prefix + " " + ee.toString(new Context(ee.env));
}
catch (EngineException ex) {
return prefix + " " + toReadable(new Context(ee.engine, ee.env), ee.value);
return prefix + " " + toReadable(new Context(ee.env), ee.value);
}
}
else if (err instanceof SyntaxException) {

View File

@ -13,7 +13,7 @@ import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("AsyncFunction")
public class AsyncFunctionLib extends FunctionValue {
public final FunctionValue factory;
public final CodeFunction func;
private static class AsyncHelper {
public PromiseLib promise = new PromiseLib();
@ -67,15 +67,19 @@ public class AsyncFunctionLib extends FunctionValue {
@Override
public Object call(Context ctx, Object thisArg, Object ...args) {
var handler = new AsyncHelper();
var func = factory.call(ctx, thisArg, new NativeFunction("await", handler::await));
if (!(func instanceof CodeFunction)) throw EngineException.ofType("Return value of argument must be a js function.");
handler.frame = new Frame(ctx, thisArg, args, (CodeFunction)func);
var newArgs = new Object[args.length + 1];
newArgs[0] = new NativeFunction("await", handler::await);
System.arraycopy(args, 0, newArgs, 1, args.length);
handler.frame = new Frame(ctx, thisArg, newArgs, (CodeFunction)func);
handler.next(ctx, Values.NO_RETURN, null);
return handler.promise;
}
public AsyncFunctionLib(FunctionValue factory) {
super(factory.name, factory.length);
this.factory = factory;
public AsyncFunctionLib(FunctionValue func) {
super(func.name, func.length);
if (!(func instanceof CodeFunction)) throw EngineException.ofType("Return value of argument must be a js function.");
this.func = (CodeFunction)func;
}
}

View File

@ -10,22 +10,24 @@ import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("AsyncGeneratorFunction")
public class AsyncGeneratorFunctionLib extends FunctionValue {
public final FunctionValue factory;
public final CodeFunction func;
@Override
public Object call(Context ctx, Object thisArg, Object ...args) {
var handler = new AsyncGeneratorLib();
var func = factory.call(ctx, thisArg,
new NativeFunction("await", handler::await),
new NativeFunction("yield", handler::yield)
);
if (!(func instanceof CodeFunction)) throw EngineException.ofType("Return value of argument must be a js function.");
handler.frame = new Frame(ctx, thisArg, args, (CodeFunction)func);
var newArgs = new Object[args.length + 2];
newArgs[0] = new NativeFunction("await", handler::await);
newArgs[1] = new NativeFunction("yield", handler::yield);
System.arraycopy(args, 0, newArgs, 2, args.length);
handler.frame = new Frame(ctx, thisArg, newArgs, func);
return handler;
}
public AsyncGeneratorFunctionLib(FunctionValue factory) {
super(factory.name, factory.length);
this.factory = factory;
public AsyncGeneratorFunctionLib(CodeFunction func) {
super(func.name, func.length);
if (!(func instanceof CodeFunction)) throw EngineException.ofType("Return value of argument must be a js function.");
this.func = func;
}
}

View File

@ -1,39 +0,0 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.core.Environment;
import me.topchetoeu.jscript.core.values.FunctionValue;
import me.topchetoeu.jscript.core.values.ObjectValue;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeType;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("Environment")
public class EnvironmentLib {
private Environment env;
@Expose(value = "@@env", type = ExposeType.GETTER)
public Environment __env() { return env; }
@Expose(type = ExposeType.GETTER)
public int __id(Arguments args) {
return env.hashCode();
}
@Expose(type = ExposeType.GETTER)
public ObjectValue __global(Arguments args) {
return env.global.obj;
}
@Expose(type = ExposeType.GETTER)
public FunctionValue __compile() {
return Environment.compileFunc(env);
}
@Expose(type = ExposeType.SETTER)
public void __compile(Arguments args) {
env.add(Environment.COMPILE_FUNC, args.convert(0, FunctionValue.class));
}
public EnvironmentLib(Environment env) {
this.env = env;
}
}

View File

@ -1,6 +1,7 @@
package me.topchetoeu.jscript.lib;
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.NativeFunction;
import me.topchetoeu.jscript.utils.interop.Arguments;
@ -44,10 +45,10 @@ public class FunctionLib {
}
@Expose(target = ExposeTarget.STATIC)
public static FunctionValue __asyncGenerator(Arguments args) {
return new AsyncGeneratorFunctionLib(args.convert(0, FunctionValue.class));
return new AsyncGeneratorFunctionLib(args.convert(0, CodeFunction.class));
}
@Expose(target = ExposeTarget.STATIC)
public static FunctionValue __generator(Arguments args) {
return new GeneratorFunctionLib(args.convert(0, FunctionValue.class));
return new GeneratorFunctionLib(args.convert(0, CodeFunction.class));
}
}

View File

@ -10,18 +10,22 @@ import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("GeneratorFunction")
public class GeneratorFunctionLib extends FunctionValue {
public final FunctionValue factory;
public final CodeFunction func;
@Override public Object call(Context ctx, Object thisArg, Object ...args) {
var handler = new GeneratorLib();
var func = factory.call(ctx, thisArg, new NativeFunction("yield", handler::yield));
if (!(func instanceof CodeFunction)) throw EngineException.ofType("Return value of argument must be a js function.");
handler.frame = new Frame(ctx, thisArg, args, (CodeFunction)func);
var newArgs = new Object[args.length + 1];
newArgs[0] = new NativeFunction("yield", handler::yield);
System.arraycopy(args, 0, newArgs, 1, args.length);
handler.frame = new Frame(ctx, thisArg, newArgs, func);
return handler;
}
public GeneratorFunctionLib(FunctionValue factory) {
super(factory.name, factory.length);
this.factory = factory;
public GeneratorFunctionLib(CodeFunction func) {
super(func.name, func.length);
if (!(func instanceof CodeFunction)) throw EngineException.ofType("Return value of argument must be a js function.");
this.func = func;
}
}

View File

@ -4,9 +4,10 @@ import java.util.HashMap;
import me.topchetoeu.jscript.core.Context;
import me.topchetoeu.jscript.core.Environment;
import me.topchetoeu.jscript.core.EventLoop;
import me.topchetoeu.jscript.core.Key;
import me.topchetoeu.jscript.core.scope.GlobalScope;
import me.topchetoeu.jscript.core.values.FunctionValue;
import me.topchetoeu.jscript.core.values.Symbol;
import me.topchetoeu.jscript.core.values.Values;
import me.topchetoeu.jscript.core.exceptions.EngineException;
import me.topchetoeu.jscript.utils.interop.Arguments;
@ -16,8 +17,8 @@ import me.topchetoeu.jscript.utils.interop.ExposeTarget;
import me.topchetoeu.jscript.utils.modules.ModuleRepo;
public class Internals {
private static final Symbol THREADS = new Symbol("Internals.threads");
private static final Symbol I = new Symbol("Internals.i");
private static final Key<HashMap<Integer, Thread>> THREADS = new Key<>();
private static final Key<Integer> I = new Key<>();
@Expose(target = ExposeTarget.STATIC)
public static Object __require(Arguments args) {
@ -38,6 +39,8 @@ public class Internals {
var delay = args.getDouble(1);
var arguments = args.slice(2).args;
if (!args.ctx.hasNotNull(EventLoop.KEY)) throw EngineException.ofError("No event loop");
var thread = new Thread(() -> {
var ms = (long)delay;
var ns = (int)((delay - ms) * 10000000);
@ -45,7 +48,7 @@ public class Internals {
try { Thread.sleep(ms, ns); }
catch (InterruptedException e) { return; }
args.ctx.engine.pushMsg(false, args.ctx.environment, func, null, arguments);
args.ctx.get(EventLoop.KEY).pushMsg(() -> func.call(new Context(args.ctx.environment), null, arguments), false);
});
thread.start();
@ -61,6 +64,8 @@ public class Internals {
var delay = args.getDouble(1);
var arguments = args.slice(2).args;
if (!args.ctx.hasNotNull(EventLoop.KEY)) throw EngineException.ofError("No event loop");
var thread = new Thread(() -> {
var ms = (long)delay;
var ns = (int)((delay - ms) * 10000000);
@ -71,7 +76,7 @@ public class Internals {
}
catch (InterruptedException e) { return; }
args.ctx.engine.pushMsg(false, args.ctx.environment, func, null, arguments);
args.ctx.get(EventLoop.KEY).pushMsg(() -> func.call(new Context(args.ctx.environment), null, arguments), false);
}
});
thread.start();

View File

@ -6,12 +6,14 @@ import java.util.List;
import me.topchetoeu.jscript.common.ResultRunnable;
import me.topchetoeu.jscript.core.Context;
import me.topchetoeu.jscript.core.EventLoop;
import me.topchetoeu.jscript.core.Extensions;
import me.topchetoeu.jscript.core.values.ArrayValue;
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;
import me.topchetoeu.jscript.core.exceptions.InterruptException;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor;
@ -24,14 +26,17 @@ public class PromiseLib {
void onFulfil(Object val);
void onReject(EngineException err);
default Handle defer(EventLoop loop) {
default Handle defer(Extensions loop) {
var self = this;
return new Handle() {
@Override public void onFulfil(Object val) {
loop.pushMsg(() -> self.onFulfil(val), true);
if (!loop.hasNotNull(EventLoop.KEY)) throw EngineException.ofError("No event loop");
loop.get(EventLoop.KEY).pushMsg(() -> self.onFulfil(val), true);
}
@Override public void onReject(EngineException val) {
loop.pushMsg(() -> self.onReject(val), true);
if (!loop.hasNotNull(EventLoop.KEY)) throw EngineException.ofError("No event loop");
loop.get(EventLoop.KEY).pushMsg(() -> self.onReject(val), true);
}
};
}
@ -48,7 +53,9 @@ public class PromiseLib {
private Object val;
private void resolveSynchronized(Context ctx, Object val, int newState) {
ctx.engine.pushMsg(() -> {
if (!ctx.hasNotNull(EventLoop.KEY)) throw EngineException.ofError("No event loop");
ctx.get(EventLoop.KEY).pushMsg(() -> {
this.val = val;
this.state = newState;
@ -118,6 +125,12 @@ public class PromiseLib {
catch (EngineException e) {
res.reject(ctx, e);
}
catch (Exception e) {
if (e instanceof InterruptException) throw e;
else {
res.reject(ctx, EngineException.ofError("Native code failed with " + e.getMessage()));
}
}
}, "Promisifier").start();
return res;
@ -144,7 +157,8 @@ public class PromiseLib {
try {
var then = Values.getMember(ctx, obj, "then");
Values.call(ctx, then, obj,
if (then instanceof FunctionValue) Values.call(ctx, then, obj,
new NativeFunction(args -> {
try { handle.onFulfil(args.get(0)); }
catch (Exception e) {
@ -162,6 +176,7 @@ public class PromiseLib {
return null;
})
);
else handle.onFulfil(obj);
return;
}
@ -325,7 +340,7 @@ public class PromiseLib {
try { res.fulfill(args.ctx, onReject.call(args.ctx, null, err.value)); }
catch (EngineException e) { res.reject(args.ctx, e); }
}
}.defer(args.ctx.engine));
}.defer(args.ctx));
return res;
}
@ -354,7 +369,7 @@ public class PromiseLib {
}
catch (EngineException e) { res.reject(args.ctx, e); }
}
}.defer(args.ctx.engine));
}.defer(args.ctx));
return res;
}

View File

@ -0,0 +1,34 @@
package me.topchetoeu.jscript.utils;
import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.common.FunctionBody;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.parsing.Parsing;
import me.topchetoeu.jscript.core.Compiler;
import me.topchetoeu.jscript.core.Extensions;
import me.topchetoeu.jscript.core.debug.DebugContext;
public class JSCompiler implements Compiler {
public final Extensions ext;
private void registerFunc(FunctionBody body, CompileResult res) {
var map = res.map();
DebugContext.get(ext).onFunctionLoad(body, map);
for (var i = 0; i < body.children.length; i++) {
registerFunc(body.children[i], res.children.get(i));
}
}
@Override public FunctionBody compile(Filename filename, String source) {
var res = Parsing.compile(filename, source);
var func = res.body();
registerFunc(func, res);
return func;
}
public JSCompiler(Extensions ext) {
this.ext = ext;
}
}

View File

@ -8,8 +8,11 @@ import java.nio.file.Path;
import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.common.Metadata;
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;
@ -36,7 +39,6 @@ public class JScriptRepl {
static Environment environment = new Environment();
static int j = 0;
static boolean exited = false;
static String[] args;
private static void reader() {
@ -74,25 +76,21 @@ public class JScriptRepl {
}
catch (IOException e) {
System.out.println(e.toString());
exited = true;
engine.thread().interrupt();
}
catch (RuntimeException ex) {
if (!exited) {
if (ex instanceof InterruptException) return;
else {
System.out.println("Internal error ocurred:");
ex.printStackTrace();
}
}
if (exited) {
debugTask.interrupt();
engineTask.interrupt();
}
}
private static void initEnv() {
environment = Internals.apply(environment);
environment.global.define(false, new NativeFunction("exit", args -> {
exited = true;
throw new InterruptException();
}));
environment.global.define(false, new NativeFunction("go", args -> {
@ -105,26 +103,35 @@ public class JScriptRepl {
throw new EngineException("Couldn't open do.js");
}
}));
environment.global.define(false, new NativeFunction("log", args -> {
for (var el : args.args) {
Values.printValue(args.ctx, el);
}
return null;
}));
var fs = new RootFilesystem(PermissionsProvider.get(environment));
fs.protocols.put("temp", new MemoryFilesystem(Mode.READ_WRITE));
fs.protocols.put("file", new PhysicalFilesystem("."));
fs.protocols.put("std", STDFilesystem.ofStd(System.in, System.out, System.err));
environment.add(PermissionsProvider.ENV_KEY, PermissionsManager.ALL_PERMS);
environment.add(Filesystem.ENV_KEY, fs);
environment.add(ModuleRepo.ENV_KEY, ModuleRepo.ofFilesystem(fs));
environment.add(PermissionsProvider.KEY, PermissionsManager.ALL_PERMS);
environment.add(Filesystem.KEY, fs);
environment.add(ModuleRepo.KEY, ModuleRepo.ofFilesystem(fs));
environment.add(Compiler.KEY, new JSCompiler(new Context(environment)));
environment.add(EventLoop.KEY, engine);
}
private static void initEngine() {
// var ctx = new DebugContext();
// engine.add(DebugContext.ENV_KEY, ctx);
var ctx = new DebugContext();
environment.add(DebugContext.KEY, ctx);
// debugServer.targets.put("target", (ws, req) -> new SimpleDebugger(ws).attach(ctx));
engineTask = engine.start();
// debugTask = debugServer.start(new InetSocketAddress("127.0.0.1", 9229), true);
debugTask = debugServer.start(new InetSocketAddress("127.0.0.1", 9229), true);
}
public static void main(String args[]) {
public static void main(String args[]) throws InterruptedException {
System.out.println(String.format("Running %s v%s by %s", Metadata.name(), Metadata.version(), Metadata.author()));
JScriptRepl.args = args;
@ -136,5 +143,9 @@ public class JScriptRepl {
reader.setDaemon(true);
reader.setName("STD Reader");
reader.start();
engine.thread().join();
debugTask.interrupt();
engineTask.interrupt();
}
}

View File

@ -1,33 +0,0 @@
package me.topchetoeu.jscript.utils.debug;
import java.io.IOException;
public interface DebugHandler {
void enable(V8Message msg) throws IOException;
void disable(V8Message msg) throws IOException;
void setBreakpointByUrl(V8Message msg) throws IOException;
void removeBreakpoint(V8Message msg) throws IOException;
void continueToLocation(V8Message msg) throws IOException;
void getScriptSource(V8Message msg) throws IOException;
void getPossibleBreakpoints(V8Message msg) throws IOException;
void resume(V8Message msg) throws IOException;
void pause(V8Message msg) throws IOException;
void stepInto(V8Message msg) throws IOException;
void stepOut(V8Message msg) throws IOException;
void stepOver(V8Message msg) throws IOException;
void setPauseOnExceptions(V8Message msg) throws IOException;
void evaluateOnCallFrame(V8Message msg) throws IOException;
void getProperties(V8Message msg) throws IOException;
void releaseObjectGroup(V8Message msg) throws IOException;
void releaseObject(V8Message msg) throws IOException;
void callFunctionOn(V8Message msg) throws IOException;
void runtimeEnable(V8Message msg) throws IOException;
}

View File

@ -1,7 +1,36 @@
package me.topchetoeu.jscript.utils.debug;
import me.topchetoeu.jscript.core.debug.DebugController;
import me.topchetoeu.jscript.core.debug.DebugHandler;
import java.io.IOException;
public interface Debugger extends DebugHandler, DebugController {
public interface Debugger extends DebugHandler {
void close();
void enable(V8Message msg) throws IOException;
void disable(V8Message msg) throws IOException;
void setBreakpointByUrl(V8Message msg) throws IOException;
void removeBreakpoint(V8Message msg) throws IOException;
void continueToLocation(V8Message msg) throws IOException;
void getScriptSource(V8Message msg) throws IOException;
void getPossibleBreakpoints(V8Message msg) throws IOException;
void resume(V8Message msg) throws IOException;
void pause(V8Message msg) throws IOException;
void stepInto(V8Message msg) throws IOException;
void stepOut(V8Message msg) throws IOException;
void stepOver(V8Message msg) throws IOException;
void setPauseOnExceptions(V8Message msg) throws IOException;
void evaluateOnCallFrame(V8Message msg) throws IOException;
void getProperties(V8Message msg) throws IOException;
void releaseObjectGroup(V8Message msg) throws IOException;
void releaseObject(V8Message msg) throws IOException;
void callFunctionOn(V8Message msg) throws IOException;
void runtimeEnable(V8Message msg) throws IOException;
}

View File

@ -15,24 +15,31 @@ public interface File {
default byte[] readAll() {
var parts = new LinkedList<byte[]>();
var sizes = new LinkedList<Integer>();
var buff = new byte[1024];
var size = 0;
while (true) {
var n = read(buff);
if (n == 0) break;
if (n < 0) break;
else if (n == 0) continue;
parts.add(buff);
sizes.add(n);
size += n;
buff = new byte[1024];
}
buff = new byte[size];
var i = 0;
var j = 0;
for (var part : parts) {
System.arraycopy(part, 0, buff, i, part.length);
i += part.length;
var currSize = sizes.get(j++);
System.arraycopy(part, 0, buff, i, currSize);
i += currSize;
}
return buff;

View File

@ -1,10 +1,10 @@
package me.topchetoeu.jscript.utils.filesystem;
import me.topchetoeu.jscript.core.Extensions;
import me.topchetoeu.jscript.core.values.Symbol;
import me.topchetoeu.jscript.core.Key;
public interface Filesystem {
public static final Symbol ENV_KEY = Symbol.get("Environment.fs");
public static final Key<Filesystem> KEY = new Key<>();
default String normalize(String... path) { return Paths.normalize(path); }
default boolean create(String path, EntryType type) { throw new FilesystemException(ErrorReason.UNSUPPORTED).setAction(ActionType.CREATE); }
@ -13,6 +13,6 @@ public interface Filesystem {
void close();
public static Filesystem get(Extensions exts) {
return exts.get(ENV_KEY);
return exts.get(KEY);
}
}

View File

@ -6,6 +6,7 @@ class MemoryFile extends BaseFile<Buffer> {
private int ptr;
@Override protected int onRead(byte[] buff) {
if (ptr >= handle().length()) return -1;
var res = handle().read(ptr, buff);
ptr += res;
return res;

View File

@ -39,7 +39,7 @@ public class NativeWrapperProvider implements WrapperProvider {
throw ((EngineException)e.getTargetException()).add(ctx, name, Location.INTERNAL);
}
else if (e.getTargetException() instanceof NullPointerException) {
e.printStackTrace();
// e.getTargetException().printStackTrace();
throw EngineException.ofType("Unexpected value of 'undefined'.").add(ctx, name, Location.INTERNAL);
}
else if (e.getTargetException() instanceof InterruptException || e.getTargetException() instanceof InterruptedException) {
@ -172,7 +172,7 @@ public class NativeWrapperProvider implements WrapperProvider {
if (props.contains(key) || nonProps.contains(key)) repeat = true;
else {
checkSignature(method, true, Environment.class);
obj.defineProperty(null, key, call(new Context(null, env), name, method, null, env), true, true, false);
obj.defineProperty(null, key, call(new Context(env), name, method, null, env), true, true, false);
nonProps.add(key);
}
@ -195,7 +195,7 @@ public class NativeWrapperProvider implements WrapperProvider {
if (props.contains(key) || nonProps.contains(key)) repeat = true;
else {
try {
obj.defineProperty(null, key, Values.normalize(new Context(null, env), field.get(null)), true, true, false);
obj.defineProperty(null, key, Values.normalize(new Context(env), field.get(null)), true, true, false);
nonProps.add(key);
}
catch (IllegalArgumentException | IllegalAccessException e) { }

View File

@ -1,4 +1,4 @@
package me.topchetoeu.jscript.compilation.mapping;
package me.topchetoeu.jscript.utils.mapping;
import java.util.ArrayList;
import java.util.List;
@ -6,7 +6,6 @@ import java.util.TreeMap;
import java.util.stream.Collectors;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.VLQ;
import me.topchetoeu.jscript.common.json.JSON;
public class SourceMap {

View File

@ -1,4 +1,4 @@
package me.topchetoeu.jscript.common;
package me.topchetoeu.jscript.utils.mapping;
import java.util.ArrayList;
import java.util.List;

View File

@ -5,13 +5,13 @@ import java.util.HashMap;
import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.core.Context;
import me.topchetoeu.jscript.core.Extensions;
import me.topchetoeu.jscript.core.values.Symbol;
import me.topchetoeu.jscript.core.Key;
import me.topchetoeu.jscript.utils.filesystem.Filesystem;
import me.topchetoeu.jscript.utils.filesystem.Mode;
public interface ModuleRepo {
public static final Symbol ENV_KEY = Symbol.get("Environment.modules");
public static final Symbol CWD = Symbol.get("Environment.moduleCwd");
public static final Key<ModuleRepo> KEY = new Key<>();
public static final Key<String> CWD = new Key<>();
public Module getModule(Context ctx, String cwd, String name);
@ -39,6 +39,6 @@ public interface ModuleRepo {
return exts.init(CWD, "/");
}
public static ModuleRepo get(Extensions exts) {
return exts.get(ENV_KEY);
return exts.get(KEY);
}
}

View File

@ -11,7 +11,7 @@ public class SourceModule extends Module {
@Override
protected Object onLoad(Context ctx) {
var res = new Context(ctx.engine, env).compile(filename, source);
var res = new Context(env).compile(filename, source);
return res.call(ctx);
}

View File

@ -1,10 +1,10 @@
package me.topchetoeu.jscript.utils.permissions;
import me.topchetoeu.jscript.core.Extensions;
import me.topchetoeu.jscript.core.values.Symbol;
import me.topchetoeu.jscript.core.Key;
public interface PermissionsProvider {
public static final Symbol ENV_KEY = new Symbol("Environment.perms");
public static final Key<PermissionsProvider> KEY = new Key<>();
public static final PermissionsProvider ALL_PERMS = (perm, value) -> true;
boolean hasPermission(Permission perm, String value);
@ -22,7 +22,7 @@ public interface PermissionsProvider {
public static PermissionsProvider get(Extensions exts) {
return (perm, value) -> {
if (exts.hasNotNull(ENV_KEY)) return ((PermissionsProvider)exts.get(ENV_KEY)).hasPermission(perm);
if (exts.hasNotNull(KEY)) return exts.get(KEY).hasPermission(perm);
else return true;
};
}