feat: create build process for environment

This commit is contained in:
TopchetoEU 2024-12-11 11:51:03 +02:00
parent 3abdd8d3c9
commit 17406c6b81
Signed by: topchetoeu
GPG Key ID: 6531B8583E5F6ED4
7 changed files with 187 additions and 797 deletions

18
.gitignore vendored
View File

@ -1,26 +1,18 @@
* /*
!/src/
!/src/**/*
!/src
!/doc !/doc
!/doc/**/*
!/tests !/tests
!/tests/**/*
!/.github !/.github
!/.github/**/*
!/.gitignore !/.gitignore
!/.gitattributes !/.gitattributes
!/LICENSE !/LICENSE
!/README.md !/README.md
!/settings.gradle !/settings.gradle
!/build.gradle !/build.gradle
!/gradle.properties !/gradle.properties
!/gradle
!/gradle/wrapper
!/gradle/wrapper/gradle-wrapper.properties
!/ !/package.json
!/rollup.config.js

View File

@ -2,6 +2,7 @@ import java.text.SimpleDateFormat
plugins { plugins {
id 'application' id 'application'
id 'com.github.node-gradle.node' version '5.0.0'
id 'net.nemerosa.versioning' version '2.15.0' id 'net.nemerosa.versioning' version '2.15.0'
id 'org.ajoberstar.grgit' version '5.0.0-rc.3' // required by gradle id 'org.ajoberstar.grgit' version '5.0.0-rc.3' // required by gradle
@ -14,6 +15,31 @@ version = project.project_version
group = project.project_group group = project.project_group
description = 'ES5-compliant JavaScript interpreter' description = 'ES5-compliant JavaScript interpreter'
node {
version = '20.0.0'
npmVersion = '8.0.0'
download = true
}
task compileEnv(type: NpmTask) {
inputs.files('rollup.config.js')
inputs.dir('src/lib/libs')
outputs.files("build/js/env.js")
// group = 'build'
args = ['run', 'build-env']
}
task compileTypescript(type: NpmTask) {
inputs.files('rollup.config.js')
inputs.dir('src/lib/ts')
outputs.files("build/js/ts.js")
environment.put("NODE_OPTIONS", "--max-old-space-size=4096")
// group = 'build'
args = ['run', 'build-ts']
}
repositories { repositories {
mavenCentral() mavenCentral()
} }
@ -73,6 +99,13 @@ distTar {
} }
processResources { processResources {
dependsOn compileEnv
dependsOn compileTypescript
from("build/js") {
into "lib"
}
filesMatching "metadata.json", { filesMatching "metadata.json", {
expand( expand(
version: project.project_version, version: project.project_version,

View File

@ -1,7 +0,0 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

24
package.json Normal file
View File

@ -0,0 +1,24 @@
{
"scripts": {
"build-env": "rollup -c --environment INPUT:src/lib/libs/_entry.ts,OUTPUT:build/js/index.js,POLYFILLS:src/lib/libs/polyfills",
"build-ts": "rollup -c --environment INPUT:src/lib/ts/_entry.ts,OUTPUT:build/js/ts.js"
},
"dependencies": {
"@babel/runtime": "^7.26.0",
"typescript": "^5.7.2"
},
"devDependencies": {
"@babel/plugin-transform-class-properties": "^7.25.9",
"@babel/plugin-transform-runtime": "^7.25.9",
"@babel/plugin-transform-typescript": "^7.25.9",
"@babel/preset-env": "^7.26.0",
"@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^12.1.1",
"@types/node": "^22.10.1",
"rollup": "^4.24.0",
"tslib": "^2.8.0"
}
}

125
rollup.config.js Normal file
View File

@ -0,0 +1,125 @@
const { defineConfig } = require("rollup");
const terser = require("@rollup/plugin-terser");
const typescript = require("@rollup/plugin-typescript");
const babel = require("@rollup/plugin-babel");
const commonjs = require("@rollup/plugin-commonjs");
const nodeResolve = require("@rollup/plugin-node-resolve");
const { resolve } = require("path");
const shouldMinify = () => false;
const shouldEmitSourcemaps = () => true;
const shouldPolyfill = () => !!process.env.POLYFILLS;
const construct = (input, output) => defineConfig({
input,
plugins: [
shouldPolyfill() && {
name: "babel-fake-runtime",
resolveId(source) {
if (source.startsWith("!polyfills:/helpers")) return resolve(process.env.POLYFILLS) + source.slice(19) + ".js";
}
},
commonjs(),
nodeResolve(),
babel({
extensions: [],
exclude: ["node_modules/**"],
babelHelpers: "runtime",
plugins: [
["@babel/plugin-transform-typescript", {
onlyRemoveTypeImports: true,
optimizeConstEnums: true,
allowDeclareFields: true,
}],
["@babel/plugin-transform-class-properties"],
["@babel/plugin-transform-runtime", {
moduleName: shouldPolyfill() ? "!polyfills:" : undefined,
version: "^7.24.0",
}],
]
}),
babel({
extensions: [],
exclude: shouldPolyfill() ? [process.env.POLYFILLS + "/**"] : [],
assumptions: {
ignoreToPrimitiveHint: true,
noClassCalls: true,
},
env: {
development: { compact: false },
},
babelHelpers: "runtime",
plugins: [
"@babel/plugin-transform-arrow-functions",
"@babel/plugin-transform-block-scoping",
"@babel/plugin-transform-classes",
"@babel/plugin-transform-computed-properties",
"@babel/plugin-transform-destructuring",
"@babel/plugin-transform-for-of",
"@babel/plugin-transform-object-super",
"@babel/plugin-transform-parameters",
"@babel/plugin-transform-shorthand-properties",
"@babel/plugin-transform-spread",
"@babel/plugin-transform-object-rest-spread",
"@babel/plugin-transform-template-literals",
"@babel/plugin-transform-unicode-escapes",
"@babel/plugin-transform-unicode-regex",
"@babel/plugin-transform-exponentiation-operator",
"@babel/plugin-transform-async-to-generator",
"@babel/plugin-transform-async-generator-functions",
"@babel/plugin-transform-nullish-coalescing-operator",
"@babel/plugin-transform-optional-chaining",
"@babel/plugin-transform-logical-assignment-operators",
"@babel/plugin-transform-numeric-separator",
"@babel/plugin-transform-class-properties",
"@babel/plugin-transform-class-static-block",
"@babel/plugin-transform-regenerator",
["@babel/plugin-transform-runtime", {
moduleName: shouldPolyfill() ? "!polyfills:" : undefined,
version: "^7.24.0",
}],
],
}),
typescript({
exclude: ["node_modules/**", "*.js"],
compilerOptions: {
allowImportingTsExtensions: true,
noEmit: true,
},
noForceEmit: true,
noEmitOnError: true,
}),
shouldMinify() && terser({
sourceMap: shouldEmitSourcemaps(),
keep_classnames: true,
}),
{
load(source) {
console.log(source);
}
},
],
output: {
file: output,
format: "iife",
globals: {
fs: "null",
path: "null",
os: "null",
inspector: "null",
},
// plugins: [babel.getBabelOutputPlugin({
// allowAllFormats: true,
// })],
sourcemap: shouldEmitSourcemaps(),
inlineDynamicImports: true,
},
});
module.exports = construct(process.env.INPUT, process.env.OUTPUT);

View File

@ -1,235 +0,0 @@
import { parse } from "acorn";
import {} from "acorn";
import { traverse } from "estraverse";
import { Declaration, Identifier, Node, VariableDeclaration } from "estree";
enum VariableType {
Var,
Let,
Const,
}
class Variable {
public constructor(
public readonly scope: Scope,
public readonly name: string,
public readonly type: VariableType,
public readonly readers = new Set<Node>(),
public readonly writers = new Set<Node>(),
) { }
public child(scope: Scope) {
return new Variable(scope, this.name, this.type, this.readers, this.writers);
}
public get writable() {
return this.type !== VariableType.Const;
}
}
class Scope {
private _locals = new Set<Variable>();
private _capturables = new Set<Variable>();
private _captures = new Set<Variable>();
private _localNames = new Map<string, Variable>();
private _captureNames = new Map<string, Variable>();
private _parentToChild = new Map<Variable, Variable>();
private _childToParent = new Map<Variable, Variable>();
public get locals() {
return Iterator.from(this._locals.values());
}
private _addCapture(v?: Variable) {
if (v != null && this._locals.delete(v)) {
this._capturables.add(v);
}
return v;
}
public capture(name: string) {
if (this._localNames.has(name)) return this._addCapture(this._localNames.get(name));
if (this._captureNames.has(name)) return this._addCapture(this._captureNames.get(name));
const parent = this.parent?.capture(name);
if (parent == null) return undefined;
const child = parent.child(this);
this._parentToChild.set(parent, child);
this._childToParent.set(child, parent);
this._captures.add(child);
this._captureNames.set(child.name, child);
}
public add(name: string, type: VariableType) {
let res = this.get(name, false);
if (res != null) return res;
res = new Variable(this, name, type);
this._locals.add(res);
this._localNames.set(name, res);
return res;
}
public get(name: string, capture = true): Variable | undefined {
if (this._localNames.has(name)) return this._localNames.get(name);
if (this._captureNames.has(name)) return this._captureNames.get(name);
if (capture) this.parent?.capture(name);
else return undefined;
}
public constructor(
public readonly major: boolean,
public readonly node: Node,
public readonly parent?: Scope,
) { }
}
class BiMap<A, B> implements Iterable<[A, B]> {
private _first = new Map<A, B>();
private _second = new Map<B, A>();
public get(val: A): B;
public get(val: B): A;
public get(val: any) {
if (this._first.has(val)) return this._first.get(val);
if (this._second.has(val)) return this._second.get(val);
if (this._same.has(val)) return val;
return undefined;
}
public set(a: A, b: B) {
this._first.set(a, b);
this._second.set(b, a);
return this;
}
public has(val: A | B) {
return this._first.has(val as any) || this._second.has(val as any);
}
public delete(val: A | B) {
if (this._first.has(val as any)) {
const second = this._first.get(val as any)!;
this._first.delete(val as any);
this._second.delete(second);
return true;
}
else if (this._second.has(val as any)) {
const first = this._second.get(val as any)!;
this._second.delete(val as any);
this._first.delete(first);
return true;
}
else return false;
}
public *[Symbol.iterator]() {
yield *this._first;
}
public *keys() {
yield *this._first.keys();
}
public *values() {
yield *this._second.keys();
}
public *entries() {
yield *this._first.entries();
}
}
class ResolutionContext {
public readonly variableRefs = new Map<Identifier, Scope>();
public readonly declarations = new BiMap<Variable, Declaration>();
public resolveVariables() {
for (const el of this.variableRefs) {
}
}
}
class NodeContext {
public node: Node = undefined!;
public path: Node[] = [];
public atPath(i: number) {
return this.path[this.path.length - 1 - i];
}
public scope: Scope = undefined!;
public declType?: VariableType;
}
interface Collector {
enter(ctx: NodeContext, root: ResolutionContext): void;
leave(ctx: NodeContext, root: ResolutionContext): void;
}
function collect(node: Node, root: ResolutionContext, ...collectors: Collector[]) {
const nodeCtx = new NodeContext();
const path: Node[] = [];
traverse(node, {
enter(node) {
nodeCtx.node = node;
nodeCtx.path.push(node);
for (let i = 0; i < collectors.length; i++) {
collectors[i].enter(nodeCtx, root);
}
},
leave(node) {
nodeCtx.node = node;
nodeCtx.path.pop();
for (let i = 0; i < collectors.length; i++) {
collectors[i].leave(nodeCtx, root);
}
},
});
}
function assertDefined(val: unknown): asserts val is {} {
if (val == null) throw new Error("Undefined or null expression");
}
const scopeCollector: Collector = {
enter(ctx, root) {
if (ctx.node.type === "BlockStatement") {
ctx.scope = new Scope(false, ctx.node, ctx.scope.parent);
}
else if (ctx.node.type === "VariableDeclaration") {
switch (ctx.node.kind) {
case "var": ctx.declType = VariableType.Var; break;
case "let": ctx.declType = VariableType.Let; break;
case "const": ctx.declType = VariableType.Const; break;
default: throw new Error(`Unknown variable type '${(ctx.node as any).kind}'`);
}
}
else if (ctx.node.type === "VariableDeclarator") {
ctx.scope.
}
else if (ctx.node.type === "ClassDeclaration") {
}
else if (ctx.node.type === "Identifier") {
}
},
leave(ctx, root) {
if (ctx.scope.node === ctx.node) {
assertDefined(ctx.scope.parent);
ctx.scope = ctx.scope.parent;
}
else if (ctx.node.type === "VariableDeclaration") {
ctx.declType = undefined;
}
},
};
const program = parse("const a = 10;", { ecmaVersion: "latest" }) as Node;
collect(program, domain, ...stage1);

View File

@ -1,542 +0,0 @@
(function main() {
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
};
function extend(derived, base) {
if (base == null) {
object.setPrototype(derived.prototype, null);
}
else {
object.setPrototype(derived, base);
object.setPrototype(derived.prototype, base.prototype);
}
}
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 map = primordials.map;
var regex = primordials.regex;
var setGlobalPrototypes = primordials.setGlobalPrototypes;
var compile = primordials.compile;
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) { }
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"));
};
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);
target.Symbol = Symbol;
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.prototype[Symbol.iterator] = function () {
var i = 0;
var arr = this;
var obj = {
next: function () {
if (arr == null) return { done: true, value: undefined };
if (i > arr.length) {
arr = undefined;
return { done: true, value: undefined };
}
else {
var val = arr[i++];
if (i >= arr.length) arr = undefined;
return { done: false, value: val };
}
}
};
obj[Symbol.iterator] = function () { return this; };
return obj;
}
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);
extend(Object, null);
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");
}
Array.prototype[Symbol.iterator] = function () {
var i = 0;
var arr = this;
var obj = {
next: function () {
if (arr == null) return { done: true, value: undefined };
if (i > arr.length) {
arr = undefined;
return { done: true, value: undefined };
}
else {
var val = arr[i++];
if (i >= arr.length) arr = undefined;
return { done: false, value: val };
}
}
};
obj[Symbol.iterator] = function () { return this; };
return obj;
}
Array.isArray = function (val) {
return val instanceof Array;
}
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;
extend(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;
extend(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;
extend(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;
var mapKey = Symbol("Map.impl");
function Map(iterable) {
var _map = this[mapKey] = new map();
if (iterable != null) {
var it = iterable[Symbol.iterator]();
for (var val = it.next(); !val.done; val = it.next()) {
_map.set(val.value[0], val.value[1]);
}
}
}
Map.prototype.get = function (key) {
return this[mapKey].get(key);
}
Map.prototype.has = function (key) {
return this[mapKey].has(key);
}
Map.prototype.set = function (key, val) {
return this[mapKey].set(key, val);
}
Map.prototype.delete = function (key, val) {
return this[mapKey].delete(key, val);
}
Map.prototype.keys = function (key, val) {
return this[mapKey].keys(key, val);
}
Map.prototype.values = function (key, val) {
var res = this[mapKey].keys(key, val);
for (var i = 0; i < res.length; i++) res[i] = this[mapKey].get(res[i]);
return res;
}
Map.prototype.entries = function (key, val) {
var res = this[mapKey].keys(key, val);
for (var i = 0; i < res.length; i++) res[i] = [res[i], this[mapKey].get(res[i])];
return res;
}
func.setCallable(Map, false);
target.Map = Map;
var regexKey = Symbol("RegExp.impl");
function RegExp(source, flags) {
var _regex = this[regexKey] = new regex();
source = this.source = String("source" in source ? source.source : source);
flags = String(flags);
var indices = false, global = false, ignoreCase = false, multiline = false, dotall = false, unicode = false, unicodeSets = false, sticky = false;
for (var i = 0; i < flags.length; i++) {
switch (flags[i]) {
case "d": indices = true; break;
case "g": global = true; break;
case "i": ignoreCase = true; break;
case "m": multiline = true; break;
case "s": dotall = true; break;
case "u": unicode = true; break;
case "v": unicodeSets = true; break;
case "y": sticky = true; break;
}
}
flags = "";
if (indices) flags += "d";
if (global) flags += "g";
if (ignoreCase) flags += "i";
if (multiline) flags += "m";
if (dotall) flags += "s";
if (unicode) flags += "u";
if (unicodeSets) flags += "v";
if (sticky) flags += "y";
this.flags = flags;
}
target.RegExp = RegExp;
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,
regex: RegExp,
});
})(arguments[0], arguments[1]);