ES6 Object and assignment destructors + object stuff #28
@ -22,7 +22,9 @@ public interface Compiler {
|
||||
return body;
|
||||
}
|
||||
catch (SyntaxException e) {
|
||||
throw EngineException.ofSyntax(e.loc + ": " + e.msg);
|
||||
var res = EngineException.ofSyntax(e.msg);
|
||||
res.add(env, e.loc.filename() + "", e.loc);
|
||||
throw res;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -41,7 +41,7 @@ public class SimpleRepl {
|
||||
try {
|
||||
try { initGlobals(); } catch (ExecutionException e) { throw e.getCause(); }
|
||||
}
|
||||
catch (EngineException | SyntaxException e) { System.err.println(Value.errorToReadable(e, null)); }
|
||||
catch (EngineException | SyntaxException e) { System.err.println(Value.errorToReadable(environment, e, null)); }
|
||||
|
||||
for (var arg : args) {
|
||||
try {
|
||||
@ -58,7 +58,7 @@ public class SimpleRepl {
|
||||
}
|
||||
catch (ExecutionException e) { throw e.getCause(); }
|
||||
}
|
||||
catch (EngineException | SyntaxException e) { System.err.println(Value.errorToReadable(e, null)); }
|
||||
catch (EngineException | SyntaxException e) { System.err.println(Value.errorToReadable(environment, e, null)); }
|
||||
}
|
||||
|
||||
for (var i = 0; ; i++) {
|
||||
@ -77,7 +77,7 @@ public class SimpleRepl {
|
||||
}
|
||||
catch (ExecutionException e) { throw e.getCause(); }
|
||||
}
|
||||
catch (EngineException | SyntaxException e) { System.err.println(Value.errorToReadable(e, null)); }
|
||||
catch (EngineException | SyntaxException e) { System.err.println(Value.errorToReadable(environment, e, null)); }
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
@ -293,18 +293,6 @@ public class SimpleRepl {
|
||||
var obj = (ObjectValue)args.get(1);
|
||||
|
||||
switch (type) {
|
||||
case "string":
|
||||
args.env.add(Value.STRING_PROTO, obj);
|
||||
break;
|
||||
case "number":
|
||||
args.env.add(Value.NUMBER_PROTO, obj);
|
||||
break;
|
||||
case "boolean":
|
||||
args.env.add(Value.BOOL_PROTO, obj);
|
||||
break;
|
||||
case "symbol":
|
||||
args.env.add(Value.SYMBOL_PROTO, obj);
|
||||
break;
|
||||
case "object":
|
||||
args.env.add(Value.OBJECT_PROTO, obj);
|
||||
break;
|
||||
@ -314,6 +302,30 @@ public class SimpleRepl {
|
||||
case "array":
|
||||
args.env.add(Value.ARRAY_PROTO, obj);
|
||||
break;
|
||||
case "boolean":
|
||||
args.env.add(Value.BOOL_PROTO, obj);
|
||||
break;
|
||||
case "number":
|
||||
args.env.add(Value.NUMBER_PROTO, obj);
|
||||
break;
|
||||
case "string":
|
||||
args.env.add(Value.STRING_PROTO, obj);
|
||||
break;
|
||||
case "symbol":
|
||||
args.env.add(Value.SYMBOL_PROTO, obj);
|
||||
break;
|
||||
case "error":
|
||||
args.env.add(Value.ERROR_PROTO, obj);
|
||||
break;
|
||||
case "syntax":
|
||||
args.env.add(Value.SYNTAX_ERR_PROTO, obj);
|
||||
break;
|
||||
case "type":
|
||||
args.env.add(Value.TYPE_ERR_PROTO, obj);
|
||||
break;
|
||||
case "range":
|
||||
args.env.add(Value.RANGE_ERR_PROTO, obj);
|
||||
break;
|
||||
}
|
||||
|
||||
return Value.UNDEFINED;
|
||||
|
@ -66,7 +66,7 @@ public class EngineException extends RuntimeException {
|
||||
public String toString(Environment env) {
|
||||
var ss = new StringBuilder();
|
||||
try {
|
||||
ss.append(value.toString(env)).append('\n');
|
||||
ss.append(value.toString(env).value).append('\n');
|
||||
}
|
||||
catch (EngineException e) {
|
||||
var name = value.getMember(env, "name");
|
||||
|
@ -236,8 +236,8 @@ public abstract class Value {
|
||||
public final boolean setMember(Environment env, KeyCache key, Value val) {
|
||||
for (Value obj = this; obj != null; obj = obj.getPrototype(env)) {
|
||||
var member = obj.getOwnMember(env, key);
|
||||
if (member != null) {
|
||||
if (member.set(env, val, obj)) {
|
||||
if (member instanceof PropertyMember prop) {
|
||||
if (prop.set(env, val, obj)) {
|
||||
if (val instanceof FunctionValue) ((FunctionValue)val).setName(key.toString(env));
|
||||
return true;
|
||||
}
|
||||
@ -670,22 +670,22 @@ public abstract class Value {
|
||||
return a.toString(env).equals(b.toString(env));
|
||||
}
|
||||
|
||||
// public static Value operation(Environment env, Operation op, Value ...args) {
|
||||
// }
|
||||
|
||||
public static final String errorToReadable(RuntimeException err, String prefix) {
|
||||
public static final String errorToReadable(Environment env, RuntimeException err, String prefix) {
|
||||
prefix = prefix == null ? "Uncaught" : "Uncaught " + prefix;
|
||||
if (err instanceof EngineException) {
|
||||
var ee = ((EngineException)err);
|
||||
if (err instanceof EngineException ee) {
|
||||
if (env == null) env = ee.env;
|
||||
|
||||
try {
|
||||
return prefix + " " + ee.toString(ee.env);
|
||||
return prefix + " " + ee.toString(env);
|
||||
}
|
||||
catch (EngineException ex) {
|
||||
return prefix + " " + ee.value.toReadable(ee.env);
|
||||
return prefix + " " + ee.value.toReadable(env);
|
||||
}
|
||||
}
|
||||
else if (err instanceof SyntaxException) {
|
||||
return prefix + " SyntaxError " + ((SyntaxException)err).msg;
|
||||
else if (err instanceof SyntaxException syntax) {
|
||||
var newErr = EngineException.ofSyntax(syntax.msg);
|
||||
newErr.add(null, syntax.loc.filename() + "", syntax.loc);
|
||||
return errorToReadable(env, newErr, prefix);
|
||||
}
|
||||
else if (err.getCause() instanceof InterruptedException) return "";
|
||||
else {
|
||||
|
@ -1,16 +1,32 @@
|
||||
const target = arguments[0];
|
||||
const primordials = arguments[1];
|
||||
|
||||
const makeSymbol = primordials.symbol.makeSymbol;
|
||||
const getSymbol = primordials.symbol.getSymbol;
|
||||
const getSymbolKey = primordials.symbol.getSymbolKey;
|
||||
const getSymbolDescription = primordials.symbol.getSymbolDescription;
|
||||
const symbol = primordials.symbol || (() => {
|
||||
const repo = {};
|
||||
|
||||
const parseInt = primordials.number.parseInt;
|
||||
const parseFloat = primordials.number.parseFloat;
|
||||
const isNaN = primordials.number.isNaN;
|
||||
const NaN = primordials.number.NaN;
|
||||
const Infinity = primordials.number.Infinity;
|
||||
return {
|
||||
makeSymbol: (name) => { name },
|
||||
getSymbol(name) {
|
||||
if (name in repo) return repo[name];
|
||||
else return repo[name] = { name };
|
||||
},
|
||||
getSymbolKey(symbol) {
|
||||
if (symbol.name in repo && repo[symbol.name] === symbol) return symbol.name;
|
||||
else return undefined;
|
||||
},
|
||||
getSymbolDescription: ({ name }) => name,
|
||||
};
|
||||
});
|
||||
|
||||
const number = primordials.number || (() => {
|
||||
return {
|
||||
parseInt() { throw new Error("parseInt not supported"); },
|
||||
parseFloat() { throw new Error("parseFloat not supported"); },
|
||||
isNaN: (val) => val !== val,
|
||||
NaN: 0 / 0,
|
||||
Infinity: 1 / 0,
|
||||
};
|
||||
});
|
||||
|
||||
const fromCharCode = primordials.string.fromCharCode;
|
||||
const fromCodePoint = primordials.string.fromCodePoint;
|
||||
@ -37,7 +53,7 @@ const setGlobalPrototype = primordials.setGlobalPrototype;
|
||||
const compile = primordials.compile;
|
||||
const setIntrinsic = primordials.setIntrinsic;
|
||||
|
||||
const valueKey = makeSymbol("Primitive.value");
|
||||
const valueKey = symbol.makeSymbol("Primitive.value");
|
||||
const undefined = ({}).definitelyDefined;
|
||||
|
||||
target.undefined = undefined;
|
||||
@ -54,13 +70,13 @@ const unwrapThis = (self, type, constr, name, arg, defaultVal) => {
|
||||
|
||||
const wrapIndex = (i, len) => {};
|
||||
|
||||
const Symbol = (name = "") => makeSymbol(name);
|
||||
const Symbol = (name = "") => symbol.makeSymbol(name);
|
||||
|
||||
defineField(Symbol, "for", true, false, true, function(name) {
|
||||
return getSymbol(name + "");
|
||||
return symbol.getSymbol(name + "");
|
||||
});
|
||||
defineField(Symbol, "keyFor", true, false, true, function(symbol) {
|
||||
return getSymbolKey(unwrapThis(symbol, "symbol", Symbol, "Symbol.keyFor"));
|
||||
defineField(Symbol, "keyFor", true, false, true, function(value) {
|
||||
return symbol.getSymbolKey(unwrapThis(value, "symbol", Symbol, "Symbol.keyFor"));
|
||||
});
|
||||
|
||||
defineField(Symbol, "asyncIterator", false, false, false, Symbol("Symbol.asyncIterator"));
|
||||
@ -74,7 +90,7 @@ defineField(Symbol, "toStringTag", false, false, false, Symbol("Symbol.toStringT
|
||||
defineField(Symbol, "prototype", false, false, false, {});
|
||||
|
||||
defineProperty(Symbol.prototype, "description", false, true, function () {
|
||||
return getSymbolDescription(unwrapThis(this, "symbol", Symbol, "Symbol.prototype.description"));
|
||||
return symbol.getSymbolDescription(unwrapThis(this, "symbol", Symbol, "Symbol.prototype.description"));
|
||||
}, undefined);
|
||||
defineField(Symbol.prototype, "toString", true, false, true, function() {
|
||||
return "Symbol(" + unwrapThis(this, "symbol", Symbol, "Symbol.prototype.toString").description + ")";
|
||||
@ -97,7 +113,7 @@ const Number = function(value) {
|
||||
defineField(Number, "isFinite", true, false, true, function(value) {
|
||||
value = unwrapThis(value, "number", Number, "Number.isFinite", "value", undefined);
|
||||
|
||||
if (value === undefined || isNaN(value)) return false;
|
||||
if (value === undefined || value !== value) return false;
|
||||
if (value === Infinity || value === -Infinity) return false;
|
||||
|
||||
return true;
|
||||
@ -105,34 +121,34 @@ defineField(Number, "isFinite", true, false, true, function(value) {
|
||||
defineField(Number, "isInteger", true, false, true, function(value) {
|
||||
value = unwrapThis(value, "number", Number, "Number.isInteger", "value", undefined);
|
||||
if (value === undefined) return false;
|
||||
return parseInt(value) === value;
|
||||
return number.parseInt(value) === value;
|
||||
});
|
||||
defineField(Number, "isNaN", true, false, true, function(value) {
|
||||
return isNaN(value);
|
||||
return number.isNaN(value);
|
||||
});
|
||||
defineField(Number, "isSafeInteger", true, false, true, function(value) {
|
||||
value = unwrapThis(value, "number", Number, "Number.isSafeInteger", "value", undefined);
|
||||
if (value === undefined || parseInt(value) !== value) return false;
|
||||
if (value === undefined || number.parseInt(value) !== value) return false;
|
||||
return value >= -9007199254740991 && value <= 9007199254740991;
|
||||
});
|
||||
defineField(Number, "parseFloat", true, false, true, function(value) {
|
||||
value = 0 + value;
|
||||
return parseFloat(value);
|
||||
return number.parseFloat(value);
|
||||
});
|
||||
defineField(Number, "parseInt", true, false, true, function(value, radix) {
|
||||
value = 0 + value;
|
||||
radix = +radix;
|
||||
if (isNaN(radix)) radix = 10;
|
||||
if (number.isNaN(radix)) radix = 10;
|
||||
|
||||
return parseInt(value, radix);
|
||||
return number.parseInt(value, radix);
|
||||
});
|
||||
|
||||
defineField(Number, "EPSILON", false, false, false, 2.220446049250313e-16);
|
||||
defineField(Number, "MIN_SAFE_INTEGER", false, false, false, -9007199254740991);
|
||||
defineField(Number, "MAX_SAFE_INTEGER", false, false, false, 9007199254740991);
|
||||
defineField(Number, "POSITIVE_INFINITY", false, false, false, +Infinity);
|
||||
defineField(Number, "NEGATIVE_INFINITY", false, false, false, -Infinity);
|
||||
defineField(Number, "NaN", false, false, false, NaN);
|
||||
defineField(Number, "POSITIVE_INFINITY", false, false, false, +number.Infinity);
|
||||
defineField(Number, "NEGATIVE_INFINITY", false, false, false, -number.Infinity);
|
||||
defineField(Number, "NaN", false, false, false, number.NaN);
|
||||
defineField(Number, "MAX_VALUE", false, false, false, 1.7976931348623157e+308);
|
||||
defineField(Number, "MIN_VALUE", false, false, false, 5e-324);
|
||||
defineField(Number, "prototype", false, false, false, {});
|
||||
@ -146,6 +162,10 @@ defineField(Number.prototype, "valueOf", true, false, true, function() {
|
||||
});
|
||||
|
||||
target.Number = Number;
|
||||
target.parseInt = Number.parseInt;
|
||||
target.parseFloat = Number.parseFloat;
|
||||
target.NaN = Number.NaN;
|
||||
target.Infinity = Number.POSITIVE_INFINITY;
|
||||
|
||||
const String = function(value) {
|
||||
if (invokeType(arguments) === "call") {
|
||||
@ -337,31 +357,61 @@ defineField(Function.prototype, "valueOf", true, false, true, function() {
|
||||
|
||||
target.Function = Function;
|
||||
|
||||
setIntrinsic("spread_obj", target.spread_obj = (target, obj) => {
|
||||
if (obj === null || obj === undefined) return;
|
||||
const members = getOwnMembers(obj, true);
|
||||
const symbols = getOwnSymbolMembers(obj, true);
|
||||
// setIntrinsic("spread_obj", target.spread_obj = (target, obj) => {
|
||||
// if (obj === null || obj === undefined) return;
|
||||
// const members = getOwnMembers(obj, true);
|
||||
// const symbols = getOwnSymbolMembers(obj, true);
|
||||
|
||||
for (let i = 0; i < members.length; i++) {
|
||||
const member = members[i];
|
||||
target[member] = obj[member];
|
||||
}
|
||||
// for (let i = 0; i < members.length; i++) {
|
||||
// const member = members[i];
|
||||
// target[member] = obj[member];
|
||||
// }
|
||||
|
||||
for (let i = 0; i < symbols.length; i++) {
|
||||
const member = symbols[i];
|
||||
target[member] = obj[member];
|
||||
}
|
||||
});
|
||||
setIntrinsic("apply", target.spread_call = (func, self, args) => {
|
||||
return invoke(func, self, args);
|
||||
});
|
||||
setIntrinsic("apply", target.spread_new = (func, args) => {
|
||||
return invoke(func, null, args);
|
||||
// for (let i = 0; i < symbols.length; i++) {
|
||||
// const member = symbols[i];
|
||||
// target[member] = obj[member];
|
||||
// }
|
||||
// });
|
||||
// setIntrinsic("apply", target.spread_call = (func, self, args) => {
|
||||
// return invoke(func, self, args);
|
||||
// });
|
||||
// setIntrinsic("apply", target.spread_new = (func, args) => {
|
||||
// return invoke(func, null, args);
|
||||
// });
|
||||
|
||||
const Error = function(msg = "") {
|
||||
if (invokeType(arguments) === "call") return new Error(msg);
|
||||
this.message = msg + "";
|
||||
};
|
||||
defineField(Error.prototype, "name", true, false, true, "Error");
|
||||
defineField(Error.prototype, "message", true, false, true, "");
|
||||
defineField(Error.prototype, "toString", true, false, true, function toString() {
|
||||
let res = this.name || "Error";
|
||||
|
||||
const msg = this.message;
|
||||
if (msg) res += ": " + msg;
|
||||
|
||||
return res;
|
||||
});
|
||||
|
||||
target.Error = Error;
|
||||
|
||||
const SyntaxError = function(msg = "") {
|
||||
if (invokeType(arguments) === "call") return new SyntaxError(msg);
|
||||
this.message = msg + "";
|
||||
};
|
||||
defineField(SyntaxError.prototype, "name", true, false, true, "SyntaxError");
|
||||
|
||||
setPrototype(SyntaxError, Error);
|
||||
setPrototype(SyntaxError.prototype, Error.prototype);
|
||||
|
||||
target.SyntaxError = SyntaxError;
|
||||
|
||||
setGlobalPrototype("string", String.prototype);
|
||||
setGlobalPrototype("number", Number.prototype);
|
||||
setGlobalPrototype("boolean", Boolean.prototype);
|
||||
setGlobalPrototype("symbol", Symbol.prototype);
|
||||
setGlobalPrototype("object", Object.prototype);
|
||||
setGlobalPrototype("function", Function.prototype);
|
||||
setGlobalPrototype("error", Error.prototype);
|
||||
setGlobalPrototype("syntax", SyntaxError.prototype);
|
||||
|
Loading…
Reference in New Issue
Block a user