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 class FunctionBody {
public final FunctionBody[] children; 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.DataInputStream;
import java.io.DataOutputStream; 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.Operation;
import me.topchetoeu.jscript.core.exceptions.SyntaxException; import me.topchetoeu.jscript.core.exceptions.SyntaxException;
public class Instruction { public class Instruction {

View File

@ -1,7 +1,9 @@
package me.topchetoeu.jscript.common; package me.topchetoeu.jscript.common;
import java.util.ArrayList;
public class Location implements Comparable<Location> { 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 line;
private int start; private int start;
private Filename filename; private Filename filename;
@ -12,7 +14,13 @@ public class Location implements Comparable<Location> {
@Override @Override
public String toString() { 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) { 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; import java.util.HashMap;

View File

@ -13,11 +13,6 @@ public class Reading {
return reader.readLine(); return reader.readLine();
} }
/**
* Reads the given stream to a string
* @param in
* @return
*/
public static String streamToString(InputStream in) { public static String streamToString(InputStream in) {
try { try {
return new String(in.readAllBytes()); 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 { public enum ConvertType {
Exact, 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.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -9,8 +9,9 @@ import java.util.TreeMap;
import java.util.TreeSet; import java.util.TreeSet;
import me.topchetoeu.jscript.common.Location; 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.core.scope.LocalScopeRecord;
import me.topchetoeu.jscript.utils.mapping.SourceMap;
public class FunctionMap { public class FunctionMap {
public static class FunctionMapBuilder { public static class FunctionMapBuilder {
@ -22,10 +23,12 @@ public class FunctionMap {
} }
public FunctionMapBuilder setDebug(Location loc, BreakpointType type) { public FunctionMapBuilder setDebug(Location loc, BreakpointType type) {
if (loc == null || type == null || type == BreakpointType.NONE) return this;
breakpoints.put(loc, type); breakpoints.put(loc, type);
return this; return this;
} }
public FunctionMapBuilder setLocation(int i, Location loc) { public FunctionMapBuilder setLocation(int i, Location loc) {
if (loc == null || i < 0) return this;
sourceMap.put(i, loc); sourceMap.put(i, loc);
return this; return this;
} }
@ -36,9 +39,11 @@ public class FunctionMap {
} }
public Location first() { public Location first() {
if (sourceMap.size() == 0) return null;
return sourceMap.firstEntry().getValue(); return sourceMap.firstEntry().getValue();
} }
public Location last() { public Location last() {
if (sourceMap.size() == 0) return null;
return sourceMap.lastEntry().getValue(); return sourceMap.lastEntry().getValue();
} }
@ -68,7 +73,9 @@ public class FunctionMap {
public Location toLocation(int pc, boolean approxiamte) { public Location toLocation(int pc, boolean approxiamte) {
var res = pcToLoc.get(pc); var res = pcToLoc.get(pc);
if (!approxiamte || res != null) return res; 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) { public Location toLocation(int pc) {
return toLocation(pc, false); return toLocation(pc, false);
@ -85,9 +92,11 @@ public class FunctionMap {
} }
public Location start() { public Location start() {
if (pcToLoc.size() == 0) return null;
return pcToLoc.firstEntry().getValue(); return pcToLoc.firstEntry().getValue();
} }
public Location end() { public Location end() {
if (pcToLoc.size() == 0) return null;
return pcToLoc.lastEntry().getValue(); return pcToLoc.lastEntry().getValue();
} }
@ -126,6 +135,9 @@ public class FunctionMap {
if (b != null) pcToLoc.remove(b); if (b != null) pcToLoc.remove(b);
if (a != null) locToPc.remove(a); if (a != null) locToPc.remove(a);
pcToLoc.put(pc, loc);
locToPc.put(loc, pc);
} }
for (var el : breakpoints.entrySet()) { for (var el : breakpoints.entrySet()) {
if (el.getValue() == null || el.getValue() == BreakpointType.NONE) continue; if (el.getValue() == null || el.getValue() == BreakpointType.NONE) continue;

View File

@ -1,7 +1,7 @@
package me.topchetoeu.jscript.compilation; package me.topchetoeu.jscript.compilation;
import me.topchetoeu.jscript.common.Location; 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 class AssignableStatement extends Statement {
public abstract Statement toAssign(Statement val, Operation operation); 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.LinkedList;
import java.util.Vector; 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.common.Location;
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType; import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.mapping.FunctionMap; import me.topchetoeu.jscript.common.mapping.FunctionMap;
import me.topchetoeu.jscript.compilation.mapping.FunctionMap.FunctionMapBuilder; import me.topchetoeu.jscript.common.mapping.FunctionMap.FunctionMapBuilder;
import me.topchetoeu.jscript.core.scope.LocalScopeRecord; import me.topchetoeu.jscript.core.scope.LocalScopeRecord;
public class CompileResult { public class CompileResult {
@ -59,6 +61,9 @@ public class CompileResult {
return child; return child;
} }
public FunctionMap map() {
return map.build(scope);
}
public FunctionBody body() { public FunctionBody body() {
var builtChildren = new FunctionBody[children.size()]; var builtChildren = new FunctionBody[children.size()];
@ -67,10 +72,6 @@ public class CompileResult {
return new FunctionBody(scope.localsCount(), length, instructions.toArray(Instruction[]::new), builtChildren); return new FunctionBody(scope.localsCount(), length, instructions.toArray(Instruction[]::new), builtChildren);
} }
public FunctionMap map() {
return map.build();
}
public CompileResult(LocalScopeRecord scope) { public CompileResult(LocalScopeRecord scope) {
this.scope = scope; this.scope = scope;
} }

View File

@ -3,8 +3,9 @@ package me.topchetoeu.jscript.compilation;
import java.util.List; import java.util.List;
import java.util.Vector; import java.util.Vector;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location; 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; import me.topchetoeu.jscript.compilation.values.FunctionStatement;
public class CompoundStatement extends Statement { public class CompoundStatement extends Statement {

View File

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

View File

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

View File

@ -2,8 +2,9 @@ package me.topchetoeu.jscript.compilation;
import java.util.List; import java.util.List;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location; 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; import me.topchetoeu.jscript.compilation.values.FunctionStatement;
public class VariableDeclareStatement extends Statement { public class VariableDeclareStatement extends Statement {

View File

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

View File

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

View File

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

View File

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

View File

@ -1,10 +1,10 @@
package me.topchetoeu.jscript.compilation.control; package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location; import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.CompileResult; import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement; import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
public class DoWhileStatement extends Statement { public class DoWhileStatement extends Statement {
public final Statement condition, body; public final Statement condition, body;

View File

@ -1,11 +1,11 @@
package me.topchetoeu.jscript.compilation.control; package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location; 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.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement; 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 class ForInStatement extends Statement {
public final String varName; public final String varName;

View File

@ -1,10 +1,10 @@
package me.topchetoeu.jscript.compilation.control; package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location; import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.CompileResult; import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement; import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
public class ForStatement extends Statement { public class ForStatement extends Statement {
public final Statement declaration, assignment, condition, body; public final Statement declaration, assignment, condition, body;

View File

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

View File

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

View File

@ -2,13 +2,13 @@ package me.topchetoeu.jscript.compilation.control;
import java.util.HashMap; import java.util.HashMap;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location; 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.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement; 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 class SwitchStatement extends Statement {
public static class SwitchCase { public static class SwitchCase {

View File

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

View File

@ -1,10 +1,10 @@
package me.topchetoeu.jscript.compilation.control; package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location; import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.CompileResult; import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement; import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.compilation.Instruction.BreakpointType;
public class TryStatement extends Statement { public class TryStatement extends Statement {
public final Statement tryBody; public final Statement tryBody;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,12 +1,12 @@
package me.topchetoeu.jscript.compilation.values; package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
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.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.Instruction;
import me.topchetoeu.jscript.compilation.Statement; 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; import me.topchetoeu.jscript.core.exceptions.SyntaxException;
public class FunctionStatement extends Statement { public class FunctionStatement extends Statement {

View File

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

View File

@ -1,11 +1,11 @@
package me.topchetoeu.jscript.compilation.values; package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location; 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.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement; 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 class IndexAssignStatement extends Statement {
public final Statement object; public final Statement object;

View File

@ -1,12 +1,12 @@
package me.topchetoeu.jscript.compilation.values; package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location; 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.AssignableStatement;
import me.topchetoeu.jscript.compilation.CompileResult; import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement; 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 class IndexStatement extends AssignableStatement {
public final Statement object; public final Statement object;

View File

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

View File

@ -1,8 +1,8 @@
package me.topchetoeu.jscript.compilation.values; package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location; import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult; import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement; import me.topchetoeu.jscript.compilation.Statement;
public class LazyOrStatement extends 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.ArrayList;
import java.util.Map; import java.util.Map;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location; import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult; import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement; import me.topchetoeu.jscript.compilation.Statement;
public class ObjectStatement extends Statement { public class ObjectStatement extends Statement {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,8 +1,17 @@
package me.topchetoeu.jscript.core; package me.topchetoeu.jscript.core;
import me.topchetoeu.jscript.common.Filename; 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 interface Compiler {
public Key<Compiler> KEY = new Key<>();
public FunctionBody compile(Filename filename, String source); 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; package me.topchetoeu.jscript.core;
import java.util.Iterator; 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.common.Filename;
import me.topchetoeu.jscript.core.debug.DebugContext; 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.FunctionValue;
import me.topchetoeu.jscript.core.values.Symbol;
import me.topchetoeu.jscript.core.exceptions.EngineException; 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 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 Context parent;
public final Environment environment; public final Environment environment;
public final Frame frame; public final Frame frame;
public final Engine engine; // public final Engine engine;
public final int stackSize; 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); 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); 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; return null;
} }
@Override public boolean has(Symbol key) { @Override public boolean has(Key<?> key) {
return return
environment != null && environment.has(key) || environment != null && environment.has(key);
engine != null && engine.has(key); // engine != null && engine.has(key);
} }
@Override public boolean remove(Symbol key) { @Override public boolean remove(Key<?> key) {
var res = false; var res = false;
if (environment != null) res |= environment.remove(key); 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; return res;
} }
@Override public Iterable<Symbol> keys() { @Override public Iterable<Key<?>> keys() {
if (engine == null && environment == null) return List.of(); return environment.keys();
if (engine == null) return environment.keys();
if (environment == null) return engine.keys();
return () -> Stream.concat( // if (engine == null && environment == null) return List.of();
StreamSupport.stream(engine.keys().spliterator(), false), // if (engine == null) return environment.keys();
StreamSupport.stream(environment.keys().spliterator(), false) // if (environment == null) return engine.keys();
).distinct().iterator();
// return () -> Stream.concat(
// StreamSupport.stream(engine.keys().spliterator(), false),
// StreamSupport.stream(environment.keys().spliterator(), false)
// ).distinct().iterator();
} }
public FunctionValue compile(Filename filename, String raw) { 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); DebugContext.get(this).onSource(filename, raw);
return (FunctionValue)result; var result = new CodeFunction(environment, filename.toString(), Compiler.get(this).compile(filename, raw), new ValueVariable[0]);
return 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;
// }
} }
public Context pushFrame(Frame frame) { 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; 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.parent = parent;
this.environment = environment; this.environment = environment;
this.frame = frame; this.frame = frame;
this.engine = engine;
this.stackSize = stackSize; this.stackSize = stackSize;
if (hasNotNull(Environment.MAX_STACK_COUNT) && stackSize > (int)get(Environment.MAX_STACK_COUNT)) { 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) { public Context() {
this(null, null, null, engine, 0); this(null, null, null, 0);
} }
public Context(Engine engine, Environment env) { public Context(Environment env) {
this(null, env, null, engine, 0); this(null, env, null, 0);
} }
} }

View File

@ -1,54 +1,92 @@
package me.topchetoeu.jscript.core; 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.Filename;
import me.topchetoeu.jscript.common.ResultRunnable;
import me.topchetoeu.jscript.common.events.DataNotifier; 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.FunctionValue;
import me.topchetoeu.jscript.core.values.Symbol;
public class Engine extends EventLoop implements Extensions { public class Engine implements EventLoop {
public static final HashMap<Integer, FunctionBody> functions = new HashMap<>(); 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 @Override
public <T> void add(Symbol key, T obj) { public int compareTo(Task<?> other) {
this.env.add(key, obj); return Integer.compare(this.micro ? 0 : 1, other.micro ? 0 : 1);
} }
@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();
} }
public Engine copy() { private PriorityBlockingQueue<Task<?>> tasks = new PriorityBlockingQueue<>();
var res = new Engine(); private Thread thread;
res.env.addAll(env);
return res; @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) { public DataNotifier<Object> pushMsg(boolean micro, Environment env, FunctionValue func, Object thisArg, Object ...args) {
return pushMsg(() -> { return pushMsg(() -> {
return func.call(new Context(this, env), thisArg, args); return func.call(new Context(env), thisArg, args);
}, micro); }, micro);
} }
public DataNotifier<Object> pushMsg(boolean micro, Environment env, Filename filename, String raw, Object thisArg, Object ...args) { public DataNotifier<Object> pushMsg(boolean micro, Environment env, Filename filename, String raw, Object thisArg, Object ...args) {
return pushMsg(() -> { return pushMsg(() -> {
var ctx = new Context(this, env); var ctx = new Context(env);
return ctx.compile(filename, raw).call(new Context(this, env), thisArg, args); return ctx.compile(filename, raw).call(new Context(env), thisArg, args);
}, micro); }, micro);
} }

View File

@ -5,77 +5,57 @@ import java.util.HashMap;
import me.topchetoeu.jscript.core.scope.GlobalScope; import me.topchetoeu.jscript.core.scope.GlobalScope;
import me.topchetoeu.jscript.core.values.FunctionValue; import me.topchetoeu.jscript.core.values.FunctionValue;
import me.topchetoeu.jscript.core.values.NativeFunction; 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.core.exceptions.EngineException;
import me.topchetoeu.jscript.utils.interop.NativeWrapperProvider; import me.topchetoeu.jscript.utils.interop.NativeWrapperProvider;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class Environment implements Extensions { 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"); private HashMap<Key<?>, Object> data = new HashMap<>();
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<>();
public GlobalScope global; public GlobalScope global;
public WrapperProvider wrappers; 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); data.put(key, obj);
} }
@Override public <T> T get(Symbol key) { @Override public <T> T get(Key<T> key) {
return (T)data.get(key); return (T)data.get(key);
} }
@Override public boolean remove(Symbol key) { @Override public boolean remove(Key<?> key) {
if (data.containsKey(key)) { if (data.containsKey(key)) {
data.remove(key); data.remove(key);
return true; return true;
} }
return false; return false;
} }
@Override public boolean has(Symbol key) { @Override public boolean has(Key<?> key) {
return data.containsKey(key); return data.containsKey(key);
} }
@Override public Iterable<Symbol> keys() { @Override public Iterable<Key<?>> keys() {
return data.keySet(); 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) { 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); throw EngineException.ofError("Regular expressions not supported.").setCtx(args.ctx);
})); }));
} }
@ -95,8 +75,8 @@ public class Environment implements Extensions {
return res; return res;
} }
public Context context(Engine engine) { public Context context() {
return new Context(engine, this); return new Context(this);
} }
public Environment(WrapperProvider nativeConverter, GlobalScope global) { public Environment(WrapperProvider nativeConverter, GlobalScope global) {

View File

@ -1,80 +1,23 @@
package me.topchetoeu.jscript.core; package me.topchetoeu.jscript.core;
import java.util.concurrent.PriorityBlockingQueue;
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.core.exceptions.EngineException;
public class EventLoop { public interface EventLoop {
private static class Task implements Comparable<Task> { public static final Key<EventLoop> KEY = new Key<>();
public final ResultRunnable<?> runnable;
public final DataNotifier<Object> notifier = new DataNotifier<>();
public final boolean micro;
public Task(ResultRunnable<?> runnable, boolean micro) { public static EventLoop get(Extensions ext) {
this.runnable = runnable; if (ext.hasNotNull(KEY)) return ext.get(KEY);
this.micro = micro; else return new EventLoop() {
} @Override public <T> DataNotifier<T> pushMsg(ResultRunnable<T> runnable, boolean micro) {
throw EngineException.ofError("No event loop attached to environment.");
@Override }
public int compareTo(Task other) { };
return Integer.compare(this.micro ? 0 : 1, other.micro ? 0 : 1);
}
} }
private PriorityBlockingQueue<Task> tasks = new PriorityBlockingQueue<>(); public <T> DataNotifier<T> pushMsg(ResultRunnable<T> runnable, boolean micro);
private Thread thread; public default DataNotifier<Void> pushMsg(Runnable runnable, boolean micro) {
@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) {
return pushMsg(() -> { runnable.run(); return null; }, 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; package me.topchetoeu.jscript.core;
import me.topchetoeu.jscript.core.values.Symbol;
public interface Extensions { public interface Extensions {
<T> T get(Symbol key); <T> T get(Key<T> key);
<T> void add(Symbol key, T obj); <T> void add(Key<T> key, T obj);
Iterable<Symbol> keys(); Iterable<Key<?>> keys();
boolean has(Symbol key); boolean has(Key<?> key);
boolean remove(Symbol key); boolean remove(Key<?> key);
default boolean hasNotNull(Symbol key) { default boolean hasNotNull(Key<?> key) {
return has(key) && get(key) != null; 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); if (has(key)) return get(key);
else return defaultVal; 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); if (has(key)) return get(key);
else { else {
add(key, val); add(key, val);
return val; return val;
} }
} }
@SuppressWarnings("unchecked")
default void addAll(Extensions source) { default void addAll(Extensions source) {
for (var key : source.keys()) { 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.List;
import java.util.Stack; 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.debug.DebugContext;
import me.topchetoeu.jscript.core.scope.LocalScope; import me.topchetoeu.jscript.core.scope.LocalScope;
import me.topchetoeu.jscript.core.scope.ValueVariable; import me.topchetoeu.jscript.core.scope.ValueVariable;
@ -159,7 +159,7 @@ public class Frame {
returnValue = InstructionRunner.exec(ctx, instr, this); returnValue = InstructionRunner.exec(ctx, instr, this);
} }
catch (EngineException e) { 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 java.util.Collections;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.core.scope.ValueVariable; import me.topchetoeu.jscript.core.scope.ValueVariable;
import me.topchetoeu.jscript.core.values.ArrayValue; import me.topchetoeu.jscript.core.values.ArrayValue;
import me.topchetoeu.jscript.core.values.CodeFunction; 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.ObjectValue;
import me.topchetoeu.jscript.core.values.Symbol; import me.topchetoeu.jscript.core.values.Symbol;
import me.topchetoeu.jscript.core.values.Values; 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; import me.topchetoeu.jscript.core.exceptions.EngineException;
public class InstructionRunner { public class InstructionRunner {

View File

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

View File

@ -1,12 +1,14 @@
package me.topchetoeu.jscript.core.debug; package me.topchetoeu.jscript.core.debug;
import me.topchetoeu.jscript.common.Filename; 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.Context;
import me.topchetoeu.jscript.core.Frame; import me.topchetoeu.jscript.core.Frame;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.core.exceptions.EngineException;
public interface DebugController { public interface DebugHandler {
/** /**
* Called when a script has been loaded * Called when a script has been loaded
* @param filename The name of the source * @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 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 * @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. * 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); void onFramePop(Context ctx, Frame frame);
public static DebugController empty() { public static DebugHandler empty() {
return new DebugController () { return new DebugHandler () {
@Override public void onFramePop(Context ctx, Frame frame) { } @Override public void onFramePop(Context ctx, Frame frame) { }
@Override public void onFramePush(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) { @Override public boolean onInstruction(Context ctx, Frame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught) {
return false; 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.common.Location;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.core.Context;
import me.topchetoeu.jscript.core.Engine;
import me.topchetoeu.jscript.core.Environment; import me.topchetoeu.jscript.core.Environment;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.core.values.ObjectValue;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.core.values.Values;
@ -35,7 +34,7 @@ public class EngineException extends RuntimeException {
if (name.equals("")) name = null; if (name.equals("")) name = null;
if (ctx == null) this.ctx = 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.location = location;
this.name = name; this.name = name;
} }
@ -44,7 +43,6 @@ public class EngineException extends RuntimeException {
public final Object value; public final Object value;
public EngineException cause; public EngineException cause;
public Environment env = null; public Environment env = null;
public Engine engine = 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(Context ctx, String name, Location location) {
@ -60,7 +58,6 @@ public class EngineException extends RuntimeException {
} }
public EngineException setCtx(Context ctx) { public EngineException setCtx(Context ctx) {
if (this.env == null) this.env = ctx.environment; if (this.env == null) this.env = ctx.environment;
if (this.engine == null) this.engine = ctx.engine;
return this; return this;
} }

View File

@ -1,6 +1,6 @@
package me.topchetoeu.jscript.core.values; 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.Context;
import me.topchetoeu.jscript.core.Environment; import me.topchetoeu.jscript.core.Environment;
import me.topchetoeu.jscript.core.Frame; import me.topchetoeu.jscript.core.Frame;

View File

@ -12,9 +12,9 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.core.Context; import me.topchetoeu.jscript.core.Context;
import me.topchetoeu.jscript.core.Environment; import me.topchetoeu.jscript.core.Environment;
import me.topchetoeu.jscript.core.Operation;
import me.topchetoeu.jscript.core.debug.DebugContext; import me.topchetoeu.jscript.core.debug.DebugContext;
import me.topchetoeu.jscript.core.exceptions.ConvertException; import me.topchetoeu.jscript.core.exceptions.ConvertException;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.core.exceptions.EngineException;
@ -664,7 +664,7 @@ public class Values {
if (val instanceof FunctionValue) { if (val instanceof FunctionValue) {
res.append(val.toString()); 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); if (loc != null) res.append(" @ " + loc);
} }
@ -734,10 +734,10 @@ public class Values {
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.engine, ee.env)); return prefix + " " + ee.toString(new Context(ee.env));
} }
catch (EngineException ex) { 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) { else if (err instanceof SyntaxException) {

View File

@ -13,7 +13,7 @@ import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("AsyncFunction") @WrapperName("AsyncFunction")
public class AsyncFunctionLib extends FunctionValue { public class AsyncFunctionLib extends FunctionValue {
public final FunctionValue factory; public final CodeFunction func;
private static class AsyncHelper { private static class AsyncHelper {
public PromiseLib promise = new PromiseLib(); public PromiseLib promise = new PromiseLib();
@ -67,15 +67,19 @@ public class AsyncFunctionLib extends FunctionValue {
@Override @Override
public Object call(Context ctx, Object thisArg, Object ...args) { public Object call(Context ctx, Object thisArg, Object ...args) {
var handler = new AsyncHelper(); 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."); var newArgs = new Object[args.length + 1];
handler.frame = new Frame(ctx, thisArg, args, (CodeFunction)func); 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); handler.next(ctx, Values.NO_RETURN, null);
return handler.promise; return handler.promise;
} }
public AsyncFunctionLib(FunctionValue factory) { public AsyncFunctionLib(FunctionValue func) {
super(factory.name, factory.length); super(func.name, func.length);
this.factory = factory; 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") @WrapperName("AsyncGeneratorFunction")
public class AsyncGeneratorFunctionLib extends FunctionValue { public class AsyncGeneratorFunctionLib extends FunctionValue {
public final FunctionValue factory; public final CodeFunction func;
@Override @Override
public Object call(Context ctx, Object thisArg, Object ...args) { public Object call(Context ctx, Object thisArg, Object ...args) {
var handler = new AsyncGeneratorLib(); var handler = new AsyncGeneratorLib();
var func = factory.call(ctx, thisArg,
new NativeFunction("await", handler::await), var newArgs = new Object[args.length + 2];
new NativeFunction("yield", handler::yield) newArgs[0] = new NativeFunction("await", handler::await);
); newArgs[1] = new NativeFunction("yield", handler::yield);
if (!(func instanceof CodeFunction)) throw EngineException.ofType("Return value of argument must be a js function."); System.arraycopy(args, 0, newArgs, 2, args.length);
handler.frame = new Frame(ctx, thisArg, args, (CodeFunction)func);
handler.frame = new Frame(ctx, thisArg, newArgs, func);
return handler; return handler;
} }
public AsyncGeneratorFunctionLib(FunctionValue factory) { public AsyncGeneratorFunctionLib(CodeFunction func) {
super(factory.name, factory.length); super(func.name, func.length);
this.factory = factory; 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; package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.core.values.ArrayValue; 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.FunctionValue;
import me.topchetoeu.jscript.core.values.NativeFunction; import me.topchetoeu.jscript.core.values.NativeFunction;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
@ -44,10 +45,10 @@ public class FunctionLib {
} }
@Expose(target = ExposeTarget.STATIC) @Expose(target = ExposeTarget.STATIC)
public static FunctionValue __asyncGenerator(Arguments args) { 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) @Expose(target = ExposeTarget.STATIC)
public static FunctionValue __generator(Arguments args) { 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") @WrapperName("GeneratorFunction")
public class GeneratorFunctionLib extends FunctionValue { public class GeneratorFunctionLib extends FunctionValue {
public final FunctionValue factory; public final CodeFunction func;
@Override public Object call(Context ctx, Object thisArg, Object ...args) { @Override public Object call(Context ctx, Object thisArg, Object ...args) {
var handler = new GeneratorLib(); 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."); var newArgs = new Object[args.length + 1];
handler.frame = new Frame(ctx, thisArg, args, (CodeFunction)func); 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; return handler;
} }
public GeneratorFunctionLib(FunctionValue factory) { public GeneratorFunctionLib(CodeFunction func) {
super(factory.name, factory.length); super(func.name, func.length);
this.factory = factory; 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.Context;
import me.topchetoeu.jscript.core.Environment; 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.scope.GlobalScope;
import me.topchetoeu.jscript.core.values.FunctionValue; 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.values.Values;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.core.exceptions.EngineException;
import me.topchetoeu.jscript.utils.interop.Arguments; 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; import me.topchetoeu.jscript.utils.modules.ModuleRepo;
public class Internals { public class Internals {
private static final Symbol THREADS = new Symbol("Internals.threads"); private static final Key<HashMap<Integer, Thread>> THREADS = new Key<>();
private static final Symbol I = new Symbol("Internals.i"); private static final Key<Integer> I = new Key<>();
@Expose(target = ExposeTarget.STATIC) @Expose(target = ExposeTarget.STATIC)
public static Object __require(Arguments args) { public static Object __require(Arguments args) {
@ -38,6 +39,8 @@ public class Internals {
var delay = args.getDouble(1); var delay = args.getDouble(1);
var arguments = args.slice(2).args; var arguments = args.slice(2).args;
if (!args.ctx.hasNotNull(EventLoop.KEY)) throw EngineException.ofError("No event loop");
var thread = new Thread(() -> { var thread = new Thread(() -> {
var ms = (long)delay; var ms = (long)delay;
var ns = (int)((delay - ms) * 10000000); var ns = (int)((delay - ms) * 10000000);
@ -45,7 +48,7 @@ public class Internals {
try { Thread.sleep(ms, ns); } try { Thread.sleep(ms, ns); }
catch (InterruptedException e) { return; } 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(); thread.start();
@ -61,6 +64,8 @@ public class Internals {
var delay = args.getDouble(1); var delay = args.getDouble(1);
var arguments = args.slice(2).args; var arguments = args.slice(2).args;
if (!args.ctx.hasNotNull(EventLoop.KEY)) throw EngineException.ofError("No event loop");
var thread = new Thread(() -> { var thread = new Thread(() -> {
var ms = (long)delay; var ms = (long)delay;
var ns = (int)((delay - ms) * 10000000); var ns = (int)((delay - ms) * 10000000);
@ -71,7 +76,7 @@ public class Internals {
} }
catch (InterruptedException e) { return; } 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(); thread.start();

View File

@ -6,12 +6,14 @@ 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.core.Context;
import me.topchetoeu.jscript.core.EventLoop; 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.ArrayValue;
import me.topchetoeu.jscript.core.values.FunctionValue; import me.topchetoeu.jscript.core.values.FunctionValue;
import me.topchetoeu.jscript.core.values.NativeFunction; import me.topchetoeu.jscript.core.values.NativeFunction;
import me.topchetoeu.jscript.core.values.ObjectValue; import me.topchetoeu.jscript.core.values.ObjectValue;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.core.values.Values;
import me.topchetoeu.jscript.core.exceptions.EngineException; 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.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;
@ -24,14 +26,17 @@ public class PromiseLib {
void onFulfil(Object val); void onFulfil(Object val);
void onReject(EngineException err); void onReject(EngineException err);
default Handle defer(EventLoop loop) { default Handle defer(Extensions loop) {
var self = this; var self = this;
return new Handle() { return new Handle() {
@Override public void onFulfil(Object val) { @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) { @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 Object val;
private void resolveSynchronized(Context ctx, Object val, int newState) { 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.val = val;
this.state = newState; this.state = newState;
@ -118,6 +125,12 @@ public class PromiseLib {
catch (EngineException e) { catch (EngineException e) {
res.reject(ctx, 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(); }, "Promisifier").start();
return res; return res;
@ -144,7 +157,8 @@ public class PromiseLib {
try { try {
var then = Values.getMember(ctx, obj, "then"); var then = Values.getMember(ctx, obj, "then");
Values.call(ctx, then, obj,
if (then instanceof FunctionValue) Values.call(ctx, then, obj,
new NativeFunction(args -> { new NativeFunction(args -> {
try { handle.onFulfil(args.get(0)); } try { handle.onFulfil(args.get(0)); }
catch (Exception e) { catch (Exception e) {
@ -162,6 +176,7 @@ public class PromiseLib {
return null; return null;
}) })
); );
else handle.onFulfil(obj);
return; return;
} }
@ -325,7 +340,7 @@ public class PromiseLib {
try { res.fulfill(args.ctx, onReject.call(args.ctx, null, err.value)); } try { res.fulfill(args.ctx, onReject.call(args.ctx, null, err.value)); }
catch (EngineException e) { res.reject(args.ctx, e); } catch (EngineException e) { res.reject(args.ctx, e); }
} }
}.defer(args.ctx.engine)); }.defer(args.ctx));
return res; return res;
} }
@ -354,7 +369,7 @@ public class PromiseLib {
} }
catch (EngineException e) { res.reject(args.ctx, e); } catch (EngineException e) { res.reject(args.ctx, e); }
} }
}.defer(args.ctx.engine)); }.defer(args.ctx));
return res; 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.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.Engine;
import me.topchetoeu.jscript.core.Environment; import me.topchetoeu.jscript.core.Environment;
import me.topchetoeu.jscript.core.EventLoop;
import me.topchetoeu.jscript.core.debug.DebugContext; import me.topchetoeu.jscript.core.debug.DebugContext;
import me.topchetoeu.jscript.core.values.NativeFunction; import me.topchetoeu.jscript.core.values.NativeFunction;
import me.topchetoeu.jscript.core.values.Values; import me.topchetoeu.jscript.core.values.Values;
@ -36,7 +39,6 @@ public class JScriptRepl {
static Environment environment = new Environment(); static Environment environment = new Environment();
static int j = 0; static int j = 0;
static boolean exited = false;
static String[] args; static String[] args;
private static void reader() { private static void reader() {
@ -74,25 +76,21 @@ public class JScriptRepl {
} }
catch (IOException e) { catch (IOException e) {
System.out.println(e.toString()); System.out.println(e.toString());
exited = true; engine.thread().interrupt();
} }
catch (RuntimeException ex) { catch (RuntimeException ex) {
if (!exited) { if (ex instanceof InterruptException) return;
else {
System.out.println("Internal error ocurred:"); System.out.println("Internal error ocurred:");
ex.printStackTrace(); ex.printStackTrace();
} }
} }
if (exited) {
debugTask.interrupt();
engineTask.interrupt();
}
} }
private static void initEnv() { private static void initEnv() {
environment = Internals.apply(environment); environment = Internals.apply(environment);
environment.global.define(false, new NativeFunction("exit", args -> { environment.global.define(false, new NativeFunction("exit", args -> {
exited = true;
throw new InterruptException(); throw new InterruptException();
})); }));
environment.global.define(false, new NativeFunction("go", args -> { environment.global.define(false, new NativeFunction("go", args -> {
@ -105,26 +103,35 @@ 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 -> {
for (var el : args.args) {
Values.printValue(args.ctx, el);
}
return null;
}));
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", STDFilesystem.ofStd(System.in, System.out, System.err));
environment.add(PermissionsProvider.ENV_KEY, PermissionsManager.ALL_PERMS); environment.add(PermissionsProvider.KEY, PermissionsManager.ALL_PERMS);
environment.add(Filesystem.ENV_KEY, fs); environment.add(Filesystem.KEY, fs);
environment.add(ModuleRepo.ENV_KEY, ModuleRepo.ofFilesystem(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() { private static void initEngine() {
// var ctx = new DebugContext(); var ctx = new DebugContext();
// engine.add(DebugContext.ENV_KEY, ctx); environment.add(DebugContext.KEY, ctx);
// debugServer.targets.put("target", (ws, req) -> new SimpleDebugger(ws).attach(ctx)); // debugServer.targets.put("target", (ws, req) -> new SimpleDebugger(ws).attach(ctx));
engineTask = engine.start(); 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())); System.out.println(String.format("Running %s v%s by %s", Metadata.name(), Metadata.version(), Metadata.author()));
JScriptRepl.args = args; JScriptRepl.args = args;
@ -136,5 +143,9 @@ public class JScriptRepl {
reader.setDaemon(true); reader.setDaemon(true);
reader.setName("STD Reader"); reader.setName("STD Reader");
reader.start(); 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; 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 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() { default byte[] readAll() {
var parts = new LinkedList<byte[]>(); var parts = new LinkedList<byte[]>();
var sizes = new LinkedList<Integer>();
var buff = new byte[1024]; var buff = new byte[1024];
var size = 0; var size = 0;
while (true) { while (true) {
var n = read(buff); var n = read(buff);
if (n == 0) break; if (n < 0) break;
else if (n == 0) continue;
parts.add(buff); parts.add(buff);
sizes.add(n);
size += n; size += n;
buff = new byte[1024];
} }
buff = new byte[size]; buff = new byte[size];
var i = 0; var i = 0;
var j = 0;
for (var part : parts) { for (var part : parts) {
System.arraycopy(part, 0, buff, i, part.length); var currSize = sizes.get(j++);
i += part.length;
System.arraycopy(part, 0, buff, i, currSize);
i += currSize;
} }
return buff; return buff;

View File

@ -1,10 +1,10 @@
package me.topchetoeu.jscript.utils.filesystem; package me.topchetoeu.jscript.utils.filesystem;
import me.topchetoeu.jscript.core.Extensions; import me.topchetoeu.jscript.core.Extensions;
import me.topchetoeu.jscript.core.values.Symbol; import me.topchetoeu.jscript.core.Key;
public interface Filesystem { 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 String normalize(String... path) { return Paths.normalize(path); }
default boolean create(String path, EntryType type) { throw new FilesystemException(ErrorReason.UNSUPPORTED).setAction(ActionType.CREATE); } default boolean create(String path, EntryType type) { throw new FilesystemException(ErrorReason.UNSUPPORTED).setAction(ActionType.CREATE); }
@ -13,6 +13,6 @@ public interface Filesystem {
void close(); void close();
public static Filesystem get(Extensions exts) { 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; private int ptr;
@Override protected int onRead(byte[] buff) { @Override protected int onRead(byte[] buff) {
if (ptr >= handle().length()) return -1;
var res = handle().read(ptr, buff); var res = handle().read(ptr, buff);
ptr += res; ptr += res;
return res; return res;

View File

@ -39,7 +39,7 @@ public class NativeWrapperProvider implements WrapperProvider {
throw ((EngineException)e.getTargetException()).add(ctx, name, Location.INTERNAL); throw ((EngineException)e.getTargetException()).add(ctx, name, Location.INTERNAL);
} }
else if (e.getTargetException() instanceof NullPointerException) { else if (e.getTargetException() instanceof NullPointerException) {
e.printStackTrace(); // e.getTargetException().printStackTrace();
throw EngineException.ofType("Unexpected value of 'undefined'.").add(ctx, name, Location.INTERNAL); throw EngineException.ofType("Unexpected value of 'undefined'.").add(ctx, name, Location.INTERNAL);
} }
else if (e.getTargetException() instanceof InterruptException || e.getTargetException() instanceof InterruptedException) { 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; if (props.contains(key) || nonProps.contains(key)) repeat = true;
else { else {
checkSignature(method, true, Environment.class); 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); nonProps.add(key);
} }
@ -195,7 +195,7 @@ public class NativeWrapperProvider implements WrapperProvider {
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(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); nonProps.add(key);
} }
catch (IllegalArgumentException | IllegalAccessException e) { } 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.ArrayList;
import java.util.List; import java.util.List;
@ -6,7 +6,6 @@ import java.util.TreeMap;
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.common.VLQ;
import me.topchetoeu.jscript.common.json.JSON; import me.topchetoeu.jscript.common.json.JSON;
public class SourceMap { 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.ArrayList;
import java.util.List; import java.util.List;

View File

@ -5,13 +5,13 @@ 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.core.Context;
import me.topchetoeu.jscript.core.Extensions; 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.Filesystem;
import me.topchetoeu.jscript.utils.filesystem.Mode; import me.topchetoeu.jscript.utils.filesystem.Mode;
public interface ModuleRepo { public interface ModuleRepo {
public static final Symbol ENV_KEY = Symbol.get("Environment.modules"); public static final Key<ModuleRepo> KEY = new Key<>();
public static final Symbol CWD = Symbol.get("Environment.moduleCwd"); public static final Key<String> CWD = new Key<>();
public Module getModule(Context ctx, String cwd, String name); public Module getModule(Context ctx, String cwd, String name);
@ -39,6 +39,6 @@ public interface ModuleRepo {
return exts.init(CWD, "/"); return exts.init(CWD, "/");
} }
public static ModuleRepo get(Extensions exts) { 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 @Override
protected Object onLoad(Context ctx) { 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); return res.call(ctx);
} }

View File

@ -1,10 +1,10 @@
package me.topchetoeu.jscript.utils.permissions; package me.topchetoeu.jscript.utils.permissions;
import me.topchetoeu.jscript.core.Extensions; import me.topchetoeu.jscript.core.Extensions;
import me.topchetoeu.jscript.core.values.Symbol; import me.topchetoeu.jscript.core.Key;
public interface PermissionsProvider { 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; public static final PermissionsProvider ALL_PERMS = (perm, value) -> true;
boolean hasPermission(Permission perm, String value); boolean hasPermission(Permission perm, String value);
@ -22,7 +22,7 @@ public interface PermissionsProvider {
public static PermissionsProvider get(Extensions exts) { public static PermissionsProvider get(Extensions exts) {
return (perm, value) -> { 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; else return true;
}; };
} }