feat: implement simple env + ts loader

This commit is contained in:
TopchetoEU 2024-12-11 11:53:02 +02:00
parent 17406c6b81
commit bed4014bef
Signed by: topchetoeu
GPG Key ID: 6531B8583E5F6ED4
24 changed files with 989 additions and 20 deletions

56
src/lib/libs/_entry.ts Normal file
View File

@ -0,0 +1,56 @@
import { Boolean } from "./boolean.ts";
import { Error, RangeError, SyntaxError, TypeError } from "./errors.ts";
import { Function } from "./function.ts";
import { Number } from "./number.ts";
import { Object } from "./object.ts";
import { object, setGlobalPrototypes, target } from "./primordials.ts";
import { String } from "./string.ts";
import { Symbol } from "./symbol.ts";
import { Array } from "./array.ts";
import { Map } from "./map.ts";
import { RegExp } from "./regex.ts";
declare global {
function print(...args: any[]): void;
}
object.defineField(target, "undefined", false, false, false, undefined);
target.Symbol = Symbol;
target.Number = Number;
target.String = String;
target.Boolean = Boolean;
target.Object = Object;
target.Function = Function;
target.Array = Array;
target.Error = Error;
target.RangeError = RangeError;
target.SyntaxError = SyntaxError;
target.TypeError = TypeError;
target.Map = Map;
target.parseInt = Number.parseInt;
target.parseFloat = Number.parseFloat;
target.NaN = Number.NaN;
target.Infinity = Number.POSITIVE_INFINITY;
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,
});

53
src/lib/libs/array.ts Normal file
View File

@ -0,0 +1,53 @@
import { func, object } from "./primordials.ts";
import { Symbol } from "./symbol.ts";
export const Array = (() => {
class Array {
public forEach(this: any[], cb: (val: any, i: number, self: this[]) => void, self?: any) {
for (let i = 0; i < this.length; i++) {
if (i in this) func.invoke(cb, self, [this[i], i, this]);
}
}
public [Symbol.iterator](this: any[]) {
let i = 0;
let arr: any[] | undefined = this;
return {
next() {
if (arr == null) return { done: true, value: undefined };
if (i > arr.length) {
arr = undefined;
return { done: true, value: undefined };
}
else {
const val = arr[i++];
if (i >= arr.length) arr = undefined;
return { done: false, value: val };
}
},
[Symbol.iterator]() { return this; }
};
}
public constructor (len: unknown) {
if (arguments.length === 1 && typeof len === "number") {
const res: any[] = [];
res.length = len;
return res as any;
}
// TODO: Implement spreading
else throw new Error("Spreading not implemented");
}
public static isArray(val: any[]) {
object.isArray(val);
}
}
func.setCallable(Array, true);
func.setConstructable(Array, true);
return Array as any as typeof Array & ((value?: unknown) => object);
})();
export type Array = InstanceType<typeof Array>;

29
src/lib/libs/boolean.ts Normal file
View File

@ -0,0 +1,29 @@
import { func } from "./primordials.ts";
import { unwrapThis, valueKey } from "./utils.ts";
export const Boolean = (() => {
class Boolean {
[valueKey]!: boolean;
public toString() {
return "" + unwrapThis(this, "boolean", Boolean, "Boolean.prototype.toString");
}
public valueOf() {
return unwrapThis(this, "boolean", Boolean, "Boolean.prototype.valueOf");
}
public constructor(value?: unknown) {
if (func.invokeType(arguments, this) === "call") {
if (arguments.length === 0) return false as any;
else return !!value as any;
}
this[valueKey] = (Boolean as any)(value);
}
};
func.setCallable(Boolean, true);
func.setConstructable(Boolean, true);
return Boolean as any as typeof Boolean & ((value?: unknown) => symbol);
})();
export type Boolean = InstanceType<typeof Boolean>;

39
src/lib/libs/errors.ts Normal file
View File

