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