TopchetoEU/revert-ES5 #31

Merged
TopchetoEU merged 41 commits from TopchetoEU/revert-ES5 into master 2024-12-09 21:39:57 +00:00
4 changed files with 443 additions and 480 deletions
Showing only changes of commit 61c5df5003 - Show all commits

6
.gitignore vendored
View File

@ -1,6 +1,6 @@
*
!/src
!/src/
!/src/**/*
!/doc
@ -21,4 +21,6 @@
!/gradle.properties
!/gradle
!/gradle/wrapper
!/gradle/wrapper/gradle-wrapper.properties
!/gradle/wrapper/gradle-wrapper.properties
!/

View File

@ -80,7 +80,7 @@ public class IfNode extends Node {
var a = JavaScript.parseExpression(src, i + n, 2);
if (!a.isSuccess()) return a.chainError(src.loc(i + n), "Expected a value after the ternary operator.");
n += a.n;
n += Parsing.skipEmpty(src, i);
n += Parsing.skipEmpty(src, i + n);
if (!src.is(i + n, ":")) return ParseRes.failed();
n++;

View File

@ -10,6 +10,7 @@ import me.topchetoeu.jscript.common.Metadata;
import me.topchetoeu.jscript.common.Reading;
import me.topchetoeu.jscript.common.SyntaxException;
import me.topchetoeu.jscript.common.environment.Environment;
import me.topchetoeu.jscript.common.environment.Key;
import me.topchetoeu.jscript.common.json.JSON;
import me.topchetoeu.jscript.common.parsing.Filename;
import me.topchetoeu.jscript.runtime.debug.DebugContext;
@ -252,21 +253,17 @@ public class SimpleRepl {
res.defineOwnMember(env, "parse", new NativeFunction(args -> {
return JSONConverter.toJs(JSON.parse(null, args.get(0).toString(env)));
}));
res.defineOwnMember(env, "invokeType", new NativeFunction(args -> {
if (((ArgumentsValue)args.get(0)).frame.isNew) return StringValue.of("new");
else return StringValue.of("call");
}));
res.defineOwnMember(env, "invoke", new NativeFunction(args -> {
var func = (FunctionValue)args.get(0);
var self = args.get(1);
var funcArgs = (ArrayValue)args.get(2);
return func.apply(env, self, funcArgs.toArray());
}));
return res;
}
private static void setProto(Environment env, Environment target, Key<ObjectValue> key, ObjectValue repo, String name) {
var val = repo.getMember(env, name);
if (val instanceof ObjectValue obj) {
target.add(key, obj);
}
}
private static ObjectValue primordials(Environment env) {
var res = new ObjectValue();
res.setPrototype(null, null);
@ -280,45 +277,20 @@ public class SimpleRepl {
int[] i = new int[1];
res.defineOwnMember(env, "setGlobalPrototype", new NativeFunction(args -> {
var type = args.get(0).toString(env);
res.defineOwnMember(env, "setGlobalPrototypes", new NativeFunction(args -> {
var obj = (ObjectValue)args.get(1);
switch (type) {
case "object":
args.env.add(Value.OBJECT_PROTO, obj);
break;
case "function":
args.env.add(Value.FUNCTION_PROTO, obj);
break;
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;
}
setProto(args.env, env, Value.OBJECT_PROTO, obj, "object");
setProto(args.env, env, Value.FUNCTION_PROTO, obj, "function");
setProto(args.env, env, Value.ARRAY_PROTO, obj, "array");
setProto(args.env, env, Value.BOOL_PROTO, obj, "boolean");
setProto(args.env, env, Value.NUMBER_PROTO, obj, "number");
setProto(args.env, env, Value.STRING_PROTO, obj, "string");
setProto(args.env, env, Value.SYMBOL_PROTO, obj, "symbol");
setProto(args.env, env, Value.ERROR_PROTO, obj, "error");
setProto(args.env, env, Value.SYNTAX_ERR_PROTO, obj, "syntax");
setProto(args.env, env, Value.TYPE_ERR_PROTO, obj, "type");
setProto(args.env, env, Value.RANGE_ERR_PROTO, obj, "range");
return Value.UNDEFINED;
}));

View File

@ -1,429 +1,418 @@
const target = arguments[0];
const primordials = arguments[1];
const symbol = primordials.symbol || (() => {
const repo = {};
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 || {
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 string = primordials.string;
const object = primordials.object || {
defineProperty() { throw new Error("Define property not polyfillable"); },
defineField(obj, key, a, b, c, value) { obj[key] = value; },
getOwnMember() { throw new Error("Get own member not polyfillable"); },
getOwnSymbolMember() { throw new Error("Get own symbol member not polyfillable"); },
getOwnMembers() { throw new Error("Get own members not polyfillable"); },
getOwnSymbolMembers() { throw new Error("Get own symbol members not polyfillable"); },
getPrototype() { throw new Error("Get prototype not polyfillable"); },
setPrototype() { throw new Error("Set prototype not polyfillable"); },
}
const invokeType = primordials.function.invokeType;
const setConstructable = primordials.function.setConstructable;
const setCallable = primordials.function.setCallable;
const invoke = primordials.function.invoke;
const construct = primordials.function.construct;
const json = primordials.json;
const setGlobalPrototype = primordials.setGlobalPrototype;
const compile = primordials.compile;
const setIntrinsic = primordials.setIntrinsic;
const valueKey = symbol.makeSymbol("Primitive.value");
const undefined = ({}).definitelyDefined;
target.undefined = undefined;
const unwrapThis = (self, type, constr, name, arg = "this", defaultVal) => {
if (typeof self === type) return self;
if (self instanceof constr && valueKey in self) self = self[valueKey];
if (typeof self === type) return self;
if (defaultVal !== undefined) return defaultVal;
throw new TypeError(name + " requires that '" + arg + "' be a " + constr.name);
}
const wrapIndex = (i, len) => {};
class Symbol {
get description() {
return symbol.getSymbolDescriptor(unwrapThis(this, "symbol", Symbol, "Symbol.prototype.description"));
}
toString() {
return "Symbol(" + unwrapThis(this, "symbol", Symbol, "Symbol.prototype.toString").description + ")";
}
valueOf() {
return unwrapThis(this, "symbol", Symbol, "Symbol.prototype.valueOf");
}
constructor(name = "") {
return symbol.makeSymbol(name);
}
static for(name) {
return symbol.getSymbol(name + "");
}
static keyFor(value) {
return symbol.getSymbolKey(unwrapThis(value, "symbol", Symbol, "Symbol.keyFor"));
}
}
setCallable(Symbol, true);
setConstructable(Symbol, false);
object.defineField(Symbol, "asyncIterator", false, false, false, Symbol("Symbol.asyncIterator"));
object.defineField(Symbol, "iterator", false, false, false, Symbol("Symbol.iterator"));
object.defineField(Symbol, "match", false, false, false, Symbol("Symbol.match"));
object.defineField(Symbol, "matchAll", false, false, false, Symbol("Symbol.matchAll"));
object.defineField(Symbol, "replace", false, false, false, Symbol("Symbol.replace"));
object.defineField(Symbol, "search", false, false, false, Symbol("Symbol.search"));
object.defineField(Symbol, "split", false, false, false, Symbol("Symbol.split"));
object.defineField(Symbol, "toStringTag", false, false, false, Symbol("Symbol.toStringTag"));
Symbol();
target.Symbol = Symbol;
class Number {
toString() {
return "" + unwrapThis(this, "number", Number, "Number.prototype.toString");
}
valueOf() {
return unwrapThis(this, "number", Number, "Number.prototype.toString");
}
constructor(value) {
if (invokeType(arguments) === "call") {
if (arguments.length === 0) return 0;
else return +value;
}
this[valueKey] = target.Number(value);
}
static isFinite(value) {
value = unwrapThis(value, "number", Number, "Number.isFinite", "value", undefined);
if (value === undefined || value !== value) return false;
if (value === Infinity || value === -Infinity) return false;
return true;
}
static isInteger(value) {
value = unwrapThis(value, "number", Number, "Number.isInteger", "value", undefined);
if (value === undefined) return false;
return number.parseInt(value) === value;
}
static isNaN(value) {
return number.isNaN(value);
}
static isSafeInteger(value) {
value = unwrapThis(value, "number", Number, "Number.isSafeInteger", "value", undefined);
if (value === undefined || number.parseInt(value) !== value) return false;
return value >= -9007199254740991 && value <= 9007199254740991;
}
static parseFloat(value) {
value = 0 + value;
return number.parseFloat(value);
}
static parseInt(value, radix) {
value = 0 + value;
radix = +radix;
if (number.isNaN(radix)) radix = 10;
return number.parseInt(value, radix);
}
}
object.defineField(Number, "EPSILON", false, false, false, 2.220446049250313e-16);
object.defineField(Number, "MIN_SAFE_INTEGER", false, false, false, -9007199254740991);
object.defineField(Number, "MAX_SAFE_INTEGER", false, false, false, 9007199254740991);
object.defineField(Number, "POSITIVE_INFINITY", false, false, false, +number.Infinity);
object.defineField(Number, "NEGATIVE_INFINITY", false, false, false, -number.Infinity);
object.defineField(Number, "NaN", false, false, false, number.NaN);
object.defineField(Number, "MAX_VALUE", false, false, false, 1.7976931348623157e+308);
object.defineField(Number, "MIN_VALUE", false, false, false, 5e-324);
setCallable(Number, true);
target.Number = Number;
target.parseInt = Number.parseInt;
target.parseFloat = Number.parseFloat;
target.NaN = Number.NaN;
target.Infinity = Number.POSITIVE_INFINITY;
class String {
at(index) {
throw "Not implemented :/";
return unwrapThis(this, "string", String, "String.prototype.at")[index];
}
toString() {
return unwrapThis(this, "string", String, "String.prototype.toString");
}
valueOf() {
return unwrapThis(this, "string", String, "String.prototype.valueOf");
}
constructor(value) {
if (invokeType(arguments) === "call") {
if (arguments.length === 0) return "";
else return value + "";
}
this[valueKey] = String(value);
}
static fromCharCode() {
const res = [];
res[arguments.length] = 0;
for (let i = 0; i < arguments.length; i++) {
res[i] = string.fromCharCode(+arguments[i]);
}
return string.stringBuild(res);
}
static fromCodePoint() {
const res = [];
res[arguments.length] = 0;
for (let i = 0; i < arguments.length; i++) {
res[i] = string.fromCodePoint(+arguments[i]);
}
return string.stringBuild(res);
}
}
setCallable(String, true);
target.String = String;
class Boolean {
toString() {
return "" + unwrapThis(this, "boolean", Boolean, "Boolean.prototype.toString");
}
valueOf() {
return unwrapThis(this, "boolean", Boolean, "Boolean.prototype.valueOf");
}
constructor(value) {
if (invokeType(arguments) === "call") {
if (arguments.length === 0) return false;
else return !!value;
}
this[valueKey] = Boolean(value);
}
}
setCallable(Boolean, true);
target.Boolean = Boolean;
class Object {
toString() {
if (this !== null && this !== undefined && (Symbol.toStringTag in this)) return "[object " + this[Symbol.toStringTag] + "]";
else if (typeof this === "number" || this instanceof Number) return "[object Number]";
else if (typeof this === "symbol" || this instanceof Symbol) return "[object Symbol]";
else if (typeof this === "string" || this instanceof String) return "[object String]";
else if (typeof this === "boolean" || this instanceof Boolean) return "[object Boolean]";
else if (typeof this === "function") return "[object Function]";
else return "[object Object]";
}
valueOf() {
return this;
}
constructor(value) {
if (typeof value === 'object' && value !== null) return value;
if (typeof value === 'string') return new String(value);
if (typeof value === 'number') return new Number(value);
if (typeof value === 'boolean') return new Boolean(value);
if (typeof value === 'symbol') {
const res = {};
setPrototype(res, Symbol.prototype);
res[valueKey] = value;
return res;
}
return {};
// // TODO: use new.target.prototype as proto
// if (target == null || typeof target !== 'object') target = {};
// return target;
}
static defineProperty(obj, key, desc) {
if (typeof obj !== "object" || obj === null) throw new TypeError("Object.defineProperty called on non-object");
if (typeof desc !== "object" || desc === null) throw new TypeError("Property description must be an object: " + desc);
if ("get" in desc || "set" in desc) {
let get = desc.get, set = desc.set;
if (get !== undefined && typeof get !== "function") throw new TypeError("Getter must be a function: " + get);
if (set !== undefined && typeof set !== "function") throw new TypeError("Setter must be a function: " + set);
if ("value" in desc || "writable" in desc) {
throw new TypeError("Invalid property descriptor. Cannot both specify accessors and a value or writable attribute");
}
if (!object.defineProperty(obj, key, desc.enumerable, desc.configurable, get, set)) {
throw new TypeError("Cannot redefine property: " + key);
}
}
else if (!object.defineField(obj, key, desc.writable, desc.enumerable, desc.configurable, desc.value)) {
throw new TypeError("Cannot redefine property: " + key);
}
return obj;
}
}
setCallable(Object, true);
object.setPrototype(Object.prototype, null);
target.Object = Object;
class Function {
toString() {
if (this.name !== "") return "function " + this.name + "(...) { ... }";
else return "function (...) { ... }";
}
constructor() {
const parts = ["(function annonymous("];
for (let i = 0; i < arguments.length - 1; i++) {
if (i > 0) parts[parts.length] = ",";
parts[parts.length] = arguments[i];
}
parts[parts.length] = "){\n";
parts[parts.length] = String(arguments[arguments.length - 1]);
parts[parts.length] = "\n})";
const res = compile(string.stringBuild(parts))();
return res;
}
static compile(src = "", { globals = [], wrap = false } = {}) {
const parts = [];
if (wrap) parts[parts.length] = "return (function() {\n";
if (globals.length > 0) {
parts[parts.length] = "let {";
for (let i = 0; i < globals.length; i++) {
if (i > 0) parts[parts.length] = ",";
parts[parts.length] = globals[i];
}
parts[parts.length] = "} = arguments[0];";
}
parts[parts.length] = src;
if (wrap) parts[parts.length] = "\n})(arguments[0])";
const res = compile(string.stringBuild(parts));
return res;
}
}
setCallable(Function, true);
target.Function = Function;
class Array {
constructor(len) {
if (arguments.length === 1 && typeof len === "number") {
const res = [];
res.length = len;
return res;
}
// TODO: Implement spreading
else throw new Error("Spreading not implemented");
}
}
setCallable(Array, true);
target.Array = Array;
class Error {
toString() {
let res = this.name || "Error";
const msg = this.message;
if (msg) res += ": " + msg;
return res;
}
constructor (msg = "") {
if (invokeType(arguments) === "call") return new Error(msg);
this.message = msg + "";
}
}
object.defineField(Error.prototype, "name", true, false, true, "Error");
object.defineField(Error.prototype, "message", true, false, true, "");
setCallable(Error, true);
target.Error = Error;
class SyntaxError extends Error {
constructor (msg) {
if (invokeType(arguments) === "call") return new SyntaxError(msg);
super(msg);
}
}
object.defineField(SyntaxError.prototype, "name", true, false, true, "SyntaxError");
setCallable(SyntaxError, true);
target.SyntaxError = SyntaxError;
class TypeError extends Error {
constructor (msg) {
if (invokeType(arguments) === "call") return new TypeError(msg);
super(msg);
}
}
object.defineField(TypeError.prototype, "name", true, false, true, "TypeError");
setCallable(TypeError, true);
target.TypeError = TypeError;
class RangeError extends Error {
constructor (msg) {
if (invokeType(arguments) === "call") return new RangeError(msg);
super(msg);
}
}
object.defineField(RangeError.prototype, "name", true, false, true, "RangeError");
setCallable(RangeError, true);
target.RangeError = RangeError;
setGlobalPrototype("string", String.prototype);
setGlobalPrototype("number", Number.prototype);
setGlobalPrototype("boolean", Boolean.prototype);
setGlobalPrototype("symbol", Symbol.prototype);
setGlobalPrototype("object", Object.prototype);
setGlobalPrototype("array", Array.prototype);
setGlobalPrototype("function", Function.prototype);
setGlobalPrototype("error", Error.prototype);
setGlobalPrototype("syntax", SyntaxError.prototype);
return;
(function main() {
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var target = arguments[0];
var primordials = arguments[1];
var symbol = primordials.symbol || (function () {
var repo = {};
return {
makeSymbol: function (name) { return { name: name }; },
getSymbol: function (name) {
if (name in repo) return repo[name];
else return repo[name] = { name: name };
},
getSymbolKey: function (symbol) {
if (symbol.name in repo && repo[symbol.name] === symbol) return symbol.name;
else return undefined;
},
getSymbolDescription: function (symbol) {
return symbol.name;
}
};
});
var number = primordials.number || {
parseInt: function () { throw new Error("parseInt not supported"); },
parseFloat: function () { throw new Error("parseFloat not supported"); },
isNaN: function (val) { return val !== val; },
NaN: 0 / 0,
Infinity: 1 / 0,
};
var string = primordials.string;
var object = primordials.object || {
defineProperty: function () { throw new Error("Define property not polyfillable"); },
defineField: function (obj, key, a, b, c, value) { obj[key] = value; },
getOwnMember: function () { throw new Error("Get own member not polyfillable"); },
getOwnSymbolMember: function () { throw new Error("Get own symbol member not polyfillable"); },
getOwnMembers: function () { throw new Error("Get own members not polyfillable"); },
getOwnSymbolMembers: function () { throw new Error("Get own symbol members not polyfillable"); },
getPrototype: function () { throw new Error("Get prototype not polyfillable"); },
setPrototype: function () { throw new Error("Set prototype not polyfillable"); },
};
var func = primordials.function || {
invokeType: function (args, self) {
if (typeof self === "object") return "new";
else return "call";
},
setConstructable: function () { throw new Error("Set constructable not polyfillable"); },
setCallable: function () { throw new Error("Set callable not polyfillable"); },
invoke: function () { throw new Error("Invoke not polyfillable"); },
construct: function () { throw new Error("Construct not polyfillable"); },
};
var json = primordials.json || {
stringify: function (val) { throw new Error("JSON stringify not polyfillable"); },
parse: function (val) { throw new Error("JSON parse not polyfillable"); },
}
var setGlobalPrototypes = primordials.setGlobalPrototype;
var compile = primordials.compile;
var setIntrinsic = primordials.setIntrinsic;
var valueKey = symbol.makeSymbol("Primitive.value");
var undefined = void 0;
target.undefined = undefined;
function unwrapThis(self, type, constr, name, arg, defaultVal) {
if (arg === void 0) { arg = "this"; }
if (typeof self === type)
return self;
if (self instanceof constr && valueKey in self)
self = self[valueKey];
if (typeof self === type)
return self;
if (defaultVal !== undefined)
return defaultVal;
throw new TypeError(name + " requires that '" + arg + "' be a " + constr.name);
}
function wrapIndex(i, len) { }
var Symbol = /** @class */ (function () {
function Symbol(name) {
if (name === undefined) name = "";
return symbol.makeSymbol(name);
}
Symbol.prototype.toString = function () {
return "Symbol(" + unwrapThis(this, "symbol", Symbol, "Symbol.prototype.toString").description + ")";
};
Symbol.prototype.valueOf = function () {
return unwrapThis(this, "symbol", Symbol, "Symbol.prototype.valueOf");
};
Symbol.for = function (name) {
return symbol.getSymbol(name + "");
};
Symbol.keyFor = function (value) {
return symbol.getSymbolKey(unwrapThis(value, "symbol", Symbol, "Symbol.keyFor"));
};
return Symbol;
}());
;
object.defineProperty(Symbol.prototype, "desc", false, true, function () {
return symbol.getSymbolDescriptor(unwrapThis(this, "symbol", Symbol, "Symbol.prototype.description"));
});
object.defineField(Symbol, "asyncIterator", false, false, false, Symbol("Symbol.asyncIterator"));
object.defineField(Symbol, "iterator", false, false, false, Symbol("Symbol.iterator"));
object.defineField(Symbol, "match", false, false, false, Symbol("Symbol.match"));
object.defineField(Symbol, "matchAll", false, false, false, Symbol("Symbol.matchAll"));
object.defineField(Symbol, "replace", false, false, false, Symbol("Symbol.replace"));
object.defineField(Symbol, "search", false, false, false, Symbol("Symbol.search"));
object.defineField(Symbol, "split", false, false, false, Symbol("Symbol.split"));
object.defineField(Symbol, "toStringTag", false, false, false, Symbol("Symbol.toStringTag"));
func.setConstructable(Symbol, false);
function Number(value) {
if (func.invokeType(arguments, this) === "call") {
if (arguments.length === 0) return 0;
else return +value;
}
this[valueKey] = target.Number(value);
}
Number.prototype.toString = function () {
return "" + unwrapThis(this, "number", Number, "Number.prototype.toString");
};
Number.prototype.valueOf = function () {
return unwrapThis(this, "number", Number, "Number.prototype.toString");
};
Number.isFinite = function (value) {
value = unwrapThis(value, "number", Number, "Number.isFinite", "value", undefined);
if (value === undefined || value !== value)
return false;
if (value === Infinity || value === -Infinity)
return false;
return true;
};
Number.isInteger = function (value) {
value = unwrapThis(value, "number", Number, "Number.isInteger", "value", undefined);
if (value === undefined)
return false;
return number.parseInt(value) === value;
};
Number.isNaN = function (value) {
return number.isNaN(value);
};
Number.isSafeInteger = function (value) {
value = unwrapThis(value, "number", Number, "Number.isSafeInteger", "value", undefined);
if (value === undefined || number.parseInt(value) !== value)
return false;
return value >= -9007199254740991 && value <= 9007199254740991;
};
Number.parseFloat = function (value) {
value = 0 + value;
return number.parseFloat(value);
};
Number.parseInt = function (value, radix) {
value = 0 + value;
radix = +radix;
if (number.isNaN(radix))
radix = 10;
return number.parseInt(value, radix);
};
object.defineField(Number, "EPSILON", false, false, false, 2.220446049250313e-16);
object.defineField(Number, "MIN_SAFE_INTEGER", false, false, false, -9007199254740991);
object.defineField(Number, "MAX_SAFE_INTEGER", false, false, false, 9007199254740991);
object.defineField(Number, "POSITIVE_INFINITY", false, false, false, +number.Infinity);
object.defineField(Number, "NEGATIVE_INFINITY", false, false, false, -number.Infinity);
object.defineField(Number, "NaN", false, false, false, number.NaN);
object.defineField(Number, "MAX_VALUE", false, false, false, 1.7976931348623157e+308);
object.defineField(Number, "MIN_VALUE", false, false, false, 5e-324);
func.setCallable(Number, true);
target.Number = Number;
target.parseInt = Number.parseInt;
target.parseFloat = Number.parseFloat;
target.NaN = Number.NaN;
target.Infinity = Number.POSITIVE_INFINITY;
function String(value) {
if (func.invokeType(arguments, this) === "call") {
if (arguments.length === 0)
return "";
else
return value + "";
}
this[valueKey] = String(value);
}
String.prototype.at = function (index) {
throw "Not implemented :/";
return unwrapThis(this, "string", String, "String.prototype.at")[index];
};
String.prototype.toString = function () {
return unwrapThis(this, "string", String, "String.prototype.toString");
};
String.prototype.valueOf = function () {
return unwrapThis(this, "string", String, "String.prototype.valueOf");
};
String.fromCharCode = function () {
var res = [];
res[arguments.length] = 0;
for (var i = 0; i < arguments.length; i++) {
res[i] = string.fromCharCode(+arguments[i]);
}
return string.stringBuild(res);
};
String.fromCodePoint = function () {
var res = [];
res[arguments.length] = 0;
for (var i = 0; i < arguments.length; i++) {
res[i] = string.fromCodePoint(+arguments[i]);
}
return string.stringBuild(res);
};
func.setCallable(String, true);
target.String = String;
function Boolean(value) {
if (func.invokeType(arguments, this) === "call") {
if (arguments.length === 0) return false;
else return !!value;
}
this[valueKey] = Boolean(value);
}
Boolean.prototype.toString = function () {
return "" + unwrapThis(this, "boolean", Boolean, "Boolean.prototype.toString");
};
Boolean.prototype.valueOf = function () {
return unwrapThis(this, "boolean", Boolean, "Boolean.prototype.valueOf");
};
func.setCallable(Boolean, true);
target.Boolean = Boolean;
function Object(value) {
if (typeof value === 'object' && value !== null) return value;
if (typeof value === 'string') return new String(value);
if (typeof value === 'number') return new Number(value);
if (typeof value === 'boolean') return new Boolean(value);
if (typeof value === 'symbol') {
var res = {};
setPrototype(res, Symbol.prototype);
res[valueKey] = value;
return res;
}
return {};
// // TODO: use new.target.prototype as proto
// if (target == null || typeof target !== 'object') target = {};
// return target;
}
Object.prototype.toString = function () {
if (this !== null && this !== undefined && (Symbol.toStringTag in this)) return "[object " + this[Symbol.toStringTag] + "]";
else if (typeof this === "number" || this instanceof Number) return "[object Number]";
else if (typeof this === "symbol" || this instanceof Symbol) return "[object Symbol]";
else if (typeof this === "string" || this instanceof String) return "[object String]";
else if (typeof this === "boolean" || this instanceof Boolean) return "[object Boolean]";
else if (typeof this === "function") return "[object Function]";
else return "[object Object]";
};
Object.prototype.valueOf = function () {
return this;
};
Object.defineProperty = function (obj, key, desc) {
if (typeof obj !== "object" || obj === null) throw new TypeError("Object.defineProperty called on non-object");
if (typeof desc !== "object" || desc === null) throw new TypeError("Property description must be an object: " + desc);
if ("get" in desc || "set" in desc) {
var get = desc.get, set = desc.set;
if (get !== undefined && typeof get !== "function") throw new TypeError("Getter must be a function: " + get);
if (set !== undefined && typeof set !== "function") throw new TypeError("Setter must be a function: " + set);
if ("value" in desc || "writable" in desc) {
throw new TypeError("Invalid property descriptor. Cannot both specify accessors and a value or writable attribute");
}
if (!object.defineProperty(obj, key, desc.enumerable, desc.configurable, get, set)) {
throw new TypeError("Cannot redefine property: " + key);
}
}
else if (!object.defineField(obj, key, desc.writable, desc.enumerable, desc.configurable, desc.value)) {
throw new TypeError("Cannot redefine property: " + key);
}
return obj;
};
func.setCallable(Object, true);
object.setPrototype(Object.prototype, null);
target.Object = Object;
function Function() {
var parts = ["(function annonymous("];
for (var i = 0; i < arguments.length - 1; i++) {
if (i > 0)
parts[parts.length] = ",";
parts[parts.length] = arguments[i];
}
parts[parts.length] = "){\n";
parts[parts.length] = String(arguments[arguments.length - 1]);
parts[parts.length] = "\n})";
var res = compile(string.stringBuild(parts))();
return res;
}
Function.prototype.toString = function () {
if (this.name !== "")
return "function " + this.name + "(...) { ... }";
else
return "function (...) { ... }";
};
Function.compile = function (src, opts) {
if (src === void 0) src = "";
if (opts === void 0) opts = {};
if (opts.globals === void 0) opts.globals = [];
if (opts.wrap === void 0) opts.wrap = false;
var globals = opts.globals;
var wrap = opts.wrap;
var parts = [];
if (wrap) parts[parts.length] = "return (function() {\n";
if (globals.length > 0) {
parts[parts.length] = "let {";
for (var i = 0; i < globals.length; i++) {
if (i > 0) parts[parts.length] = ",";
parts[parts.length] = globals[i];
}
parts[parts.length] = "} = arguments[0];";
}
parts[parts.length] = src;
if (wrap) parts[parts.length] = "\n})(arguments[0])";
var res = compile(string.stringBuild(parts));
return res;
};
func.setCallable(Function, true);
target.Function = Function;
function Array(len) {
if (arguments.length === 1 && typeof len === "number") {
var res = [];
res.length = len;
return res;
}
// TODO: Implement spreading
else throw new Error("Spreading not implemented");
}
func.setCallable(Array, true);
target.Array = Array;
function Error(msg) {
if (msg === void 0) { msg = ""; }
if (func.invokeType(arguments, this) === "call")
return new Error(msg);
this.message = msg + "";
}
Error.prototype.toString = function () {
var res = this.name || "Error";
var msg = this.message;
if (msg)
res += ": " + msg;
return res;
};
object.defineField(Error.prototype, "name", true, false, true, "Error");
object.defineField(Error.prototype, "message", true, false, true, "");
func.setCallable(Error, true);
target.Error = Error;
__extends(SyntaxError, Error);
function SyntaxError(msg) {
if (func.invokeType(arguments, this) === "call")
return new SyntaxError(msg);
return _super.call(this, msg) || this;
}
object.defineField(SyntaxError.prototype, "name", true, false, true, "SyntaxError");
func.setCallable(SyntaxError, true);
target.SyntaxError = SyntaxError;
__extends(TypeError, Error);
function TypeError(msg) {
if (func.invokeType(arguments, this) === "call")
return new TypeError(msg);
return _super.call(this, msg) || this;
}
object.defineField(TypeError.prototype, "name", true, false, true, "TypeError");
func.setCallable(TypeError, true);
target.TypeError = TypeError;
__extends(RangeError, Error);
function RangeError(msg) {
if (func.invokeType(arguments, this) === "call")
return new RangeError(msg);
return _super.call(this, msg) || this;
}
object.defineField(RangeError.prototype, "name", true, false, true, "RangeError");
func.setCallable(RangeError, true);
target.RangeError = RangeError;
target.uint8 = primordials.uint8;
setGlobalPrototypes({
string: String.prototype,
number: Number.prototype,
boolean: Boolean.prototype,
symbol: Symbol.prototype,
object: Object.prototype,
array: Array.prototype,
function: Function.prototype,
error: Error.prototype,
syntax: SyntaxError.prototype,
range: RangeError.prototype,
type: TypeError.prototype,
});
})(arguments[0], arguments[1]);