feat: merge all operation instructions in one
This commit is contained in:
parent
79a93ef971
commit
b8b000ddf0
@ -14,6 +14,7 @@ import me.topchetoeu.jscript.events.Observer;
|
|||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.exceptions.SyntaxException;
|
import me.topchetoeu.jscript.exceptions.SyntaxException;
|
||||||
import me.topchetoeu.jscript.polyfills.PolyfillEngine;
|
import me.topchetoeu.jscript.polyfills.PolyfillEngine;
|
||||||
|
import me.topchetoeu.jscript.polyfills.TypescriptEngine;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
static Thread task;
|
static Thread task;
|
||||||
|
19
src/me/topchetoeu/jscript/compilation/AssignStatement.java
Normal file
19
src/me/topchetoeu/jscript/compilation/AssignStatement.java
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package me.topchetoeu.jscript.compilation;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.Location;
|
||||||
|
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
|
public abstract class AssignStatement extends Statement {
|
||||||
|
public abstract void compile(List<Instruction> target, ScopeRecord scope, boolean retPrevValue);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void compile(List<Instruction> target, ScopeRecord scope) {
|
||||||
|
compile(target, scope, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AssignStatement(Location loc) {
|
||||||
|
super(loc);
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,10 @@
|
|||||||
package me.topchetoeu.jscript.compilation;
|
package me.topchetoeu.jscript.compilation;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.Location;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.Type;
|
import me.topchetoeu.jscript.engine.Operation;
|
||||||
|
|
||||||
public abstract class AssignableStatement extends Statement {
|
public abstract class AssignableStatement extends Statement {
|
||||||
public abstract Statement toAssign(Statement val, Type operation);
|
public abstract AssignStatement toAssign(Statement val, Operation operation);
|
||||||
|
|
||||||
protected AssignableStatement(Location loc) {
|
protected AssignableStatement(Location loc) {
|
||||||
super(loc);
|
super(loc);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package me.topchetoeu.jscript.compilation;
|
package me.topchetoeu.jscript.compilation;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.Location;
|
||||||
|
import me.topchetoeu.jscript.engine.Operation;
|
||||||
import me.topchetoeu.jscript.exceptions.SyntaxException;
|
import me.topchetoeu.jscript.exceptions.SyntaxException;
|
||||||
|
|
||||||
public class Instruction {
|
public class Instruction {
|
||||||
@ -33,55 +34,58 @@ public class Instruction {
|
|||||||
LOAD_REGEX,
|
LOAD_REGEX,
|
||||||
|
|
||||||
DUP,
|
DUP,
|
||||||
|
MOVE,
|
||||||
|
|
||||||
STORE_VAR,
|
STORE_VAR,
|
||||||
STORE_MEMBER,
|
STORE_MEMBER,
|
||||||
DISCARD,
|
DISCARD,
|
||||||
|
|
||||||
MAKE_VAR,
|
MAKE_VAR,
|
||||||
DEF_PROP,
|
DEF_PROP,
|
||||||
KEYS,
|
KEYS,
|
||||||
|
|
||||||
TYPEOF,
|
TYPEOF,
|
||||||
INSTANCEOF(true),
|
OPERATION;
|
||||||
IN(true),
|
// TYPEOF,
|
||||||
|
// INSTANCEOF(true),
|
||||||
|
// IN(true),
|
||||||
|
|
||||||
MULTIPLY(true),
|
// MULTIPLY(true),
|
||||||
DIVIDE(true),
|
// DIVIDE(true),
|
||||||
MODULO(true),
|
// MODULO(true),
|
||||||
ADD(true),
|
// ADD(true),
|
||||||
SUBTRACT(true),
|
// SUBTRACT(true),
|
||||||
|
|
||||||
USHIFT_RIGHT(true),
|
// USHIFT_RIGHT(true),
|
||||||
SHIFT_RIGHT(true),
|
// SHIFT_RIGHT(true),
|
||||||
SHIFT_LEFT(true),
|
// SHIFT_LEFT(true),
|
||||||
|
|
||||||
GREATER(true),
|
// GREATER(true),
|
||||||
LESS(true),
|
// LESS(true),
|
||||||
GREATER_EQUALS(true),
|
// GREATER_EQUALS(true),
|
||||||
LESS_EQUALS(true),
|
// LESS_EQUALS(true),
|
||||||
LOOSE_EQUALS(true),
|
// LOOSE_EQUALS(true),
|
||||||
LOOSE_NOT_EQUALS(true),
|
// LOOSE_NOT_EQUALS(true),
|
||||||
EQUALS(true),
|
// EQUALS(true),
|
||||||
NOT_EQUALS(true),
|
// NOT_EQUALS(true),
|
||||||
|
|
||||||
AND(true),
|
// AND(true),
|
||||||
OR(true),
|
// OR(true),
|
||||||
XOR(true),
|
// XOR(true),
|
||||||
|
|
||||||
NEG(true),
|
// NEG(true),
|
||||||
POS(true),
|
// POS(true),
|
||||||
NOT(true),
|
// NOT(true),
|
||||||
INVERSE(true);
|
// INVERSE(true);
|
||||||
|
|
||||||
final boolean isOperation;
|
// final boolean isOperation;
|
||||||
|
|
||||||
private Type(boolean isOperation) {
|
// private Type(boolean isOperation) {
|
||||||
this.isOperation = isOperation;
|
// this.isOperation = isOperation;
|
||||||
}
|
// }
|
||||||
private Type() {
|
// private Type() {
|
||||||
this(false);
|
// this(false);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
public final Type type;
|
public final Type type;
|
||||||
@ -103,6 +107,11 @@ public class Instruction {
|
|||||||
if (i >= params.length || i < 0) return null;
|
if (i >= params.length || i < 0) return null;
|
||||||
return (T)params[i];
|
return (T)params[i];
|
||||||
}
|
}
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> T get(int i, T defaultVal) {
|
||||||
|
if (i >= params.length || i < 0) return defaultVal;
|
||||||
|
return (T)params[i];
|
||||||
|
}
|
||||||
public boolean match(Object ...args) {
|
public boolean match(Object ...args) {
|
||||||
if (args.length != params.length) return false;
|
if (args.length != params.length) return false;
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
@ -226,11 +235,14 @@ public class Instruction {
|
|||||||
public static Instruction loadArr(int count) {
|
public static Instruction loadArr(int count) {
|
||||||
return new Instruction(null, Type.LOAD_ARR, count);
|
return new Instruction(null, Type.LOAD_ARR, count);
|
||||||
}
|
}
|
||||||
public static Instruction dup(int count) {
|
public static Instruction dup() {
|
||||||
return new Instruction(null, Type.DUP, count, 0);
|
return new Instruction(null, Type.DUP, 0, 1);
|
||||||
}
|
}
|
||||||
public static Instruction dup(int count, int offset) {
|
public static Instruction dup(int count, int offset) {
|
||||||
return new Instruction(null, Type.DUP, count, offset);
|
return new Instruction(null, Type.DUP, offset, count);
|
||||||
|
}
|
||||||
|
public static Instruction move(int count, int offset) {
|
||||||
|
return new Instruction(null, Type.MOVE, offset, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Instruction storeSelfFunc(int i) {
|
public static Instruction storeSelfFunc(int i) {
|
||||||
@ -255,7 +267,7 @@ public class Instruction {
|
|||||||
public static Instruction typeof() {
|
public static Instruction typeof() {
|
||||||
return new Instruction(null, Type.TYPEOF);
|
return new Instruction(null, Type.TYPEOF);
|
||||||
}
|
}
|
||||||
public static Instruction typeof(String varName) {
|
public static Instruction typeof(Object varName) {
|
||||||
return new Instruction(null, Type.TYPEOF, varName);
|
return new Instruction(null, Type.TYPEOF, varName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,9 +279,8 @@ public class Instruction {
|
|||||||
return new Instruction(null, Type.DEF_PROP);
|
return new Instruction(null, Type.DEF_PROP);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Instruction operation(Type op) {
|
public static Instruction operation(Operation op) {
|
||||||
if (!op.isOperation) throw new IllegalArgumentException("The instruction type %s is not an operation.".formatted(op));
|
return new Instruction(null, Type.OPERATION, op);
|
||||||
return new Instruction(null, op);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -5,7 +5,7 @@ import java.util.List;
|
|||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.Location;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.Type;
|
import me.topchetoeu.jscript.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class ForInStatement extends Statement {
|
public class ForInStatement extends Statement {
|
||||||
@ -37,17 +37,18 @@ public class ForInStatement extends Statement {
|
|||||||
target.add(Instruction.keys());
|
target.add(Instruction.keys());
|
||||||
|
|
||||||
int start = target.size();
|
int start = target.size();
|
||||||
target.add(Instruction.dup(1));
|
target.add(Instruction.dup());
|
||||||
target.add(Instruction.loadMember("length"));
|
target.add(Instruction.loadMember("length"));
|
||||||
target.add(Instruction.loadValue(0));
|
target.add(Instruction.loadValue(0));
|
||||||
target.add(Instruction.operation(Type.LESS_EQUALS));
|
target.add(Instruction.operation(Operation.LESS_EQUALS));
|
||||||
int mid = target.size();
|
int mid = target.size();
|
||||||
target.add(Instruction.nop());
|
target.add(Instruction.nop());
|
||||||
|
|
||||||
target.add(Instruction.dup(2));
|
target.add(Instruction.dup());
|
||||||
|
target.add(Instruction.dup());
|
||||||
target.add(Instruction.loadMember("length"));
|
target.add(Instruction.loadMember("length"));
|
||||||
target.add(Instruction.loadValue(1));
|
target.add(Instruction.loadValue(1));
|
||||||
target.add(Instruction.operation(Type.SUBTRACT));
|
target.add(Instruction.operation(Operation.SUBTRACT));
|
||||||
target.add(Instruction.dup(1, 2));
|
target.add(Instruction.dup(1, 2));
|
||||||
target.add(Instruction.loadValue("length"));
|
target.add(Instruction.loadValue("length"));
|
||||||
target.add(Instruction.dup(1, 2));
|
target.add(Instruction.dup(1, 2));
|
||||||
|
@ -7,6 +7,7 @@ import me.topchetoeu.jscript.Location;
|
|||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.Type;
|
import me.topchetoeu.jscript.compilation.Instruction.Type;
|
||||||
|
import me.topchetoeu.jscript.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class SwitchStatement extends Statement {
|
public class SwitchStatement extends Statement {
|
||||||
@ -33,9 +34,9 @@ public class SwitchStatement extends Statement {
|
|||||||
value.compile(target, scope);
|
value.compile(target, scope);
|
||||||
|
|
||||||
for (var ccase : cases) {
|
for (var ccase : cases) {
|
||||||
target.add(Instruction.dup(1).locate(loc()));
|
target.add(Instruction.dup().locate(loc()));
|
||||||
ccase.value.compileWithPollution(target, scope);
|
ccase.value.compileWithPollution(target, scope);
|
||||||
target.add(Instruction.operation(Type.EQUALS).locate(loc()));
|
target.add(Instruction.operation(Operation.EQUALS).locate(loc()));
|
||||||
caseMap.put(target.size(), ccase.statementI);
|
caseMap.put(target.size(), ccase.statementI);
|
||||||
target.add(Instruction.nop());
|
target.add(Instruction.nop());
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ public class ArrayStatement extends Statement {
|
|||||||
var i = 0;
|
var i = 0;
|
||||||
for (var el : statements) {
|
for (var el : statements) {
|
||||||
if (el != null) {
|
if (el != null) {
|
||||||
target.add(Instruction.dup(1).locate(loc()));
|
target.add(Instruction.dup().locate(loc()));
|
||||||
target.add(Instruction.loadValue(i).locate(loc()));
|
target.add(Instruction.loadValue(i).locate(loc()));
|
||||||
el.compileWithPollution(target, scope);
|
el.compileWithPollution(target, scope);
|
||||||
target.add(Instruction.storeMember().locate(loc()));
|
target.add(Instruction.storeMember().locate(loc()));
|
||||||
|
@ -6,7 +6,7 @@ import me.topchetoeu.jscript.Location;
|
|||||||
import me.topchetoeu.jscript.compilation.AssignableStatement;
|
import me.topchetoeu.jscript.compilation.AssignableStatement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.Type;
|
import me.topchetoeu.jscript.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class ChangeStatement extends Statement {
|
public class ChangeStatement extends Statement {
|
||||||
@ -19,11 +19,7 @@ public class ChangeStatement extends Statement {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope) {
|
||||||
value.toAssign(new ConstantStatement(loc(), -addAmount), Type.SUBTRACT).compileWithPollution(target, scope);
|
value.toAssign(new ConstantStatement(loc(), -addAmount), Operation.SUBTRACT).compile(target, scope, postfix);
|
||||||
if (postfix) {
|
|
||||||
target.add(Instruction.loadValue(addAmount).locate(loc()));
|
|
||||||
target.add(Instruction.operation(Type.SUBTRACT).locate(loc()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChangeStatement(Location loc, AssignableStatement value, double addAmount, boolean postfix) {
|
public ChangeStatement(Location loc, AssignableStatement value, double addAmount, boolean postfix) {
|
||||||
|
@ -53,13 +53,11 @@ public class FunctionStatement extends Statement {
|
|||||||
|
|
||||||
target.add(Instruction.nop());
|
target.add(Instruction.nop());
|
||||||
subscope.define("this");
|
subscope.define("this");
|
||||||
|
|
||||||
var argsVar = subscope.define("arguments");
|
var argsVar = subscope.define("arguments");
|
||||||
if (args.length > 0) {
|
|
||||||
target.add(Instruction.loadVar(argsVar).locate(loc()));
|
|
||||||
if (args.length != 1) target.add(Instruction.dup(args.length - 1).locate(loc()));
|
|
||||||
|
|
||||||
|
if (args.length > 0) {
|
||||||
for (var i = 0; i < args.length; i++) {
|
for (var i = 0; i < args.length; i++) {
|
||||||
|
target.add(Instruction.loadVar(argsVar).locate(loc()));
|
||||||
target.add(Instruction.loadMember(i).locate(loc()));
|
target.add(Instruction.loadMember(i).locate(loc()));
|
||||||
target.add(Instruction.storeVar(subscope.define(args[i])).locate(loc()));
|
target.add(Instruction.storeVar(subscope.define(args[i])).locate(loc()));
|
||||||
}
|
}
|
||||||
@ -82,7 +80,7 @@ public class FunctionStatement extends Statement {
|
|||||||
if (name == null) name = this.name;
|
if (name == null) name = this.name;
|
||||||
|
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
target.add(Instruction.dup(1).locate(loc()));
|
target.add(Instruction.dup().locate(loc()));
|
||||||
target.add(Instruction.loadValue("name").locate(loc()));
|
target.add(Instruction.loadValue("name").locate(loc()));
|
||||||
target.add(Instruction.loadValue(name).locate(loc()));
|
target.add(Instruction.loadValue(name).locate(loc()));
|
||||||
target.add(Instruction.storeMember().locate(loc()));
|
target.add(Instruction.storeMember().locate(loc()));
|
||||||
|
@ -3,45 +3,52 @@ package me.topchetoeu.jscript.compilation.values;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.Location;
|
||||||
|
import me.topchetoeu.jscript.compilation.AssignStatement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.Type;
|
import me.topchetoeu.jscript.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class IndexAssignStatement extends Statement {
|
public class IndexAssignStatement extends AssignStatement {
|
||||||
public final Statement object;
|
public final Statement object;
|
||||||
public final Statement index;
|
public final Statement index;
|
||||||
public final Statement value;
|
public final Statement value;
|
||||||
public final Type operation;
|
public final Operation operation;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pollutesStack() { return true; }
|
public boolean pollutesStack() { return true; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean retPrevValue) {
|
||||||
int start = 0;
|
int start = 0;
|
||||||
|
|
||||||
if (operation != null) {
|
if (operation != null) {
|
||||||
object.compileWithPollution(target, scope);
|
object.compileWithPollution(target, scope);
|
||||||
index.compileWithPollution(target, scope);
|
index.compileWithPollution(target, scope);
|
||||||
|
target.add(Instruction.dup(2, 0).locate(loc()));
|
||||||
|
|
||||||
target.add(Instruction.dup(1, 1).locate(loc()));
|
|
||||||
target.add(Instruction.dup(1, 1).locate(loc()));
|
|
||||||
target.add(Instruction.loadMember().locate(loc()));
|
target.add(Instruction.loadMember().locate(loc()));
|
||||||
|
if (retPrevValue) {
|
||||||
|
target.add(Instruction.dup().locate(loc()));
|
||||||
|
target.add(Instruction.move(3, 1).locate(loc()));
|
||||||
|
}
|
||||||
value.compileWithPollution(target, scope);
|
value.compileWithPollution(target, scope);
|
||||||
target.add(Instruction.operation(operation).locate(loc()));
|
target.add(Instruction.operation(operation).locate(loc()));
|
||||||
|
|
||||||
target.add(Instruction.storeMember(true).locate(loc()));
|
target.add(Instruction.storeMember(!retPrevValue).locate(loc()).setDebug(true));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
object.compileWithPollution(target, scope);
|
object.compileWithPollution(target, scope);
|
||||||
|
if (retPrevValue) target.add(Instruction.dup().locate(loc()));
|
||||||
index.compileWithPollution(target, scope);
|
index.compileWithPollution(target, scope);
|
||||||
value.compileWithPollution(target, scope);
|
value.compileWithPollution(target, scope);
|
||||||
target.add(Instruction.storeMember(true).locate(loc()));
|
|
||||||
|
target.add(Instruction.storeMember(!retPrevValue).locate(loc()).setDebug(true));
|
||||||
}
|
}
|
||||||
target.get(start).setDebug(true);
|
target.get(start);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IndexAssignStatement(Location loc, Statement object, Statement index, Statement value, Type operation) {
|
public IndexAssignStatement(Location loc, Statement object, Statement index, Statement value, Operation operation) {
|
||||||
super(loc);
|
super(loc);
|
||||||
this.object = object;
|
this.object = object;
|
||||||
this.index = index;
|
this.index = index;
|
||||||
|
@ -3,10 +3,11 @@ package me.topchetoeu.jscript.compilation.values;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.Location;
|
||||||
|
import me.topchetoeu.jscript.compilation.AssignStatement;
|
||||||
import me.topchetoeu.jscript.compilation.AssignableStatement;
|
import me.topchetoeu.jscript.compilation.AssignableStatement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.Type;
|
import me.topchetoeu.jscript.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class IndexStatement extends AssignableStatement {
|
public class IndexStatement extends AssignableStatement {
|
||||||
@ -19,13 +20,13 @@ public class IndexStatement extends AssignableStatement {
|
|||||||
public boolean pure() { return true; }
|
public boolean pure() { return true; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Statement toAssign(Statement val, Type operation) {
|
public AssignStatement toAssign(Statement val, Operation operation) {
|
||||||
return new IndexAssignStatement(loc(), object, index, val, operation);
|
return new IndexAssignStatement(loc(), object, index, val, operation);
|
||||||
}
|
}
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope, boolean dupObj) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean dupObj) {
|
||||||
int start = 0;
|
int start = 0;
|
||||||
object.compileWithPollution(target, scope);
|
object.compileWithPollution(target, scope);
|
||||||
if (dupObj) target.add(Instruction.dup(1).locate(loc()));
|
if (dupObj) target.add(Instruction.dup().locate(loc()));
|
||||||
if (index instanceof ConstantStatement) {
|
if (index instanceof ConstantStatement) {
|
||||||
target.add(Instruction.loadMember(((ConstantStatement)index).value).locate(loc()));
|
target.add(Instruction.loadMember(((ConstantStatement)index).value).locate(loc()));
|
||||||
return;
|
return;
|
||||||
|
@ -29,7 +29,7 @@ public class LazyAndStatement extends Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
first.compileWithPollution(target, scope);
|
first.compileWithPollution(target, scope);
|
||||||
target.add(Instruction.dup(1).locate(loc()));
|
target.add(Instruction.dup().locate(loc()));
|
||||||
int start = target.size();
|
int start = target.size();
|
||||||
target.add(Instruction.nop());
|
target.add(Instruction.nop());
|
||||||
target.add(Instruction.discard().locate(loc()));
|
target.add(Instruction.discard().locate(loc()));
|
||||||
|
@ -29,7 +29,7 @@ public class LazyOrStatement extends Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
first.compileWithPollution(target, scope);
|
first.compileWithPollution(target, scope);
|
||||||
target.add(Instruction.dup(1).locate(loc()));
|
target.add(Instruction.dup().locate(loc()));
|
||||||
int start = target.size();
|
int start = target.size();
|
||||||
target.add(Instruction.nop());
|
target.add(Instruction.nop());
|
||||||
target.add(Instruction.discard().locate(loc()));
|
target.add(Instruction.discard().locate(loc()));
|
||||||
|
@ -20,9 +20,9 @@ public class ObjectStatement extends Statement {
|
|||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope) {
|
||||||
target.add(Instruction.loadObj().locate(loc()));
|
target.add(Instruction.loadObj().locate(loc()));
|
||||||
if (!map.isEmpty()) target.add(Instruction.dup(map.size()).locate(loc()));
|
|
||||||
|
|
||||||
for (var el : map.entrySet()) {
|
for (var el : map.entrySet()) {
|
||||||
|
target.add(Instruction.dup().locate(loc()));
|
||||||
target.add(Instruction.loadValue(el.getKey()).locate(loc()));
|
target.add(Instruction.loadValue(el.getKey()).locate(loc()));
|
||||||
var val = el.getValue();
|
var val = el.getValue();
|
||||||
if (val instanceof FunctionStatement) ((FunctionStatement)val).compile(target, scope, el.getKey().toString(), false);
|
if (val instanceof FunctionStatement) ((FunctionStatement)val).compile(target, scope, el.getKey().toString(), false);
|
||||||
|
@ -7,13 +7,14 @@ import me.topchetoeu.jscript.compilation.Instruction;
|
|||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.compilation.control.ThrowStatement;
|
import me.topchetoeu.jscript.compilation.control.ThrowStatement;
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.CallContext;
|
||||||
|
import me.topchetoeu.jscript.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
|
|
||||||
public class OperationStatement extends Statement {
|
public class OperationStatement extends Statement {
|
||||||
public final Statement[] args;
|
public final Statement[] args;
|
||||||
public final Instruction.Type operation;
|
public final Operation operation;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope) {
|
||||||
@ -96,7 +97,7 @@ public class OperationStatement extends Statement {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public OperationStatement(Location loc, Instruction.Type operation, Statement... args) {
|
public OperationStatement(Location loc, Operation operation, Statement... args) {
|
||||||
super(loc);
|
super(loc);
|
||||||
this.operation = operation;
|
this.operation = operation;
|
||||||
this.args = args;
|
this.args = args;
|
||||||
|
@ -6,8 +6,7 @@ import me.topchetoeu.jscript.Location;
|
|||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
||||||
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
import me.topchetoeu.jscript.engine.values.Symbol;
|
|
||||||
|
|
||||||
public class TypeofStatement extends Statement {
|
public class TypeofStatement extends Statement {
|
||||||
public final Statement value;
|
public final Statement value;
|
||||||
@ -22,7 +21,7 @@ public class TypeofStatement extends Statement {
|
|||||||
if (value instanceof VariableStatement) {
|
if (value instanceof VariableStatement) {
|
||||||
var i = scope.getKey(((VariableStatement)value).name);
|
var i = scope.getKey(((VariableStatement)value).name);
|
||||||
if (i instanceof String) {
|
if (i instanceof String) {
|
||||||
target.add(Instruction.typeof((String)i));
|
target.add(Instruction.typeof((String)i).locate(loc()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -35,15 +34,14 @@ public class TypeofStatement extends Statement {
|
|||||||
var val = value.optimize();
|
var val = value.optimize();
|
||||||
|
|
||||||
if (val instanceof ConstantStatement) {
|
if (val instanceof ConstantStatement) {
|
||||||
var cnst = (ConstantStatement)val;
|
return new ConstantStatement(loc(), Values.type(((ConstantStatement)val).value));
|
||||||
if (cnst.value == null) return new ConstantStatement(loc(), "undefined");
|
|
||||||
if (cnst.value instanceof Number) return new ConstantStatement(loc(), "number");
|
|
||||||
if (cnst.value instanceof Boolean) return new ConstantStatement(loc(), "boolean");
|
|
||||||
if (cnst.value instanceof String) return new ConstantStatement(loc(), "string");
|
|
||||||
if (cnst.value instanceof Symbol) return new ConstantStatement(loc(), "symbol");
|
|
||||||
if (cnst.value instanceof FunctionValue) return new ConstantStatement(loc(), "function");
|
|
||||||
return new ConstantStatement(loc(), "object");
|
|
||||||
}
|
}
|
||||||
|
else if (
|
||||||
|
val instanceof ObjectStatement ||
|
||||||
|
val instanceof ArrayStatement ||
|
||||||
|
val instanceof GlobalThisStatement
|
||||||
|
) return new ConstantStatement(loc(), "object");
|
||||||
|
else if(val instanceof FunctionStatement) return new ConstantStatement(loc(), "function");
|
||||||
|
|
||||||
return new TypeofStatement(loc(), val);
|
return new TypeofStatement(loc(), val);
|
||||||
}
|
}
|
||||||
|
@ -4,36 +4,39 @@ import java.util.List;
|
|||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.Location;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.compilation.Statement;
|
||||||
|
import me.topchetoeu.jscript.compilation.AssignStatement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.Type;
|
import me.topchetoeu.jscript.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class VariableAssignStatement extends Statement {
|
public class VariableAssignStatement extends AssignStatement {
|
||||||
public final String name;
|
public final String name;
|
||||||
public final Statement value;
|
public final Statement value;
|
||||||
public final Type operation;
|
public final Operation operation;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pollutesStack() { return true; }
|
public boolean pollutesStack() { return true; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void compile(List<Instruction> target, ScopeRecord scope) {
|
public void compile(List<Instruction> target, ScopeRecord scope, boolean retPrevValue) {
|
||||||
var i = scope.getKey(name);
|
var i = scope.getKey(name);
|
||||||
if (operation != null) {
|
if (operation != null) {
|
||||||
target.add(Instruction.loadVar(i).locate(loc()));
|
target.add(Instruction.loadVar(i).locate(loc()));
|
||||||
|
if (retPrevValue) target.add(Instruction.dup().locate(loc()));
|
||||||
if (value instanceof FunctionStatement) ((FunctionStatement)value).compile(target, scope, name, false);
|
if (value instanceof FunctionStatement) ((FunctionStatement)value).compile(target, scope, name, false);
|
||||||
else value.compileWithPollution(target, scope);
|
else value.compileWithPollution(target, scope);
|
||||||
target.add(Instruction.operation(operation).locate(loc()));
|
target.add(Instruction.operation(operation).locate(loc()));
|
||||||
|
target.add(Instruction.storeVar(i, !retPrevValue).locate(loc()));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
if (retPrevValue) target.add(Instruction.loadVar(i).locate(loc()));
|
||||||
if (value instanceof FunctionStatement) ((FunctionStatement)value).compile(target, scope, name, false);
|
if (value instanceof FunctionStatement) ((FunctionStatement)value).compile(target, scope, name, false);
|
||||||
else value.compileWithPollution(target, scope);
|
else value.compileWithPollution(target, scope);
|
||||||
|
target.add(Instruction.storeVar(i, !retPrevValue).locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
target.add(Instruction.storeVar(i, true).locate(loc()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public VariableAssignStatement(Location loc, String name, Statement val, Type operation) {
|
public VariableAssignStatement(Location loc, String name, Statement val, Operation operation) {
|
||||||
super(loc);
|
super(loc);
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.value = val;
|
this.value = val;
|
||||||
|
@ -3,10 +3,11 @@ package me.topchetoeu.jscript.compilation.values;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.Location;
|
||||||
|
import me.topchetoeu.jscript.compilation.AssignStatement;
|
||||||
import me.topchetoeu.jscript.compilation.AssignableStatement;
|
import me.topchetoeu.jscript.compilation.AssignableStatement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.Type;
|
import me.topchetoeu.jscript.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
||||||
|
|
||||||
public class VariableStatement extends AssignableStatement {
|
public class VariableStatement extends AssignableStatement {
|
||||||
@ -18,7 +19,7 @@ public class VariableStatement extends AssignableStatement {
|
|||||||
public boolean pure() { return true; }
|
public boolean pure() { return true; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Statement toAssign(Statement val, Type operation) {
|
public AssignStatement toAssign(Statement val, Operation operation) {
|
||||||
return new VariableAssignStatement(loc(), name, val, operation);
|
return new VariableAssignStatement(loc(), name, val, operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
42
src/me/topchetoeu/jscript/engine/Operation.java
Normal file
42
src/me/topchetoeu/jscript/engine/Operation.java
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package me.topchetoeu.jscript.engine;
|
||||||
|
|
||||||
|
public enum Operation {
|
||||||
|
INSTANCEOF(2, false),
|
||||||
|
IN(2, false),
|
||||||
|
|
||||||
|
MULTIPLY(2, true),
|
||||||
|
DIVIDE(2, true),
|
||||||
|
MODULO(2, true),
|
||||||
|
ADD(2, true),
|
||||||
|
SUBTRACT(2, true),
|
||||||
|
|
||||||
|
USHIFT_RIGHT(2, true),
|
||||||
|
SHIFT_RIGHT(2, true),
|
||||||
|
SHIFT_LEFT(2, true),
|
||||||
|
|
||||||
|
GREATER(2, true),
|
||||||
|
LESS(2, true),
|
||||||
|
GREATER_EQUALS(2, true),
|
||||||
|
LESS_EQUALS(2, true),
|
||||||
|
LOOSE_EQUALS(2, true),
|
||||||
|
LOOSE_NOT_EQUALS(2, true),
|
||||||
|
EQUALS(2, true),
|
||||||
|
NOT_EQUALS(2, true),
|
||||||
|
|
||||||
|
AND(2, true),
|
||||||
|
OR(2, true),
|
||||||
|
XOR(2, true),
|
||||||
|
|
||||||
|
NEG(1, true),
|
||||||
|
POS(1, true),
|
||||||
|
NOT(1, true),
|
||||||
|
INVERSE(1, true);
|
||||||
|
|
||||||
|
public final int operands;
|
||||||
|
public final boolean optimizable;
|
||||||
|
|
||||||
|
private Operation(int n, boolean opt) {
|
||||||
|
this.operands = n;
|
||||||
|
this.optimizable = opt;
|
||||||
|
}
|
||||||
|
}
|
@ -4,8 +4,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.Location;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.Type;
|
|
||||||
import me.topchetoeu.jscript.engine.BreakpointData;
|
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.CallContext;
|
||||||
import me.topchetoeu.jscript.engine.DebugCommand;
|
import me.topchetoeu.jscript.engine.DebugCommand;
|
||||||
import me.topchetoeu.jscript.engine.Engine;
|
import me.topchetoeu.jscript.engine.Engine;
|
||||||
@ -17,6 +15,8 @@ import me.topchetoeu.jscript.engine.values.Values;
|
|||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
|
|
||||||
public class CodeFrame {
|
public class CodeFrame {
|
||||||
|
private record TryCtx(int tryStart, int tryEnd, int catchStart, int catchEnd, int finallyStart, int finallyEnd) { }
|
||||||
|
|
||||||
public static final DataKey<Integer> STACK_N_KEY = new DataKey<>();
|
public static final DataKey<Integer> STACK_N_KEY = new DataKey<>();
|
||||||
public static final DataKey<Integer> MAX_STACK_KEY = new DataKey<>();
|
public static final DataKey<Integer> MAX_STACK_KEY = new DataKey<>();
|
||||||
public static final DataKey<Boolean> STOP_AT_START_KEY = new DataKey<>();
|
public static final DataKey<Boolean> STOP_AT_START_KEY = new DataKey<>();
|
||||||
@ -25,10 +25,11 @@ public class CodeFrame {
|
|||||||
public final LocalScope scope;
|
public final LocalScope scope;
|
||||||
public final Object thisArg;
|
public final Object thisArg;
|
||||||
public final Object[] args;
|
public final Object[] args;
|
||||||
public final List<Object> stack = new ArrayList<>();
|
public final List<TryCtx> tryStack = new ArrayList<>();
|
||||||
public final List<TryContext> tryCtxs = new ArrayList<>();
|
|
||||||
public final CodeFunction function;
|
public final CodeFunction function;
|
||||||
|
|
||||||
|
public Object[] stack = new Object[32];
|
||||||
|
public int stackPtr = 0;
|
||||||
public int codePtr = 0;
|
public int codePtr = 0;
|
||||||
private DebugCommand debugCmd = null;
|
private DebugCommand debugCmd = null;
|
||||||
private Location prevLoc = null;
|
private Location prevLoc = null;
|
||||||
@ -37,41 +38,50 @@ public class CodeFrame {
|
|||||||
return peek(0);
|
return peek(0);
|
||||||
}
|
}
|
||||||
public Object peek(int offset) {
|
public Object peek(int offset) {
|
||||||
if (stack.size() <= offset) return null;
|
if (stackPtr <= offset) return null;
|
||||||
else return stack.get(stack.size() - 1 - offset);
|
else return stack[stackPtr - 1 - offset];
|
||||||
}
|
}
|
||||||
public Object pop() {
|
public Object pop() {
|
||||||
if (stack.size() == 0) return null;
|
if (stackPtr == 0) return null;
|
||||||
else return stack.remove(stack.size() - 1);
|
return stack[--stackPtr];
|
||||||
|
}
|
||||||
|
public Object[] take(int n) {
|
||||||
|
int srcI = stackPtr - n;
|
||||||
|
if (srcI < 0) srcI = 0;
|
||||||
|
|
||||||
|
int dstI = n + srcI - stackPtr;
|
||||||
|
int copyN = stackPtr - srcI;
|
||||||
|
|
||||||
|
Object[] res = new Object[n];
|
||||||
|
System.arraycopy(stack, srcI, res, dstI, copyN);
|
||||||
|
stackPtr -= copyN;
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
public void push(Object val) {
|
public void push(Object val) {
|
||||||
stack.add(stack.size(), Values.normalize(val));
|
if (stack.length <= stackPtr) {
|
||||||
|
var newStack = new Object[stack.length * 2];
|
||||||
|
System.arraycopy(stack, 0, newStack, 0, stack.length);
|
||||||
|
stack = newStack;
|
||||||
|
}
|
||||||
|
stack[stackPtr++] = Values.normalize(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cleanup(CallContext ctx) {
|
public void start(CallContext ctx) {
|
||||||
stack.clear();
|
if (ctx.getData(STACK_N_KEY, 0) >= ctx.addData(MAX_STACK_KEY, 10000)) throw EngineException.ofRange("Stack overflow!");
|
||||||
codePtr = 0;
|
ctx.changeData(STACK_N_KEY);
|
||||||
debugCmd = null;
|
|
||||||
|
var debugState = ctx.getData(Engine.DEBUG_STATE_KEY);
|
||||||
|
if (debugState != null) debugState.pushFrame(this);
|
||||||
|
}
|
||||||
|
public void end(CallContext ctx) {
|
||||||
var debugState = ctx.getData(Engine.DEBUG_STATE_KEY);
|
var debugState = ctx.getData(Engine.DEBUG_STATE_KEY);
|
||||||
|
|
||||||
if (debugState != null) debugState.popFrame();
|
if (debugState != null) debugState.popFrame();
|
||||||
ctx.changeData(STACK_N_KEY, -1);
|
ctx.changeData(STACK_N_KEY, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object next(CallContext ctx) throws InterruptedException {
|
private Object nextNoTry(CallContext ctx) throws InterruptedException {
|
||||||
var debugState = ctx.getData(Engine.DEBUG_STATE_KEY);
|
|
||||||
|
|
||||||
if (debugCmd == null) {
|
|
||||||
if (ctx.getData(STACK_N_KEY, 0) >= ctx.addData(MAX_STACK_KEY, 100000))
|
|
||||||
throw EngineException.ofRange("Stack overflow!");
|
|
||||||
ctx.changeData(STACK_N_KEY);
|
|
||||||
|
|
||||||
if (ctx.getData(STOP_AT_START_KEY, false)) debugCmd = DebugCommand.STEP_OVER;
|
|
||||||
else debugCmd = DebugCommand.NORMAL;
|
|
||||||
|
|
||||||
if (debugState != null) debugState.pushFrame(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Thread.currentThread().isInterrupted()) throw new InterruptedException();
|
if (Thread.currentThread().isInterrupted()) throw new InterruptedException();
|
||||||
if (codePtr < 0 || codePtr >= function.body.length) return null;
|
if (codePtr < 0 || codePtr >= function.body.length) return null;
|
||||||
|
|
||||||
@ -80,20 +90,28 @@ public class CodeFrame {
|
|||||||
var loc = instr.location;
|
var loc = instr.location;
|
||||||
if (loc != null) prevLoc = loc;
|
if (loc != null) prevLoc = loc;
|
||||||
|
|
||||||
if (debugState != null && loc != null) {
|
// var debugState = ctx.getData(Engine.DEBUG_STATE_KEY);
|
||||||
if (
|
// if (debugCmd == null) {
|
||||||
instr.type == Type.NOP && instr.match("debug") || debugState.breakpoints.contains(loc) || (
|
// if (ctx.getData(STOP_AT_START_KEY, false)) debugCmd = DebugCommand.STEP_OVER;
|
||||||
ctx.getData(STEPPING_TROUGH_KEY, false) &&
|
// else debugCmd = DebugCommand.NORMAL;
|
||||||
(debugCmd == DebugCommand.STEP_INTO || debugCmd == DebugCommand.STEP_OVER)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
ctx.setData(STEPPING_TROUGH_KEY, true);
|
|
||||||
|
|
||||||
debugState.breakpointNotifier.next(new BreakpointData(loc, ctx));
|
// if (debugState != null) debugState.pushFrame(this);
|
||||||
debugCmd = debugState.commandNotifier.toAwaitable().await();
|
// }
|
||||||
if (debugCmd == DebugCommand.NORMAL) ctx.setData(STEPPING_TROUGH_KEY, false);
|
|
||||||
}
|
// if (debugState != null && loc != null) {
|
||||||
}
|
// if (
|
||||||
|
// instr.type == Type.NOP && instr.match("debug") || debugState.breakpoints.contains(loc) || (
|
||||||
|
// ctx.getData(STEPPING_TROUGH_KEY, false) &&
|
||||||
|
// (debugCmd == DebugCommand.STEP_INTO || debugCmd == DebugCommand.STEP_OVER)
|
||||||
|
// )
|
||||||
|
// ) {
|
||||||
|
// ctx.setData(STEPPING_TROUGH_KEY, true);
|
||||||
|
|
||||||
|
// debugState.breakpointNotifier.next(new BreakpointData(loc, ctx));
|
||||||
|
// debugCmd = debugState.commandNotifier.toAwaitable().await();
|
||||||
|
// if (debugCmd == DebugCommand.NORMAL) ctx.setData(STEPPING_TROUGH_KEY, false);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return Runners.exec(debugCmd, instr, this, ctx);
|
return Runners.exec(debugCmd, instr, this, ctx);
|
||||||
@ -103,73 +121,21 @@ public class CodeFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Object next(CallContext ctx) throws InterruptedException {
|
||||||
|
return nextNoTry(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
public Object run(CallContext ctx) throws InterruptedException {
|
public Object run(CallContext ctx) throws InterruptedException {
|
||||||
try {
|
try {
|
||||||
|
start(ctx);
|
||||||
while (true) {
|
while (true) {
|
||||||
var res = next(ctx);
|
var res = next(ctx);
|
||||||
if (res != Runners.NO_RETURN) return res;
|
if (res != Runners.NO_RETURN) return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
cleanup(ctx);
|
end(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// var debugState = ctx.getData(Engine.DEBUG_STATE_KEY);
|
|
||||||
// DebugCommand command = ctx.getData(STOP_AT_START_KEY, false) ? DebugCommand.STEP_OVER : DebugCommand.NORMAL;
|
|
||||||
|
|
||||||
// if (ctx.getData(STACK_N_KEY, 0) >= ctx.addData(MAX_STACK_KEY, 200)) throw EngineException.ofRange("Stack overflow!");
|
|
||||||
// ctx.changeData(STACK_N_KEY);
|
|
||||||
|
|
||||||
// if (debugState != null) debugState.pushFrame(this);
|
|
||||||
|
|
||||||
// Location loc = null;
|
|
||||||
|
|
||||||
|
|
||||||
// Location loc = null;
|
|
||||||
|
|
||||||
// try {
|
|
||||||
// while (codePtr >= 0 && codePtr < function.body.length) {
|
|
||||||
// var _loc = function.body[codePtr].location;
|
|
||||||
// if (_loc != null) loc = _loc;
|
|
||||||
|
|
||||||
// if (Thread.currentThread().isInterrupted()) throw new InterruptedException();
|
|
||||||
// var instr = function.body[codePtr];
|
|
||||||
|
|
||||||
// if (debugState != null && loc != null) {
|
|
||||||
// if (
|
|
||||||
// instr.type == Type.NOP && instr.match("debug") ||
|
|
||||||
// (
|
|
||||||
// (command == DebugCommand.STEP_INTO || command == DebugCommand.STEP_OVER) &&
|
|
||||||
// ctx.getData(STEPPING_TROUGH_KEY, false)
|
|
||||||
// ) ||
|
|
||||||
// debugState.breakpoints.contains(loc)
|
|
||||||
// ) {
|
|
||||||
// ctx.setData(STEPPING_TROUGH_KEY, true);
|
|
||||||
|
|
||||||
// debugState.breakpointNotifier.next(new BreakpointData(loc, ctx));
|
|
||||||
// command = debugState.commandNotifier.toAwaitable().await();
|
|
||||||
// if (command == DebugCommand.NORMAL) ctx.setData(STEPPING_TROUGH_KEY, false);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// try {
|
|
||||||
// var res = Runners.exec(command, instr, this, ctx);
|
|
||||||
// if (res != Runners.NO_RETURN) return res;
|
|
||||||
// }
|
|
||||||
// catch (EngineException e) {
|
|
||||||
// throw e.add(function.name, instr.location);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// // catch (StackOverflowError e) {
|
|
||||||
// // e.printStackTrace();
|
|
||||||
// // throw EngineException.ofRange("Stack overflow!").add(function.name, loc);
|
|
||||||
// // }
|
|
||||||
// finally {
|
|
||||||
// ctx.changeData(STACK_N_KEY, -1);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CodeFrame(Object thisArg, Object[] args, CodeFunction func) {
|
public CodeFrame(Object thisArg, Object[] args, CodeFunction func) {
|
||||||
|
@ -5,6 +5,7 @@ import java.util.Collections;
|
|||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.CallContext;
|
||||||
import me.topchetoeu.jscript.engine.DebugCommand;
|
import me.topchetoeu.jscript.engine.DebugCommand;
|
||||||
|
import me.topchetoeu.jscript.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.ValueVariable;
|
import me.topchetoeu.jscript.engine.scope.ValueVariable;
|
||||||
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
||||||
import me.topchetoeu.jscript.engine.values.CodeFunction;
|
import me.topchetoeu.jscript.engine.values.CodeFunction;
|
||||||
@ -38,10 +39,7 @@ public class Runners {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Object execCall(DebugCommand state, Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
public static Object execCall(DebugCommand state, Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
||||||
int n = instr.get(0);
|
var callArgs = frame.take(instr.get(0));
|
||||||
|
|
||||||
var callArgs = new Object[n];
|
|
||||||
for (var i = n - 1; i >= 0; i--) callArgs[i] = frame.pop();
|
|
||||||
var func = frame.pop();
|
var func = frame.pop();
|
||||||
var thisArg = frame.pop();
|
var thisArg = frame.pop();
|
||||||
|
|
||||||
@ -51,10 +49,7 @@ public class Runners {
|
|||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execCallNew(DebugCommand state, Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
public static Object execCallNew(DebugCommand state, Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
||||||
int n = instr.get(0);
|
var callArgs = frame.take(instr.get(0));
|
||||||
|
|
||||||
var callArgs = new Object[n];
|
|
||||||
for (var i = n - 1; i >= 0; i--) callArgs[i] = frame.pop();
|
|
||||||
var funcObj = frame.pop();
|
var funcObj = frame.pop();
|
||||||
|
|
||||||
if (Values.isFunction(funcObj) && Values.function(funcObj).special) {
|
if (Values.isFunction(funcObj) && Values.function(funcObj).special) {
|
||||||
@ -159,7 +154,7 @@ public class Runners {
|
|||||||
exception = null;
|
exception = null;
|
||||||
try {
|
try {
|
||||||
ctx.setData(CodeFrame.STOP_AT_START_KEY, state != DebugCommand.NORMAL);
|
ctx.setData(CodeFrame.STOP_AT_START_KEY, state != DebugCommand.NORMAL);
|
||||||
var _res = Values.call(ctx, catchFunc, frame.thisArg, exc);
|
var _res = Values.call(ctx, catchFunc, frame.thisArg, exc.value);
|
||||||
if (!SignalValue.isSignal(_res, "no_return")) res = _res;
|
if (!SignalValue.isSignal(_res, "no_return")) res = _res;
|
||||||
}
|
}
|
||||||
catch (EngineException e) {
|
catch (EngineException e) {
|
||||||
@ -194,10 +189,24 @@ public class Runners {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Object execDup(Instruction instr, CodeFrame frame, CallContext ctx) {
|
public static Object execDup(Instruction instr, CodeFrame frame, CallContext ctx) {
|
||||||
var val = frame.peek(instr.get(1));
|
int offset = instr.get(0), count = instr.get(1);
|
||||||
for (int i = 0; i < (int)instr.get(0); i++) {
|
|
||||||
frame.push(val);
|
for (var i = 0; i < count; i++) {
|
||||||
|
frame.push(frame.peek(offset + count - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frame.codePtr++;
|
||||||
|
return NO_RETURN;
|
||||||
|
}
|
||||||
|
public static Object execMove(Instruction instr, CodeFrame frame, CallContext ctx) {
|
||||||
|
int offset = instr.get(0), count = instr.get(1);
|
||||||
|
|
||||||
|
var tmp = frame.take(offset);
|
||||||
|
var res = frame.take(count);
|
||||||
|
|
||||||
|
for (var i = 0; i < offset; i++) frame.push(tmp[i]);
|
||||||
|
for (var i = 0; i < count; i++) frame.push(res[i]);
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
@ -376,157 +385,13 @@ public class Runners {
|
|||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object execAdd(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
public static Object execOperation(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
||||||
Object b = frame.pop(), a = frame.pop();
|
Operation op = instr.get(0);
|
||||||
frame.push(Values.add(ctx, a, b));
|
var args = new Object[op.operands];
|
||||||
frame.codePtr++;
|
|
||||||
return NO_RETURN;
|
|
||||||
}
|
|
||||||
public static Object execSubtract(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
|
||||||
Object b = frame.pop(), a = frame.pop();
|
|
||||||
frame.push(Values.subtract(ctx, a, b));
|
|
||||||
frame.codePtr++;
|
|
||||||
return NO_RETURN;
|
|
||||||
}
|
|
||||||
public static Object execMultiply(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
|
||||||
Object b = frame.pop(), a = frame.pop();
|
|
||||||
frame.push(Values.multiply(ctx, a, b));
|
|
||||||
frame.codePtr++;
|
|
||||||
return NO_RETURN;
|
|
||||||
}
|
|
||||||
public static Object execDivide(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
|
||||||
Object b = frame.pop(), a = frame.pop();
|
|
||||||
frame.push(Values.divide(ctx, a, b));
|
|
||||||
frame.codePtr++;
|
|
||||||
return NO_RETURN;
|
|
||||||
}
|
|
||||||
public static Object execModulo(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
|
||||||
Object b = frame.pop(), a = frame.pop();
|
|
||||||
frame.push(Values.modulo(ctx, a, b));
|
|
||||||
frame.codePtr++;
|
|
||||||
return NO_RETURN;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Object execAnd(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
for (var i = op.operands - 1; i >= 0; i--) args[i] = frame.pop();
|
||||||
Object b = frame.pop(), a = frame.pop();
|
|
||||||
|
|
||||||
frame.push(Values.and(ctx, a, b));
|
frame.push(Values.operation(ctx, op, args));
|
||||||
frame.codePtr++;
|
|
||||||
return NO_RETURN;
|
|
||||||
}
|
|
||||||
public static Object execOr(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
|
||||||
Object b = frame.pop(), a = frame.pop();
|
|
||||||
|
|
||||||
frame.push(Values.or(ctx, a, b));
|
|
||||||
frame.codePtr++;
|
|
||||||
return NO_RETURN;
|
|
||||||
}
|
|
||||||
public static Object execXor(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
|
||||||
Object b = frame.pop(), a = frame.pop();
|
|
||||||
|
|
||||||
frame.push(Values.xor(ctx, a, b));
|
|
||||||
frame.codePtr++;
|
|
||||||
return NO_RETURN;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Object execLeftShift(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
|
||||||
Object b = frame.pop(), a = frame.pop();
|
|
||||||
|
|
||||||
frame.push(Values.shiftLeft(ctx, a, b));
|
|
||||||
frame.codePtr++;
|
|
||||||
return NO_RETURN;
|
|
||||||
}
|
|
||||||
public static Object execRightShift(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
|
||||||
Object b = frame.pop(), a = frame.pop();
|
|
||||||
|
|
||||||
frame.push(Values.shiftRight(ctx, a, b));
|
|
||||||
frame.codePtr++;
|
|
||||||
return NO_RETURN;
|
|
||||||
}
|
|
||||||
public static Object execUnsignedRightShift(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
|
||||||
Object b = frame.pop(), a = frame.pop();
|
|
||||||
|
|
||||||
frame.push(Values.unsignedShiftRight(ctx, a, b));
|
|
||||||
frame.codePtr++;
|
|
||||||
return NO_RETURN;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Object execNot(Instruction instr, CodeFrame frame, CallContext ctx) {
|
|
||||||
frame.push(Values.not(frame.pop()));
|
|
||||||
frame.codePtr++;
|
|
||||||
return NO_RETURN;
|
|
||||||
}
|
|
||||||
public static Object execNeg(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
|
||||||
frame.push(Values.negative(ctx, frame.pop()));
|
|
||||||
frame.codePtr++;
|
|
||||||
return NO_RETURN;
|
|
||||||
}
|
|
||||||
public static Object execPos(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
|
||||||
frame.push(Values.toNumber(ctx, frame.pop()));
|
|
||||||
frame.codePtr++;
|
|
||||||
return NO_RETURN;
|
|
||||||
}
|
|
||||||
public static Object execInverse(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
|
||||||
frame.push(Values.bitwiseNot(ctx, frame.pop()));
|
|
||||||
frame.codePtr++;
|
|
||||||
return NO_RETURN;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Object execGreaterThan(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
|
||||||
Object b = frame.pop(), a = frame.pop();
|
|
||||||
|
|
||||||
frame.push(Values.compare(ctx, a, b) > 0);
|
|
||||||
frame.codePtr++;
|
|
||||||
return NO_RETURN;
|
|
||||||
}
|
|
||||||
public static Object execLessThan(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
|
||||||
Object b = frame.pop(), a = frame.pop();
|
|
||||||
|
|
||||||
frame.push(Values.compare(ctx, a, b) < 0);
|
|
||||||
frame.codePtr++;
|
|
||||||
return NO_RETURN;
|
|
||||||
}
|
|
||||||
public static Object execGreaterThanEquals(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
|
||||||
Object b = frame.pop(), a = frame.pop();
|
|
||||||
|
|
||||||
frame.push(Values.compare(ctx, a, b) >= 0);
|
|
||||||
frame.codePtr++;
|
|
||||||
return NO_RETURN;
|
|
||||||
}
|
|
||||||
public static Object execLessThanEquals(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
|
||||||
Object b = frame.pop(), a = frame.pop();
|
|
||||||
|
|
||||||
frame.push(Values.compare(ctx, a, b) <= 0);
|
|
||||||
frame.codePtr++;
|
|
||||||
return NO_RETURN;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Object execLooseEquals(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
|
||||||
Object b = frame.pop(), a = frame.pop();
|
|
||||||
|
|
||||||
frame.push(Values.looseEqual(ctx, a, b));
|
|
||||||
frame.codePtr++;
|
|
||||||
return NO_RETURN;
|
|
||||||
}
|
|
||||||
public static Object execLooseNotEquals(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
|
||||||
Object b = frame.pop(), a = frame.pop();
|
|
||||||
|
|
||||||
frame.push(!Values.looseEqual(ctx, a, b));
|
|
||||||
frame.codePtr++;
|
|
||||||
return NO_RETURN;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Object execEquals(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
|
||||||
Object b = frame.pop(), a = frame.pop();
|
|
||||||
|
|
||||||
frame.push(Values.strictEquals(a, b));
|
|
||||||
frame.codePtr++;
|
|
||||||
return NO_RETURN;
|
|
||||||
}
|
|
||||||
public static Object execNotEquals(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
|
||||||
Object b = frame.pop(), a = frame.pop();
|
|
||||||
|
|
||||||
frame.push(!Values.strictEquals(a, b));
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
@ -544,6 +409,7 @@ public class Runners {
|
|||||||
case TRY: return execTry(state, instr, frame, ctx);
|
case TRY: return execTry(state, instr, frame, ctx);
|
||||||
|
|
||||||
case DUP: return execDup(instr, frame, ctx);
|
case DUP: return execDup(instr, frame, ctx);
|
||||||
|
case MOVE: return execMove(instr, frame, ctx);
|
||||||
case LOAD_VALUE: return execLoadValue(instr, frame, ctx);
|
case LOAD_VALUE: return execLoadValue(instr, frame, ctx);
|
||||||
case LOAD_VAR: return execLoadVar(instr, frame, ctx);
|
case LOAD_VAR: return execLoadVar(instr, frame, ctx);
|
||||||
case LOAD_OBJ: return execLoadObj(instr, frame, ctx);
|
case LOAD_OBJ: return execLoadObj(instr, frame, ctx);
|
||||||
@ -560,45 +426,16 @@ public class Runners {
|
|||||||
case STORE_SELF_FUNC: return execStoreSelfFunc(instr, frame, ctx);
|
case STORE_SELF_FUNC: return execStoreSelfFunc(instr, frame, ctx);
|
||||||
case MAKE_VAR: return execMakeVar(instr, frame, ctx);
|
case MAKE_VAR: return execMakeVar(instr, frame, ctx);
|
||||||
|
|
||||||
case IN: return execIn(instr, frame, ctx);
|
|
||||||
case KEYS: return execKeys(instr, frame, ctx);
|
case KEYS: return execKeys(instr, frame, ctx);
|
||||||
case DEF_PROP: return execDefProp(instr, frame, ctx);
|
case DEF_PROP: return execDefProp(instr, frame, ctx);
|
||||||
case TYPEOF: return execTypeof(instr, frame, ctx);
|
case TYPEOF: return execTypeof(instr, frame, ctx);
|
||||||
case DELETE: return execDelete(instr, frame, ctx);
|
case DELETE: return execDelete(instr, frame, ctx);
|
||||||
case INSTANCEOF: return execInstanceof(instr, frame, ctx);
|
|
||||||
|
|
||||||
case JMP: return execJmp(instr, frame, ctx);
|
case JMP: return execJmp(instr, frame, ctx);
|
||||||
case JMP_IF: return execJmpIf(instr, frame, ctx);
|
case JMP_IF: return execJmpIf(instr, frame, ctx);
|
||||||
case JMP_IFN: return execJmpIfNot(instr, frame, ctx);
|
case JMP_IFN: return execJmpIfNot(instr, frame, ctx);
|
||||||
|
|
||||||
case ADD: return execAdd(instr, frame, ctx);
|
case OPERATION: return execOperation(instr, frame, ctx);
|
||||||
case SUBTRACT: return execSubtract(instr, frame, ctx);
|
|
||||||
case MULTIPLY: return execMultiply(instr, frame, ctx);
|
|
||||||
case DIVIDE: return execDivide(instr, frame, ctx);
|
|
||||||
case MODULO: return execModulo(instr, frame, ctx);
|
|
||||||
|
|
||||||
case AND: return execAnd(instr, frame, ctx);
|
|
||||||
case OR: return execOr(instr, frame, ctx);
|
|
||||||
case XOR: return execXor(instr, frame, ctx);
|
|
||||||
|
|
||||||
case SHIFT_LEFT: return execLeftShift(instr, frame, ctx);
|
|
||||||
case SHIFT_RIGHT: return execRightShift(instr, frame, ctx);
|
|
||||||
case USHIFT_RIGHT: return execUnsignedRightShift(instr, frame, ctx);
|
|
||||||
|
|
||||||
case NOT: return execNot(instr, frame, ctx);
|
|
||||||
case NEG: return execNeg(instr, frame, ctx);
|
|
||||||
case POS: return execPos(instr, frame, ctx);
|
|
||||||
case INVERSE: return execInverse(instr, frame, ctx);
|
|
||||||
|
|
||||||
case GREATER: return execGreaterThan(instr, frame, ctx);
|
|
||||||
case GREATER_EQUALS: return execGreaterThanEquals(instr, frame, ctx);
|
|
||||||
case LESS: return execLessThan(instr, frame, ctx);
|
|
||||||
case LESS_EQUALS: return execLessThanEquals(instr, frame, ctx);
|
|
||||||
|
|
||||||
case LOOSE_EQUALS: return execLooseEquals(instr, frame, ctx);
|
|
||||||
case LOOSE_NOT_EQUALS: return execLooseNotEquals(instr, frame, ctx);
|
|
||||||
case EQUALS: return execEquals(instr, frame, ctx);
|
|
||||||
case NOT_EQUALS: return execNotEquals(instr, frame, ctx);
|
|
||||||
|
|
||||||
default: throw EngineException.ofSyntax("Invalid instruction " + instr.type.name() + ".");
|
default: throw EngineException.ofSyntax("Invalid instruction " + instr.type.name() + ".");
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.CallContext;
|
||||||
|
import me.topchetoeu.jscript.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.frame.ConvertHint;
|
import me.topchetoeu.jscript.engine.frame.ConvertHint;
|
||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
|
|
||||||
@ -218,6 +219,47 @@ public class Values {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Object operation(CallContext ctx, Operation op, Object... args) throws InterruptedException {
|
||||||
|
switch (op) {
|
||||||
|
case ADD: return add(ctx, args[0], args[1]);
|
||||||
|
case SUBTRACT: return subtract(ctx, args[0], args[1]);
|
||||||
|
case DIVIDE: return divide(ctx, args[0], args[1]);
|
||||||
|
case MULTIPLY: return multiply(ctx, args[0], args[1]);
|
||||||
|
case MODULO: return modulo(ctx, args[0], args[1]);
|
||||||
|
|
||||||
|
case AND: return and(ctx, args[0], args[1]);
|
||||||
|
case OR: return or(ctx, args[0], args[1]);
|
||||||
|
case XOR: return xor(ctx, args[0], args[1]);
|
||||||
|
|
||||||
|
case EQUALS: return strictEquals(args[0], args[1]);
|
||||||
|
case NOT_EQUALS: return !strictEquals(args[0], args[1]);
|
||||||
|
case LOOSE_EQUALS: return looseEqual(ctx, args[0], args[1]);
|
||||||
|
case LOOSE_NOT_EQUALS: return !looseEqual(ctx, args[0], args[1]);
|
||||||
|
|
||||||
|
case GREATER: return compare(ctx, args[0], args[1]) > 0;
|
||||||
|
case GREATER_EQUALS: return compare(ctx, args[0], args[1]) >= 0;
|
||||||
|
case LESS: return compare(ctx, args[0], args[1]) < 0;
|
||||||
|
case LESS_EQUALS: return compare(ctx, args[0], args[1]) <= 0;
|
||||||
|
|
||||||
|
case INVERSE: return bitwiseNot(ctx, args[0]);
|
||||||
|
case NOT: return not(args[0]);
|
||||||
|
case POS: return toNumber(ctx, args[0]);
|
||||||
|
case NEG: return negative(ctx, args[0]);
|
||||||
|
|
||||||
|
case SHIFT_LEFT: return shiftLeft(ctx, args[0], args[1]);
|
||||||
|
case SHIFT_RIGHT: return shiftRight(ctx, args[0], args[1]);
|
||||||
|
case USHIFT_RIGHT: return unsignedShiftRight(ctx, args[0], args[1]);
|
||||||
|
|
||||||
|
case IN: return hasMember(ctx, args[1], args[0], false);
|
||||||
|
case INSTANCEOF: {
|
||||||
|
var proto = getMember(ctx, args[1], "prototype");
|
||||||
|
return isInstanceOf(ctx, args[0], proto);
|
||||||
|
}
|
||||||
|
|
||||||
|
default: return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static Object getMember(CallContext ctx, Object obj, Object key) throws InterruptedException {
|
public static Object getMember(CallContext ctx, Object obj, Object key) throws InterruptedException {
|
||||||
obj = normalize(obj); key = normalize(key);
|
obj = normalize(obj); key = normalize(key);
|
||||||
if (obj == null) throw new IllegalArgumentException("Tried to access member of undefined.");
|
if (obj == null) throw new IllegalArgumentException("Tried to access member of undefined.");
|
||||||
|
@ -3,29 +3,28 @@ package me.topchetoeu.jscript.parsing;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.engine.Operation;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.Type;
|
|
||||||
|
|
||||||
public enum Operator {
|
public enum Operator {
|
||||||
MULTIPLY("*", Type.MULTIPLY, 13),
|
MULTIPLY("*", Operation.MULTIPLY, 13),
|
||||||
DIVIDE("/", Type.DIVIDE, 12),
|
DIVIDE("/", Operation.DIVIDE, 12),
|
||||||
MODULO("%", Type.MODULO, 12),
|
MODULO("%", Operation.MODULO, 12),
|
||||||
SUBTRACT("-", Type.SUBTRACT, 11),
|
SUBTRACT("-", Operation.SUBTRACT, 11),
|
||||||
ADD("+", Type.ADD, 11),
|
ADD("+", Operation.ADD, 11),
|
||||||
SHIFT_RIGHT(">>", Type.SHIFT_RIGHT, 10),
|
SHIFT_RIGHT(">>", Operation.SHIFT_RIGHT, 10),
|
||||||
SHIFT_LEFT("<<", Type.SHIFT_LEFT, 10),
|
SHIFT_LEFT("<<", Operation.SHIFT_LEFT, 10),
|
||||||
USHIFT_RIGHT(">>>", Type.USHIFT_RIGHT, 10),
|
USHIFT_RIGHT(">>>", Operation.USHIFT_RIGHT, 10),
|
||||||
GREATER(">", Type.GREATER, 9),
|
GREATER(">", Operation.GREATER, 9),
|
||||||
LESS("<", Type.LESS, 9),
|
LESS("<", Operation.LESS, 9),
|
||||||
GREATER_EQUALS(">=", Type.GREATER_EQUALS, 9),
|
GREATER_EQUALS(">=", Operation.GREATER_EQUALS, 9),
|
||||||
LESS_EQUALS("<=", Type.LESS_EQUALS, 9),
|
LESS_EQUALS("<=", Operation.LESS_EQUALS, 9),
|
||||||
NOT_EQUALS("!=", Type.LOOSE_NOT_EQUALS, 8),
|
NOT_EQUALS("!=", Operation.LOOSE_NOT_EQUALS, 8),
|
||||||
LOOSE_NOT_EQUALS("!==", Type.NOT_EQUALS, 8),
|
LOOSE_NOT_EQUALS("!==", Operation.NOT_EQUALS, 8),
|
||||||
EQUALS("==", Type.LOOSE_EQUALS, 8),
|
EQUALS("==", Operation.LOOSE_EQUALS, 8),
|
||||||
LOOSE_EQUALS("===", Type.EQUALS, 8),
|
LOOSE_EQUALS("===", Operation.EQUALS, 8),
|
||||||
AND("&", Type.AND, 7),
|
AND("&", Operation.AND, 7),
|
||||||
XOR("^", Type.XOR, 6),
|
XOR("^", Operation.XOR, 6),
|
||||||
OR("|", Type.OR, 5),
|
OR("|", Operation.OR, 5),
|
||||||
LAZY_AND("&&", 4),
|
LAZY_AND("&&", 4),
|
||||||
LAZY_OR("||", 3),
|
LAZY_OR("||", 3),
|
||||||
ASSIGN_SHIFT_LEFT("<<=", 2, true),
|
ASSIGN_SHIFT_LEFT("<<=", 2, true),
|
||||||
@ -57,7 +56,7 @@ public enum Operator {
|
|||||||
DECREASE("--");
|
DECREASE("--");
|
||||||
|
|
||||||
public final String value;
|
public final String value;
|
||||||
public final Instruction.Type operation;
|
public final Operation operation;
|
||||||
public final int precedence;
|
public final int precedence;
|
||||||
public final boolean reverse;
|
public final boolean reverse;
|
||||||
private static final Map<String, Operator> ops = new HashMap<>();
|
private static final Map<String, Operator> ops = new HashMap<>();
|
||||||
@ -99,13 +98,13 @@ public enum Operator {
|
|||||||
this.reverse = reverse;
|
this.reverse = reverse;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Operator(String value, Instruction.Type funcName, int precedence) {
|
private Operator(String value, Operation funcName, int precedence) {
|
||||||
this. value = value;
|
this. value = value;
|
||||||
this.operation = funcName;
|
this.operation = funcName;
|
||||||
this.precedence = precedence;
|
this.precedence = precedence;
|
||||||
this.reverse = false;
|
this.reverse = false;
|
||||||
}
|
}
|
||||||
private Operator(String value, Instruction.Type funcName, int precedence, boolean reverse) {
|
private Operator(String value, Operation funcName, int precedence, boolean reverse) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.operation = funcName;
|
this.operation = funcName;
|
||||||
this.precedence = precedence;
|
this.precedence = precedence;
|
||||||
|
@ -13,6 +13,7 @@ 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.values.*;
|
import me.topchetoeu.jscript.compilation.values.*;
|
||||||
|
import me.topchetoeu.jscript.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.GlobalScope;
|
import me.topchetoeu.jscript.engine.scope.GlobalScope;
|
||||||
import me.topchetoeu.jscript.engine.scope.ValueVariable;
|
import me.topchetoeu.jscript.engine.scope.ValueVariable;
|
||||||
import me.topchetoeu.jscript.engine.values.CodeFunction;
|
import me.topchetoeu.jscript.engine.values.CodeFunction;
|
||||||
@ -938,12 +939,12 @@ public class Parsing {
|
|||||||
if (!opState.isSuccess()) return ParseRes.failed();
|
if (!opState.isSuccess()) return ParseRes.failed();
|
||||||
var op = opState.result;
|
var op = opState.result;
|
||||||
|
|
||||||
Type operation = null;
|
Operation operation = null;
|
||||||
|
|
||||||
if (op == Operator.ADD) operation = Type.POS;
|
if (op == Operator.ADD) operation = Operation.POS;
|
||||||
else if (op == Operator.SUBTRACT) operation = Type.NEG;
|
else if (op == Operator.SUBTRACT) operation = Operation.NEG;
|
||||||
else if (op == Operator.INVERSE) operation = Type.INVERSE;
|
else if (op == Operator.INVERSE) operation = Operation.INVERSE;
|
||||||
else if (op == Operator.NOT) operation = Type.NOT;
|
else if (op == Operator.NOT) operation = Operation.NOT;
|
||||||
else return ParseRes.failed();
|
else return ParseRes.failed();
|
||||||
|
|
||||||
var res = parseValue(filename, tokens, n + i, 14);
|
var res = parseValue(filename, tokens, n + i, 14);
|
||||||
@ -1103,19 +1104,19 @@ public class Parsing {
|
|||||||
if (!res.isSuccess()) return ParseRes.error(loc, "Expected value after assignment operator '%s'.".formatted(op.value), res);
|
if (!res.isSuccess()) return ParseRes.error(loc, "Expected value after assignment operator '%s'.".formatted(op.value), res);
|
||||||
n += res.n;
|
n += res.n;
|
||||||
|
|
||||||
Type operation = null;
|
Operation operation = null;
|
||||||
|
|
||||||
if (op == Operator.ASSIGN_ADD) operation = Type.ADD;
|
if (op == Operator.ASSIGN_ADD) operation = Operation.ADD;
|
||||||
if (op == Operator.ASSIGN_SUBTRACT) operation = Type.SUBTRACT;
|
if (op == Operator.ASSIGN_SUBTRACT) operation = Operation.SUBTRACT;
|
||||||
if (op == Operator.ASSIGN_MULTIPLY) operation = Type.MULTIPLY;
|
if (op == Operator.ASSIGN_MULTIPLY) operation = Operation.MULTIPLY;
|
||||||
if (op == Operator.ASSIGN_DIVIDE) operation = Type.DIVIDE;
|
if (op == Operator.ASSIGN_DIVIDE) operation = Operation.DIVIDE;
|
||||||
if (op == Operator.ASSIGN_MODULO) operation = Type.MODULO;
|
if (op == Operator.ASSIGN_MODULO) operation = Operation.MODULO;
|
||||||
if (op == Operator.ASSIGN_OR) operation = Type.OR;
|
if (op == Operator.ASSIGN_OR) operation = Operation.OR;
|
||||||
if (op == Operator.ASSIGN_XOR) operation = Type.XOR;
|
if (op == Operator.ASSIGN_XOR) operation = Operation.XOR;
|
||||||
if (op == Operator.ASSIGN_AND) operation = Type.AND;
|
if (op == Operator.ASSIGN_AND) operation = Operation.AND;
|
||||||
if (op == Operator.ASSIGN_SHIFT_LEFT) operation = Type.SHIFT_LEFT;
|
if (op == Operator.ASSIGN_SHIFT_LEFT) operation = Operation.SHIFT_LEFT;
|
||||||
if (op == Operator.ASSIGN_SHIFT_RIGHT) operation = Type.SHIFT_RIGHT;
|
if (op == Operator.ASSIGN_SHIFT_RIGHT) operation = Operation.SHIFT_RIGHT;
|
||||||
if (op == Operator.ASSIGN_USHIFT_RIGHT) operation = Type.USHIFT_RIGHT;
|
if (op == Operator.ASSIGN_USHIFT_RIGHT) operation = Operation.USHIFT_RIGHT;
|
||||||
|
|
||||||
return ParseRes.res(((AssignableStatement)prev).toAssign(res.result, operation), n);
|
return ParseRes.res(((AssignableStatement)prev).toAssign(res.result, operation), n);
|
||||||
}
|
}
|
||||||
@ -1180,7 +1181,7 @@ public class Parsing {
|
|||||||
if (!valRes.isSuccess()) return ParseRes.error(loc, "Expected a value after 'instanceof'.", valRes);
|
if (!valRes.isSuccess()) return ParseRes.error(loc, "Expected a value after 'instanceof'.", valRes);
|
||||||
n += valRes.n;
|
n += valRes.n;
|
||||||
|
|
||||||
return ParseRes.res(new OperationStatement(loc, Type.INSTANCEOF, prev, valRes.result), n);
|
return ParseRes.res(new OperationStatement(loc, Operation.INSTANCEOF, prev, valRes.result), n);
|
||||||
}
|
}
|
||||||
public static ParseRes<OperationStatement> parseIn(String filename, List<Token> tokens, int i, Statement prev, int precedence) {
|
public static ParseRes<OperationStatement> parseIn(String filename, List<Token> tokens, int i, Statement prev, int precedence) {
|
||||||
var loc = getLoc(filename, tokens, i);
|
var loc = getLoc(filename, tokens, i);
|
||||||
@ -1193,7 +1194,7 @@ public class Parsing {
|
|||||||
if (!valRes.isSuccess()) return ParseRes.error(loc, "Expected a value after 'in'.", valRes);
|
if (!valRes.isSuccess()) return ParseRes.error(loc, "Expected a value after 'in'.", valRes);
|
||||||
n += valRes.n;
|
n += valRes.n;
|
||||||
|
|
||||||
return ParseRes.res(new OperationStatement(loc, Type.IN, prev, valRes.result), n);
|
return ParseRes.res(new OperationStatement(loc, Operation.IN, prev, valRes.result), n);
|
||||||
}
|
}
|
||||||
public static ParseRes<CommaStatement> parseComma(String filename, List<Token> tokens, int i, Statement prev, int precedence) {
|
public static ParseRes<CommaStatement> parseComma(String filename, List<Token> tokens, int i, Statement prev, int precedence) {
|
||||||
var loc = getLoc(filename, tokens, i);
|
var loc = getLoc(filename, tokens, i);
|
||||||
|
@ -28,6 +28,8 @@ public class AsyncFunction extends FunctionValue {
|
|||||||
public Object fulfill(CallContext ctx, Object thisArg, Object[] args) throws InterruptedException {
|
public Object fulfill(CallContext ctx, Object thisArg, Object[] args) throws InterruptedException {
|
||||||
if (args.length == 1) frame.push(args[0]);
|
if (args.length == 1) frame.push(args[0]);
|
||||||
|
|
||||||
|
frame.start(ctx);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
awaiting = false;
|
awaiting = false;
|
||||||
awaited = null;
|
awaited = null;
|
||||||
@ -36,12 +38,12 @@ public class AsyncFunction extends FunctionValue {
|
|||||||
var res = frame.next(ctx);
|
var res = frame.next(ctx);
|
||||||
if (res != Runners.NO_RETURN) {
|
if (res != Runners.NO_RETURN) {
|
||||||
promise.fulfill(ctx, res);
|
promise.fulfill(ctx, res);
|
||||||
return null;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (EngineException e) {
|
catch (EngineException e) {
|
||||||
promise.reject(e);
|
promise.reject(e);
|
||||||
return null;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!awaiting) continue;
|
if (!awaiting) continue;
|
||||||
@ -54,15 +56,18 @@ public class AsyncFunction extends FunctionValue {
|
|||||||
var res = Values.getMember(ctx, awaited, "then");
|
var res = Values.getMember(ctx, awaited, "then");
|
||||||
if (res instanceof FunctionValue) {
|
if (res instanceof FunctionValue) {
|
||||||
Values.function(res).call(ctx, awaited, fulfillFunc, rejectFunc);
|
Values.function(res).call(ctx, awaited, fulfillFunc, rejectFunc);
|
||||||
return null;
|
break;
|
||||||
}
|
}
|
||||||
else frame.push(awaited);
|
else frame.push(awaited);
|
||||||
}
|
}
|
||||||
catch (EngineException e) {
|
catch (EngineException e) {
|
||||||
promise.reject(e);
|
promise.reject(e);
|
||||||
return null;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frame.end(ctx);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object await(CallContext ctx, Object thisArg, Object[] args) {
|
public Object await(CallContext ctx, Object thisArg, Object[] args) {
|
||||||
|
Loading…
Reference in New Issue
Block a user