feat: merge all operation instructions in one

This commit is contained in:
TopchetoEU 2023-08-25 11:08:57 +03:00
parent 79a93ef971
commit b8b000ddf0
No known key found for this signature in database
GPG Key ID: 24E57B2E9C61AD19
25 changed files with 365 additions and 435 deletions

View File

@ -14,6 +14,7 @@ import me.topchetoeu.jscript.events.Observer;
import me.topchetoeu.jscript.exceptions.EngineException;
import me.topchetoeu.jscript.exceptions.SyntaxException;
import me.topchetoeu.jscript.polyfills.PolyfillEngine;
import me.topchetoeu.jscript.polyfills.TypescriptEngine;
public class Main {
static Thread task;

View 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);
}
}

View File

@ -1,10 +1,10 @@
package me.topchetoeu.jscript.compilation;
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 Statement toAssign(Statement val, Type operation);
public abstract AssignStatement toAssign(Statement val, Operation operation);
protected AssignableStatement(Location loc) {
super(loc);

View File

@ -1,6 +1,7 @@
package me.topchetoeu.jscript.compilation;
import me.topchetoeu.jscript.Location;
import me.topchetoeu.jscript.engine.Operation;
import me.topchetoeu.jscript.exceptions.SyntaxException;
public class Instruction {
@ -33,6 +34,7 @@ public class Instruction {
LOAD_REGEX,
DUP,
MOVE,
STORE_VAR,
STORE_MEMBER,
@ -43,45 +45,47 @@ public class Instruction {
KEYS,
TYPEOF,
INSTANCEOF(true),
IN(true),
OPERATION;
// TYPEOF,
// INSTANCEOF(true),
// IN(true),
MULTIPLY(true),
DIVIDE(true),
MODULO(true),
ADD(true),
SUBTRACT(true),
// MULTIPLY(true),
// DIVIDE(true),
// MODULO(true),
// ADD(true),
// SUBTRACT(true),
USHIFT_RIGHT(true),
SHIFT_RIGHT(true),
SHIFT_LEFT(true),
// USHIFT_RIGHT(true),
// SHIFT_RIGHT(true),
// SHIFT_LEFT(true),
GREATER(true),
LESS(true),
GREATER_EQUALS(true),
LESS_EQUALS(true),
LOOSE_EQUALS(true),
LOOSE_NOT_EQUALS(true),
EQUALS(true),
NOT_EQUALS(true),
// GREATER(true),
// LESS(true),
// GREATER_EQUALS(true),
// LESS_EQUALS(true),
// LOOSE_EQUALS(true),
// LOOSE_NOT_EQUALS(true),
// EQUALS(true),
// NOT_EQUALS(true),
AND(true),
OR(true),
XOR(true),
// AND(true),
// OR(true),
// XOR(true),
NEG(true),
POS(true),
NOT(true),
INVERSE(true);
// NEG(true),
// POS(true),
// NOT(true),
// INVERSE(true);
final boolean isOperation;
// final boolean isOperation;
private Type(boolean isOperation) {
this.isOperation = isOperation;
}
private Type() {
this(false);
}
// private Type(boolean isOperation) {
// this.isOperation = isOperation;
// }
// private Type() {
// this(false);
// }
}
public final Type type;
@ -103,6 +107,11 @@ public class Instruction {
if (i >= params.length || i < 0) return null;
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) {
if (args.length != params.length) return false;
for (int i = 0; i < args.length; i++) {
@ -226,11 +235,14 @@ public class Instruction {
public static Instruction loadArr(int count) {
return new Instruction(null, Type.LOAD_ARR, count);
}
public static Instruction dup(int count) {
return new Instruction(null, Type.DUP, count, 0);
public static Instruction dup() {
return new Instruction(null, Type.DUP, 0, 1);
}
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) {
@ -255,7 +267,7 @@ public class Instruction {
public static Instruction 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);
}
@ -267,9 +279,8 @@ public class Instruction {
return new Instruction(null, Type.DEF_PROP);
}
public static Instruction operation(Type op) {
if (!op.isOperation) throw new IllegalArgumentException("The instruction type %s is not an operation.".formatted(op));
return new Instruction(null, op);
public static Instruction operation(Operation op) {
return new Instruction(null, Type.OPERATION, op);
}
@Override

View File

@ -5,7 +5,7 @@ import java.util.List;
import me.topchetoeu.jscript.Location;
import me.topchetoeu.jscript.compilation.Instruction;
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;
public class ForInStatement extends Statement {
@ -37,17 +37,18 @@ public class ForInStatement extends Statement {
target.add(Instruction.keys());
int start = target.size();
target.add(Instruction.dup(1));
target.add(Instruction.dup());
target.add(Instruction.loadMember("length"));
target.add(Instruction.loadValue(0));
target.add(Instruction.operation(Type.LESS_EQUALS));
target.add(Instruction.operation(Operation.LESS_EQUALS));
int mid = target.size();
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.loadValue(1));
target.add(Instruction.operation(Type.SUBTRACT));
target.add(Instruction.operation(Operation.SUBTRACT));
target.add(Instruction.dup(1, 2));
target.add(Instruction.loadValue("length"));
target.add(Instruction.dup(1, 2));

View File

@ -7,6 +7,7 @@ import me.topchetoeu.jscript.Location;
import me.topchetoeu.jscript.compilation.Instruction;
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;
public class SwitchStatement extends Statement {
@ -33,9 +34,9 @@ public class SwitchStatement extends Statement {
value.compile(target, scope);
for (var ccase : cases) {
target.add(Instruction.dup(1).locate(loc()));
target.add(Instruction.dup().locate(loc()));
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);
target.add(Instruction.nop());
}

View File

@ -21,7 +21,7 @@ public class ArrayStatement extends Statement {
var i = 0;
for (var el : statements) {
if (el != null) {
target.add(Instruction.dup(1).locate(loc()));
target.add(Instruction.dup().locate(loc()));
target.add(Instruction.loadValue(i).locate(loc()));
el.compileWithPollution(target, scope);
target.add(Instruction.storeMember().locate(loc()));

View File

@ -6,7 +6,7 @@ import me.topchetoeu.jscript.Location;
import me.topchetoeu.jscript.compilation.AssignableStatement;
import me.topchetoeu.jscript.compilation.Instruction;
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;
public class ChangeStatement extends Statement {
@ -19,11 +19,7 @@ public class ChangeStatement extends Statement {
@Override
public void compile(List<Instruction> target, ScopeRecord scope) {
value.toAssign(new ConstantStatement(loc(), -addAmount), Type.SUBTRACT).compileWithPollution(target, scope);
if (postfix) {
target.add(Instruction.loadValue(addAmount).locate(loc()));
target.add(Instruction.operation(Type.SUBTRACT).locate(loc()));
}
value.toAssign(new ConstantStatement(loc(), -addAmount), Operation.SUBTRACT).compile(target, scope, postfix);
}
public ChangeStatement(Location loc, AssignableStatement value, double addAmount, boolean postfix) {

View File

@ -53,13 +53,11 @@ public class FunctionStatement extends Statement {
target.add(Instruction.nop());
subscope.define("this");
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++) {
target.add(Instruction.loadVar(argsVar).locate(loc()));
target.add(Instruction.loadMember(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) {
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.storeMember().locate(loc()));

View File

@ -3,45 +3,52 @@ package me.topchetoeu.jscript.compilation.values;
import java.util.List;
import me.topchetoeu.jscript.Location;
import me.topchetoeu.jscript.compilation.AssignStatement;
import me.topchetoeu.jscript.compilation.Instruction;
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;
public class IndexAssignStatement extends Statement {
public class IndexAssignStatement extends AssignStatement {
public final Statement object;
public final Statement index;
public final Statement value;
public final Type operation;
public final Operation operation;
@Override
public boolean pollutesStack() { return true; }
@Override
public void compile(List<Instruction> target, ScopeRecord scope) {
public void compile(List<Instruction> target, ScopeRecord scope, boolean retPrevValue) {
int start = 0;
if (operation != null) {
object.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()));
if (retPrevValue) {
target.add(Instruction.dup().locate(loc()));
target.add(Instruction.move(3, 1).locate(loc()));
}
value.compileWithPollution(target, scope);
target.add(Instruction.operation(operation).locate(loc()));
target.add(Instruction.storeMember(true).locate(loc()));
target.add(Instruction.storeMember(!retPrevValue).locate(loc()).setDebug(true));
}
else {
object.compileWithPollution(target, scope);
if (retPrevValue) target.add(Instruction.dup().locate(loc()));
index.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);
this.object = object;
this.index = index;

View File

@ -3,10 +3,11 @@ package me.topchetoeu.jscript.compilation.values;
import java.util.List;
import me.topchetoeu.jscript.Location;
import me.topchetoeu.jscript.compilation.AssignStatement;
import me.topchetoeu.jscript.compilation.AssignableStatement;
import me.topchetoeu.jscript.compilation.Instruction;
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;
public class IndexStatement extends AssignableStatement {
@ -19,13 +20,13 @@ public class IndexStatement extends AssignableStatement {
public boolean pure() { return true; }
@Override
public Statement toAssign(Statement val, Type operation) {
public AssignStatement toAssign(Statement val, Operation operation) {
return new IndexAssignStatement(loc(), object, index, val, operation);
}
public void compile(List<Instruction> target, ScopeRecord scope, boolean dupObj) {
int start = 0;
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) {
target.add(Instruction.loadMember(((ConstantStatement)index).value).locate(loc()));
return;

View File

@ -29,7 +29,7 @@ public class LazyAndStatement extends Statement {
}
first.compileWithPollution(target, scope);
target.add(Instruction.dup(1).locate(loc()));
target.add(Instruction.dup().locate(loc()));
int start = target.size();
target.add(Instruction.nop());
target.add(Instruction.discard().locate(loc()));

View File

@ -29,7 +29,7 @@ public class LazyOrStatement extends Statement {
}
first.compileWithPollution(target, scope);
target.add(Instruction.dup(1).locate(loc()));
target.add(Instruction.dup().locate(loc()));
int start = target.size();
target.add(Instruction.nop());
target.add(Instruction.discard().locate(loc()));

View File

@ -20,9 +20,9 @@ public class ObjectStatement extends Statement {
@Override
public void compile(List<Instruction> target, ScopeRecord scope) {
target.add(Instruction.loadObj().locate(loc()));
if (!map.isEmpty()) target.add(Instruction.dup(map.size()).locate(loc()));
for (var el : map.entrySet()) {
target.add(Instruction.dup().locate(loc()));
target.add(Instruction.loadValue(el.getKey()).locate(loc()));
var val = el.getValue();
if (val instanceof FunctionStatement) ((FunctionStatement)val).compile(target, scope, el.getKey().toString(), false);

View File

@ -7,13 +7,14 @@ import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.compilation.control.ThrowStatement;
import me.topchetoeu.jscript.engine.CallContext;
import me.topchetoeu.jscript.engine.Operation;
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.exceptions.EngineException;
public class OperationStatement extends Statement {
public final Statement[] args;
public final Instruction.Type operation;
public final Operation operation;
@Override
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);
this.operation = operation;
this.args = args;

View File

@ -6,8 +6,7 @@ import me.topchetoeu.jscript.Location;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
import me.topchetoeu.jscript.engine.values.FunctionValue;
import me.topchetoeu.jscript.engine.values.Symbol;
import me.topchetoeu.jscript.engine.values.Values;
public class TypeofStatement extends Statement {
public final Statement value;
@ -22,7 +21,7 @@ public class TypeofStatement extends Statement {
if (value instanceof VariableStatement) {
var i = scope.getKey(((VariableStatement)value).name);
if (i instanceof String) {
target.add(Instruction.typeof((String)i));
target.add(Instruction.typeof((String)i).locate(loc()));
return;
}
}
@ -35,15 +34,14 @@ public class TypeofStatement extends Statement {
var val = value.optimize();
if (val instanceof ConstantStatement) {
var cnst = (ConstantStatement)val;
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");
return new ConstantStatement(loc(), Values.type(((ConstantStatement)val).value));
}
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);
}

View File

@ -4,36 +4,39 @@ import java.util.List;
import me.topchetoeu.jscript.Location;
import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.compilation.AssignStatement;
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;
public class VariableAssignStatement extends Statement {
public class VariableAssignStatement extends AssignStatement {
public final String name;
public final Statement value;
public final Type operation;
public final Operation operation;
@Override
public boolean pollutesStack() { return true; }
@Override
public void compile(List<Instruction> target, ScopeRecord scope) {
public void compile(List<Instruction> target, ScopeRecord scope, boolean retPrevValue) {
var i = scope.getKey(name);
if (operation != null) {
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);
else value.compileWithPollution(target, scope);
target.add(Instruction.operation(operation).locate(loc()));
target.add(Instruction.storeVar(i, !retPrevValue).locate(loc()));
}
else {
if (retPrevValue) target.add(Instruction.loadVar(i).locate(loc()));
if (value instanceof FunctionStatement) ((FunctionStatement)value).compile(target, scope, name, false);
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);
this.name = name;
this.value = val;

View File

@ -3,10 +3,11 @@ package me.topchetoeu.jscript.compilation.values;
import java.util.List;
import me.topchetoeu.jscript.Location;
import me.topchetoeu.jscript.compilation.AssignStatement;
import me.topchetoeu.jscript.compilation.AssignableStatement;
import me.topchetoeu.jscript.compilation.Instruction;
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;
public class VariableStatement extends AssignableStatement {
@ -18,7 +19,7 @@ public class VariableStatement extends AssignableStatement {
public boolean pure() { return true; }
@Override
public Statement toAssign(Statement val, Type operation) {
public AssignStatement toAssign(Statement val, Operation operation) {
return new VariableAssignStatement(loc(), name, val, operation);
}

View 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;
}
}

View File

@ -4,8 +4,6 @@ import java.util.ArrayList;
import java.util.List;
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.DebugCommand;
import me.topchetoeu.jscript.engine.Engine;
@ -17,6 +15,8 @@ import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.exceptions.EngineException;
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> MAX_STACK_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 Object thisArg;
public final Object[] args;
public final List<Object> stack = new ArrayList<>();
public final List<TryContext> tryCtxs = new ArrayList<>();
public final List<TryCtx> tryStack = new ArrayList<>();
public final CodeFunction function;
public Object[] stack = new Object[32];
public int stackPtr = 0;
public int codePtr = 0;
private DebugCommand debugCmd = null;
private Location prevLoc = null;
@ -37,41 +38,50 @@ public class CodeFrame {
return peek(0);
}
public Object peek(int offset) {
if (stack.size() <= offset) return null;
else return stack.get(stack.size() - 1 - offset);
if (stackPtr <= offset) return null;
else return stack[stackPtr - 1 - offset];
}
public Object pop() {
if (stack.size() == 0) return null;
else return stack.remove(stack.size() - 1);
if (stackPtr == 0) return null;
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) {
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) {
stack.clear();
codePtr = 0;
debugCmd = null;
public void start(CallContext ctx) {
if (ctx.getData(STACK_N_KEY, 0) >= ctx.addData(MAX_STACK_KEY, 10000)) throw EngineException.ofRange("Stack overflow!");
ctx.changeData(STACK_N_KEY);
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);
if (debugState != null) debugState.popFrame();
ctx.changeData(STACK_N_KEY, -1);
}
public Object next(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);
}
private Object nextNoTry(CallContext ctx) throws InterruptedException {
if (Thread.currentThread().isInterrupted()) throw new InterruptedException();
if (codePtr < 0 || codePtr >= function.body.length) return null;
@ -80,20 +90,28 @@ public class CodeFrame {
var loc = instr.location;
if (loc != null) prevLoc = loc;
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);
// var debugState = ctx.getData(Engine.DEBUG_STATE_KEY);
// if (debugCmd == null) {
// if (ctx.getData(STOP_AT_START_KEY, false)) debugCmd = DebugCommand.STEP_OVER;
// else debugCmd = DebugCommand.NORMAL;
debugState.breakpointNotifier.next(new BreakpointData(loc, ctx));
debugCmd = debugState.commandNotifier.toAwaitable().await();
if (debugCmd == DebugCommand.NORMAL) ctx.setData(STEPPING_TROUGH_KEY, false);
}
}
// if (debugState != null) debugState.pushFrame(this);
// }
// 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 {
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 {
try {
start(ctx);
while (true) {
var res = next(ctx);
if (res != Runners.NO_RETURN) return res;
}
}
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) {

View File

@ -5,6 +5,7 @@ import java.util.Collections;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.engine.CallContext;
import me.topchetoeu.jscript.engine.DebugCommand;
import me.topchetoeu.jscript.engine.Operation;
import me.topchetoeu.jscript.engine.scope.ValueVariable;
import me.topchetoeu.jscript.engine.values.ArrayValue;
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 {
int n = instr.get(0);
var callArgs = new Object[n];
for (var i = n - 1; i >= 0; i--) callArgs[i] = frame.pop();
var callArgs = frame.take(instr.get(0));
var func = frame.pop();
var thisArg = frame.pop();
@ -51,10 +49,7 @@ public class Runners {
return NO_RETURN;
}
public static Object execCallNew(DebugCommand state, Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
int n = instr.get(0);
var callArgs = new Object[n];
for (var i = n - 1; i >= 0; i--) callArgs[i] = frame.pop();
var callArgs = frame.take(instr.get(0));
var funcObj = frame.pop();
if (Values.isFunction(funcObj) && Values.function(funcObj).special) {
@ -159,7 +154,7 @@ public class Runners {
exception = null;
try {
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;
}
catch (EngineException e) {
@ -194,10 +189,24 @@ public class Runners {
}
public static Object execDup(Instruction instr, CodeFrame frame, CallContext ctx) {
var val = frame.peek(instr.get(1));
for (int i = 0; i < (int)instr.get(0); i++) {
frame.push(val);
int offset = instr.get(0), count = instr.get(1);
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++;
return NO_RETURN;
}
@ -376,157 +385,13 @@ public class Runners {
return NO_RETURN;
}
public static Object execAdd(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
Object b = frame.pop(), a = frame.pop();
frame.push(Values.add(ctx, a, b));
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 execOperation(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
Operation op = instr.get(0);
var args = new Object[op.operands];
public static Object execAnd(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
Object b = frame.pop(), a = frame.pop();
for (var i = op.operands - 1; i >= 0; i--) args[i] = frame.pop();
frame.push(Values.and(ctx, a, b));
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.push(Values.operation(ctx, op, args));
frame.codePtr++;
return NO_RETURN;
}
@ -544,6 +409,7 @@ public class Runners {
case TRY: return execTry(state, 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_VAR: return execLoadVar(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 MAKE_VAR: return execMakeVar(instr, frame, ctx);
case IN: return execIn(instr, frame, ctx);
case KEYS: return execKeys(instr, frame, ctx);
case DEF_PROP: return execDefProp(instr, frame, ctx);
case TYPEOF: return execTypeof(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_IF: return execJmpIf(instr, frame, ctx);
case JMP_IFN: return execJmpIfNot(instr, frame, ctx);
case ADD: return execAdd(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);
case OPERATION: return execOperation(instr, frame, ctx);
default: throw EngineException.ofSyntax("Invalid instruction " + instr.type.name() + ".");
}

View File

@ -11,6 +11,7 @@ import java.util.List;
import java.util.Map;
import me.topchetoeu.jscript.engine.CallContext;
import me.topchetoeu.jscript.engine.Operation;
import me.topchetoeu.jscript.engine.frame.ConvertHint;
import me.topchetoeu.jscript.exceptions.EngineException;
@ -218,6 +219,47 @@ public class Values {
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 {
obj = normalize(obj); key = normalize(key);
if (obj == null) throw new IllegalArgumentException("Tried to access member of undefined.");

View File

@ -3,29 +3,28 @@ package me.topchetoeu.jscript.parsing;
import java.util.HashMap;
import java.util.Map;
import me.topchetoeu.jscript.compilation.Instruction;
import me.topchetoeu.jscript.compilation.Instruction.Type;
import me.topchetoeu.jscript.engine.Operation;
public enum Operator {
MULTIPLY("*", Type.MULTIPLY, 13),
DIVIDE("/", Type.DIVIDE, 12),
MODULO("%", Type.MODULO, 12),
SUBTRACT("-", Type.SUBTRACT, 11),
ADD("+", Type.ADD, 11),
SHIFT_RIGHT(">>", Type.SHIFT_RIGHT, 10),
SHIFT_LEFT("<<", Type.SHIFT_LEFT, 10),
USHIFT_RIGHT(">>>", Type.USHIFT_RIGHT, 10),
GREATER(">", Type.GREATER, 9),
LESS("<", Type.LESS, 9),
GREATER_EQUALS(">=", Type.GREATER_EQUALS, 9),
LESS_EQUALS("<=", Type.LESS_EQUALS, 9),
NOT_EQUALS("!=", Type.LOOSE_NOT_EQUALS, 8),
LOOSE_NOT_EQUALS("!==", Type.NOT_EQUALS, 8),
EQUALS("==", Type.LOOSE_EQUALS, 8),
LOOSE_EQUALS("===", Type.EQUALS, 8),
AND("&", Type.AND, 7),
XOR("^", Type.XOR, 6),
OR("|", Type.OR, 5),
MULTIPLY("*", Operation.MULTIPLY, 13),
DIVIDE("/", Operation.DIVIDE, 12),
MODULO("%", Operation.MODULO, 12),
SUBTRACT("-", Operation.SUBTRACT, 11),
ADD("+", Operation.ADD, 11),
SHIFT_RIGHT(">>", Operation.SHIFT_RIGHT, 10),
SHIFT_LEFT("<<", Operation.SHIFT_LEFT, 10),
USHIFT_RIGHT(">>>", Operation.USHIFT_RIGHT, 10),
GREATER(">", Operation.GREATER, 9),
LESS("<", Operation.LESS, 9),
GREATER_EQUALS(">=", Operation.GREATER_EQUALS, 9),
LESS_EQUALS("<=", Operation.LESS_EQUALS, 9),
NOT_EQUALS("!=", Operation.LOOSE_NOT_EQUALS, 8),
LOOSE_NOT_EQUALS("!==", Operation.NOT_EQUALS, 8),
EQUALS("==", Operation.LOOSE_EQUALS, 8),
LOOSE_EQUALS("===", Operation.EQUALS, 8),
AND("&", Operation.AND, 7),
XOR("^", Operation.XOR, 6),
OR("|", Operation.OR, 5),
LAZY_AND("&&", 4),
LAZY_OR("||", 3),
ASSIGN_SHIFT_LEFT("<<=", 2, true),
@ -57,7 +56,7 @@ public enum Operator {
DECREASE("--");
public final String value;
public final Instruction.Type operation;
public final Operation operation;
public final int precedence;
public final boolean reverse;
private static final Map<String, Operator> ops = new HashMap<>();
@ -99,13 +98,13 @@ public enum Operator {
this.reverse = reverse;
}
private Operator(String value, Instruction.Type funcName, int precedence) {
private Operator(String value, Operation funcName, int precedence) {
this. value = value;
this.operation = funcName;
this.precedence = precedence;
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.operation = funcName;
this.precedence = precedence;

View File

@ -13,6 +13,7 @@ import me.topchetoeu.jscript.compilation.VariableDeclareStatement.Pair;
import me.topchetoeu.jscript.compilation.control.*;
import me.topchetoeu.jscript.compilation.control.SwitchStatement.SwitchCase;
import me.topchetoeu.jscript.compilation.values.*;
import me.topchetoeu.jscript.engine.Operation;
import me.topchetoeu.jscript.engine.scope.GlobalScope;
import me.topchetoeu.jscript.engine.scope.ValueVariable;
import me.topchetoeu.jscript.engine.values.CodeFunction;
@ -938,12 +939,12 @@ public class Parsing {
if (!opState.isSuccess()) return ParseRes.failed();
var op = opState.result;
Type operation = null;
Operation operation = null;
if (op == Operator.ADD) operation = Type.POS;
else if (op == Operator.SUBTRACT) operation = Type.NEG;
else if (op == Operator.INVERSE) operation = Type.INVERSE;
else if (op == Operator.NOT) operation = Type.NOT;
if (op == Operator.ADD) operation = Operation.POS;
else if (op == Operator.SUBTRACT) operation = Operation.NEG;
else if (op == Operator.INVERSE) operation = Operation.INVERSE;
else if (op == Operator.NOT) operation = Operation.NOT;
else return ParseRes.failed();
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);
n += res.n;
Type operation = null;
Operation operation = null;
if (op == Operator.ASSIGN_ADD) operation = Type.ADD;
if (op == Operator.ASSIGN_SUBTRACT) operation = Type.SUBTRACT;
if (op == Operator.ASSIGN_MULTIPLY) operation = Type.MULTIPLY;
if (op == Operator.ASSIGN_DIVIDE) operation = Type.DIVIDE;
if (op == Operator.ASSIGN_MODULO) operation = Type.MODULO;
if (op == Operator.ASSIGN_OR) operation = Type.OR;
if (op == Operator.ASSIGN_XOR) operation = Type.XOR;
if (op == Operator.ASSIGN_AND) operation = Type.AND;
if (op == Operator.ASSIGN_SHIFT_LEFT) operation = Type.SHIFT_LEFT;
if (op == Operator.ASSIGN_SHIFT_RIGHT) operation = Type.SHIFT_RIGHT;
if (op == Operator.ASSIGN_USHIFT_RIGHT) operation = Type.USHIFT_RIGHT;
if (op == Operator.ASSIGN_ADD) operation = Operation.ADD;
if (op == Operator.ASSIGN_SUBTRACT) operation = Operation.SUBTRACT;
if (op == Operator.ASSIGN_MULTIPLY) operation = Operation.MULTIPLY;
if (op == Operator.ASSIGN_DIVIDE) operation = Operation.DIVIDE;
if (op == Operator.ASSIGN_MODULO) operation = Operation.MODULO;
if (op == Operator.ASSIGN_OR) operation = Operation.OR;
if (op == Operator.ASSIGN_XOR) operation = Operation.XOR;
if (op == Operator.ASSIGN_AND) operation = Operation.AND;
if (op == Operator.ASSIGN_SHIFT_LEFT) operation = Operation.SHIFT_LEFT;
if (op == Operator.ASSIGN_SHIFT_RIGHT) operation = Operation.SHIFT_RIGHT;
if (op == Operator.ASSIGN_USHIFT_RIGHT) operation = Operation.USHIFT_RIGHT;
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);
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) {
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);
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) {
var loc = getLoc(filename, tokens, i);

View File

@ -28,6 +28,8 @@ public class AsyncFunction extends FunctionValue {
public Object fulfill(CallContext ctx, Object thisArg, Object[] args) throws InterruptedException {
if (args.length == 1) frame.push(args[0]);
frame.start(ctx);
while (true) {
awaiting = false;
awaited = null;
@ -36,12 +38,12 @@ public class AsyncFunction extends FunctionValue {
var res = frame.next(ctx);
if (res != Runners.NO_RETURN) {
promise.fulfill(ctx, res);
return null;
break;
}
}
catch (EngineException e) {
promise.reject(e);
return null;
break;
}
if (!awaiting) continue;
@ -54,16 +56,19 @@ public class AsyncFunction extends FunctionValue {
var res = Values.getMember(ctx, awaited, "then");
if (res instanceof FunctionValue) {
Values.function(res).call(ctx, awaited, fulfillFunc, rejectFunc);
return null;
break;
}
else frame.push(awaited);
}
catch (EngineException e) {
promise.reject(e);
break;
}
}
frame.end(ctx);
return null;
}
}
}
public Object await(CallContext ctx, Object thisArg, Object[] args) {
this.awaiting = true;