@ -0,0 +1,39 @@
import { func, object } from "./primordials.ts";
import { String } from "./string.ts";
export class Error {
public declare name: string;
public declare message: string;
public toString() {
let res = this.name || "Error";
const msg = this.message;
if (msg) res += ": " + msg;
return res;
}
public constructor (msg = "") {
if (func.invokeType(arguments, this) === "call") return new Error(msg);
this.message = String(msg);
}
}
object.defineField(Error.prototype, "name", true, false, true, "Error");
object.defineField(Error.prototype, "message", true, false, true, "");
func.setCallable(Error, true);
func.setConstructable(Error, true);
export class SyntaxError extends Error { }
object.defineField(SyntaxError.prototype, "name", true, false, true, "SyntaxError");
func.setCallable(SyntaxError, true);
func.setConstructable(SyntaxError, true);
export class TypeError extends Error { }
object.defineField(TypeError.prototype, "name", true, false, true, "TypeError");
func.setCallable(TypeError, true);
func.setConstructable(TypeError, true);
export class RangeError extends Error { }
object.defineField(RangeError.prototype, "name", true, false, true, "RangeError");
func.setCallable(RangeError, true);
func.setConstructable(RangeError, true);

61
src/lib/libs/function.ts Normal file
View File

@ -0,0 +1,61 @@
import { compile, func, string } from "./primordials.ts";
import { String } from "./string.ts";
export const Function = (() => {
class Function {
declare public readonly name: string;
declare public readonly length: number;
public toString(this: Function) {
if (this.name !== "") return "function " + this.name + "(...) { ... }";
else return "function (...) { ... }";
}
public valueOf() {
return this;
}
public apply(this: (...args: any) => any, self: any, args: any[]) {
return func.invoke(this, self, args);
}
public call(this: (...args: any) => any, self: any, ...args: any[]) {
return func.invoke(this, self, args);
}
public constructor (...args: string[]) {
const parts = ["(function anonymous("];
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})";
var res = compile(string.stringBuild(parts))();
return res;
}
public static compile(src = "", { globals = [], wrap = false }: { globals?: string[], wrap?: boolean } = {}) {
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;
}
}
func.setCallable(Function, true);
func.setConstructable(Function, true);
return Function as any as typeof Function & ((value?: unknown) => (...args: any[]) => any);
})();

61
src/lib/libs/map.ts Normal file
View File

@ -0,0 +1,61 @@
import { func, map } from "./primordials.ts";
import { Symbol } from "./symbol.ts";
const mapKey: unique symbol = Symbol("Map.impl") as any;
export class Map<K, V> {
private [mapKey]: InstanceType<typeof map>;
public get(key: K): V {
return this[mapKey].get(key);
}
public has(key: K): boolean {
return this[mapKey].has(key);
}
public set(key: K, val: V) {
this[mapKey].set(key, val);
return this;
}
public delete(key: K): boolean {
if (!this[mapKey].has(key)) return false;
else {
this[mapKey].delete(key);
return true;
}
}
public keys(): K[] {
return this[mapKey].keys();
}
public values(): V[] {
const res = this[mapKey].keys();
for (let i = 0; i < res.length; i++) {
res[i] = this[mapKey].get(res[i]);
}
return res;
}
public entries(): [K, V][] {
const res = this[mapKey].keys();
for (let i = 0; i < res.length; i++) {
res[i] = [res[i], this[mapKey].get(res[i])];
}
return res;
}
public [Symbol.iterator](): Iterator<[K, V]> {
return func.invoke(Array.prototype[Symbol.iterator as any], this.entries(), []) as any;
}
public constructor(iterable?: Iterable<[K, V]>) {
const _map = this[mapKey] = new map();
if (iterable != null) {
const it = (iterable as any)[Symbol.iterator]();
for (let val = it.next(); !val.done; val = it.next()) {
_map.set(val.value[0], val.value[1]);
}
}
}
}
func.setCallable(Map, false);

77
src/lib/libs/number.ts Normal file
View File

