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.ArrayValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.primitives.BoolValue;
|
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.StringValue;
|
||||||
|
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
|
||||||
|
|
||||||
public class InstructionRunner {
|
public class InstructionRunner {
|
||||||
private static Value execReturn(Environment env, Instruction instr, Frame frame) {
|
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_UNDEFINED: frame.push(Value.UNDEFINED); break;
|
||||||
case PUSH_NULL: frame.push(Value.NULL); break;
|
case PUSH_NULL: frame.push(Value.NULL); break;
|
||||||
case PUSH_BOOL: frame.push(BoolValue.of(instr.get(0))); 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;
|
case PUSH_STRING: frame.push(new StringValue(instr.get(0))); break;
|
||||||
default:
|
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.ArrayValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.primitives.BoolValue;
|
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.StringValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.primitives.VoidValue;
|
import me.topchetoeu.jscript.runtime.values.primitives.VoidValue;
|
||||||
|
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
|
||||||
|
|
||||||
public class JSONConverter {
|
public class JSONConverter {
|
||||||
public static Value toJs(JSONElement val) {
|
public static Value toJs(JSONElement val) {
|
||||||
if (val.isBoolean()) return BoolValue.of(val.bool());
|
if (val.isBoolean()) return BoolValue.of(val.bool());
|
||||||
if (val.isString()) return new StringValue(val.string());
|
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.isList()) return ArrayValue.of(val.list().stream().map(JSONConverter::toJs).collect(Collectors.toList()));
|
||||||
if (val.isMap()) {
|
if (val.isMap()) {
|
||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
@ -43,7 +43,7 @@ public class JSONConverter {
|
|||||||
|
|
||||||
public static JSONElement fromJs(Environment env, Value val, HashSet<Object> prev) {
|
public static JSONElement fromJs(Environment env, Value val, HashSet<Object> prev) {
|
||||||
if (val instanceof BoolValue) return JSONElement.bool(((BoolValue)val).value);
|
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 instanceof StringValue) return JSONElement.string(((StringValue)val).value);
|
||||||
if (val == Value.NULL) return JSONElement.NULL;
|
if (val == Value.NULL) return JSONElement.NULL;
|
||||||
if (val instanceof VoidValue) return 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.ArrayValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.primitives.BoolValue;
|
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.StringValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.primitives.SymbolValue;
|
import me.topchetoeu.jscript.runtime.values.primitives.SymbolValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.primitives.VoidValue;
|
import me.topchetoeu.jscript.runtime.values.primitives.VoidValue;
|
||||||
|
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
|
||||||
|
|
||||||
public class SimpleRepl {
|
public class SimpleRepl {
|
||||||
static Thread engineTask;
|
static Thread engineTask;
|
||||||
@ -94,8 +94,8 @@ public class SimpleRepl {
|
|||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
res.setPrototype(null, null);
|
res.setPrototype(null, null);
|
||||||
|
|
||||||
res.defineOwnMember(env, "makeSymbol", new NativeFunction(args -> new SymbolValue(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).value)));
|
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, "getSymbolKey", new NativeFunction(args -> ((SymbolValue)args.get(0)).key()));
|
||||||
res.defineOwnMember(env, "getSymbolDescriptor", new NativeFunction(args -> new StringValue(((SymbolValue)args.get(0)).value)));
|
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.setPrototype(null, null);
|
||||||
|
|
||||||
res.defineOwnMember(env, "parseInt", new NativeFunction(args -> {
|
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) {
|
if (radix != 10 && args.get(0) instanceof NumberValue num) {
|
||||||
return new NumberValue(args.get(0).toNumber(env).value - args.get(0).toNumber(env).value % 1);
|
if (num.isInt()) return num;
|
||||||
}
|
else return NumberValue.of(num.getDouble() - num.getDouble() % 1);
|
||||||
else {
|
|
||||||
return NumberValue.parseInt(args.get(0).toString(), radix, false);
|
|
||||||
}
|
}
|
||||||
|
else return NumberValue.parseInt(args.get(0).toString(), radix, false);
|
||||||
}));
|
}));
|
||||||
res.defineOwnMember(env, "parseFloat", new NativeFunction(args -> {
|
res.defineOwnMember(env, "parseFloat", new NativeFunction(args -> {
|
||||||
if (args.get(0) instanceof NumberValue) {
|
if (args.get(0) instanceof NumberValue) {
|
||||||
@ -123,8 +123,8 @@ public class SimpleRepl {
|
|||||||
else return NumberValue.parseFloat(args.get(0).toString(), false);
|
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, "isNaN", new NativeFunction(args -> BoolValue.of(args.get(0).isNaN())));
|
||||||
res.defineOwnMember(env, "NaN", new NumberValue(Double.NaN));
|
res.defineOwnMember(env, "NaN", NumberValue.NAN);
|
||||||
res.defineOwnMember(env, "Infinity", new NumberValue(Double.POSITIVE_INFINITY));
|
res.defineOwnMember(env, "Infinity", NumberValue.of(Double.POSITIVE_INFINITY));
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -229,14 +229,14 @@ public class SimpleRepl {
|
|||||||
var func = (FunctionValue)args.get(0);
|
var func = (FunctionValue)args.get(0);
|
||||||
var self = args.get(1);
|
var self = args.get(1);
|
||||||
var funcArgs = (ArrayValue)args.get(2);
|
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());
|
return func.invoke(env, name, self, funcArgs.toArray());
|
||||||
}));
|
}));
|
||||||
res.defineOwnMember(env, "construct", new NativeFunction(args -> {
|
res.defineOwnMember(env, "construct", new NativeFunction(args -> {
|
||||||
var func = (FunctionValue)args.get(0);
|
var func = (FunctionValue)args.get(0);
|
||||||
var funcArgs = (ArrayValue)args.get(1);
|
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());
|
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))));
|
return new StringValue(JSON.stringify(JSONConverter.fromJs(env, args.get(0))));
|
||||||
}));
|
}));
|
||||||
res.defineOwnMember(env, "parse", new NativeFunction(args -> {
|
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 -> {
|
res.defineOwnMember(env, "setConstructable", new NativeFunction(args -> {
|
||||||
var func = (FunctionValue)args.get(0);
|
var func = (FunctionValue)args.get(0);
|
||||||
@ -288,7 +288,7 @@ public class SimpleRepl {
|
|||||||
int[] i = new int[1];
|
int[] i = new int[1];
|
||||||
|
|
||||||
res.defineOwnMember(env, "setGlobalPrototype", new NativeFunction(args -> {
|
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);
|
var obj = (ObjectValue)args.get(1);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -330,7 +330,7 @@ public class SimpleRepl {
|
|||||||
return Value.UNDEFINED;
|
return Value.UNDEFINED;
|
||||||
}));
|
}));
|
||||||
res.defineOwnMember(env, "setIntrinsic", new NativeFunction(args -> {
|
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);
|
var val = args.get(1);
|
||||||
|
|
||||||
Value.intrinsics(environment).put(name, val);
|
Value.intrinsics(environment).put(name, val);
|
||||||
@ -338,7 +338,7 @@ public class SimpleRepl {
|
|||||||
return Value.UNDEFINED;
|
return Value.UNDEFINED;
|
||||||
}));
|
}));
|
||||||
res.defineOwnMember(env, "compile", new NativeFunction(args -> {
|
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;
|
return res;
|
||||||
|
@ -66,7 +66,7 @@ public class EngineException extends RuntimeException {
|
|||||||
public String toString(Environment env) {
|
public String toString(Environment env) {
|
||||||
var ss = new StringBuilder();
|
var ss = new StringBuilder();
|
||||||
try {
|
try {
|
||||||
ss.append(value.toString(env).value).append('\n');
|
ss.append(value.toString(env)).append('\n');
|
||||||
}
|
}
|
||||||
catch (EngineException e) {
|
catch (EngineException e) {
|
||||||
var name = value.getMember(env, "name");
|
var name = value.getMember(env, "name");
|
||||||
@ -74,10 +74,10 @@ public class EngineException extends RuntimeException {
|
|||||||
|
|
||||||
if (name.isPrimitive() && desc.isPrimitive()) {
|
if (name.isPrimitive() && desc.isPrimitive()) {
|
||||||
if (name instanceof VoidValue) ss.append("Error: ");
|
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");
|
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");
|
ss.append("\n");
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,39 @@
|
|||||||
package me.topchetoeu.jscript.runtime.values;
|
package me.topchetoeu.jscript.runtime.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.common.environment.Environment;
|
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.StringValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.primitives.SymbolValue;
|
import me.topchetoeu.jscript.runtime.values.primitives.SymbolValue;
|
||||||
|
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
|
||||||
|
|
||||||
public final class KeyCache {
|
public final class KeyCache {
|
||||||
public final Value value;
|
public final Value value;
|
||||||
private Integer intCache;
|
private boolean isInt;
|
||||||
|
private int intCache;
|
||||||
private Double doubleCache;
|
private Double doubleCache;
|
||||||
private Boolean booleanCache;
|
private Boolean booleanCache;
|
||||||
private String stringCache;
|
private String stringCache;
|
||||||
|
|
||||||
public String toString(Environment env) {
|
public String toString(Environment env) {
|
||||||
if (stringCache != null) return stringCache;
|
if (stringCache != null) return stringCache;
|
||||||
else return stringCache = value.toString(env).value;
|
else return stringCache = value.toString(env);
|
||||||
}
|
}
|
||||||
public double toNumber(Environment env) {
|
public double toNumber(Environment env) {
|
||||||
if (doubleCache != null) return doubleCache;
|
if (doubleCache == null) {
|
||||||
else return doubleCache = value.toNumber(env).value;
|
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) {
|
public int toInt(Environment env) {
|
||||||
if (intCache != null) return intCache;
|
if (doubleCache == null) toNumber(env);
|
||||||
else return intCache = (int)toNumber(env);
|
return intCache;
|
||||||
}
|
}
|
||||||
public boolean toBoolean() {
|
public boolean toBoolean() {
|
||||||
if (booleanCache != null) return booleanCache;
|
if (booleanCache != null) return booleanCache;
|
||||||
@ -45,13 +56,13 @@ public final class KeyCache {
|
|||||||
this.booleanCache = !value.equals("");
|
this.booleanCache = !value.equals("");
|
||||||
}
|
}
|
||||||
public KeyCache(int value) {
|
public KeyCache(int value) {
|
||||||
this.value = new NumberValue(value);
|
this.value = NumberValue.of(value);
|
||||||
this.intCache = value;
|
this.intCache = value;
|
||||||
this.doubleCache = (double)value;
|
this.doubleCache = (double)value;
|
||||||
this.booleanCache = value != 0;
|
this.booleanCache = value != 0;
|
||||||
}
|
}
|
||||||
public KeyCache(double value) {
|
public KeyCache(double value) {
|
||||||
this.value = new NumberValue(value);
|
this.value = NumberValue.of(value);
|
||||||
this.intCache = (int)value;
|
this.intCache = (int)value;
|
||||||
this.doubleCache = value;
|
this.doubleCache = value;
|
||||||
this.booleanCache = value != 0;
|
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.ArrayValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.primitives.BoolValue;
|
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.StringValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.primitives.SymbolValue;
|
import me.topchetoeu.jscript.runtime.values.primitives.SymbolValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.primitives.VoidValue;
|
import me.topchetoeu.jscript.runtime.values.primitives.VoidValue;
|
||||||
|
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
|
||||||
|
|
||||||
public abstract class Value {
|
public abstract class Value {
|
||||||
public static enum State {
|
public static enum State {
|
||||||
@ -81,7 +81,7 @@ public abstract class Value {
|
|||||||
public abstract boolean isPrimitive();
|
public abstract boolean isPrimitive();
|
||||||
|
|
||||||
public final boolean isNaN() {
|
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) {
|
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 Value toPrimitive(Environment env);
|
||||||
public abstract NumberValue toNumber(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 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) {
|
public final boolean isInstanceOf(Environment env, Value proto) {
|
||||||
for (var val = getPrototype(env); val != null; val = getPrototype(env)) {
|
for (var val = getPrototype(env); val != null; val = getPrototype(env)) {
|
||||||
if (val.equals(proto)) return true;
|
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 VoidValue) return ((VoidValue)this).name;
|
||||||
else if (this instanceof StringValue) return JSON.stringify(JSONElement.string(((StringValue)this).value));
|
else if (this instanceof StringValue) return JSON.stringify(JSONElement.string(((StringValue)this).value));
|
||||||
else if (this instanceof SymbolValue) return this.toString();
|
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) {
|
public final String toReadable(Environment ext) {
|
||||||
@ -560,7 +557,11 @@ public abstract class Value {
|
|||||||
return aStr.value.compareTo(bStr.value) <= 0;
|
return aStr.value.compareTo(bStr.value) <= 0;
|
||||||
}
|
}
|
||||||
else {
|
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) {
|
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;
|
return aStr.value.compareTo(bStr.value) >= 0;
|
||||||
}
|
}
|
||||||
else {
|
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) {
|
public static final boolean less(Environment env, Value a, Value b) {
|
||||||
@ -579,10 +584,14 @@ public abstract class Value {
|
|||||||
b = b.toPrimitive(env);
|
b = b.toPrimitive(env);
|
||||||
|
|
||||||
if (a instanceof StringValue aStr && b instanceof StringValue bStr) {
|
if (a instanceof StringValue aStr && b instanceof StringValue bStr) {
|
||||||
return aStr.value.compareTo(bStr.value) >= 0;
|
return aStr.value.compareTo(bStr.value) < 0;
|
||||||
}
|
}
|
||||||
else {
|
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) {
|
public static final boolean greater(Environment env, Value a, Value b) {
|
||||||
@ -590,10 +599,14 @@ public abstract class Value {
|
|||||||
b = b.toPrimitive(env);
|
b = b.toPrimitive(env);
|
||||||
|
|
||||||
if (a instanceof StringValue aStr && b instanceof StringValue bStr) {
|
if (a instanceof StringValue aStr && b instanceof StringValue bStr) {
|
||||||
return aStr.value.compareTo(bStr.value) >= 0;
|
return aStr.value.compareTo(bStr.value) > 0;
|
||||||
}
|
}
|
||||||
else {
|
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);
|
b = b.toPrimitive(env);
|
||||||
|
|
||||||
if (a instanceof StringValue || b instanceof StringValue) {
|
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 {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
public static final NumberValue unsignedShiftRight(Environment env, Value a, Value b) {
|
||||||
long _a = a.toInt(env);
|
long _a = a.toNumber(env).getLong() & 0xFFFFFFFF;
|
||||||
long _b = b.toInt(env);
|
long _b = b.toNumber(env).getLong() & 0xFFFFFFFF;
|
||||||
|
|
||||||
if (_a < 0) _a += 0x100000000l;
|
if (_a < 0) _a += 0x100000000l;
|
||||||
if (_b < 0) _b += 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) {
|
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.Value;
|
||||||
import me.topchetoeu.jscript.runtime.values.Member.FieldMember;
|
import me.topchetoeu.jscript.runtime.values.Member.FieldMember;
|
||||||
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
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.StringValue;
|
||||||
|
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
|
||||||
|
|
||||||
public abstract class FunctionValue extends ObjectValue {
|
public abstract class FunctionValue extends ObjectValue {
|
||||||
private static final StringValue typeString = new StringValue("function");
|
private static final StringValue typeString = new StringValue("function");
|
||||||
@ -25,13 +25,13 @@ public abstract class FunctionValue extends ObjectValue {
|
|||||||
return new StringValue(name);
|
return new StringValue(name);
|
||||||
}
|
}
|
||||||
@Override public boolean set(Environment env, Value val, Value self) {
|
@Override public boolean set(Environment env, Value val, Value self) {
|
||||||
name = val.toString(env).value;
|
name = val.toString(env);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
private final FieldMember lengthField = new FieldMember(this, true, false, false) {
|
private final FieldMember lengthField = new FieldMember(this, true, false, false) {
|
||||||
@Override public Value get(Environment env, Value self) {
|
@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) {
|
@Override public boolean set(Environment env, Value val, Value self) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -4,11 +4,12 @@ import java.util.LinkedHashSet;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.common.environment.Environment;
|
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.KeyCache;
|
||||||
import me.topchetoeu.jscript.runtime.values.Member;
|
import me.topchetoeu.jscript.runtime.values.Member;
|
||||||
import me.topchetoeu.jscript.runtime.values.Member.FieldMember;
|
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.Value;
|
||||||
import me.topchetoeu.jscript.runtime.values.primitives.NumberValue;
|
|
||||||
|
|
||||||
public abstract class ArrayLikeValue extends ObjectValue {
|
public abstract class ArrayLikeValue extends ObjectValue {
|
||||||
private static class IndexField extends FieldMember {
|
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) {
|
private final FieldMember lengthField = new FieldMember(this, false, false, true) {
|
||||||
@Override public Value get(Environment env, Value self) {
|
@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) {
|
@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.common.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.values.Value;
|
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
|
// TODO: Make methods generic
|
||||||
public class ByteBufferValue extends ArrayLikeValue implements Iterable<Value> {
|
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) {
|
@Override public Value get(int i) {
|
||||||
if (i < 0 || i >= values.length) return null;
|
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) {
|
@Override public boolean set(Environment env, int i, Value val) {
|
||||||
if (i < 0 || i >= values.length) return false;
|
if (i < 0 || i >= values.length) return false;
|
||||||
values[i] = (byte)val.toNumber(env).value;
|
values[i] = (byte)val.toNumber(env).getInt();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@Override public boolean has(int i) {
|
@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.Member;
|
||||||
import me.topchetoeu.jscript.runtime.values.Value;
|
import me.topchetoeu.jscript.runtime.values.Value;
|
||||||
import me.topchetoeu.jscript.runtime.values.functions.FunctionValue;
|
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.StringValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.primitives.SymbolValue;
|
import me.topchetoeu.jscript.runtime.values.primitives.SymbolValue;
|
||||||
|
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
|
||||||
|
|
||||||
public class ObjectValue extends Value {
|
public class ObjectValue extends Value {
|
||||||
public static interface PrototypeProvider {
|
public static interface PrototypeProvider {
|
||||||
@ -56,7 +56,7 @@ public class ObjectValue extends Value {
|
|||||||
|
|
||||||
throw EngineException.ofType("Value couldn't be converted to a primitive.");
|
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 boolean toBoolean() { return true; }
|
||||||
@Override public NumberValue toNumber(Environment env) { return toPrimitive(env).toNumber(env); }
|
@Override public NumberValue toNumber(Environment env) { return toPrimitive(env).toNumber(env); }
|
||||||
@Override public StringValue type() { return typeString; }
|
@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.common.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
||||||
|
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
|
||||||
|
|
||||||
public final class BoolValue extends PrimitiveValue {
|
public final class BoolValue extends PrimitiveValue {
|
||||||
public static final BoolValue TRUE = new BoolValue(true);
|
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 StringValue type() { return typeString; }
|
||||||
|
|
||||||
@Override public boolean toBoolean() { return value; }
|
@Override public boolean toBoolean() { return value; }
|
||||||
@Override public NumberValue toNumber(Environment ext) {
|
@Override public NumberValue toNumber(Environment ext) { return NumberValue.of(value ? 1 : 0); }
|
||||||
return value ? new NumberValue(1) : new NumberValue(0);
|
@Override public String toString(Environment ext) { return value ? "true" : "false"; }
|
||||||
}
|
|
||||||
@Override public StringValue toString(Environment ext) { return new StringValue(value ? "true" : "false"); }
|
|
||||||
|
|
||||||
@Override public ObjectValue getPrototype(Environment env) {
|
@Override public ObjectValue getPrototype(Environment env) {
|
||||||
return env.get(BOOL_PROTO);
|
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;
|
||||||
import me.topchetoeu.jscript.runtime.values.Member.FieldMember;
|
import me.topchetoeu.jscript.runtime.values.Member.FieldMember;
|
||||||
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
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 class StringValue extends PrimitiveValue {
|
||||||
public final String value;
|
public final String value;
|
||||||
@ -20,13 +21,13 @@ public final class StringValue extends PrimitiveValue {
|
|||||||
@Override public boolean toBoolean() { return !value.equals(""); }
|
@Override public boolean toBoolean() { return !value.equals(""); }
|
||||||
@Override public NumberValue toNumber(Environment ext) {
|
@Override public NumberValue toNumber(Environment ext) {
|
||||||
var val = value.trim();
|
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);
|
var res = Parsing.parseNumber(new Source(val), 0, true);
|
||||||
|
|
||||||
if (res.isSuccess() && res.n == val.length()) return new NumberValue(res.result);
|
if (res.isSuccess() && res.n == val.length()) return NumberValue.of(res.result);
|
||||||
else return new NumberValue(Double.NaN);
|
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) {
|
@Override public boolean equals(Object other) {
|
||||||
if (other instanceof StringValue val) return value.length() == val.value.length() && value.equals(val.value);
|
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);
|
return FieldMember.of(this, new StringValue(value.charAt(i) + ""), false, true, false);
|
||||||
}
|
}
|
||||||
else if (key.toString(env).equals("length")) {
|
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);
|
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.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.values.Value;
|
import me.topchetoeu.jscript.runtime.values.Value;
|
||||||
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
||||||
|
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
|
||||||
|
|
||||||
public final class SymbolValue extends PrimitiveValue {
|
public final class SymbolValue extends PrimitiveValue {
|
||||||
private static final HashMap<String, SymbolValue> registry = new HashMap<>();
|
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 StringValue type() { return typeString; }
|
||||||
|
|
||||||
@Override public boolean toBoolean() { return false; }
|
@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");
|
throw EngineException.ofType("Cannot convert a Symbol value to a string");
|
||||||
}
|
}
|
||||||
@Override public NumberValue toNumber(Environment env) {
|
@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.KeyCache;
|
||||||
import me.topchetoeu.jscript.runtime.values.Member;
|
import me.topchetoeu.jscript.runtime.values.Member;
|
||||||
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
||||||
|
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
|
||||||
|
|
||||||
public final class VoidValue extends PrimitiveValue {
|
public final class VoidValue extends PrimitiveValue {
|
||||||
private final StringValue nameString;
|
|
||||||
|
|
||||||
public final String name;
|
public final String name;
|
||||||
public final StringValue typeString;
|
public final StringValue typeString;
|
||||||
|
|
||||||
@Override public StringValue type() { return typeString; }
|
@Override public StringValue type() { return typeString; }
|
||||||
@Override public boolean toBoolean() { return false; }
|
@Override public boolean toBoolean() { return false; }
|
||||||
@Override public NumberValue toNumber(Environment ext) { return NumberValue.NAN; }
|
@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; }
|
@Override public ObjectValue getPrototype(Environment env) { return null; }
|
||||||
|
|
||||||
@ -26,6 +25,5 @@ public final class VoidValue extends PrimitiveValue {
|
|||||||
public VoidValue(String name, StringValue type) {
|
public VoidValue(String name, StringValue type) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.typeString = type;
|
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