feat: implement hidden integers
This commit is contained in:
parent
e11d182631
commit
e9f889576c
@ -14,8 +14,8 @@ import me.topchetoeu.jscript.runtime.values.functions.FunctionValue;
|
||||
import me.topchetoeu.jscript.runtime.values.objects.ArrayValue;
|
||||
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.BoolValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.NumberValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.StringValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
|
||||
|
||||
public class InstructionRunner {
|
||||
private static Value execReturn(Environment env, Instruction instr, Frame frame) {
|
||||
@ -136,7 +136,7 @@ public class InstructionRunner {
|
||||
case PUSH_UNDEFINED: frame.push(Value.UNDEFINED); break;
|
||||
case PUSH_NULL: frame.push(Value.NULL); break;
|
||||
case PUSH_BOOL: frame.push(BoolValue.of(instr.get(0))); break;
|
||||
case PUSH_NUMBER: frame.push(new NumberValue(instr.get(0))); break;
|
||||
case PUSH_NUMBER: frame.push(NumberValue.of((double)instr.get(0))); break;
|
||||
case PUSH_STRING: frame.push(new StringValue(instr.get(0))); break;
|
||||
default:
|
||||
}
|
||||
|
@ -12,15 +12,15 @@ import me.topchetoeu.jscript.runtime.values.Value;
|
||||
import me.topchetoeu.jscript.runtime.values.objects.ArrayValue;
|
||||
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.BoolValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.NumberValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.StringValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.VoidValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
|
||||
|
||||
public class JSONConverter {
|
||||
public static Value toJs(JSONElement val) {
|
||||
if (val.isBoolean()) return BoolValue.of(val.bool());
|
||||
if (val.isString()) return new StringValue(val.string());
|
||||
if (val.isNumber()) return new NumberValue(val.number());
|
||||
if (val.isNumber()) return NumberValue.of(val.number());
|
||||
if (val.isList()) return ArrayValue.of(val.list().stream().map(JSONConverter::toJs).collect(Collectors.toList()));
|
||||
if (val.isMap()) {
|
||||
var res = new ObjectValue();
|
||||
@ -43,7 +43,7 @@ public class JSONConverter {
|
||||
|
||||
public static JSONElement fromJs(Environment env, Value val, HashSet<Object> prev) {
|
||||
if (val instanceof BoolValue) return JSONElement.bool(((BoolValue)val).value);
|
||||
if (val instanceof NumberValue) return JSONElement.number(((NumberValue)val).value);
|
||||
if (val instanceof NumberValue) return JSONElement.number(((NumberValue)val).getDouble());
|
||||
if (val instanceof StringValue) return JSONElement.string(((StringValue)val).value);
|
||||
if (val == Value.NULL) return JSONElement.NULL;
|
||||
if (val instanceof VoidValue) return null;
|
||||
|
@ -22,10 +22,10 @@ import me.topchetoeu.jscript.runtime.values.functions.NativeFunction;
|
||||
import me.topchetoeu.jscript.runtime.values.objects.ArrayValue;
|
||||
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.BoolValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.NumberValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.StringValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.SymbolValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.VoidValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
|
||||
|
||||
public class SimpleRepl {
|
||||
static Thread engineTask;
|
||||
@ -94,8 +94,8 @@ public class SimpleRepl {
|
||||
var res = new ObjectValue();
|
||||
res.setPrototype(null, null);
|
||||
|
||||
res.defineOwnMember(env, "makeSymbol", new NativeFunction(args -> new SymbolValue(args.get(0).toString(args.env).value)));
|
||||
res.defineOwnMember(env, "getSymbol", new NativeFunction(args -> SymbolValue.get(args.get(0).toString(args.env).value)));
|
||||
res.defineOwnMember(env, "makeSymbol", new NativeFunction(args -> new SymbolValue(args.get(0).toString(args.env))));
|
||||
res.defineOwnMember(env, "getSymbol", new NativeFunction(args -> SymbolValue.get(args.get(0).toString(args.env))));
|
||||
res.defineOwnMember(env, "getSymbolKey", new NativeFunction(args -> ((SymbolValue)args.get(0)).key()));
|
||||
res.defineOwnMember(env, "getSymbolDescriptor", new NativeFunction(args -> new StringValue(((SymbolValue)args.get(0)).value)));
|
||||
|
||||
@ -107,14 +107,14 @@ public class SimpleRepl {
|
||||
res.setPrototype(null, null);
|
||||
|
||||
res.defineOwnMember(env, "parseInt", new NativeFunction(args -> {
|
||||
var radix = args.get(1).toInt(env);
|
||||
var nradix = args.get(1).toNumber(env);
|
||||
var radix = nradix.isInt() ? nradix.getInt() : 10;
|
||||
|
||||
if (radix != 10 && args.get(0) instanceof NumberValue) {
|
||||
return new NumberValue(args.get(0).toNumber(env).value - args.get(0).toNumber(env).value % 1);
|
||||
}
|
||||
else {
|
||||
return NumberValue.parseInt(args.get(0).toString(), radix, false);
|
||||
if (radix != 10 && args.get(0) instanceof NumberValue num) {
|
||||
if (num.isInt()) return num;
|
||||
else return NumberValue.of(num.getDouble() - num.getDouble() % 1);
|
||||
}
|
||||
else return NumberValue.parseInt(args.get(0).toString(), radix, false);
|
||||
}));
|
||||
res.defineOwnMember(env, "parseFloat", new NativeFunction(args -> {
|
||||
if (args.get(0) instanceof NumberValue) {
|
||||
@ -123,8 +123,8 @@ public class SimpleRepl {
|
||||
else return NumberValue.parseFloat(args.get(0).toString(), false);
|
||||
}));
|
||||
res.defineOwnMember(env, "isNaN", new NativeFunction(args -> BoolValue.of(args.get(0).isNaN())));
|
||||
res.defineOwnMember(env, "NaN", new NumberValue(Double.NaN));
|
||||
res.defineOwnMember(env, "Infinity", new NumberValue(Double.POSITIVE_INFINITY));
|
||||
res.defineOwnMember(env, "NaN", NumberValue.NAN);
|
||||
res.defineOwnMember(env, "Infinity", NumberValue.of(Double.POSITIVE_INFINITY));
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -229,14 +229,14 @@ public class SimpleRepl {
|
||||
var func = (FunctionValue)args.get(0);
|
||||
var self = args.get(1);
|
||||
var funcArgs = (ArrayValue)args.get(2);
|
||||
var name = args.get(3).toString(env).value;
|
||||
var name = args.get(3).toString(env);
|
||||
|
||||
return func.invoke(env, name, self, funcArgs.toArray());
|
||||
}));
|
||||
res.defineOwnMember(env, "construct", new NativeFunction(args -> {
|
||||
var func = (FunctionValue)args.get(0);
|
||||
var funcArgs = (ArrayValue)args.get(1);
|
||||
var name = args.get(2).toString(env).value;
|
||||
var name = args.get(2).toString(env);
|
||||
|
||||
return func.construct(env, name, funcArgs.toArray());
|
||||
}));
|
||||
@ -252,7 +252,7 @@ public class SimpleRepl {
|
||||
return new StringValue(JSON.stringify(JSONConverter.fromJs(env, args.get(0))));
|
||||
}));
|
||||
res.defineOwnMember(env, "parse", new NativeFunction(args -> {
|
||||
return JSONConverter.toJs(JSON.parse(null, args.get(0).toString(env).value));
|
||||
return JSONConverter.toJs(JSON.parse(null, args.get(0).toString(env)));
|
||||
}));
|
||||
res.defineOwnMember(env, "setConstructable", new NativeFunction(args -> {
|
||||
var func = (FunctionValue)args.get(0);
|
||||
@ -288,7 +288,7 @@ public class SimpleRepl {
|
||||
int[] i = new int[1];
|
||||
|
||||
res.defineOwnMember(env, "setGlobalPrototype", new NativeFunction(args -> {
|
||||
var type = args.get(0).toString(env).value;
|
||||
var type = args.get(0).toString(env);
|
||||
var obj = (ObjectValue)args.get(1);
|
||||
|
||||
switch (type) {
|
||||
@ -330,7 +330,7 @@ public class SimpleRepl {
|
||||
return Value.UNDEFINED;
|
||||
}));
|
||||
res.defineOwnMember(env, "setIntrinsic", new NativeFunction(args -> {
|
||||
var name = args.get(0).toString(env).value;
|
||||
var name = args.get(0).toString(env);
|
||||
var val = args.get(1);
|
||||
|
||||
Value.intrinsics(environment).put(name, val);
|
||||
@ -338,7 +338,7 @@ public class SimpleRepl {
|
||||
return Value.UNDEFINED;
|
||||
}));
|
||||
res.defineOwnMember(env, "compile", new NativeFunction(args -> {
|
||||
return Compiler.compileFunc(env, new Filename("jscript", "func" + i[0]++ + ".js"), args.get(0).toString(env).value);
|
||||
return Compiler.compileFunc(env, new Filename("jscript", "func" + i[0]++ + ".js"), args.get(0).toString(env));
|
||||
}));
|
||||
|
||||
return res;
|
||||
|
@ -66,7 +66,7 @@ public class EngineException extends RuntimeException {
|
||||
public String toString(Environment env) {
|
||||
var ss = new StringBuilder();
|
||||
try {
|
||||
ss.append(value.toString(env).value).append('\n');
|
||||
ss.append(value.toString(env)).append('\n');
|
||||
}
|
||||
catch (EngineException e) {
|
||||
var name = value.getMember(env, "name");
|
||||
@ -74,10 +74,10 @@ public class EngineException extends RuntimeException {
|
||||
|
||||
if (name.isPrimitive() && desc.isPrimitive()) {
|
||||
if (name instanceof VoidValue) ss.append("Error: ");
|
||||
else ss.append(name.toString(env).value + ": ");
|
||||
else ss.append(name.toString(env) + ": ");
|
||||
|
||||
if (desc instanceof VoidValue) ss.append("An error occurred");
|
||||
else ss.append(desc.toString(env).value);
|
||||
else ss.append(desc.toString(env));
|
||||
|
||||
ss.append("\n");
|
||||
}
|
||||
|
@ -1,28 +1,39 @@
|
||||
package me.topchetoeu.jscript.runtime.values;
|
||||
|
||||
import me.topchetoeu.jscript.common.environment.Environment;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.NumberValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.StringValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.SymbolValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
|
||||
|
||||
public final class KeyCache {
|
||||
public final Value value;
|
||||
private Integer intCache;
|
||||
private boolean isInt;
|
||||
private int intCache;
|
||||
private Double doubleCache;
|
||||
private Boolean booleanCache;
|
||||
private String stringCache;
|
||||
|
||||
public String toString(Environment env) {
|
||||
if (stringCache != null) return stringCache;
|
||||
else return stringCache = value.toString(env).value;
|
||||
else return stringCache = value.toString(env);
|
||||
}
|
||||
public double toNumber(Environment env) {
|
||||
if (doubleCache != null) return doubleCache;
|
||||
else return doubleCache = value.toNumber(env).value;
|
||||
if (doubleCache == null) {
|
||||
var res = value.toNumber(env);
|
||||
isInt = res.isInt();
|
||||
intCache = res.getInt();
|
||||
doubleCache = res.getDouble();
|
||||
}
|
||||
|
||||
return doubleCache;
|
||||
}
|
||||
public boolean isInt(Environment env) {
|
||||
if (doubleCache == null) toNumber(env);
|
||||
return isInt;
|
||||
}
|
||||
public int toInt(Environment env) {
|
||||
if (intCache != null) return intCache;
|
||||
else return intCache = (int)toNumber(env);
|
||||
if (doubleCache == null) toNumber(env);
|
||||
return intCache;
|
||||
}
|
||||
public boolean toBoolean() {
|
||||
if (booleanCache != null) return booleanCache;
|
||||
@ -45,13 +56,13 @@ public final class KeyCache {
|
||||
this.booleanCache = !value.equals("");
|
||||
}
|
||||
public KeyCache(int value) {
|
||||
this.value = new NumberValue(value);
|
||||
this.value = NumberValue.of(value);
|
||||
this.intCache = value;
|
||||
this.doubleCache = (double)value;
|
||||
this.booleanCache = value != 0;
|
||||
}
|
||||
public KeyCache(double value) {
|
||||
this.value = new NumberValue(value);
|
||||
this.value = NumberValue.of(value);
|
||||
this.intCache = (int)value;
|
||||
this.doubleCache = value;
|
||||
this.booleanCache = value != 0;
|
||||
|
@ -26,10 +26,10 @@ import me.topchetoeu.jscript.runtime.values.functions.NativeFunction;
|
||||
import me.topchetoeu.jscript.runtime.values.objects.ArrayValue;
|
||||
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.BoolValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.NumberValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.StringValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.SymbolValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.VoidValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
|
||||
|
||||
public abstract class Value {
|
||||
public static enum State {
|
||||
@ -81,7 +81,7 @@ public abstract class Value {
|
||||
public abstract boolean isPrimitive();
|
||||
|
||||
public final boolean isNaN() {
|
||||
return this instanceof NumberValue && Double.isNaN(((NumberValue)this).value);
|
||||
return this == NumberValue.NAN || this instanceof NumberValue num && Double.isNaN(num.getDouble());
|
||||
}
|
||||
|
||||
public Value call(Environment env, boolean isNew, String name, Value self, Value ...args) {
|
||||
@ -116,12 +116,9 @@ public abstract class Value {
|
||||
|
||||
public abstract Value toPrimitive(Environment env);
|
||||
public abstract NumberValue toNumber(Environment env);
|
||||
public abstract StringValue toString(Environment env);
|
||||
public abstract String toString(Environment env);
|
||||
public abstract boolean toBoolean();
|
||||
|
||||
public final int toInt(Environment env) { return (int)toNumber(env).value; }
|
||||
public final long toLong(Environment env) { return (long)toNumber(env).value; }
|
||||
|
||||
public final boolean isInstanceOf(Environment env, Value proto) {
|
||||
for (var val = getPrototype(env); val != null; val = getPrototype(env)) {
|
||||
if (val.equals(proto)) return true;
|
||||
@ -525,7 +522,7 @@ public abstract class Value {
|
||||
else if (this instanceof VoidValue) return ((VoidValue)this).name;
|
||||
else if (this instanceof StringValue) return JSON.stringify(JSONElement.string(((StringValue)this).value));
|
||||
else if (this instanceof SymbolValue) return this.toString();
|
||||
else return this.toString(env).value;
|
||||
else return this.toString(env);
|
||||
}
|
||||
|
||||
public final String toReadable(Environment ext) {
|
||||
@ -560,7 +557,11 @@ public abstract class Value {
|
||||
return aStr.value.compareTo(bStr.value) <= 0;
|
||||
}
|
||||
else {
|
||||
return a.toNumber(env).value <= b.toNumber(env).value;
|
||||
var na = a.toNumber(env);
|
||||
var nb = b.toNumber(env);
|
||||
|
||||
if (na.isLong() && nb.isLong()) return na.getLong() <= nb.getLong();
|
||||
else return na.getDouble() <= nb.getDouble();
|
||||
}
|
||||
}
|
||||
public static final boolean greaterOrEqual(Environment env, Value a, Value b) {
|
||||
@ -571,7 +572,11 @@ public abstract class Value {
|
||||
return aStr.value.compareTo(bStr.value) >= 0;
|
||||
}
|
||||
else {
|
||||
return a.toNumber(env).value >= b.toNumber(env).value;
|
||||
var na = a.toNumber(env);
|
||||
var nb = b.toNumber(env);
|
||||
|
||||
if (na.isLong() && nb.isLong()) return na.getLong() >= nb.getLong();
|
||||
else return na.getDouble() >= nb.getDouble();
|
||||
}
|
||||
}
|
||||
public static final boolean less(Environment env, Value a, Value b) {
|
||||
@ -579,10 +584,14 @@ public abstract class Value {
|
||||
b = b.toPrimitive(env);
|
||||
|
||||
if (a instanceof StringValue aStr && b instanceof StringValue bStr) {
|
||||
return aStr.value.compareTo(bStr.value) >= 0;
|
||||
return aStr.value.compareTo(bStr.value) < 0;
|
||||
}
|
||||
else {
|
||||
return a.toNumber(env).value < b.toNumber(env).value;
|
||||
var na = a.toNumber(env);
|
||||
var nb = b.toNumber(env);
|
||||
|
||||
if (na.isLong() && nb.isLong()) return na.getLong() < nb.getLong();
|
||||
else return na.getDouble() < nb.getDouble();
|
||||
}
|
||||
}
|
||||
public static final boolean greater(Environment env, Value a, Value b) {
|
||||
@ -590,10 +599,14 @@ public abstract class Value {
|
||||
b = b.toPrimitive(env);
|
||||
|
||||
if (a instanceof StringValue aStr && b instanceof StringValue bStr) {
|
||||
return aStr.value.compareTo(bStr.value) >= 0;
|
||||
return aStr.value.compareTo(bStr.value) > 0;
|
||||
}
|
||||
else {
|
||||
return a.toNumber(env).value > b.toNumber(env).value;
|
||||
var na = a.toNumber(env);
|
||||
var nb = b.toNumber(env);
|
||||
|
||||
if (na.isLong() && nb.isLong()) return na.getLong() > nb.getLong();
|
||||
else return na.getDouble() > nb.getDouble();
|
||||
}
|
||||
}
|
||||
|
||||
@ -602,56 +615,96 @@ public abstract class Value {
|
||||
b = b.toPrimitive(env);
|
||||
|
||||
if (a instanceof StringValue || b instanceof StringValue) {
|
||||
return new StringValue(a.toString(env).value + b.toString(env).value);
|
||||
return new StringValue(a.toString(env) + b.toString(env));
|
||||
}
|
||||
else {
|
||||
return new NumberValue(a.toNumber(env).value + b.toNumber(env).value);
|
||||
var na = a.toNumber(env);
|
||||
var nb = b.toNumber(env);
|
||||
|
||||
if (na.isInt() && nb.isInt()) return NumberValue.of(na.getInt() + nb.getInt());
|
||||
else return NumberValue.of(na.getDouble() + nb.getDouble());
|
||||
}
|
||||
}
|
||||
|
||||
public static final NumberValue subtract(Environment env, Value a, Value b) {
|
||||
return new NumberValue(a.toNumber(env).value - b.toNumber(env).value);
|
||||
var na = a.toNumber(env);
|
||||
var nb = b.toNumber(env);
|
||||
|
||||
if (na.isInt() && nb.isInt()) return NumberValue.of(na.getInt() - nb.getInt());
|
||||
else return NumberValue.of(na.getDouble() - nb.getDouble());
|
||||
}
|
||||
public static final NumberValue multiply(Environment env, Value a, Value b) {
|
||||
return new NumberValue(a.toNumber(env).value - b.toNumber(env).value);
|
||||
var na = a.toNumber(env);
|
||||
var nb = b.toNumber(env);
|
||||
|
||||
if (na.isInt() && nb.isInt()) return NumberValue.of(na.getInt() - nb.getInt());
|
||||
else return NumberValue.of(na.getDouble() - nb.getDouble());
|
||||
}
|
||||
public static final NumberValue divide(Environment env, Value a, Value b) {
|
||||
return new NumberValue(a.toNumber(env).value / b.toNumber(env).value);
|
||||
var na = a.toNumber(env);
|
||||
var nb = b.toNumber(env);
|
||||
|
||||
if (na.isInt() && nb.isInt()) {
|
||||
var ia = na.getInt();
|
||||
var ib = nb.getInt();
|
||||
|
||||
if (ib == 0) {
|
||||
if (ia == 0) return NumberValue.NAN;
|
||||
else if (ia > 0) return NumberValue.of(Double.POSITIVE_INFINITY);
|
||||
else return NumberValue.of(Double.NEGATIVE_INFINITY);
|
||||
}
|
||||
else if (ia % ib != 0) return NumberValue.of((double)ia / ib);
|
||||
else return NumberValue.of(ia / ib);
|
||||
}
|
||||
else return NumberValue.of(na.getDouble() / nb.getDouble());
|
||||
}
|
||||
public static final NumberValue modulo(Environment env, Value a, Value b) {
|
||||
return new NumberValue(a.toNumber(env).value % b.toNumber(env).value);
|
||||
var na = a.toNumber(env);
|
||||
var nb = b.toNumber(env);
|
||||
|
||||
if (na.isInt() && nb.isInt()) {
|
||||
var ia = na.getInt();
|
||||
var ib = nb.getInt();
|
||||
|
||||
if (ib == 0) return NumberValue.NAN;
|
||||
else return NumberValue.of(ia % ib);
|
||||
}
|
||||
else return NumberValue.of(na.getDouble() % nb.getDouble());
|
||||
}
|
||||
public static final NumberValue negative(Environment env, Value a) {
|
||||
return new NumberValue(-a.toNumber(env).value);
|
||||
var na = a.toNumber(env);
|
||||
|
||||
if (na.isInt()) return NumberValue.of(-na.getInt());
|
||||
else return NumberValue.of(-na.getDouble());
|
||||
}
|
||||
|
||||
public static final NumberValue and(Environment env, Value a, Value b) {
|
||||
return new NumberValue(a.toInt(env) & b.toInt(env));
|
||||
return NumberValue.of(a.toNumber(env).getInt() & b.toNumber(env).getInt());
|
||||
}
|
||||
public static final NumberValue or(Environment env, Value a, Value b) {
|
||||
return new NumberValue(a.toInt(env) | b.toInt(env));
|
||||
return NumberValue.of(a.toNumber(env).getInt() | b.toNumber(env).getInt());
|
||||
}
|
||||
public static final NumberValue xor(Environment env, Value a, Value b) {
|
||||
return new NumberValue(a.toInt(env) ^ b.toInt(env));
|
||||
return NumberValue.of(a.toNumber(env).getInt() ^ b.toNumber(env).getInt());
|
||||
}
|
||||
public static final NumberValue bitwiseNot(Environment env, Value a) {
|
||||
return new NumberValue(~a.toInt(env));
|
||||
return NumberValue.of(~a.toNumber(env).getInt());
|
||||
}
|
||||
|
||||
public static final NumberValue shiftLeft(Environment env, Value a, Value b) {
|
||||
return new NumberValue(a.toInt(env) << b.toInt(env));
|
||||
return NumberValue.of(a.toNumber(env).getInt() << b.toNumber(env).getInt());
|
||||
}
|
||||
public static final NumberValue shiftRight(Environment env, Value a, Value b) {
|
||||
return new NumberValue(a.toInt(env) >> b.toInt(env));
|
||||
return NumberValue.of(a.toNumber(env).getInt() >> b.toNumber(env).getInt());
|
||||
}
|
||||
public static final NumberValue unsignedShiftRight(Environment env, Value a, Value b) {
|
||||
long _a = a.toInt(env);
|
||||
long _b = b.toInt(env);
|
||||
long _a = a.toNumber(env).getLong() & 0xFFFFFFFF;
|
||||
long _b = b.toNumber(env).getLong() & 0xFFFFFFFF;
|
||||
|
||||
if (_a < 0) _a += 0x100000000l;
|
||||
if (_b < 0) _b += 0x100000000l;
|
||||
|
||||
return new NumberValue(_a >>> _b);
|
||||
return NumberValue.of(_a >>> _b);
|
||||
}
|
||||
|
||||
public static final boolean looseEqual(Environment env, Value a, Value b) {
|
||||
|
@ -6,8 +6,8 @@ import me.topchetoeu.jscript.runtime.values.Member;
|
||||
import me.topchetoeu.jscript.runtime.values.Value;
|
||||
import me.topchetoeu.jscript.runtime.values.Member.FieldMember;
|
||||
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.NumberValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.StringValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
|
||||
|
||||
public abstract class FunctionValue extends ObjectValue {
|
||||
private static final StringValue typeString = new StringValue("function");
|
||||
@ -25,13 +25,13 @@ public abstract class FunctionValue extends ObjectValue {
|
||||
return new StringValue(name);
|
||||
}
|
||||
@Override public boolean set(Environment env, Value val, Value self) {
|
||||
name = val.toString(env).value;
|
||||
name = val.toString(env);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
private final FieldMember lengthField = new FieldMember(this, true, false, false) {
|
||||
@Override public Value get(Environment env, Value self) {
|
||||
return new NumberValue(length);
|
||||
return NumberValue.of(length);
|
||||
}
|
||||
@Override public boolean set(Environment env, Value val, Value self) {
|
||||
return false;
|
||||
|
@ -4,11 +4,12 @@ import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
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.Member.FieldMember;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
|
||||
import me.topchetoeu.jscript.runtime.values.Value;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.NumberValue;
|
||||
|
||||
public abstract class ArrayLikeValue extends ObjectValue {
|
||||
private static class IndexField extends FieldMember {
|
||||
@ -30,10 +31,16 @@ public abstract class ArrayLikeValue extends ObjectValue {
|
||||
|
||||
private final FieldMember lengthField = new FieldMember(this, false, false, true) {
|
||||
@Override public Value get(Environment env, Value self) {
|
||||
return new NumberValue(size());
|
||||
return NumberValue.of(size());
|
||||
}
|
||||
@Override public boolean set(Environment env, Value val, Value self) {
|
||||
return setSize(val.toInt(env));
|
||||
var num = val.toNumber(env);
|
||||
if (!num.isInt()) throw EngineException.ofRange("Invalid array length");
|
||||
|
||||
var i = num.getInt();
|
||||
if (i < 0) throw EngineException.ofRange("Invalid array length");
|
||||
|
||||
return setSize(i);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -5,7 +5,7 @@ import java.util.Iterator;
|
||||
|
||||
import me.topchetoeu.jscript.common.environment.Environment;
|
||||
import me.topchetoeu.jscript.runtime.values.Value;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.NumberValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
|
||||
|
||||
// TODO: Make methods generic
|
||||
public class ByteBufferValue extends ArrayLikeValue implements Iterable<Value> {
|
||||
@ -26,11 +26,11 @@ public class ByteBufferValue extends ArrayLikeValue implements Iterable<Value> {
|
||||
|
||||
@Override public Value get(int i) {
|
||||
if (i < 0 || i >= values.length) return null;
|
||||
return new NumberValue(values[i]);
|
||||
return NumberValue.of(values[i]);
|
||||
}
|
||||
@Override public boolean set(Environment env, int i, Value val) {
|
||||
if (i < 0 || i >= values.length) return false;
|
||||
values[i] = (byte)val.toNumber(env).value;
|
||||
values[i] = (byte)val.toNumber(env).getInt();
|
||||
return true;
|
||||
}
|
||||
@Override public boolean has(int i) {
|
||||
|
@ -11,9 +11,9 @@ 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.functions.FunctionValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.NumberValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.StringValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.SymbolValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
|
||||
|
||||
public class ObjectValue extends Value {
|
||||
public static interface PrototypeProvider {
|
||||
@ -56,7 +56,7 @@ public class ObjectValue extends Value {
|
||||
|
||||
throw EngineException.ofType("Value couldn't be converted to a primitive.");
|
||||
}
|
||||
@Override public StringValue toString(Environment env) { return toPrimitive(env).toString(env); }
|
||||
@Override public String toString(Environment env) { return toPrimitive(env).toString(env); }
|
||||
@Override public boolean toBoolean() { return true; }
|
||||
@Override public NumberValue toNumber(Environment env) { return toPrimitive(env).toNumber(env); }
|
||||
@Override public StringValue type() { return typeString; }
|
||||
|
@ -2,6 +2,7 @@ package me.topchetoeu.jscript.runtime.values.primitives;
|
||||
|
||||
import me.topchetoeu.jscript.common.environment.Environment;
|
||||
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
|
||||
|
||||
public final class BoolValue extends PrimitiveValue {
|
||||
public static final BoolValue TRUE = new BoolValue(true);
|
||||
@ -13,10 +14,8 @@ public final class BoolValue extends PrimitiveValue {
|
||||
@Override public StringValue type() { return typeString; }
|
||||
|
||||
@Override public boolean toBoolean() { return value; }
|
||||
@Override public NumberValue toNumber(Environment ext) {
|
||||
return value ? new NumberValue(1) : new NumberValue(0);
|
||||
}
|
||||
@Override public StringValue toString(Environment ext) { return new StringValue(value ? "true" : "false"); }
|
||||
@Override public NumberValue toNumber(Environment ext) { return NumberValue.of(value ? 1 : 0); }
|
||||
@Override public String toString(Environment ext) { return value ? "true" : "false"; }
|
||||
|
||||
@Override public ObjectValue getPrototype(Environment env) {
|
||||
return env.get(BOOL_PROTO);
|
||||
|
@ -1,54 +0,0 @@
|
||||
package me.topchetoeu.jscript.runtime.values.primitives;
|
||||
|
||||
import me.topchetoeu.jscript.common.environment.Environment;
|
||||
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.objects.ObjectValue;
|
||||
|
||||
public final class NumberValue extends PrimitiveValue {
|
||||
public static final NumberValue NAN = new NumberValue(Double.NaN);
|
||||
private static final StringValue typeString = new StringValue("number");
|
||||
|
||||
public final double value;
|
||||
|
||||
@Override public StringValue type() { return typeString; }
|
||||
|
||||
@Override public boolean toBoolean() { return value != 0; }
|
||||
@Override public NumberValue toNumber(Environment ext) { return this; }
|
||||
@Override public StringValue toString(Environment ext) { return new StringValue(toString()); }
|
||||
@Override public String toString() { return JSON.stringify(JSONElement.number(value)); }
|
||||
|
||||
@Override public ObjectValue getPrototype(Environment env) {
|
||||
return env.get(NUMBER_PROTO);
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object other) {
|
||||
if (other instanceof NumberValue val) return value == val.value;
|
||||
else return false;
|
||||
}
|
||||
|
||||
public NumberValue(double value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static NumberValue parseInt(String str, int radix, boolean relaxed) {
|
||||
if (radix < 2 || radix > 36) return new NumberValue(Double.NaN);
|
||||
|
||||
str = str.trim();
|
||||
var res = Parsing.parseInt(new Source(str), 0, "0123456789abcdefghijklmnopqrstuvwxyz".substring(0, radix), true);
|
||||
if (res.isSuccess()) {
|
||||
if (relaxed || res.n == str.length()) return new NumberValue(res.result);
|
||||
}
|
||||
return new NumberValue(Double.NaN);
|
||||
}
|
||||
public static NumberValue parseFloat(String str, boolean relaxed) {
|
||||
str = str.trim();
|
||||
var res = Parsing.parseFloat(new Source(str), 0, true);
|
||||
if (res.isSuccess()) {
|
||||
if (relaxed || res.n == str.length()) return new NumberValue(res.result);
|
||||
}
|
||||
return new NumberValue(Double.NaN);
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ import me.topchetoeu.jscript.runtime.values.KeyCache;
|
||||
import me.topchetoeu.jscript.runtime.values.Member;
|
||||
import me.topchetoeu.jscript.runtime.values.Member.FieldMember;
|
||||
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
|
||||
|
||||
public final class StringValue extends PrimitiveValue {
|
||||
public final String value;
|
||||
@ -20,13 +21,13 @@ public final class StringValue extends PrimitiveValue {
|
||||
@Override public boolean toBoolean() { return !value.equals(""); }
|
||||
@Override public NumberValue toNumber(Environment ext) {
|
||||
var val = value.trim();
|
||||
if (val.equals("")) return new NumberValue(0);
|
||||
if (val.equals("")) return NumberValue.of(0);
|
||||
var res = Parsing.parseNumber(new Source(val), 0, true);
|
||||
|
||||
if (res.isSuccess() && res.n == val.length()) return new NumberValue(res.result);
|
||||
else return new NumberValue(Double.NaN);
|
||||
if (res.isSuccess() && res.n == val.length()) return NumberValue.of(res.result);
|
||||
else return NumberValue.NAN;
|
||||
}
|
||||
@Override public StringValue toString(Environment ext) { return this; }
|
||||
@Override public String toString(Environment ext) { return value; }
|
||||
|
||||
@Override public boolean equals(Object other) {
|
||||
if (other instanceof StringValue val) return value.length() == val.value.length() && value.equals(val.value);
|
||||
@ -43,7 +44,7 @@ public final class StringValue extends PrimitiveValue {
|
||||
return FieldMember.of(this, new StringValue(value.charAt(i) + ""), false, true, false);
|
||||
}
|
||||
else if (key.toString(env).equals("length")) {
|
||||
return FieldMember.of(this, new NumberValue(value.length()), false, false, false);
|
||||
return FieldMember.of(this, NumberValue.of(value.length()), false, false, false);
|
||||
}
|
||||
else return super.getOwnMember(env, key);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import me.topchetoeu.jscript.common.environment.Environment;
|
||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||
import me.topchetoeu.jscript.runtime.values.Value;
|
||||
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
|
||||
|
||||
public final class SymbolValue extends PrimitiveValue {
|
||||
private static final HashMap<String, SymbolValue> registry = new HashMap<>();
|
||||
@ -20,7 +21,7 @@ public final class SymbolValue extends PrimitiveValue {
|
||||
@Override public StringValue type() { return typeString; }
|
||||
|
||||
@Override public boolean toBoolean() { return false; }
|
||||
@Override public StringValue toString(Environment env) {
|
||||
@Override public String toString(Environment env) {
|
||||
throw EngineException.ofType("Cannot convert a Symbol value to a string");
|
||||
}
|
||||
@Override public NumberValue toNumber(Environment env) {
|
||||
|
@ -5,17 +5,16 @@ 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.objects.ObjectValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
|
||||
|
||||
public final class VoidValue extends PrimitiveValue {
|
||||
private final StringValue nameString;
|
||||
|
||||
public final String name;
|
||||
public final StringValue typeString;
|
||||
|
||||
@Override public StringValue type() { return typeString; }
|
||||
@Override public boolean toBoolean() { return false; }
|
||||
@Override public NumberValue toNumber(Environment ext) { return NumberValue.NAN; }
|
||||
@Override public StringValue toString(Environment ext) { return nameString; }
|
||||
@Override public String toString(Environment ext) { return name; }
|
||||
|
||||
@Override public ObjectValue getPrototype(Environment env) { return null; }
|
||||
|
||||
@ -26,6 +25,5 @@ public final class VoidValue extends PrimitiveValue {
|
||||
public VoidValue(String name, StringValue type) {
|
||||
this.name = name;
|
||||
this.typeString = type;
|
||||
this.nameString = new StringValue(name);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
package me.topchetoeu.jscript.runtime.values.primitives.numbers;
|
||||
|
||||
import me.topchetoeu.jscript.common.json.JSON;
|
||||
import me.topchetoeu.jscript.common.json.JSONElement;
|
||||
|
||||
public final class DoubleValue extends NumberValue {
|
||||
public final double value;
|
||||
|
||||
@Override public boolean isInt() {
|
||||
return (int)value == value;
|
||||
}
|
||||
@Override public boolean isLong() {
|
||||
return (long)value == value;
|
||||
}
|
||||
@Override public int getInt() {
|
||||
return (int)value;
|
||||
}
|
||||
@Override public long getLong() {
|
||||
return (long)value;
|
||||
}
|
||||
@Override public double getDouble() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override public String toString() { return JSON.stringify(JSONElement.number(value)); }
|
||||
|
||||
@Override public boolean equals(Object other) {
|
||||
if (other instanceof NumberValue val) return value == val.getDouble();
|
||||
else return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructs a double value directly. In almost all cases, you want to use NumberValue.of instead
|
||||
*/
|
||||
public DoubleValue(double value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package me.topchetoeu.jscript.runtime.values.primitives.numbers;
|
||||
|
||||
public final class IntValue extends NumberValue {
|
||||
public final long value;
|
||||
|
||||
@Override public boolean isInt() {
|
||||
return (value & 0xFFFFFFFF00000000l) == 0;
|
||||
}
|
||||
@Override public boolean isLong() {
|
||||
return true;
|
||||
}
|
||||
@Override public int getInt() {
|
||||
return (int)value;
|
||||
}
|
||||
@Override public long getLong() {
|
||||
return value;
|
||||
}
|
||||
@Override public double getDouble() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override public String toString() { return value + ""; }
|
||||
@Override public boolean equals(Object other) {
|
||||
if (other instanceof NumberValue val) return val.isLong() && value == val.getLong();
|
||||
else return false;
|
||||
}
|
||||
|
||||
public IntValue(long value) {
|
||||
this.value = value;
|
||||
}
|
||||
public IntValue(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package me.topchetoeu.jscript.runtime.values.primitives.numbers;
|
||||
|
||||
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.objects.ObjectValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.PrimitiveValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.StringValue;
|
||||
|
||||
public abstract class NumberValue extends PrimitiveValue {
|
||||
public static final NumberValue NAN = new DoubleValue(Double.NaN);
|
||||
private static final StringValue typeString = new StringValue("number");
|
||||
|
||||
@Override public final StringValue type() { return typeString; }
|
||||
|
||||
public abstract double getDouble();
|
||||
public abstract int getInt();
|
||||
public abstract long getLong();
|
||||
|
||||
public abstract boolean isLong();
|
||||
public abstract boolean isInt();
|
||||
|
||||
public abstract boolean equals(Object other);
|
||||
public abstract String toString();
|
||||
|
||||
|
||||
@Override public final boolean toBoolean() { return getDouble() != 0; }
|
||||
@Override public final NumberValue toNumber(Environment ext) { return this; }
|
||||
@Override public final String toString(Environment ext) { return toString(); }
|
||||
|
||||
@Override public final ObjectValue getPrototype(Environment env) {
|
||||
return env.get(NUMBER_PROTO);
|
||||
}
|
||||
|
||||
public static NumberValue parseInt(String str, int radix, boolean relaxed) {
|
||||
if (radix < 2 || radix > 36) return NumberValue.NAN;
|
||||
|
||||
str = str.trim();
|
||||
var res = Parsing.parseInt(new Source(str), 0, "0123456789abcdefghijklmnopqrstuvwxyz".substring(0, radix), true);
|
||||
if (res.isSuccess()) {
|
||||
if (relaxed || res.n == str.length()) return of(res.result);
|
||||
}
|
||||
return NumberValue.NAN;
|
||||
}
|
||||
public static NumberValue parseFloat(String str, boolean relaxed) {
|
||||
str = str.trim();
|
||||
var res = Parsing.parseFloat(new Source(str), 0, true);
|
||||
if (res.isSuccess()) {
|
||||
if (relaxed || res.n == str.length()) return of(res.result);
|
||||
}
|
||||
return NumberValue.NAN;
|
||||
}
|
||||
|
||||
public static NumberValue of(double value) {
|
||||
if (Double.isNaN(value)) return NAN;
|
||||
else if ((int)value == value) return new IntValue((int)value);
|
||||
else return new DoubleValue(value);
|
||||
}
|
||||
public static NumberValue of(long value) {
|
||||
return new IntValue(value);
|
||||
}
|
||||
public static NumberValue of(int value) {
|
||||
return new IntValue(value);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user