@ -0,0 +1,77 @@
import { func, number, object } from "./primordials.ts";
import { unwrapThis, valueKey } from "./utils.ts";
export const Number = (() => {
class Number {
[valueKey]!: number;
public toString() {
return "" + unwrapThis(this, "number", Number, "Number.prototype.toString");
}
public valueOf() {
return unwrapThis(this, "number", Number, "Number.prototype.toString");
}
public constructor (value?: unknown) {
if (func.invokeType(arguments, this) === "call") {
if (arguments.length === 0) return 0 as any;
else return +(value as any) as any;
}
this[valueKey] = (Number as any)(value);
}
public static isFinite(value: number) {
value = unwrapThis(value, "number", Number, "Number.isFinite", "value");
if (value === undefined || value !== value) return false;
if (value === Infinity || value === -Infinity) return false;
return true;
}
public static isInteger(value: number) {
value = unwrapThis(value, "number", Number, "Number.isInteger", "value");
if (value === undefined) return false;
return number.parseInt(value) === value;
}
public static isNaN(value: number) {
return number.isNaN(value);
}
public static isSafeInteger(value: number) {
value = unwrapThis(value, "number", Number, "Number.isSafeInteger", "value");
if (value === undefined || number.parseInt(value) !== value) return false;
return value >= -9007199254740991 && value <= 9007199254740991;
}
public static parseFloat(value: unknown) {
if (typeof value === "number") return value;
else return number.parseFloat(value + "");
}
public static parseInt(value: unknown, radix = 10) {
radix = +radix;
if (number.isNaN(radix)) radix = 10;
if (typeof value === "number") return number.parseInt(value, radix);
else return number.parseInt(value + "", radix);
}
public static readonly EPSILON: number;
public static readonly MIN_SAFE_INTEGER: number;
public static readonly MAX_SAFE_INTEGER: number;
public static readonly POSITIVE_INFINITY: number;
public static readonly NEGATIVE_INFINITY: number;
public static readonly NaN: number;
public static readonly MAX_VALUE: number;
public static readonly MIN_VALUE: number;
}
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);
func.setConstructable(Number, true);
return Number as any as typeof Number & ((value?: unknown) => number);
})();
export type Number = InstanceType<typeof Number>;

90
src/lib/libs/object.ts Normal file
View File

@ -0,0 +1,90 @@
import { Boolean } from "./boolean.ts";
import { TypeError } from "./errors.ts";
import { Number } from "./number.ts";
import { func, object } from "./primordials.ts";
import { String } from "./string.ts";
import { Symbol } from "./symbol.ts";
import { valueKey } from "./utils.ts";
export const Object = (() => {
class Object {
public toString(this: unknown) {
if (this === undefined) return "[object Undefined]";
else if (this === null) return "[object Null]";
else if (typeof this === "object") {
if (Symbol.toStringTag in this) return "[object " + this[Symbol.toStringTag] + "]";
else return "[object Object]";
}
else if (typeof this === "number" || this instanceof Object) return "[object Object]";
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]";
}
public valueOf() {
return this;
}
public constructor (value?: unknown) {
if (typeof value === 'object' && value !== null) return value as any;
if (typeof value === 'string') return new String(value) as any;
if (typeof value === 'number') return new Number(value) as any;
if (typeof value === 'boolean') return new Boolean(value) as any;
if (typeof value === 'symbol') {
var res: Symbol = {} as any;
object.setPrototype(res, Symbol.prototype);
res[valueKey] = value;
return res as any;
}
return {} as any;
}
public static defineProperty(obj: object, key: string | symbol, desc: PropertyDescriptor) {
if (obj === null || typeof obj !== "function" && typeof obj !== "object") throw new TypeError("Object.defineProperty called on non-object");
if (desc === null || typeof desc !== "function" && typeof desc !== "object") 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: " + String(key));
}
}
else if (!object.defineField(obj, key, !!desc.writable, !!desc.enumerable, !!desc.configurable, desc.value)) {
throw new TypeError("Cannot redefine property: " + String(key));
}
return obj;
}
public static defineProperties(obj: object, desc: PropertyDescriptorMap) {
const keys = object.getOwnMembers(obj, false);
const symbols = object.getOwnSymbolMembers(obj, false);
for (let i = 0; i < keys.length; i++) {
Object.defineProperty(obj, keys[i], desc[keys[i]]);
}
for (let i = 0; i < symbols.length; i++) {
Object.defineProperty(obj, symbols[i], desc[symbols[i]]);
}
return obj;
}
public static create(proto: object, desc?: PropertyDescriptorMap) {
let res = object.setPrototype({}, proto);
if (desc != null) this.defineProperties(res, desc);
return res;
}
}
func.setCallable(Object, true);
func.setConstructable(Object, true);
return Object as any as typeof Object & ((value?: unknown) => object);
})();
export type Object = InstanceType<typeof Object>;

