diff --git a/.gitignore b/.gitignore index 9254aec..edf93b9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ * -!/src +!/src/ !/src/**/* !/doc @@ -21,4 +21,6 @@ !/gradle.properties !/gradle !/gradle/wrapper -!/gradle/wrapper/gradle-wrapper.properties \ No newline at end of file +!/gradle/wrapper/gradle-wrapper.properties + +!/ \ No newline at end of file diff --git a/src/main/java/me/topchetoeu/jscript/compilation/control/IfNode.java b/src/main/java/me/topchetoeu/jscript/compilation/control/IfNode.java index ef6546b..bd75010 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/control/IfNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/control/IfNode.java @@ -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++; diff --git a/src/main/java/me/topchetoeu/jscript/runtime/SimpleRepl.java b/src/main/java/me/topchetoeu/jscript/runtime/SimpleRepl.java index 0e8bf90..f36e833 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/SimpleRepl.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/SimpleRepl.java @@ -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 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; })); diff --git a/src/main/resources/lib/index.js b/src/main/resources/lib/index.js index 023a569..cbdd81f 100644 --- a/src/main/resources/lib/index.js +++ b/src/main/resources/lib/index.js @@ -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]);