diff --git a/build.gradle b/build.gradle index 34358c7..96537a3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,14 +1,21 @@ + plugins { id "application" + // these idiots don't optimize in the compile-time, but in the runtime + // who let these knuckleheads make a language + + // TODO: figure out how to integrate proguard + // id "com.github.xaverkapeller.proguard-annotations" } repositories { mavenCentral() + gradlePluginPortal() } dependencies { - annotationProcessor 'com.github.bsideup.jabel:jabel-javac-plugin:0.4.2' // Genuinely fuck Java + annotationProcessor 'com.github.bsideup.jabel:jabel-javac-plugin:0.4.2' compileOnly 'com.github.bsideup.jabel:jabel-javac-plugin:0.4.2' } diff --git a/settings.gradle b/settings.gradle index fc7ee6c..2129498 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,13 @@ +pluginManagement { + repositories { + mavenCentral() + gradlePluginPortal() + } +} + plugins { id 'org.gradle.toolchains.foojay-resolver-convention' version '0.7.0' } + rootProject.name = properties.project_name diff --git a/src/java/me/topchetoeu/jscript/runtime/Frame.java b/src/java/me/topchetoeu/jscript/runtime/Frame.java index 4e9fb8c..c979933 100644 --- a/src/java/me/topchetoeu/jscript/runtime/Frame.java +++ b/src/java/me/topchetoeu/jscript/runtime/Frame.java @@ -1,7 +1,6 @@ package me.topchetoeu.jscript.runtime; import java.util.ArrayList; -import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -109,6 +108,7 @@ public final class Frame { public final Stack tryStack = new Stack<>(); public final CodeFunction function; public final Environment env; + private final DebugContext dbg; public Value[] getVar(int i) { if (i < 0) return captures[~i]; @@ -132,24 +132,15 @@ public final class Frame { return peek(0); } public Value peek(int offset) { - if (stackPtr <= offset) return null; - else return stack[stackPtr - 1 - offset]; + return stack[stackPtr - 1 - offset]; } public Value pop() { - if (stackPtr == 0) return Value.UNDEFINED; return stack[--stackPtr]; } public Value[] take(int n) { - int srcI = stackPtr - n; - if (srcI < 0) srcI = 0; - - int dstI = n + srcI - stackPtr; - int copyN = stackPtr - srcI; - Value[] res = new Value[n]; - Arrays.fill(res, Value.UNDEFINED); - System.arraycopy(stack, srcI, res, dstI, copyN); - stackPtr -= copyN; + System.arraycopy(stack, stackPtr - n, res, 0, n); + stackPtr -= n; return res; } @@ -162,33 +153,45 @@ public final class Frame { stack[stackPtr++] = val; } + public void replace(Value val) { + stack[stackPtr - 1] = val; + } // for the love of christ don't touch this - private Value next(Value value, Value returnValue, EngineException error) { + /** + * This is provided only for optimization-sike. All parameters must be null except at most one, otherwise undefined behavior + */ + public final Value next(Value value, Value returnValue, EngineException error) { if (value != null) push(value); Instruction instr = null; - if (codePtr >= 0 && codePtr < function.body.instructions.length) instr = function.body.instructions[codePtr]; + if (codePtr != function.body.instructions.length) instr = function.body.instructions[codePtr]; if (returnValue == null && error == null) { try { if (Thread.interrupted()) throw new InterruptException(); - if (instr == null) returnValue = null; + if (instr == null) { + if (stackPtr > 0) returnValue = stack[stackPtr - 1]; + else returnValue = Value.UNDEFINED; + } else { - DebugContext.get(env).onInstruction(env, this, instr, null, null, false); + dbg.onInstruction(env, this, instr); try { this.jumpFlag = this.popTryFlag = false; returnValue = InstructionRunner.exec(env, instr, this); } catch (EngineException e) { - error = e.add(env, function.name, DebugContext.get(env).getMapOrEmpty(function).toLocation(codePtr, true)); + error = e.add(env, function.name, dbg.getMapOrEmpty(function).toLocation(codePtr, true)); } } } catch (EngineException e) { error = e; } - // catch (RuntimeException e) { error = EngineException.ofError("InternalError", e.getMessage()); } + catch (RuntimeException e) { + System.out.println(dbg.getMapOrEmpty(function).toLocation(codePtr, true)); + throw e; + } } while (!tryStack.empty()) { @@ -265,17 +268,17 @@ public final class Frame { if (error != null) { var caught = false; - for (var frame : DebugContext.get(env).getStackFrames()) { + for (var frame : dbg.getStackFrames()) { for (var tryCtx : frame.tryStack) { if (tryCtx.state == TryState.TRY) caught = true; } } - DebugContext.get(env).onInstruction(env, this, instr, null, error, caught); + dbg.onInstruction(env, this, instr, null, error, caught); throw error; } if (returnValue != null) { - DebugContext.get(env).onInstruction(env, this, instr, returnValue, null, false); + dbg.onInstruction(env, this, instr, returnValue, null, false); return returnValue; } @@ -285,7 +288,7 @@ public final class Frame { /** * Executes the next instruction in the frame */ - public Value next() { + public final Value next() { return next(null, null, null); } /** @@ -294,7 +297,7 @@ public final class Frame { * * @param value The value to induce */ - public Value next(Value value) { + public final Value next(Value value) { return next(value, null, null); } /** @@ -305,7 +308,7 @@ public final class Frame { * * @param error The error to induce */ - public Value induceError(EngineException error) { + public final Value induceError(EngineException error) { return next(null, null, error); } /** @@ -317,7 +320,7 @@ public final class Frame { * * @param value The retunr value to induce */ - public Value induceReturn(Value value) { + public final Value induceReturn(Value value) { return next(null, value, null); } @@ -408,6 +411,7 @@ public final class Frame { public Frame(Environment env, boolean isNew, Value thisArg, Value[] args, CodeFunction func) { this.env = env; + this.dbg = DebugContext.get(env); this.function = func; this.isNew = isNew; diff --git a/src/java/me/topchetoeu/jscript/runtime/InstructionRunner.java b/src/java/me/topchetoeu/jscript/runtime/InstructionRunner.java index a0bd64e..48ecd51 100644 --- a/src/java/me/topchetoeu/jscript/runtime/InstructionRunner.java +++ b/src/java/me/topchetoeu/jscript/runtime/InstructionRunner.java @@ -285,11 +285,105 @@ public class InstructionRunner { private static Value execOperation(Environment env, Instruction instr, Frame frame) { Operation op = instr.get(0); - var args = new Value[op.operands]; + Value res; + var stack = frame.stack; - for (var i = op.operands - 1; i >= 0; i--) args[i] = frame.pop(); + frame.stackPtr -= 1; + var ptr = frame.stackPtr; - frame.push(Value.operation(env, op, args)); + // for (var i = op.operands - 1; i >= 0; i--) args[i] = frame.pop(); + + switch (op) { + case ADD: + res = Value.add(env, stack[ptr - 1], stack[ptr]); + break; + case SUBTRACT: + res = Value.subtract(env, stack[ptr - 1], stack[ptr]); + break; + case DIVIDE: + res = Value.divide(env, stack[ptr - 1], stack[ptr]); + break; + case MULTIPLY: + res = Value.multiply(env, stack[ptr - 1], stack[ptr]); + break; + case MODULO: + res = Value.modulo(env, stack[ptr - 1], stack[ptr]); + break; + + case AND: + res = Value.and(env, stack[ptr - 1], stack[ptr]); + break; + case OR: + res = Value.or(env, stack[ptr - 1], stack[ptr]); + break; + case XOR: + res = Value.xor(env, stack[ptr - 1], stack[ptr]); + break; + + case EQUALS: + res = BoolValue.of(stack[ptr - 1].equals(stack[ptr])); + break; + case NOT_EQUALS: + res = BoolValue.of(!stack[ptr - 1].equals(stack[ptr])); + break; + case LOOSE_EQUALS: + res = BoolValue.of(Value.looseEqual(env, stack[ptr - 1], stack[ptr])); + break; + case LOOSE_NOT_EQUALS: + res = BoolValue.of(!Value.looseEqual(env, stack[ptr - 1], stack[ptr])); + break; + + case GREATER: + res = BoolValue.of(Value.greater(env, stack[ptr - 1], stack[ptr])); + break; + case GREATER_EQUALS: + res = BoolValue.of(Value.greaterOrEqual(env, stack[ptr - 1], stack[ptr])); + break; + case LESS: + res = BoolValue.of(Value.less(env, stack[ptr - 1], stack[ptr])); + break; + case LESS_EQUALS: + res = BoolValue.of(Value.lessOrEqual(env, stack[ptr - 1], stack[ptr])); + break; + + case INVERSE: + res = Value.bitwiseNot(env, stack[ptr++]); + frame.stackPtr++; + break; + case NOT: + res = BoolValue.of(!stack[ptr++].toBoolean()); + frame.stackPtr++; + break; + case POS: + res = stack[ptr++].toNumber(env); + frame.stackPtr++; + break; + case NEG: + res = Value.negative(env, stack[ptr++]); + frame.stackPtr++; + break; + + case SHIFT_LEFT: + res = Value.shiftLeft(env, stack[ptr], stack[ptr]); + break; + case SHIFT_RIGHT: + res = Value.shiftRight(env, stack[ptr], stack[ptr]); + break; + case USHIFT_RIGHT: + res = Value.unsignedShiftRight(env, stack[ptr], stack[ptr]); + break; + + case IN: + res = BoolValue.of(stack[ptr - 1].hasMember(env, stack[ptr], false)); + break; + case INSTANCEOF: + res = BoolValue.of(stack[ptr - 1].isInstanceOf(env, stack[ptr].getMember(env, new StringValue("prototype")))); + break; + + default: return null; + } + + stack[ptr - 1] = res; frame.codePtr++; return null; } diff --git a/src/java/me/topchetoeu/jscript/runtime/debug/DebugContext.java b/src/java/me/topchetoeu/jscript/runtime/debug/DebugContext.java index df26c27..d8f709b 100644 --- a/src/java/me/topchetoeu/jscript/runtime/debug/DebugContext.java +++ b/src/java/me/topchetoeu/jscript/runtime/debug/DebugContext.java @@ -86,6 +86,10 @@ public class DebugContext { if (debugger != null) return debugger.onInstruction(env, frame, instruction, returnVal, error, caught); else return false; } + public boolean onInstruction(Environment env, Frame frame, Instruction instruction) { + if (debugger != null) return debugger.onInstruction(env, frame, instruction, null, null, false); + else return false; + } public void onSource(Filename filename, String source) { if (debugger != null) debugger.onSourceLoad(filename, source); if (sources != null) sources.put(filename, source); diff --git a/src/java/me/topchetoeu/jscript/runtime/values/Member.java b/src/java/me/topchetoeu/jscript/runtime/values/Member.java index 8f99012..92828a0 100644 --- a/src/java/me/topchetoeu/jscript/runtime/values/Member.java +++ b/src/java/me/topchetoeu/jscript/runtime/values/Member.java @@ -87,7 +87,7 @@ public interface Member { if (field.configurable != configurable) return false; if (field.enumerable != enumerable) return false; - if (!writable) return field.get(env, self).strictEquals(env, get(env, self)); + if (!writable) return field.get(env, self).equals(get(env, self)); set(env, field.get(env, self), self); writable = field.writable; diff --git a/src/java/me/topchetoeu/jscript/runtime/values/Value.java b/src/java/me/topchetoeu/jscript/runtime/values/Value.java index 7f322f0..358fbf9 100644 --- a/src/java/me/topchetoeu/jscript/runtime/values/Value.java +++ b/src/java/me/topchetoeu/jscript/runtime/values/Value.java @@ -10,7 +10,6 @@ import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; -import me.topchetoeu.jscript.common.Operation; import me.topchetoeu.jscript.common.environment.Environment; import me.topchetoeu.jscript.common.environment.Key; import me.topchetoeu.jscript.common.json.JSON; @@ -112,65 +111,6 @@ public abstract class Value { public final int toInt(Environment env) { return (int)toNumber(env).value; } public final long toLong(Environment env) { return (long)toNumber(env).value; } - public Value add(Environment env, Value other) { - if (this instanceof StringValue || other instanceof StringValue) { - return new StringValue(this.toString(env).value + other.toString(env).value); - } - else return new NumberValue(this.toNumber(env).value + other.toNumber(env).value); - } - public NumberValue subtract(Environment env, Value other) { - return new NumberValue(toNumber(env).value - other.toNumber(env).value); - } - public NumberValue multiply(Environment env, Value other) { - return new NumberValue(toNumber(env).value - other.toNumber(env).value); - } - public NumberValue divide(Environment env, Value other) { - return new NumberValue(toNumber(env).value / other.toNumber(env).value); - } - public NumberValue modulo(Environment env, Value other) { - return new NumberValue(toNumber(env).value % other.toNumber(env).value); - } - public NumberValue negative(Environment env) { - return new NumberValue(-toNumber(env).value); - } - - public NumberValue and(Environment env, Value other) { - return new NumberValue(this.toInt(env) & other.toInt(env)); - } - public NumberValue or(Environment env, Value other) { - return new NumberValue(this.toInt(env) | other.toInt(env)); - } - public NumberValue xor(Environment env, Value other) { - return new NumberValue(this.toInt(env) ^ other.toInt(env)); - } - public NumberValue bitwiseNot(Environment env) { - return new NumberValue(~this.toInt(env)); - } - - public NumberValue shiftLeft(Environment env, Value other) { - return new NumberValue(this.toInt(env) << other.toInt(env)); - } - public NumberValue shiftRight(Environment env, Value other) { - return new NumberValue(this.toInt(env) >> other.toInt(env)); - } - public NumberValue unsignedShiftRight(Environment env, Value other) { - long a = this.toInt(env); - long b = other.toInt(env); - - if (a < 0) a += 0x100000000l; - if (b < 0) b += 0x100000000l; - - return new NumberValue(a >>> b); - } - - public CompareResult compare(Environment env, Value other) { - var a = this.toPrimitive(env); - var b = other.toPrimitive(env); - - if (a instanceof StringValue && b instanceof StringValue) return a.compare(env, b); - else return a.toNumber(env).compare(env, b.toNumber(env)); - } - public final boolean isInstanceOf(Environment env, Value proto) { for (var val = getPrototype(env); val != null; val = getPrototype(env)) { if (val.equals(proto)) return true; @@ -179,44 +119,6 @@ public abstract class Value { return false; } - public static Value operation(Environment env, Operation op, Value ...args) { - switch (op) { - case ADD: return args[0].add(env, args[1]); - case SUBTRACT: return args[0].subtract(env, args[1]); - case DIVIDE: return args[0].divide(env, args[1]); - case MULTIPLY: return args[0].multiply(env, args[1]); - case MODULO: return args[0].modulo(env, args[1]); - - case AND: return args[0].and(env, args[1]); - case OR: return args[0].or(env, args[1]); - case XOR: return args[0].xor(env, args[1]); - - case EQUALS: return BoolValue.of(args[0].strictEquals(env, args[1])); - case NOT_EQUALS: return BoolValue.of(!args[0].strictEquals(env, args[1])); - case LOOSE_EQUALS: return BoolValue.of(args[0].looseEqual(env, args[1])); - case LOOSE_NOT_EQUALS: return BoolValue.of(!args[0].looseEqual(env, args[1])); - - case GREATER: return BoolValue.of(args[0].compare(env, args[1]).greater()); - case GREATER_EQUALS: return BoolValue.of(args[0].compare(env, args[1]).greaterOrEqual()); - case LESS: return BoolValue.of(args[0].compare(env, args[1]).less()); - case LESS_EQUALS: return BoolValue.of(args[0].compare(env, args[1]).lessOrEqual()); - - case INVERSE: return args[0].bitwiseNot(env); - case NOT: return BoolValue.of(!args[0].toBoolean()); - case POS: return args[0].toNumber(env); - case NEG: return args[0].negative(env); - - case SHIFT_LEFT: return args[0].shiftLeft(env, args[1]); - case SHIFT_RIGHT: return args[0].shiftRight(env, args[1]); - case USHIFT_RIGHT: return args[0].unsignedShiftRight(env, args[1]); - - case IN: return BoolValue.of(args[0].hasMember(env, args[1], false)); - case INSTANCEOF: return BoolValue.of(args[0].isInstanceOf(env, args[1].getMember(env, new StringValue("prototype")))); - - default: return null; - } - } - public abstract Member getOwnMember(Environment env, KeyCache key); public abstract Map getOwnMembers(Environment env); public abstract Map getOwnSymbolMembers(Environment env); @@ -475,33 +377,6 @@ public abstract class Value { else return null; } - public abstract boolean strictEquals(Environment env, Value other); - - public final boolean looseEqual(Environment env, Value other) { - var a = this; - var b = other; - - // In loose equality, null is equivalent to undefined - if (a instanceof VoidValue || b instanceof VoidValue) return a instanceof VoidValue && b instanceof VoidValue; - - // If both are objects, just compare their references - if (!a.isPrimitive() && !b.isPrimitive()) return a.strictEquals(env, b); - - // Convert values to primitives - a = a.toPrimitive(env); - b = b.toPrimitive(env); - - // Compare symbols by reference - if (a instanceof SymbolValue || b instanceof SymbolValue) return a.strictEquals(env, b); - // Compare booleans as numbers - if (a instanceof BoolValue || b instanceof BoolValue) return a.toNumber(env).strictEquals(env, b.toNumber(env)); - // Comparse numbers as numbers - if (a instanceof NumberValue || b instanceof NumberValue) return a.toNumber(env).strictEquals(env, b.toNumber(env)); - - // Default to strings - return a.toString(env).strictEquals(env, b.toString(env)); - } - public Iterable toIterable(Environment env) { return () -> { if (!(this instanceof FunctionValue)) return Collections.emptyIterator(); @@ -541,19 +416,6 @@ public abstract class Value { }; } - public static FunctionValue fromIterator(Environment ext, Iterable iterable) { - var it = iterable.iterator(); - - return new NativeFunction("", args -> { - var obj = new ObjectValue(); - - if (!it.hasNext()) obj.defineOwnMember(args.env, "done", FieldMember.of(BoolValue.TRUE)); - else obj.defineOwnMember(args.env, "value", FieldMember.of(it.next())); - - return obj; - }); - } - public void callWith(Environment env, Iterable it) { for (var el : it) { this.call(env, Value.UNDEFINED, el); @@ -656,6 +518,153 @@ public abstract class Value { return toReadable(ext, new HashSet<>(), 0); } + public static final ObjectValue global(Environment env) { + return env.initFrom(GLOBAL, () -> new ObjectValue()); + } + public static final Map intrinsics(Environment env) { + return env.initFrom(INTRINSICS, () -> new HashMap<>()); + } + + public static FunctionValue fromIterator(Environment ext, Iterable iterable) { + var it = iterable.iterator(); + + return new NativeFunction("", args -> { + var obj = new ObjectValue(); + + if (!it.hasNext()) obj.defineOwnMember(args.env, "done", FieldMember.of(BoolValue.TRUE)); + else obj.defineOwnMember(args.env, "value", FieldMember.of(it.next())); + + return obj; + }); + } + + public static final boolean lessOrEqual(Environment env, Value a, Value b) { + a = a.toPrimitive(env); + b = b.toPrimitive(env); + + if (a instanceof StringValue aStr && b instanceof StringValue bStr) { + return aStr.value.compareTo(bStr.value) <= 0; + } + else { + return a.toNumber(env).value <= b.toNumber(env).value; + } + } + public static final boolean greaterOrEqual(Environment env, Value a, Value b) { + a = a.toPrimitive(env); + b = b.toPrimitive(env); + + if (a instanceof StringValue aStr && b instanceof StringValue bStr) { + return aStr.value.compareTo(bStr.value) >= 0; + } + else { + return a.toNumber(env).value >= b.toNumber(env).value; + } + } + public static final boolean less(Environment env, Value a, Value b) { + a = a.toPrimitive(env); + b = b.toPrimitive(env); + + if (a instanceof StringValue aStr && b instanceof StringValue bStr) { + return aStr.value.compareTo(bStr.value) >= 0; + } + else { + return a.toNumber(env).value < b.toNumber(env).value; + } + } + public static final boolean greater(Environment env, Value a, Value b) { + a = a.toPrimitive(env); + b = b.toPrimitive(env); + + if (a instanceof StringValue aStr && b instanceof StringValue bStr) { + return aStr.value.compareTo(bStr.value) >= 0; + } + else { + return a.toNumber(env).value > b.toNumber(env).value; + } + } + + public static final Value add(Environment env, Value a, Value b) { + a = a.toPrimitive(env); + b = b.toPrimitive(env); + + if (a instanceof StringValue || b instanceof StringValue) { + return new StringValue(a.toString(env).value + b.toString(env).value); + } + else { + return new NumberValue(a.toNumber(env).value + b.toNumber(env).value); + } + } + + public static final NumberValue subtract(Environment env, Value a, Value b) { + return new NumberValue(a.toNumber(env).value - b.toNumber(env).value); + } + public static final NumberValue multiply(Environment env, Value a, Value b) { + return new NumberValue(a.toNumber(env).value - b.toNumber(env).value); + } + public static final NumberValue divide(Environment env, Value a, Value b) { + return new NumberValue(a.toNumber(env).value / b.toNumber(env).value); + } + public static final NumberValue modulo(Environment env, Value a, Value b) { + return new NumberValue(a.toNumber(env).value % b.toNumber(env).value); + } + public static final NumberValue negative(Environment env, Value a) { + return new NumberValue(-a.toNumber(env).value); + } + + public static final NumberValue and(Environment env, Value a, Value b) { + return new NumberValue(a.toInt(env) & b.toInt(env)); + } + public static final NumberValue or(Environment env, Value a, Value b) { + return new NumberValue(a.toInt(env) | b.toInt(env)); + } + public static final NumberValue xor(Environment env, Value a, Value b) { + return new NumberValue(a.toInt(env) ^ b.toInt(env)); + } + public static final NumberValue bitwiseNot(Environment env, Value a) { + return new NumberValue(~a.toInt(env)); + } + + public static final NumberValue shiftLeft(Environment env, Value a, Value b) { + return new NumberValue(a.toInt(env) << b.toInt(env)); + } + public static final NumberValue shiftRight(Environment env, Value a, Value b) { + return new NumberValue(a.toInt(env) >> b.toInt(env)); + } + public static final NumberValue unsignedShiftRight(Environment env, Value a, Value b) { + long _a = a.toInt(env); + long _b = b.toInt(env); + + if (_a < 0) _a += 0x100000000l; + if (_b < 0) _b += 0x100000000l; + + return new NumberValue(_a >>> _b); + } + + public static final boolean looseEqual(Environment env, Value a, Value b) { + // In loose equality, null is equivalent to undefined + if (a instanceof VoidValue || b instanceof VoidValue) return a instanceof VoidValue && b instanceof VoidValue; + + // If both are objects, just compare their references + if (!a.isPrimitive() && !b.isPrimitive()) return a.equals(b); + + // Convert values to primitives + a = a.toPrimitive(env); + b = b.toPrimitive(env); + + // Compare symbols by reference + if (a instanceof SymbolValue || b instanceof SymbolValue) return a.equals(b); + // Compare booleans as numbers + if (a instanceof BoolValue || b instanceof BoolValue) return a.toNumber(env).equals(b.toNumber(env)); + // Comparse numbers as numbers + if (a instanceof NumberValue || b instanceof NumberValue) return a.toNumber(env).equals(b.toNumber(env)); + + // Default to strings + return a.toString(env).equals(b.toString(env)); + } + + // public static Value operation(Environment env, Operation op, Value ...args) { + // } + public static final String errorToReadable(RuntimeException err, String prefix) { prefix = prefix == null ? "Uncaught" : "Uncaught " + prefix; if (err instanceof EngineException) { @@ -678,11 +687,4 @@ public abstract class Value { return prefix + " internal error " + str.toString(); } } - - public static final ObjectValue global(Environment env) { - return env.initFrom(GLOBAL, () -> new ObjectValue()); - } - public static final Map intrinsics(Environment env) { - return env.initFrom(INTRINSICS, () -> new HashMap<>()); - } } diff --git a/src/java/me/topchetoeu/jscript/runtime/values/functions/CodeFunction.java b/src/java/me/topchetoeu/jscript/runtime/values/functions/CodeFunction.java index ca23b3d..335dcdf 100644 --- a/src/java/me/topchetoeu/jscript/runtime/values/functions/CodeFunction.java +++ b/src/java/me/topchetoeu/jscript/runtime/values/functions/CodeFunction.java @@ -10,13 +10,12 @@ public final class CodeFunction extends FunctionValue { public final Value[][] captures; public Environment env; - @Override public Value onCall(Environment env, boolean isNew, String name, Value thisArg, Value ...args) { - var frame = new Frame(env, isNew, thisArg, args, this); + private Value onCall(Frame frame) { frame.onPush(); try { while (true) { - var res = frame.next(); + var res = frame.next(null, null, null); if (res != null) return res; } } @@ -25,6 +24,11 @@ public final class CodeFunction extends FunctionValue { } } + @Override public Value onCall(Environment env, boolean isNew, String name, Value thisArg, Value ...args) { + var frame = new Frame(env, isNew, thisArg, args, this); + return onCall(frame); + } + public CodeFunction(Environment env, String name, FunctionBody body, Value[][] captures) { super(name, body.argsN); this.captures = captures; diff --git a/src/java/me/topchetoeu/jscript/runtime/values/objects/ObjectValue.java b/src/java/me/topchetoeu/jscript/runtime/values/objects/ObjectValue.java index f1c81b8..da5cba4 100644 --- a/src/java/me/topchetoeu/jscript/runtime/values/objects/ObjectValue.java +++ b/src/java/me/topchetoeu/jscript/runtime/values/objects/ObjectValue.java @@ -70,8 +70,6 @@ public class ObjectValue extends Value { @Override public NumberValue toNumber(Environment env) { return toPrimitive(env).toNumber(env); } @Override public StringValue type() { return typeString; } - @Override public boolean strictEquals(Environment ext, Value other) { return this == other; } - public final void preventExtensions() { extensible = false; } diff --git a/src/java/me/topchetoeu/jscript/runtime/values/primitives/BoolValue.java b/src/java/me/topchetoeu/jscript/runtime/values/primitives/BoolValue.java index a869252..4b567db 100644 --- a/src/java/me/topchetoeu/jscript/runtime/values/primitives/BoolValue.java +++ b/src/java/me/topchetoeu/jscript/runtime/values/primitives/BoolValue.java @@ -1,7 +1,6 @@ package me.topchetoeu.jscript.runtime.values.primitives; import me.topchetoeu.jscript.common.environment.Environment; -import me.topchetoeu.jscript.runtime.values.Value; import me.topchetoeu.jscript.runtime.values.objects.ObjectValue; public final class BoolValue extends PrimitiveValue { @@ -23,8 +22,8 @@ public final class BoolValue extends PrimitiveValue { return env.get(BOOL_PROTO); } - @Override public boolean strictEquals(Environment ext, Value other) { - if (other instanceof BoolValue) return value == ((BoolValue)other).value; + @Override public boolean equals(Object other) { + if (other instanceof BoolValue bool) return value == bool.value; else return false; } diff --git a/src/java/me/topchetoeu/jscript/runtime/values/primitives/NumberValue.java b/src/java/me/topchetoeu/jscript/runtime/values/primitives/NumberValue.java index 09c2029..2fe9265 100644 --- a/src/java/me/topchetoeu/jscript/runtime/values/primitives/NumberValue.java +++ b/src/java/me/topchetoeu/jscript/runtime/values/primitives/NumberValue.java @@ -5,7 +5,6 @@ import me.topchetoeu.jscript.common.json.JSON; import me.topchetoeu.jscript.common.json.JSONElement; import me.topchetoeu.jscript.common.parsing.Parsing; import me.topchetoeu.jscript.common.parsing.Source; -import me.topchetoeu.jscript.runtime.values.Value; import me.topchetoeu.jscript.runtime.values.objects.ObjectValue; public final class NumberValue extends PrimitiveValue { @@ -25,13 +24,8 @@ public final class NumberValue extends PrimitiveValue { return env.get(NUMBER_PROTO); } - @Override public CompareResult compare(Environment env, Value other) { - if (other instanceof NumberValue) return CompareResult.from(Double.compare(value, ((NumberValue)other).value)); - else return super.compare(env, other); - } - @Override public boolean strictEquals(Environment ext, Value other) { - other = other.toPrimitive(ext); - if (other instanceof NumberValue) return value == ((NumberValue)other).value; + @Override public boolean equals(Object other) { + if (other instanceof NumberValue val) return value == val.value; else return false; } diff --git a/src/java/me/topchetoeu/jscript/runtime/values/primitives/StringValue.java b/src/java/me/topchetoeu/jscript/runtime/values/primitives/StringValue.java index ec87847..8df3f52 100644 --- a/src/java/me/topchetoeu/jscript/runtime/values/primitives/StringValue.java +++ b/src/java/me/topchetoeu/jscript/runtime/values/primitives/StringValue.java @@ -1,13 +1,11 @@ package me.topchetoeu.jscript.runtime.values.primitives; import java.util.Map; -import java.util.Objects; import me.topchetoeu.jscript.common.environment.Environment; import me.topchetoeu.jscript.common.parsing.Parsing; import me.topchetoeu.jscript.common.parsing.Source; import me.topchetoeu.jscript.runtime.values.Member; -import me.topchetoeu.jscript.runtime.values.Value; import me.topchetoeu.jscript.runtime.values.objects.ObjectValue; public final class StringValue extends PrimitiveValue { @@ -27,17 +25,11 @@ public final class StringValue extends PrimitiveValue { } @Override public StringValue toString(Environment ext) { return this; } - @Override public Value add(Environment ext, Value other) { - return new StringValue(value + other.toString(ext).value); + @Override public boolean equals(Object other) { + if (other instanceof StringValue val) return value.length() == val.value.length() && value.equals(val.value); + else return false; } - @Override public CompareResult compare(Environment env, Value other) { - if (other instanceof StringValue) return CompareResult.from(value.compareTo(((StringValue)other).value)); - else return super.compare(env, other); - } - @Override public boolean strictEquals(Environment ext, Value other) { - return (other instanceof StringValue) && Objects.equals(((StringValue)other).value, value); - } @Override public ObjectValue getPrototype(Environment env) { return env.get(STRING_PROTO); } @Override public Map getOwnMembers(Environment env) { diff --git a/src/java/me/topchetoeu/jscript/runtime/values/primitives/SymbolValue.java b/src/java/me/topchetoeu/jscript/runtime/values/primitives/SymbolValue.java index f6cabf8..e5baeb4 100644 --- a/src/java/me/topchetoeu/jscript/runtime/values/primitives/SymbolValue.java +++ b/src/java/me/topchetoeu/jscript/runtime/values/primitives/SymbolValue.java @@ -27,9 +27,6 @@ public final class SymbolValue extends PrimitiveValue { throw EngineException.ofType("Cannot convert a Symbol value to a number"); } - @Override public boolean strictEquals(Environment ext, Value other) { - return other == this; - } @Override public ObjectValue getPrototype(Environment env) { return env.get(SYMBOL_PROTO); } @Override public String toString() { diff --git a/src/java/me/topchetoeu/jscript/runtime/values/primitives/VoidValue.java b/src/java/me/topchetoeu/jscript/runtime/values/primitives/VoidValue.java index 5c37052..9e0539d 100644 --- a/src/java/me/topchetoeu/jscript/runtime/values/primitives/VoidValue.java +++ b/src/java/me/topchetoeu/jscript/runtime/values/primitives/VoidValue.java @@ -6,7 +6,6 @@ import me.topchetoeu.jscript.common.environment.Environment; import me.topchetoeu.jscript.runtime.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.KeyCache; import me.topchetoeu.jscript.runtime.values.Member; -import me.topchetoeu.jscript.runtime.values.Value; import me.topchetoeu.jscript.runtime.values.objects.ObjectValue; public final class VoidValue extends PrimitiveValue { @@ -20,16 +19,6 @@ public final class VoidValue extends PrimitiveValue { @Override public NumberValue toNumber(Environment ext) { return NumberValue.NAN; } @Override public StringValue toString(Environment ext) { return nameString; } - @Override public Value add(Environment ext, Value other) { - if (!other.isPrimitive()) other = other.toPrimitive(ext); - - if (other instanceof StringValue) return nameString.add(ext, other); - else return NumberValue.NAN; - } - - @Override public boolean strictEquals(Environment ext, Value other) { - return this == other; - } @Override public ObjectValue getPrototype(Environment env) { return null; } @Override public Member getOwnMember(Environment env, KeyCache key) {