View File

@ -0,0 +1,5 @@
import { func, object } from "../primordials.ts";
export default function _callSuper(self, constr, args) {
return func.construct(object.getPrototype(constr), func.target(1), args || []);
}

View File

@ -0,0 +1,5 @@
import { func } from "../primordials.ts";
export default function _classCallCheck() {
if (func.invokeTypeInfer() !== "new") throw new TypeError("Cannot call a class as a function");
}

View File

@ -0,0 +1,25 @@
import { object } from "../primordials.ts";
function _defineProperties(target, arr) {
if (!arr) return;
for (var t = 0; t < arr.length; t++) {
var desc = arr[t];
if ("value" in desc) {
object.defineField(target, desc.key, desc.writable || true, desc.enumerable || false, desc.configurable || true, desc.value);
}
else {
object.defineProperty(target, desc.key, desc.enumerable || false, desc.configurable || true, desc.get, desc.set);
}
}
}
/* __#PURE__ */
export default function _createClass(clazz, instance, nonInstance) {
if (instance) {
_defineProperties(clazz.prototype, instance);
_defineProperties(clazz, nonInstance);
}
return clazz;
}

View File

@ -0,0 +1,7 @@
import { object } from "../primordials.ts";
export default function _defineProperty(obj, key, val) {
if (obj == null) return;
object.defineField(obj, key, true, true, true, val);
return obj;
}

View File

@ -0,0 +1,5 @@
import { object } from "../primordials.ts";
export default function _getPrototypeOf(obj) {
return object.getPrototype(obj) || null;
}

View File

@ -0,0 +1,11 @@
import { object } from "../primordials.ts";
export default function _inherits(t, e) {
if (e == null) {
object.setPrototype(t.prototype, undefined);
}
else {
object.setPrototype(t.prototype, e.prototype);
object.setPrototype(t, e);
}
}

View File

@ -0,0 +1,2 @@
export default function _possibleConstructorReturn() {
}

View File

@ -0,0 +1,5 @@
import { object } from "../primordials";
export default function _setPrototypeOf(obj, proto) {
object.setPrototype(obj, proto);
}

View File

@ -0,0 +1,3 @@
export default function _typeof(val) {
return typeof val;
}

View File

@ -0,0 +1,82 @@
export interface SymbolPrimordials {
makeSymbol(name: string): symbol;
getSymbol(name: string): symbol;
getSymbolKey(symbol: symbol): string | undefined;
getSymbolDescription(symbol: symbol): string;
}
export interface NumberPrimordials {
parseInt(raw: string | number, radix?: number): number;
parseFloat(raw: string | number): number;
isNaN(num: number): boolean;
NaN: number;
Infinity: number;
}
export interface StringPrimordials {
stringBuild(parts: string[]): string;
fromCharCode(char: number): string;
fromCodePoint(char: number): string;
}
export interface ObjectPrimordials {
defineProperty(obj: object, key: string | number | symbol, enumerable: boolean, configurable: boolean, get?: Function, set?: Function): boolean;
defineField(obj: object, key: string | number | symbol, writable: boolean, enumerable: boolean, configurable: boolean, value: any): boolean;
getOwnMember(): any;
getOwnSymbolMember(): any;
getOwnMembers(obj: object, onlyEnumerable: boolean): string[];
getOwnSymbolMembers(obj: object, onlyEnumerable: boolean): symbol[];
getPrototype(obj: object): object | undefined;
setPrototype(obj: object, proto?: object): object;
isArray(obj: any[]): boolean;
}
export interface FunctionPrimordials {
invokeType(args: IArguments, self: any): "new" | "call";
invokeTypeInfer(): "new" | "call";
target(): Function | null | undefined;
setConstructable(func: Function, flag: boolean): void;
setCallable(func: Function, flag: boolean): void;
invoke(func: Function, self: any, args: any[]): void;
construct(func: Function, self: any, args: any[]): void;
}
export interface JSONPrimordials {
parse(data: string): any;
stringify(data: any): string;
}
export interface Primordials {
symbol: SymbolPrimordials;
number: NumberPrimordials;
string: StringPrimordials;
object: ObjectPrimordials;
function: FunctionPrimordials;
json: JSONPrimordials;
map: new () => {
get(key: any): any;
has(key: any): boolean;
set(key: any, val: any): void;
delete(key: any): void;
keys(): any[];
};
regex: new (source: string) => {
exec(target: string, offset: number, indices: false): {
};
};
compile(src: string): Function;
setGlobalPrototypes(prototype: Record<string, any>): void;
}
globalThis.undefined = void 0;
export const target = (globalThis as any).target;
export const primordials: Primordials = (globalThis as any).primordials;
export const {
symbol,
number,
string,
object,
function: func,
json,
map,
regex,
setGlobalPrototypes,
compile,
} = primordials;

