ES6 Object and assignment destructors + object stuff #28

Merged
TopchetoEU merged 15 commits from TopchetoEU/destructing into master 2024-09-14 12:38:02 +00:00
5 changed files with 136 additions and 72 deletions
Showing only changes of commit f13bf584a5 - Show all commits

View File

@ -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;
} }
}; };

View File

@ -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;

View File

@ -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");

View File

@ -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 {

View File

@ -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);