54
src/lib/libs/regex.ts Normal file
View File

@ -0,0 +1,54 @@
import { func, regex } from "./primordials.ts";
import { String } from "./string.ts";
import { Symbol } from "./symbol.ts";
const regexKey: unique symbol = Symbol("RegExp.impl") as any;
export class RegExp {
private [regexKey]: InstanceType<typeof regex>;
public readonly source: string;
public readonly flags: string;
public lastIndex = 0;
public constructor(source: any, flags: string) {
source = this.source = String(typeof source === "object" && "source" in source ? source.source : source);
flags = String(flags);
const _regex = this[regexKey] = new regex(source);
let indices = false;
let global = false;
let ignoreCase = false;
let multiline = false;
let dotall = false;
let unicode = false;
let unicodeSets = false;
let sticky = false;
for (let 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;
}
}
func.setCallable(RegExp, false);

84
src/lib/libs/string.ts Normal file
View File

@ -0,0 +1,84 @@
import { func, string } from "./primordials.ts";
import { Symbol } from "./symbol.ts";
import { unwrapThis, valueKey } from "./utils.ts";
export const String = (() => {
class String {
[valueKey]!: string;
public at(index: number) {
throw "Not implemented :/";
return unwrapThis(this, "string", String, "String.prototype.at")[index];
};
public toString() {
return unwrapThis(this, "string", String, "String.prototype.toString");
}
public valueOf() {
return unwrapThis(this, "string", String, "String.prototype.valueOf");
}
// public split(val: string) {
// const res: string[] = [];
// while (true) {
// val.indexOf();
// }
// }
public [Symbol.iterator]() {
var i = 0;
var arr: string | undefined = unwrapThis(this, "string", String, "String.prototype[Symbol.iterator]");
return {
next () {
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 };
}
},
[Symbol.iterator]() { return this; }
};
}
public constructor (value?: unknown) {
if (func.invokeType(arguments, this) === "call") {
if (arguments.length === 0) return "" as any;
else if (typeof value === "symbol") return value.toString() as any;
else return (value as any) + "" as any;
}
this[valueKey] = (String as any)(value);
}
public static fromCharCode(...args: number[]) {
const res: string[] = [];
res[arguments.length] = "";
for (let i = 0; i < arguments.length; i++) {
res[i] = string.fromCharCode(+arguments[i]);
}
return string.stringBuild(res);
}
public static fromCodePoint(...args: number[]) {
const res: string[] = [];
res[arguments.length] = "";
for (var i = 0; i < arguments.length; i++) {
res[i] = string.fromCodePoint(+arguments[i]);
}
return string.stringBuild(res);
}
}
func.setCallable(String, true);
func.setConstructable(String, true);
return String as any as typeof String & ((value?: unknown) => string);
})();
export type String = InstanceType<typeof String>;

52
src/lib/libs/symbol.ts Normal file
View File

@ -0,0 +1,52 @@
import { func, object, symbol } from "./primordials.ts";
import { unwrapThis, valueKey } from "./utils.ts";
export const Symbol = (() => {
class Symbol {
[valueKey]!: symbol;
get description() {
return symbol.getSymbolDescription(unwrapThis(this, "symbol", Symbol, "Symbol.prototype.description"));
}
public toString() {
return "Symbol(" + unwrapThis(this, "symbol", Symbol, "Symbol.prototype.toString").description + ")";
}
public valueOf() {
return unwrapThis(this, "symbol", Symbol, "Symbol.prototype.valueOf");
}
public constructor(name = "") {
return symbol.makeSymbol(name + "") as any;
}
public static for(name: string) {
return symbol.getSymbol(name + "");
}
public static readonly asyncIterator: unique symbol;
public static readonly iterator: unique symbol;
public static readonly match: unique symbol;
public static readonly matchAll: unique symbol;
public static readonly replace: unique symbol;
public static readonly search: unique symbol;
public static readonly split: unique symbol;
public static readonly toStringTag: unique symbol;
};
func.setCallable(Symbol, true);
func.setConstructable(Symbol, false);
object.defineField(Symbol, "asyncIterator", false, false, false, symbol.getSymbol("Symbol.asyncIterator"));
object.defineField(Symbol, "iterator", false, false, false, symbol.getSymbol("Symbol.iterator"));
object.defineField(Symbol, "match", false, false, false, symbol.getSymbol("Symbol.match"));
object.defineField(Symbol, "matchAll", false, false, false, symbol.getSymbol("Symbol.matchAll"));
object.defineField(Symbol, "replace", false, false, false, symbol.getSymbol("Symbol.replace"));
object.defineField(Symbol, "search", false, false, false, symbol.getSymbol("Symbol.search"));
object.defineField(Symbol, "split", false, false, false, symbol.getSymbol("Symbol.split"));
object.defineField(Symbol, "toStringTag", false, false, false, symbol.getSymbol("Symbol.toStringTag"));
return Symbol as any as typeof Symbol & ((name?: string) => symbol);
})();
export type Symbol = InstanceType<typeof Symbol>;

21
src/lib/libs/utils.ts Normal file
View File

@ -0,0 +1,21 @@
import { symbol } from "./primordials.ts";
export const valueKey: unique symbol = symbol.makeSymbol("Primitive.value") as any;
export interface TypeMap {
undefined: undefined;
boolean: boolean;
string: string;
number: number;
symbol: symbol;
object: null | object;
function: Function;
}
export function unwrapThis<T extends keyof TypeMap>(self: any, type: T, constr: Function, name: string, arg = "this", defaultVal?: TypeMap[T]): TypeMap[T] {
if (typeof self === type) return self;
if (self instanceof constr && valueKey in self) self = (self as any)[valueKey];
if (typeof self === type) return self;
if (defaultVal !== undefined) return defaultVal;
throw new TypeError(name + " requires that '" + arg + "' be a " + constr.name);
}

106
src/lib/ts/_entry.ts Normal file
View File

@ -0,0 +1,106 @@
import { createDocumentRegistry, createLanguageService, ModuleKind, ScriptSnapshot, ScriptTarget, type Diagnostic, type CompilerOptions, type IScriptSnapshot, flattenDiagnosticMessageText, CompilerHost } from "typescript";
declare function getResource(name: string): string;
declare function print(...args: any[]): void;
declare function register(factory: CompilerFactory): void;
type CompilerFactory = (next: Compiler) => Compiler;
type Compiler = (filename: string, src: string, maps: any[]) => Function;
const resources: Record<string, string | undefined> = {};
function resource(name: string) {
if (name in resources) return resources[name];
else return resources[name] = getResource(name);
}
register(next => {
const files: Record<string, IScriptSnapshot> = {};
const versions: Record<string, number> = {};
let declI = 0;
const settings: CompilerOptions = {
target: ScriptTarget.ESNext,
module: ModuleKind.Preserve,
allowImportingTsExtensions: true,
verbatimModuleSyntax: true,
strict: false,
skipLibCheck: true,
forceConsistentCasingInFileNames: true,
declaration: true,
};
const service = createLanguageService({
getCurrentDirectory: () => "/",
getDefaultLibFileName: () => "/lib.d.ts",
getScriptFileNames: () => {
const res = ["/src.ts", "/lib.d.ts"];
for (let i = 0; i < declI; i++) res.push("/src." + i + ".d.ts");
return res;
},
getCompilationSettings: () => settings,
log: print,
fileExists: filename => filename in files || resource(filename) != null,
getScriptSnapshot: (filename) => {
if (filename in files) return files[filename];
else {
const src = resource(filename);
if (src == null) return undefined;
return files[filename] = ScriptSnapshot.fromString(src);
}
},
getScriptVersion: (filename) => String(versions[filename] || 0),
readFile: () => { throw "no"; },
writeFile: () => { throw "no"; },
}, createDocumentRegistry());
service.getEmitOutput("/lib.d.ts");
print("Loaded typescript...");
return (code, filename, mapChain) => {
files["/src.ts"] = ScriptSnapshot.fromString(code);
versions["/src.ts"] ??= 0;
versions["/src.ts"]++;
const emit = service.getEmitOutput("/src.ts");
const diagnostics = new Array<Diagnostic>()
.concat(service.getCompilerOptionsDiagnostics())
.concat(service.getSyntacticDiagnostics("/src.ts"))
.concat(service.getSemanticDiagnostics("/src.ts"))
.map(function (diagnostic) {
const message = flattenDiagnosticMessageText(diagnostic.messageText, "\n");
if (diagnostic.file != null) {
let file = diagnostic.file.fileName.substring(1);
if (file === "src.ts") file = filename;
if (diagnostic.start == null) return file;
const pos = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
return file + ":" + (pos.line + 1) + ":" + (pos.character + 1) + ": " + message;
}
else return message;
});
if (diagnostics.length > 0) {
throw new SyntaxError(diagnostics.join("\n"));
}
var map = JSON.parse(emit.outputFiles[0].text);
var result = emit.outputFiles[1].text;
var declaration = emit.outputFiles[2].text;
var compiled = next(result, filename, mapChain.concat(map));
return function (this: any) {
const res = compiled.apply(this, arguments);
if (declaration !== '') files["/src." + declI++ + ".d.ts"] = ScriptSnapshot.fromString(declaration);
return res;
};
};
});

View File

@ -16,7 +16,6 @@ import me.topchetoeu.jscript.common.environment.Environment;
import me.topchetoeu.jscript.common.environment.Key; import me.topchetoeu.jscript.common.environment.Key;
import me.topchetoeu.jscript.common.json.JSON; import me.topchetoeu.jscript.common.json.JSON;
import me.topchetoeu.jscript.common.parsing.Filename; import me.topchetoeu.jscript.common.parsing.Filename;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.runtime.debug.DebugContext; import me.topchetoeu.jscript.runtime.debug.DebugContext;
import me.topchetoeu.jscript.runtime.exceptions.EngineException; import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.values.Member.FieldMember; import me.topchetoeu.jscript.runtime.values.Member.FieldMember;
@ -298,6 +297,9 @@ public class SimpleRepl {
res.defineOwnMember(env, "getOwnSymbolMembers", new NativeFunction(args -> { res.defineOwnMember(env, "getOwnSymbolMembers", new NativeFunction(args -> {
return ArrayValue.of(args.get(0).getOwnSymbolMembers(env, args.get(1).toBoolean())); return ArrayValue.of(args.get(0).getOwnSymbolMembers(env, args.get(1).toBoolean()));
})); }));
res.defineOwnMember(env, "isArray", new NativeFunction(args -> {
return BoolValue.of(args.get(0) instanceof ArrayValue);
}));
return res; return res;
} }
@ -320,6 +322,16 @@ public class SimpleRepl {
if (((ArgumentsValue)args.get(0)).frame.isNew) return StringValue.of("new"); if (((ArgumentsValue)args.get(0)).frame.isNew) return StringValue.of("new");
else return StringValue.of("call"); else return StringValue.of("call");
})); }));
res.defineOwnMember(env, "invokeTypeInfer", new NativeFunction(args -> {
var frame = Frame.get(args.env, args.get(0).toNumber(args.env).getInt());
if (frame.isNew) return StringValue.of("new");
else return StringValue.of("call");
}));
res.defineOwnMember(env, "target", new NativeFunction(args -> {
var frame = Frame.get(args.env, args.get(0).toNumber(args.env).getInt());
if (frame.target == null) return Value.UNDEFINED;
else return frame.target;
}));
res.defineOwnMember(env, "invoke", new NativeFunction(args -> { res.defineOwnMember(env, "invoke", new NativeFunction(args -> {
var func = (FunctionValue)args.get(0); var func = (FunctionValue)args.get(0);
@ -330,9 +342,11 @@ public class SimpleRepl {
})); }));
res.defineOwnMember(env, "construct", new NativeFunction(args -> { res.defineOwnMember(env, "construct", new NativeFunction(args -> {
var func = (FunctionValue)args.get(0); var func = (FunctionValue)args.get(0);
var funcArgs = (ArrayValue)args.get(1); var target = args.get(1);
var funcArgs = (ArrayValue)args.get(2);
return func.constructNoSelf(env, funcArgs.toArray()); if (target == Value.UNDEFINED) return func.constructNoSelf(env, funcArgs.toArray());
else return func.construct(env, target, funcArgs.toArray());
})); }));
return res; return res;
@ -388,9 +402,9 @@ public class SimpleRepl {
setProto(args.env, env, Value.SYNTAX_ERR_PROTO, obj, "syntax"); 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.TYPE_ERR_PROTO, obj, "type");
setProto(args.env, env, Value.RANGE_ERR_PROTO, obj, "range"); setProto(args.env, env, Value.RANGE_ERR_PROTO, obj, "range");
var val = obj.getMember(env, "regex"); var val = obj.getMember(args.env, "regex");
if (val instanceof FunctionValue func) { if (val instanceof FunctionValue func) {
args.env.add(Value.REGEX_CONSTR, func); env.add(Value.REGEX_CONSTR, func);
} }
return Value.UNDEFINED; return Value.UNDEFINED;
})); }));
@ -409,13 +423,29 @@ public class SimpleRepl {
return res; return res;
} }
private static void initEnv() { private static Environment createESEnv() throws InterruptedException, ExecutionException {
environment.add(EventLoop.KEY, engine); var env = initEnv();
environment.add(DebugContext.KEY, new DebugContext()); var stubEnv = initEnv();
environment.add(Compiler.KEY, Compiler.DEFAULT); Value.global(stubEnv).defineOwnMember(stubEnv, "target", Value.global(env));
Value.global(stubEnv).defineOwnMember(stubEnv, "primordials", primordials(env));
EventLoop.get(stubEnv).pushMsg(
false, stubEnv,
Filename.parse("jscript://init.js"), Reading.resourceToString("lib/index.js"),
Value.UNDEFINED
).get();
return env;
}
private static Environment initEnv() {
var env = new Environment();
env.add(EventLoop.KEY, engine);
env.add(DebugContext.KEY, new DebugContext());
env.add(Compiler.KEY, Compiler.DEFAULT);
// environment.add(CompileResult.DEBUG_LOG); // environment.add(CompileResult.DEBUG_LOG);
var glob = Value.global(environment); var glob = Value.global(env);
glob.defineOwnMember(null, "exit", new NativeFunction("exit", args -> { glob.defineOwnMember(null, "exit", new NativeFunction("exit", args -> {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
@ -439,20 +469,26 @@ public class SimpleRepl {
return Value.UNDEFINED; return Value.UNDEFINED;
})); }));
return env;
} }
private static void initEngine() { private static void initEngine() {
engineTask = engine.start(); engineTask = engine.start();
} }
private static void initGlobals() throws InterruptedException, ExecutionException { private static void initGlobals() throws InterruptedException, ExecutionException {
EventLoop.get(environment).pushMsg( environment = createESEnv();
false, environment, var tsEnv = createESEnv();
Filename.parse("jscript://init.js"), Reading.resourceToString("lib/index.js"), var res = new FunctionValue[1];
Value.UNDEFINED, Value.global(environment), primordials(environment) var setter = new NativeFunction(args -> {
).get(); res[0] = (FunctionValue)args.get(0);
EventLoop.get(environment).pushMsg( return Value.UNDEFINED;
false, environment, });
Filename.parse("jscript://ts.js"), Reading.resourceToString("lib/ts.js"),
Value.UNDEFINED var ts = Reading.resourceToString("lib/ts.js");
if (ts != null) EventLoop.get(tsEnv).pushMsg(
false, tsEnv,
Filename.parse("jscript://ts.js"), ts,
Value.UNDEFINED, setter
).get(); ).get();
} }
@ -460,7 +496,7 @@ public class SimpleRepl {
SimpleRepl.args = args; SimpleRepl.args = args;
var reader = new Thread(SimpleRepl::reader); var reader = new Thread(SimpleRepl::reader);
initEnv(); environment = initEnv();
initEngine(); initEngine();
reader.setDaemon(true); reader.setDaemon(true);