diff --git a/lib/core.ts b/lib/core.ts index 562ac4b..75d0ff8 100644 --- a/lib/core.ts +++ b/lib/core.ts @@ -1,191 +1,68 @@ -type PropertyDescriptor = { - value: any; - writable?: boolean; - enumerable?: boolean; - configurable?: boolean; -} | { - get?(this: ThisT): T; - set(this: ThisT, val: T): void; - enumerable?: boolean; - configurable?: boolean; -} | { - get(this: ThisT): T; - set?(this: ThisT, val: T): void; - enumerable?: boolean; - configurable?: boolean; -}; -type Exclude = T extends U ? never : T; -type Extract = T extends U ? T : never; -type Record = { [x in KeyT]: ValT } +var env: Environment; -interface IArguments { - [i: number]: any; - length: number; -} - -interface MathObject { - readonly E: number; - readonly PI: number; - readonly SQRT2: number; - readonly SQRT1_2: number; - readonly LN2: number; - readonly LN10: number; - readonly LOG2E: number; - readonly LOG10E: number; - - asin(x: number): number; - acos(x: number): number; - atan(x: number): number; - atan2(y: number, x: number): number; - asinh(x: number): number; - acosh(x: number): number; - atanh(x: number): number; - sin(x: number): number; - cos(x: number): number; - tan(x: number): number; - sinh(x: number): number; - cosh(x: number): number; - tanh(x: number): number; - sqrt(x: number): number; - cbrt(x: number): number; - hypot(...vals: number[]): number; - imul(a: number, b: number): number; - exp(x: number): number; - expm1(x: number): number; - pow(x: number, y: number): number; - log(x: number): number; - log10(x: number): number; - log1p(x: number): number; - log2(x: number): number; - ceil(x: number): number; - floor(x: number): number; - round(x: number): number; - fround(x: number): number; - trunc(x: number): number; - abs(x: number): number; - max(...vals: number[]): number; - min(...vals: number[]): number; - sign(x: number): number; - random(): number; - clz32(x: number): number; -} - - -//@ts-ignore -declare const arguments: IArguments; -declare const Math: MathObject; - -declare var setTimeout: (handle: (...args: [ ...T, ...any[] ]) => void, delay?: number, ...args: T) => number; -declare var setInterval: (handle: (...args: [ ...T, ...any[] ]) => void, delay?: number, ...args: T) => number; - -declare var clearTimeout: (id: number) => void; -declare var clearInterval: (id: number) => void; - -/** @internal */ -declare var internals: any; -/** @internal */ -declare function run(file: string, pollute?: boolean): void; - -/** @internal */ -type ReplaceThis = T extends ((...args: infer ArgsT) => infer RetT) ? - ((this: ThisT, ...args: ArgsT) => RetT) : - T; - -/** @internal */ -declare var setProps: < - TargetT extends object, - DescT extends { [x in Exclude ]?: ReplaceThis } ->(target: TargetT, desc: DescT) => void; -/** @internal */ -declare var setConstr: (target: T, constr: ConstrT) => void; - -declare function log(...vals: any[]): void; -/** @internal */ -declare var lgt: typeof globalThis, gt: typeof globalThis; - -declare function assert(condition: () => unknown, message?: string): boolean; - -gt.assert = (cond, msg) => { - try { - if (!cond()) throw 'condition not satisfied'; - log('Passed ' + msg); - return true; - } - catch (e) { - log('Failed ' + msg + ' because of: ' + e); - return false; - } -} - -try { - lgt.setProps = (target, desc) => { - var props = internals.keys(desc, false); - for (var i = 0; i < props.length; i++) { - var key = props[i]; - internals.defineField( - target, key, (desc as any)[key], - true, // writable - false, // enumerable - true // configurable - ); +// @ts-ignore +return (_env: Environment) => { + env = _env; + env.global.assert = (cond, msg) => { + try { + if (!cond()) throw 'condition not satisfied'; + log('Passed ' + msg); + return true; + } + catch (e) { + log('Failed ' + msg + ' because of: ' + e); + return false; } } - lgt.setConstr = (target, constr) => { - internals.defineField( - target, 'constructor', constr, - true, // writable - false, // enumerable - true // configurable - ); + try { + run('values/object'); + run('values/symbol'); + run('values/function'); + run('values/errors'); + run('values/string'); + run('values/number'); + run('values/boolean'); + run('values/array'); + + env.internals.special(Object, Function, Error, Array); + + env.global.setTimeout = (func, delay, ...args) => { + if (typeof func !== 'function') throw new TypeError("func must be a function."); + delay = (delay ?? 0) - 0; + return env.internals.setTimeout(() => func(...args), delay) + }; + env.global.setInterval = (func, delay, ...args) => { + if (typeof func !== 'function') throw new TypeError("func must be a function."); + delay = (delay ?? 0) - 0; + return env.internals.setInterval(() => func(...args), delay) + }; + + env.global.clearTimeout = (id) => { + id = id | 0; + env.internals.clearTimeout(id); + }; + env.global.clearInterval = (id) => { + id = id | 0; + env.internals.clearInterval(id); + }; + + run('promise'); + run('map'); + run('set'); + run('regex'); + run('require'); + + log('Loaded polyfills!'); } - - run('values/object.js'); - run('values/symbol.js'); - run('values/function.js'); - run('values/errors.js'); - run('values/string.js'); - run('values/number.js'); - run('values/boolean.js'); - run('values/array.js'); - - internals.special(Object, Function, Error, Array); - - gt.setTimeout = (func, delay, ...args) => { - if (typeof func !== 'function') throw new TypeError("func must be a function."); - delay = (delay ?? 0) - 0; - return internals.setTimeout(() => func(...args), delay) - }; - gt.setInterval = (func, delay, ...args) => { - if (typeof func !== 'function') throw new TypeError("func must be a function."); - delay = (delay ?? 0) - 0; - return internals.setInterval(() => func(...args), delay) - }; - - gt.clearTimeout = (id) => { - id = id | 0; - internals.clearTimeout(id); - }; - gt.clearInterval = (id) => { - id = id | 0; - internals.clearInterval(id); - }; - - - run('iterators.js'); - run('promise.js'); - run('map.js', true); - run('set.js', true); - run('regex.js'); - run('require.js'); - - log('Loaded polyfills!'); -} -catch (e: any) { - var err = 'Uncaught error while loading polyfills: '; - if (typeof Error !== 'undefined' && e instanceof Error && e.toString !== {}.toString) err += e; - else if ('message' in e) { - if ('name' in e) err += e.name + ": " + e.message; - else err += 'Error: ' + e.message; + catch (e: any) { + if (!_env.captureErr) throw e; + var err = 'Uncaught error while loading polyfills: '; + if (typeof Error !== 'undefined' && e instanceof Error && e.toString !== {}.toString) err += e; + else if ('message' in e) { + if ('name' in e) err += e.name + ": " + e.message; + else err += 'Error: ' + e.message; + } + else err += e; + log(e); } - else err += e; -} +}; \ No newline at end of file diff --git a/lib/iterators.ts b/lib/iterators.ts deleted file mode 100644 index bdcd11f..0000000 --- a/lib/iterators.ts +++ /dev/null @@ -1,216 +0,0 @@ -interface SymbolConstructor { - readonly iterator: unique symbol; - readonly asyncIterator: unique symbol; -} - -type IteratorYieldResult = - { done?: false; } & - (TReturn extends undefined ? { value?: undefined; } : { value: TReturn; }); - -type IteratorReturnResult = - { done: true } & - (TReturn extends undefined ? { value?: undefined; } : { value: TReturn; }); - -type IteratorResult = IteratorYieldResult | IteratorReturnResult; - -interface Iterator { - next(...args: [] | [TNext]): IteratorResult; - return?(value?: TReturn): IteratorResult; - throw?(e?: any): IteratorResult; -} - -interface Iterable { - [Symbol.iterator](): Iterator; -} - -interface IterableIterator extends Iterator { - [Symbol.iterator](): IterableIterator; -} - -interface Generator extends Iterator { - // NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places. - next(...args: [] | [TNext]): IteratorResult; - return(value: TReturn): IteratorResult; - throw(e: any): IteratorResult; - [Symbol.iterator](): Generator; -} - -interface GeneratorFunction { - /** - * Creates a new Generator object. - * @param args A list of arguments the function accepts. - */ - new (...args: any[]): Generator; - /** - * Creates a new Generator object. - * @param args A list of arguments the function accepts. - */ - (...args: any[]): Generator; - /** - * The length of the arguments. - */ - readonly length: number; - /** - * Returns the name of the function. - */ - readonly name: string; - /** - * A reference to the prototype. - */ - readonly prototype: Generator; -} - -interface GeneratorFunctionConstructor { - /** - * Creates a new Generator function. - * @param args A list of arguments the function accepts. - */ - new (...args: string[]): GeneratorFunction; - /** - * Creates a new Generator function. - * @param args A list of arguments the function accepts. - */ - (...args: string[]): GeneratorFunction; - /** - * The length of the arguments. - */ - readonly length: number; - /** - * Returns the name of the function. - */ - readonly name: string; - /** - * A reference to the prototype. - */ -} - -interface AsyncIterator { - // NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places. - next(...args: [] | [TNext]): Promise>; - return?(value?: TReturn | Thenable): Promise>; - throw?(e?: any): Promise>; -} - -interface AsyncIterable { - [Symbol.asyncIterator](): AsyncIterator; -} - -interface AsyncIterableIterator extends AsyncIterator { - [Symbol.asyncIterator](): AsyncIterableIterator; -} - -interface AsyncGenerator extends AsyncIterator { - // NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places. - next(...args: [] | [TNext]): Promise>; - return(value: TReturn | Thenable): Promise>; - throw(e: any): Promise>; - [Symbol.asyncIterator](): AsyncGenerator; -} - -interface AsyncGeneratorFunction { - /** - * Creates a new AsyncGenerator object. - * @param args A list of arguments the function accepts. - */ - new (...args: any[]): AsyncGenerator; - /** - * Creates a new AsyncGenerator object. - * @param args A list of arguments the function accepts. - */ - (...args: any[]): AsyncGenerator; - /** - * The length of the arguments. - */ - readonly length: number; - /** - * Returns the name of the function. - */ - readonly name: string; - /** - * A reference to the prototype. - */ - readonly prototype: AsyncGenerator; -} - -interface AsyncGeneratorFunctionConstructor { - /** - * Creates a new AsyncGenerator function. - * @param args A list of arguments the function accepts. - */ - new (...args: string[]): AsyncGeneratorFunction; - /** - * Creates a new AsyncGenerator function. - * @param args A list of arguments the function accepts. - */ - (...args: string[]): AsyncGeneratorFunction; - /** - * The length of the arguments. - */ - readonly length: number; - /** - * Returns the name of the function. - */ - readonly name: string; - /** - * A reference to the prototype. - */ - readonly prototype: AsyncGeneratorFunction; -} - - -interface Array extends IterableIterator { - entries(): IterableIterator<[number, T]>; - values(): IterableIterator; - keys(): IterableIterator; -} - -setProps(Symbol, { - iterator: Symbol("Symbol.iterator") as any, - asyncIterator: Symbol("Symbol.asyncIterator") as any, -}); - -setProps(Array.prototype, { - [Symbol.iterator]: function() { - return this.values(); - }, - - values() { - var i = 0; - - return { - next: () => { - while (i < this.length) { - if (i++ in this) return { done: false, value: this[i - 1] }; - } - return { done: true, value: undefined }; - }, - [Symbol.iterator]() { return this; } - }; - }, - keys() { - var i = 0; - - return { - next: () => { - while (i < this.length) { - if (i++ in this) return { done: false, value: i - 1 }; - } - return { done: true, value: undefined }; - }, - [Symbol.iterator]() { return this; } - }; - }, - entries() { - var i = 0; - - return { - next: () => { - while (i < this.length) { - if (i++ in this) return { done: false, value: [i - 1, this[i - 1]] }; - } - return { done: true, value: undefined }; - }, - [Symbol.iterator]() { return this; } - }; - }, -}); diff --git a/lib/lib.d.ts b/lib/lib.d.ts new file mode 100644 index 0000000..e1c5c7d --- /dev/null +++ b/lib/lib.d.ts @@ -0,0 +1,634 @@ +type PropertyDescriptor = { + value: any; + writable?: boolean; + enumerable?: boolean; + configurable?: boolean; +} | { + get?(this: ThisT): T; + set(this: ThisT, val: T): void; + enumerable?: boolean; + configurable?: boolean; +} | { + get(this: ThisT): T; + set?(this: ThisT, val: T): void; + enumerable?: boolean; + configurable?: boolean; +}; +type Exclude = T extends U ? never : T; +type Extract = T extends U ? T : never; +type Record = { [x in KeyT]: ValT } +type ReplaceFunc = (match: string, ...args: any[]) => string; + +type PromiseFulfillFunc = (val: T) => void; +type PromiseThenFunc = (val: T) => NextT; +type PromiseRejectFunc = (err: unknown) => void; +type PromiseFunc = (resolve: PromiseFulfillFunc, reject: PromiseRejectFunc) => void; + +type PromiseResult ={ type: 'fulfilled'; value: T; } | { type: 'rejected'; reason: any; } + +// wippidy-wine, this code is now mine :D +type Awaited = + T extends null | undefined ? T : // special case for `null | undefined` when not in `--strictNullChecks` mode + T extends object & { then(onfulfilled: infer F, ...args: infer _): any } ? // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped + F extends ((value: infer V, ...args: infer _) => any) ? // if the argument to `then` is callable, extracts the first argument + Awaited : // recursively unwrap the value + never : // the argument to `then` was not callable + T; + +type IteratorYieldResult = + { done?: false; } & + (TReturn extends undefined ? { value?: undefined; } : { value: TReturn; }); + +type IteratorReturnResult = + { done: true } & + (TReturn extends undefined ? { value?: undefined; } : { value: TReturn; }); + +type IteratorResult = IteratorYieldResult | IteratorReturnResult; + +interface Thenable { + then(this: Promise, onFulfilled: PromiseThenFunc, onRejected?: PromiseRejectFunc): Promise>; + then(this: Promise, onFulfilled: undefined, onRejected?: PromiseRejectFunc): Promise; +} + +interface RegExpResultIndices extends Array<[number, number]> { + groups?: { [name: string]: [number, number]; }; +} +interface RegExpResult extends Array { + groups?: { [name: string]: string; }; + index: number; + input: string; + indices?: RegExpResultIndices; + escape(raw: string, flags: string): RegExp; +} + +interface Matcher { + [Symbol.match](target: string): RegExpResult | string[] | null; + [Symbol.matchAll](target: string): IterableIterator; +} +interface Splitter { + [Symbol.split](target: string, limit?: number, sensible?: boolean): string[]; +} +interface Replacer { + [Symbol.replace](target: string, replacement: string | ReplaceFunc): string; +} +interface Searcher { + [Symbol.search](target: string, reverse?: boolean, start?: number): number; +} + +type FlatArray = { + "done": Arr, + "recur": Arr extends Array + ? FlatArray + : Arr +}[Depth extends -1 ? "done" : "recur"]; + +interface IArguments { + [i: number]: any; + length: number; +} + +interface Iterator { + next(...args: [] | [TNext]): IteratorResult; + return?(value?: TReturn): IteratorResult; + throw?(e?: any): IteratorResult; +} +interface Iterable { + [Symbol.iterator](): Iterator; +} +interface IterableIterator extends Iterator { + [Symbol.iterator](): IterableIterator; +} + +interface AsyncIterator { + // NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places. + next(...args: [] | [TNext]): Promise>; + return?(value?: TReturn | Thenable): Promise>; + throw?(e?: any): Promise>; +} +interface AsyncIterable { + [Symbol.asyncIterator](): AsyncIterator; +} +interface AsyncIterableIterator extends AsyncIterator { + [Symbol.asyncIterator](): AsyncIterableIterator; +} + +interface Generator extends Iterator { + [Symbol.iterator](): Generator; + return(value?: TReturn): IteratorResult; + throw(e?: any): IteratorResult; +} +interface GeneratorFunction { + /** + * Creates a new Generator object. + * @param args A list of arguments the function accepts. + */ + new (...args: any[]): Generator; + /** + * Creates a new Generator object. + * @param args A list of arguments the function accepts. + */ + (...args: any[]): Generator; + /** + * The length of the arguments. + */ + readonly length: number; + /** + * Returns the name of the function. + */ + readonly name: string; + /** + * A reference to the prototype. + */ + readonly prototype: Generator; +} + +interface AsyncGenerator extends AsyncIterator { + // NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places. + next(...args: [] | [TNext]): Promise>; + return(value: TReturn | Thenable): Promise>; + throw(e: any): Promise>; + [Symbol.asyncIterator](): AsyncGenerator; +} +interface AsyncGeneratorFunction { + /** + * Creates a new AsyncGenerator object. + * @param args A list of arguments the function accepts. + */ + new (...args: any[]): AsyncGenerator; + /** + * Creates a new AsyncGenerator object. + * @param args A list of arguments the function accepts. + */ + (...args: any[]): AsyncGenerator; + /** + * The length of the arguments. + */ + readonly length: number; + /** + * Returns the name of the function. + */ + readonly name: string; + /** + * A reference to the prototype. + */ + readonly prototype: AsyncGenerator; +} + + +interface MathObject { + readonly E: number; + readonly PI: number; + readonly SQRT2: number; + readonly SQRT1_2: number; + readonly LN2: number; + readonly LN10: number; + readonly LOG2E: number; + readonly LOG10E: number; + + asin(x: number): number; + acos(x: number): number; + atan(x: number): number; + atan2(y: number, x: number): number; + asinh(x: number): number; + acosh(x: number): number; + atanh(x: number): number; + sin(x: number): number; + cos(x: number): number; + tan(x: number): number; + sinh(x: number): number; + cosh(x: number): number; + tanh(x: number): number; + sqrt(x: number): number; + cbrt(x: number): number; + hypot(...vals: number[]): number; + imul(a: number, b: number): number; + exp(x: number): number; + expm1(x: number): number; + pow(x: number, y: number): number; + log(x: number): number; + log10(x: number): number; + log1p(x: number): number; + log2(x: number): number; + ceil(x: number): number; + floor(x: number): number; + round(x: number): number; + fround(x: number): number; + trunc(x: number): number; + abs(x: number): number; + max(...vals: number[]): number; + min(...vals: number[]): number; + sign(x: number): number; + random(): number; + clz32(x: number): number; +} + +interface Array extends IterableIterator { + [i: number]: T; + + constructor: ArrayConstructor; + length: number; + + toString(): string; + // toLocaleString(): string; + join(separator?: string): string; + fill(val: T, start?: number, end?: number): T[]; + pop(): T | undefined; + push(...items: T[]): number; + concat(...items: (T | T[])[]): T[]; + concat(...items: (T | T[])[]): T[]; + join(separator?: string): string; + reverse(): T[]; + shift(): T | undefined; + slice(start?: number, end?: number): T[]; + sort(compareFn?: (a: T, b: T) => number): this; + splice(start: number, deleteCount?: number | undefined, ...items: T[]): T[]; + unshift(...items: T[]): number; + indexOf(searchElement: T, fromIndex?: number): number; + lastIndexOf(searchElement: T, fromIndex?: number): number; + every(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): boolean; + some(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): boolean; + forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void; + includes(el: any, start?: number): boolean; + + map(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[]; + filter(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): T[]; + find(predicate: (value: T, index: number, array: T[]) => boolean, thisArg?: any): T[]; + findIndex(predicate: (value: T, index: number, array: T[]) => boolean, thisArg?: any): number; + findLast(predicate: (value: T, index: number, array: T[]) => boolean, thisArg?: any): T[]; + findLastIndex(predicate: (value: T, index: number, array: T[]) => boolean, thisArg?: any): number; + + flat(depth?: D): FlatArray; + flatMap(func: (val: T, i: number, arr: T[]) => T | T[], thisAarg?: any): FlatArray; + sort(func?: (a: T, b: T) => number): this; + + reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; + reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; + reduce(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; + reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; + reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; + reduceRight(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; + + entries(): IterableIterator<[number, T]>; + values(): IterableIterator; + keys(): IterableIterator; +} +interface ArrayConstructor { + new (arrayLength?: number): T[]; + new (...items: T[]): T[]; + (arrayLength?: number): T[]; + (...items: T[]): T[]; + isArray(arg: any): arg is any[]; + prototype: Array; +} + +interface Boolean { + valueOf(): boolean; + constructor: BooleanConstructor; +} +interface BooleanConstructor { + (val: any): boolean; + new (val: any): Boolean; + prototype: Boolean; +} + +interface Error { + constructor: ErrorConstructor; + name: string; + message: string; + stack: string[]; +} +interface ErrorConstructor { + (msg?: any): Error; + new (msg?: any): Error; + prototype: Error; +} + +interface TypeErrorConstructor extends ErrorConstructor { + (msg?: any): TypeError; + new (msg?: any): TypeError; + prototype: Error; +} +interface TypeError extends Error { + constructor: TypeErrorConstructor; + name: 'TypeError'; +} + +interface RangeErrorConstructor extends ErrorConstructor { + (msg?: any): RangeError; + new (msg?: any): RangeError; + prototype: Error; +} +interface RangeError extends Error { + constructor: RangeErrorConstructor; + name: 'RangeError'; +} + +interface SyntaxErrorConstructor extends ErrorConstructor { + (msg?: any): RangeError; + new (msg?: any): RangeError; + prototype: Error; +} +interface SyntaxError extends Error { + constructor: SyntaxErrorConstructor; + name: 'SyntaxError'; +} + +interface Function { + apply(this: Function, thisArg: any, argArray?: any): any; + call(this: Function, thisArg: any, ...argArray: any[]): any; + bind(this: Function, thisArg: any, ...argArray: any[]): Function; + + toString(): string; + + prototype: any; + constructor: FunctionConstructor; + readonly length: number; + name: string; +} +interface CallableFunction extends Function { + (...args: any[]): any; + apply(this: (this: ThisArg, ...args: Args) => RetT, thisArg: ThisArg, argArray?: Args): RetT; + call(this: (this: ThisArg, ...args: Args) => RetT, thisArg: ThisArg, ...argArray: Args): RetT; + bind(this: (this: ThisArg, ...args: [ ...Args, ...Rest ]) => RetT, thisArg: ThisArg, ...argArray: Args): (this: void, ...args: Rest) => RetT; +} +interface NewableFunction extends Function { + new(...args: any[]): any; + apply(this: new (...args: Args) => RetT, thisArg: any, argArray?: Args): RetT; + call(this: new (...args: Args) => RetT, thisArg: any, ...argArray: Args): RetT; + bind(this: new (...args: Args) => RetT, thisArg: any, ...argArray: Args): new (...args: Args) => RetT; +} +interface FunctionConstructor extends Function { + (...args: string[]): (...args: any[]) => any; + new (...args: string[]): (...args: any[]) => any; + prototype: Function; + async( + func: (await: (val: T) => Awaited) => (...args: ArgsT) => RetT + ): (...args: ArgsT) => Promise; + asyncGenerator( + func: (await: (val: T) => Awaited, _yield: (val: T) => void) => (...args: ArgsT) => RetT + ): (...args: ArgsT) => AsyncGenerator; + generator( + func: (_yield: (val: T) => TNext) => (...args: ArgsT) => RetT + ): (...args: ArgsT) => Generator; +} + +interface Number { + toString(): string; + valueOf(): number; + constructor: NumberConstructor; +} +interface NumberConstructor { + (val: any): number; + new (val: any): Number; + prototype: Number; + parseInt(val: unknown): number; + parseFloat(val: unknown): number; +} + +interface Object { + constructor: NewableFunction; + [Symbol.typeName]: string; + + valueOf(): this; + toString(): string; + hasOwnProperty(key: any): boolean; +} +interface ObjectConstructor extends Function { + (arg: string): String; + (arg: number): Number; + (arg: boolean): Boolean; + (arg?: undefined | null): {}; + (arg: T): T; + + new (arg: string): String; + new (arg: number): Number; + new (arg: boolean): Boolean; + new (arg?: undefined | null): {}; + new (arg: T): T; + + prototype: Object; + + assign(target: T, ...src: object[]): T; + create(proto: T, props?: { [key: string]: PropertyDescriptor }): T; + + keys(obj: T, onlyString?: true): (keyof T)[]; + keys(obj: T, onlyString: false): any[]; + entries(obj: T, onlyString?: true): [keyof T, T[keyof T]][]; + entries(obj: T, onlyString: false): [any, any][]; + values(obj: T, onlyString?: true): (T[keyof T])[]; + values(obj: T, onlyString: false): any[]; + + fromEntries(entries: Iterable<[any, any]>): object; + + defineProperty(obj: ThisT, key: any, desc: PropertyDescriptor): ThisT; + defineProperties(obj: ThisT, desc: { [key: string]: PropertyDescriptor }): ThisT; + + getOwnPropertyNames(obj: T): (keyof T)[]; + getOwnPropertySymbols(obj: T): (keyof T)[]; + hasOwn(obj: T, key: KeyT): boolean; + + getOwnPropertyDescriptor(obj: T, key: KeyT): PropertyDescriptor; + getOwnPropertyDescriptors(obj: T): { [x in keyof T]: PropertyDescriptor }; + + getPrototypeOf(obj: any): object | null; + setPrototypeOf(obj: T, proto: object | null): T; + + preventExtensions(obj: T): T; + seal(obj: T): T; + freeze(obj: T): T; + + isExtensible(obj: object): boolean; + isSealed(obj: object): boolean; + isFrozen(obj: object): boolean; +} + +interface String { + [i: number]: string; + + toString(): string; + valueOf(): string; + + charAt(pos: number): string; + charCodeAt(pos: number): number; + substring(start?: number, end?: number): string; + slice(start?: number, end?: number): string; + substr(start?: number, length?: number): string; + + startsWith(str: string, pos?: number): string; + endsWith(str: string, pos?: number): string; + + replace(pattern: string | Replacer, val: string | ReplaceFunc): string; + replaceAll(pattern: string | Replacer, val: string | ReplaceFunc): string; + + match(pattern: string | Matcher): RegExpResult | string[] | null; + matchAll(pattern: string | Matcher): IterableIterator; + + split(pattern: string | Splitter, limit?: number, sensible?: boolean): string; + + concat(...others: string[]): string; + indexOf(term: string | Searcher, start?: number): number; + lastIndexOf(term: string | Searcher, start?: number): number; + + toLowerCase(): string; + toUpperCase(): string; + + trim(): string; + + includes(term: string, start?: number): boolean; + + length: number; + + constructor: StringConstructor; +} +interface StringConstructor { + (val: any): string; + new (val: any): String; + + fromCharCode(val: number): string; + + prototype: String; +} + +interface Symbol { + valueOf(): symbol; + constructor: SymbolConstructor; +} +interface SymbolConstructor { + (val?: any): symbol; + new(...args: any[]): never; + prototype: Symbol; + for(key: string): symbol; + keyFor(sym: symbol): string; + + readonly typeName: unique symbol; + readonly match: unique symbol; + readonly matchAll: unique symbol; + readonly split: unique symbol; + readonly replace: unique symbol; + readonly search: unique symbol; + readonly iterator: unique symbol; + readonly asyncIterator: unique symbol; +} + +interface Promise extends Thenable { + constructor: PromiseConstructor; + catch(func: PromiseRejectFunc): Promise; + finally(func: () => void): Promise; +} +interface PromiseConstructor { + prototype: Promise; + + new (func: PromiseFunc): Promise>; + resolve(val: T): Promise>; + reject(val: any): Promise; + + any(promises: (Promise|T)[]): Promise; + race(promises: (Promise|T)[]): Promise; + all(promises: T): Promise<{ [Key in keyof T]: Awaited }>; + allSettled(...promises: T): Promise<[...{ [P in keyof T]: PromiseResult>}]>; +} + +declare var String: StringConstructor; +//@ts-ignore +declare const arguments: IArguments; +declare var NaN: number; +declare var Infinity: number; + +declare var setTimeout: (handle: (...args: [ ...T, ...any[] ]) => void, delay?: number, ...args: T) => number; +declare var setInterval: (handle: (...args: [ ...T, ...any[] ]) => void, delay?: number, ...args: T) => number; + +declare var clearTimeout: (id: number) => void; +declare var clearInterval: (id: number) => void; + +declare var parseInt: typeof Number.parseInt; +declare var parseFloat: typeof Number.parseFloat; + +declare function log(...vals: any[]): void; +declare function assert(condition: () => unknown, message?: string): boolean; + +declare var Array: ArrayConstructor; +declare var Boolean: BooleanConstructor; +declare var Promise: PromiseConstructor; +declare var Function: FunctionConstructor; +declare var Number: NumberConstructor; +declare var Object: ObjectConstructor; +declare var Symbol: SymbolConstructor; +declare var Promise: PromiseConstructor; +declare var Math: MathObject; + +declare var Error: ErrorConstructor; +declare var RangeError: RangeErrorConstructor; +declare var TypeError: TypeErrorConstructor; +declare var SyntaxError: SyntaxErrorConstructor; + +declare class Map { + public [Symbol.iterator](): IterableIterator<[KeyT, ValueT]>; + + public clear(): void; + public delete(key: KeyT): boolean; + + public entries(): IterableIterator<[KeyT, ValueT]>; + public keys(): IterableIterator; + public values(): IterableIterator; + + public get(key: KeyT): ValueT; + public set(key: KeyT, val: ValueT): this; + public has(key: KeyT): boolean; + + public get size(): number; + + public forEach(func: (key: KeyT, val: ValueT, map: Map) => void, thisArg?: any): void; + + public constructor(); +} +declare class Set { + public [Symbol.iterator](): IterableIterator; + + public entries(): IterableIterator<[T, T]>; + public keys(): IterableIterator; + public values(): IterableIterator; + + public clear(): void; + + public add(val: T): this; + public delete(val: T): boolean; + public has(key: T): boolean; + + public get size(): number; + + public forEach(func: (key: T, set: Set) => void, thisArg?: any): void; + + public constructor(); +} + +declare class RegExp implements Matcher, Splitter, Replacer, Searcher { + static escape(raw: any, flags?: string): RegExp; + + prototype: RegExp; + + exec(val: string): RegExpResult | null; + test(val: string): boolean; + toString(): string; + + [Symbol.match](target: string): RegExpResult | string[] | null; + [Symbol.matchAll](target: string): IterableIterator; + [Symbol.split](target: string, limit?: number, sensible?: boolean): string[]; + [Symbol.replace](target: string, replacement: string | ReplaceFunc): string; + [Symbol.search](target: string, reverse?: boolean, start?: number): number; + + readonly dotAll: boolean; + readonly global: boolean; + readonly hasIndices: boolean; + readonly ignoreCase: boolean; + readonly multiline: boolean; + readonly sticky: boolean; + readonly unicode: boolean; + + readonly source: string; + readonly flags: string; + + lastIndex: number; + + constructor(pattern?: string, flags?: string); + constructor(pattern?: RegExp, flags?: string); +} diff --git a/lib/map.ts b/lib/map.ts index f48c235..2c45e0c 100644 --- a/lib/map.ts +++ b/lib/map.ts @@ -1,44 +1,29 @@ -declare class Map { - public [Symbol.iterator](): IterableIterator<[KeyT, ValueT]>; +define("map", () => { + var Map = env.global.Map = env.internals.Map; - public clear(): void; - public delete(key: KeyT): boolean; + Map.prototype[Symbol.iterator] = function() { + return this.entries(); + }; - public entries(): IterableIterator<[KeyT, ValueT]>; - public keys(): IterableIterator; - public values(): IterableIterator; + var entries = Map.prototype.entries; + var keys = Map.prototype.keys; + var values = Map.prototype.values; - public get(key: KeyT): ValueT; - public set(key: KeyT, val: ValueT): this; - public has(key: KeyT): boolean; + Map.prototype.entries = function() { + var it = entries.call(this); + it[Symbol.iterator] = () => it; + return it; + }; + Map.prototype.keys = function() { + var it = keys.call(this); + it[Symbol.iterator] = () => it; + return it; + }; + Map.prototype.values = function() { + var it = values.call(this); + it[Symbol.iterator] = () => it; + return it; + }; - public get size(): number; - - public forEach(func: (key: KeyT, val: ValueT, map: Map) => void, thisArg?: any): void; - - public constructor(); -} - -Map.prototype[Symbol.iterator] = function() { - return this.entries(); -}; - -var entries = Map.prototype.entries; -var keys = Map.prototype.keys; -var values = Map.prototype.values; - -Map.prototype.entries = function() { - var it = entries.call(this); - it[Symbol.iterator] = () => it; - return it; -}; -Map.prototype.keys = function() { - var it = keys.call(this); - it[Symbol.iterator] = () => it; - return it; -}; -Map.prototype.values = function() { - var it = values.call(this); - it[Symbol.iterator] = () => it; - return it; -}; + env.global.Map = Map; +}); diff --git a/lib/modules.ts b/lib/modules.ts new file mode 100644 index 0000000..8eb68a0 --- /dev/null +++ b/lib/modules.ts @@ -0,0 +1,12 @@ +var { define, run } = (() => { + const modules: Record = {}; + + function define(name: string, func: Function) { + modules[name] = func; + } + function run(name: string) { + return modules[name](); + } + + return { define, run }; +})(); diff --git a/lib/promise.ts b/lib/promise.ts index 99fb463..9eb1404 100644 --- a/lib/promise.ts +++ b/lib/promise.ts @@ -1,43 +1,3 @@ -type PromiseFulfillFunc = (val: T) => void; -type PromiseThenFunc = (val: T) => NextT; -type PromiseRejectFunc = (err: unknown) => void; -type PromiseFunc = (resolve: PromiseFulfillFunc, reject: PromiseRejectFunc) => void; - -type PromiseResult ={ type: 'fulfilled'; value: T; } | { type: 'rejected'; reason: any; } - -interface Thenable { - then(this: Promise, onFulfilled: PromiseThenFunc, onRejected?: PromiseRejectFunc): Promise>; - then(this: Promise, onFulfilled: undefined, onRejected?: PromiseRejectFunc): Promise; -} - -// wippidy-wine, this code is now mine :D -type Awaited = - T extends null | undefined ? T : // special case for `null | undefined` when not in `--strictNullChecks` mode - T extends object & { then(onfulfilled: infer F, ...args: infer _): any } ? // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped - F extends ((value: infer V, ...args: infer _) => any) ? // if the argument to `then` is callable, extracts the first argument - Awaited : // recursively unwrap the value - never : // the argument to `then` was not callable - T; - -interface PromiseConstructor { - prototype: Promise; - - new (func: PromiseFunc): Promise>; - resolve(val: T): Promise>; - reject(val: any): Promise; - - any(promises: (Promise|T)[]): Promise; - race(promises: (Promise|T)[]): Promise; - all(promises: T): Promise<{ [Key in keyof T]: Awaited }>; - allSettled(...promises: T): Promise<[...{ [P in keyof T]: PromiseResult>}]>; -} - -interface Promise extends Thenable { - constructor: PromiseConstructor; - catch(func: PromiseRejectFunc): Promise; - finally(func: () => void): Promise; -} - -declare var Promise: PromiseConstructor; - -(Promise.prototype as any)[Symbol.typeName] = 'Promise'; +define("promise", () => { + (env.global.Promise = env.internals.Promise).prototype[Symbol.typeName] = 'Promise'; +}); diff --git a/lib/regex.ts b/lib/regex.ts index 4a1e6ff..cb1217f 100644 --- a/lib/regex.ts +++ b/lib/regex.ts @@ -1,211 +1,143 @@ -interface RegExpResultIndices extends Array<[number, number]> { - groups?: { [name: string]: [number, number]; }; -} -interface RegExpResult extends Array { - groups?: { [name: string]: string; }; - index: number; - input: string; - indices?: RegExpResultIndices; - escape(raw: string, flags: string): RegExp; -} -interface SymbolConstructor { - readonly match: unique symbol; - readonly matchAll: unique symbol; - readonly split: unique symbol; - readonly replace: unique symbol; - readonly search: unique symbol; -} +define("regex", () => { + var RegExp = env.global.RegExp = env.internals.RegExp; -type ReplaceFunc = (match: string, ...args: any[]) => string; - -interface Matcher { - [Symbol.match](target: string): RegExpResult | string[] | null; - [Symbol.matchAll](target: string): IterableIterator; -} -interface Splitter { - [Symbol.split](target: string, limit?: number, sensible?: boolean): string[]; -} -interface Replacer { - [Symbol.replace](target: string, replacement: string): string; -} -interface Searcher { - [Symbol.search](target: string, reverse?: boolean, start?: number): number; -} - -declare class RegExp implements Matcher, Splitter, Replacer, Searcher { - static escape(raw: any, flags?: string): RegExp; - - prototype: RegExp; - - exec(val: string): RegExpResult | null; - test(val: string): boolean; - toString(): string; - - [Symbol.match](target: string): RegExpResult | string[] | null; - [Symbol.matchAll](target: string): IterableIterator; - [Symbol.split](target: string, limit?: number, sensible?: boolean): string[]; - [Symbol.replace](target: string, replacement: string | ReplaceFunc): string; - [Symbol.search](target: string, reverse?: boolean, start?: number): number; - - readonly dotAll: boolean; - readonly global: boolean; - readonly hasIndices: boolean; - readonly ignoreCase: boolean; - readonly multiline: boolean; - readonly sticky: boolean; - readonly unicode: boolean; - - readonly source: string; - readonly flags: string; - - lastIndex: number; - - constructor(pattern?: string, flags?: string); - constructor(pattern?: RegExp, flags?: string); -} - -(Symbol as any).replace = Symbol('Symbol.replace'); -(Symbol as any).match = Symbol('Symbol.match'); -(Symbol as any).matchAll = Symbol('Symbol.matchAll'); -(Symbol as any).split = Symbol('Symbol.split'); -(Symbol as any).search = Symbol('Symbol.search'); - -setProps(RegExp.prototype, { - [Symbol.typeName]: 'RegExp', - - test(val) { - return !!this.exec(val); - }, - toString() { - return '/' + this.source + '/' + this.flags; - }, - - [Symbol.match](target) { - if (this.global) { + setProps(RegExp.prototype as RegExp, env, { + [Symbol.typeName]: 'RegExp', + + test(val) { + return !!this.exec(val); + }, + toString() { + return '/' + this.source + '/' + this.flags; + }, + + [Symbol.match](target) { + if (this.global) { + const res: string[] = []; + let val; + while (val = this.exec(target)) { + res.push(val[0]); + } + this.lastIndex = 0; + return res; + } + else { + const res = this.exec(target); + if (!this.sticky) this.lastIndex = 0; + return res; + } + }, + [Symbol.matchAll](target) { + let pattern: RegExp | undefined = new this.constructor(this, this.flags + "g") as RegExp; + + return { + next: (): IteratorResult => { + const val = pattern?.exec(target); + + if (val === null || val === undefined) { + pattern = undefined; + return { done: true }; + } + else return { value: val }; + }, + [Symbol.iterator]() { return this; } + } + }, + [Symbol.split](target, limit, sensible) { + const pattern = new this.constructor(this, this.flags + "g") as RegExp; + let match: RegExpResult | null; + let lastEnd = 0; const res: string[] = []; - let val; - while (val = this.exec(target)) { - res.push(val[0]); + + while ((match = pattern.exec(target)) !== null) { + let added: string[] = []; + + if (match.index >= target.length) break; + + if (match[0].length === 0) { + added = [ target.substring(lastEnd, pattern.lastIndex), ]; + if (pattern.lastIndex < target.length) added.push(...match.slice(1)); + } + else if (match.index - lastEnd > 0) { + added = [ target.substring(lastEnd, match.index), ...match.slice(1) ]; + } + else { + for (let i = 1; i < match.length; i++) { + res[res.length - match.length + i] = match[i]; + } + } + + if (sensible) { + if (limit !== undefined && res.length + added.length >= limit) break; + else res.push(...added); + } + else { + for (let i = 0; i < added.length; i++) { + if (limit !== undefined && res.length >= limit) return res; + else res.push(added[i]); + } + } + + lastEnd = pattern.lastIndex; } - this.lastIndex = 0; + + if (lastEnd < target.length) { + res.push(target.substring(lastEnd)); + } + return res; - } - else { - const res = this.exec(target); - if (!this.sticky) this.lastIndex = 0; - return res; - } - }, - [Symbol.matchAll](target) { - let pattern: RegExp | undefined = new this.constructor(this, this.flags + "g") as RegExp; - - return { - next: (): IteratorResult => { - const val = pattern?.exec(target); - - if (val === null || val === undefined) { - pattern = undefined; - return { done: true }; + }, + [Symbol.replace](target, replacement) { + const pattern = new this.constructor(this, this.flags + "d") as RegExp; + let match: RegExpResult | null; + let lastEnd = 0; + const res: string[] = []; + + // log(pattern.toString()); + + while ((match = pattern.exec(target)) !== null) { + const indices = match.indices![0]; + res.push(target.substring(lastEnd, indices[0])); + if (replacement instanceof Function) { + res.push(replacement(target.substring(indices[0], indices[1]), ...match.slice(1), indices[0], target)); } - else return { value: val }; - }, - [Symbol.iterator]() { return this; } - } - }, - [Symbol.split](target, limit, sensible) { - const pattern = new this.constructor(this, this.flags + "g") as RegExp; - let match: RegExpResult | null; - let lastEnd = 0; - const res: string[] = []; - - while ((match = pattern.exec(target)) !== null) { - let added: string[] = []; - - if (match.index >= target.length) break; - - if (match[0].length === 0) { - added = [ target.substring(lastEnd, pattern.lastIndex), ]; - if (pattern.lastIndex < target.length) added.push(...match.slice(1)); + else { + res.push(replacement); + } + lastEnd = indices[1]; + if (!pattern.global) break; } - else if (match.index - lastEnd > 0) { - added = [ target.substring(lastEnd, match.index), ...match.slice(1) ]; + + if (lastEnd < target.length) { + res.push(target.substring(lastEnd)); + } + + return res.join(''); + }, + [Symbol.search](target, reverse, start) { + const pattern: RegExp | undefined = new this.constructor(this, this.flags + "g") as RegExp; + + + if (!reverse) { + pattern.lastIndex = (start as any) | 0; + const res = pattern.exec(target); + if (res) return res.index; + else return -1; } else { - for (let i = 1; i < match.length; i++) { - res[res.length - match.length + i] = match[i]; + start ??= target.length; + start |= 0; + let res: RegExpResult | null = null; + + while (true) { + const tmp = pattern.exec(target); + if (tmp === null || tmp.index > start) break; + res = tmp; } + + if (res && res.index <= start) return res.index; + else return -1; } - - if (sensible) { - if (limit !== undefined && res.length + added.length >= limit) break; - else res.push(...added); - } - else { - for (let i = 0; i < added.length; i++) { - if (limit !== undefined && res.length >= limit) return res; - else res.push(added[i]); - } - } - - lastEnd = pattern.lastIndex; - } - - if (lastEnd < target.length) { - res.push(target.substring(lastEnd)); - } - - return res; - }, - [Symbol.replace](target, replacement) { - const pattern = new this.constructor(this, this.flags + "d") as RegExp; - let match: RegExpResult | null; - let lastEnd = 0; - const res: string[] = []; - - // log(pattern.toString()); - - while ((match = pattern.exec(target)) !== null) { - const indices = match.indices![0]; - res.push(target.substring(lastEnd, indices[0])); - if (replacement instanceof Function) { - res.push(replacement(target.substring(indices[0], indices[1]), ...match.slice(1), indices[0], target)); - } - else { - res.push(replacement); - } - lastEnd = indices[1]; - if (!pattern.global) break; - } - - if (lastEnd < target.length) { - res.push(target.substring(lastEnd)); - } - - return res.join(''); - }, - [Symbol.search](target, reverse, start) { - const pattern: RegExp | undefined = new this.constructor(this, this.flags + "g") as RegExp; - - - if (!reverse) { - pattern.lastIndex = (start as any) | 0; - const res = pattern.exec(target); - if (res) return res.index; - else return -1; - } - else { - start ??= target.length; - start |= 0; - let res: RegExpResult | null = null; - - while (true) { - const tmp = pattern.exec(target); - if (tmp === null || tmp.index > start) break; - res = tmp; - } - - if (res && res.index <= start) return res.index; - else return -1; - } - }, -}); + }, + }); +}); \ No newline at end of file diff --git a/lib/require.ts b/lib/require.ts deleted file mode 100644 index 811d6a5..0000000 --- a/lib/require.ts +++ /dev/null @@ -1,15 +0,0 @@ -type RequireFunc = (path: string) => any; - -interface Module { - exports: any; - name: string; -} - -declare var require: RequireFunc; -declare var exports: any; -declare var module: Module; - -gt.require = function(path: string) { - if (typeof path !== 'string') path = path + ''; - return internals.require(path); -}; diff --git a/lib/set.ts b/lib/set.ts index 4ef9ab6..3a21671 100644 --- a/lib/set.ts +++ b/lib/set.ts @@ -1,28 +1,9 @@ -declare class Set { - public [Symbol.iterator](): IterableIterator; +define("set", () => { + var Set = env.global.Set = env.internals.Set; + Set.prototype[Symbol.iterator] = function() { + return this.values(); + }; - public entries(): IterableIterator<[T, T]>; - public keys(): IterableIterator; - public values(): IterableIterator; - - public clear(): void; - - public add(val: T): this; - public delete(val: T): boolean; - public has(key: T): boolean; - - public get size(): number; - - public forEach(func: (key: T, set: Set) => void, thisArg?: any): void; - - public constructor(); -} - -Set.prototype[Symbol.iterator] = function() { - return this.values(); -}; - -(() => { var entries = Set.prototype.entries; var keys = Set.prototype.keys; var values = Set.prototype.values; @@ -42,4 +23,4 @@ Set.prototype[Symbol.iterator] = function() { it[Symbol.iterator] = () => it; return it; }; -})(); \ No newline at end of file +}); diff --git a/lib/utils.ts b/lib/utils.ts new file mode 100644 index 0000000..90fdba4 --- /dev/null +++ b/lib/utils.ts @@ -0,0 +1,44 @@ +interface Environment { + global: typeof globalThis & Record; + captureErr: boolean; + internals: any; +} + +function setProps< + TargetT extends object, + DescT extends { + [x in Exclude ]?: TargetT[x] extends ((...args: infer ArgsT) => infer RetT) ? + ((this: TargetT, ...args: ArgsT) => RetT) : + TargetT[x] + } +>(target: TargetT, env: Environment, desc: DescT) { + var props = env.internals.keys(desc, false); + for (var i = 0; i < props.length; i++) { + var key = props[i]; + env.internals.defineField( + target, key, (desc as any)[key], + true, // writable + false, // enumerable + true // configurable + ); + } +} +function setConstr(target: T, constr: ConstrT, env: Environment) { + env.internals.defineField( + target, 'constructor', constr, + true, // writable + false, // enumerable + true // configurable + ); +} + +function wrapI(max: number, i: number) { + i |= 0; + if (i < 0) i = max + i; + return i; +} +function clampI(max: number, i: number) { + if (i < 0) i = 0; + if (i > max) i = max; + return i; +} \ No newline at end of file diff --git a/lib/values/array.ts b/lib/values/array.ts index dc3eceb..43290b4 100644 --- a/lib/values/array.ts +++ b/lib/values/array.ts @@ -1,369 +1,335 @@ -// god this is awful -type FlatArray = { - "done": Arr, - "recur": Arr extends Array - ? FlatArray - : Arr -}[Depth extends -1 ? "done" : "recur"]; - -interface Array { - [i: number]: T; - - constructor: ArrayConstructor; - length: number; - - toString(): string; - // toLocaleString(): string; - join(separator?: string): string; - fill(val: T, start?: number, end?: number): T[]; - pop(): T | undefined; - push(...items: T[]): number; - concat(...items: (T | T[])[]): T[]; - concat(...items: (T | T[])[]): T[]; - join(separator?: string): string; - reverse(): T[]; - shift(): T | undefined; - slice(start?: number, end?: number): T[]; - sort(compareFn?: (a: T, b: T) => number): this; - splice(start: number, deleteCount?: number | undefined, ...items: T[]): T[]; - unshift(...items: T[]): number; - indexOf(searchElement: T, fromIndex?: number): number; - lastIndexOf(searchElement: T, fromIndex?: number): number; - every(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): boolean; - some(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): boolean; - forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void; - includes(el: any, start?: number): boolean; - - map(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[]; - filter(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): T[]; - find(predicate: (value: T, index: number, array: T[]) => boolean, thisArg?: any): T[]; - findIndex(predicate: (value: T, index: number, array: T[]) => boolean, thisArg?: any): number; - findLast(predicate: (value: T, index: number, array: T[]) => boolean, thisArg?: any): T[]; - findLastIndex(predicate: (value: T, index: number, array: T[]) => boolean, thisArg?: any): number; - - flat(depth?: D): FlatArray; - flatMap(func: (val: T, i: number, arr: T[]) => T | T[], thisAarg?: any): FlatArray; - sort(func?: (a: T, b: T) => number): this; - - reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; - reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; - reduce(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; - reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; - reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; - reduceRight(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; -} -interface ArrayConstructor { - new (arrayLength?: number): T[]; - new (...items: T[]): T[]; - (arrayLength?: number): T[]; - (...items: T[]): T[]; - isArray(arg: any): arg is any[]; - prototype: Array; -} - -declare var Array: ArrayConstructor; - -gt.Array = function(len?: number) { - var res = []; - - if (typeof len === 'number' && arguments.length === 1) { - if (len < 0) throw 'Invalid array length.'; - res.length = len; - } - else { - for (var i = 0; i < arguments.length; i++) { - res[i] = arguments[i]; - } - } - - return res; -} as ArrayConstructor; - -Array.prototype = ([] as any).__proto__ as Array; -setConstr(Array.prototype, Array); - -function wrapI(max: number, i: number) { - i |= 0; - if (i < 0) i = max + i; - return i; -} -function clampI(max: number, i: number) { - if (i < 0) i = 0; - if (i > max) i = max; - return i; -} - -lgt.wrapI = wrapI; -lgt.clampI = clampI; - -(Array.prototype as any)[Symbol.typeName] = "Array"; - -setProps(Array.prototype, { - concat() { - var res = [] as any[]; - res.push.apply(res, this); - - for (var i = 0; i < arguments.length; i++) { - var arg = arguments[i]; - if (arg instanceof Array) { - res.push.apply(res, arg); - } - else { - res.push(arg); - } - } - - return res; - }, - every(func, thisArg) { - if (typeof func !== 'function') throw new TypeError("Given argument not a function."); - func = func.bind(thisArg); - - for (var i = 0; i < this.length; i++) { - if (!func(this[i], i, this)) return false; - } - - return true; - }, - some(func, thisArg) { - if (typeof func !== 'function') throw new TypeError("Given argument not a function."); - func = func.bind(thisArg); - - for (var i = 0; i < this.length; i++) { - if (func(this[i], i, this)) return true; - } - - return false; - }, - fill(val, start, end) { - if (arguments.length < 3) end = this.length; - if (arguments.length < 2) start = 0; - - start = clampI(this.length, wrapI(this.length + 1, start ?? 0)); - end = clampI(this.length, wrapI(this.length + 1, end ?? this.length)); - - for (; start < end; start++) { - this[start] = val; - } - - return this; - }, - filter(func, thisArg) { - if (typeof func !== 'function') throw new TypeError("Given argument is not a function."); - +define("values/array", () => { + var Array = env.global.Array = function(len?: number) { var res = []; - for (var i = 0; i < this.length; i++) { - if (i in this && func.call(thisArg, this[i], i, this)) res.push(this[i]); + + if (typeof len === 'number' && arguments.length === 1) { + if (len < 0) throw 'Invalid array length.'; + res.length = len; } + else { + for (var i = 0; i < arguments.length; i++) { + res[i] = arguments[i]; + } + } + return res; - }, - find(func, thisArg) { - if (typeof func !== 'function') throw new TypeError("Given argument is not a function."); - - for (var i = 0; i < this.length; i++) { - if (i in this && func.call(thisArg, this[i], i, this)) return this[i]; - } - - return undefined; - }, - findIndex(func, thisArg) { - if (typeof func !== 'function') throw new TypeError("Given argument is not a function."); - - for (var i = 0; i < this.length; i++) { - if (i in this && func.call(thisArg, this[i], i, this)) return i; - } - - return -1; - }, - findLast(func, thisArg) { - if (typeof func !== 'function') throw new TypeError("Given argument is not a function."); + } as ArrayConstructor; - for (var i = this.length - 1; i >= 0; i--) { - if (i in this && func.call(thisArg, this[i], i, this)) return this[i]; - } + Array.prototype = ([] as any).__proto__ as Array; + setConstr(Array.prototype, Array, env); - return undefined; - }, - findLastIndex(func, thisArg) { - if (typeof func !== 'function') throw new TypeError("Given argument is not a function."); + (Array.prototype as any)[Symbol.typeName] = "Array"; - for (var i = this.length - 1; i >= 0; i--) { - if (i in this && func.call(thisArg, this[i], i, this)) return i; - } + setProps(Array.prototype, env, { + [Symbol.iterator]: function() { + return this.values(); + }, - return -1; - }, - flat(depth) { - var res = [] as any[]; - var buff = []; - res.push(...this); + values() { + var i = 0; - for (var i = 0; i < (depth ?? 1); i++) { - var anyArrays = false; - for (var el of res) { - if (el instanceof Array) { - buff.push(...el); - anyArrays = true; + return { + next: () => { + while (i < this.length) { + if (i++ in this) return { done: false, value: this[i - 1] }; + } + return { done: true, value: undefined }; + }, + [Symbol.iterator]() { return this; } + }; + }, + keys() { + var i = 0; + + return { + next: () => { + while (i < this.length) { + if (i++ in this) return { done: false, value: i - 1 }; + } + return { done: true, value: undefined }; + }, + [Symbol.iterator]() { return this; } + }; + }, + entries() { + var i = 0; + + return { + next: () => { + while (i < this.length) { + if (i++ in this) return { done: false, value: [i - 1, this[i - 1]] }; + } + return { done: true, value: undefined }; + }, + [Symbol.iterator]() { return this; } + }; + }, + concat() { + var res = [] as any[]; + res.push.apply(res, this); + + for (var i = 0; i < arguments.length; i++) { + var arg = arguments[i]; + if (arg instanceof Array) { + res.push.apply(res, arg); + } + else { + res.push(arg); } - else buff.push(el); } - res = buff; - buff = []; - if (!anyArrays) break; - } + return res; + }, + every(func, thisArg) { + if (typeof func !== 'function') throw new TypeError("Given argument not a function."); + func = func.bind(thisArg); - return res; - }, - flatMap(func, th) { - return this.map(func, th).flat(); - }, - forEach(func, thisArg) { - for (var i = 0; i < this.length; i++) { - if (i in this) func.call(thisArg, this[i], i, this); - } - }, - map(func, thisArg) { - if (typeof func !== 'function') throw new TypeError("Given argument is not a function."); - - var res = []; - for (var i = 0; i < this.length; i++) { - if (i in this) res[i] = func.call(thisArg, this[i], i, this); - } - return res; - }, - pop() { - if (this.length === 0) return undefined; - var val = this[this.length - 1]; - this.length--; - return val; - }, - push() { - for (var i = 0; i < arguments.length; i++) { - this[this.length] = arguments[i]; - } - return arguments.length; - }, - shift() { - if (this.length === 0) return undefined; - var res = this[0]; - - for (var i = 0; i < this.length - 1; i++) { - this[i] = this[i + 1]; - } - - this.length--; - - return res; - }, - unshift() { - for (var i = this.length - 1; i >= 0; i--) { - this[i + arguments.length] = this[i]; - } - for (var i = 0; i < arguments.length; i++) { - this[i] = arguments[i]; - } - - return arguments.length; - }, - slice(start, end) { - start = clampI(this.length, wrapI(this.length + 1, start ?? 0)); - end = clampI(this.length, wrapI(this.length + 1, end ?? this.length)); - - var res: any[] = []; - var n = end - start; - if (n <= 0) return res; - - for (var i = 0; i < n; i++) { - res[i] = this[start + i]; - } - - return res; - }, - toString() { - let res = ''; - for (let i = 0; i < this.length; i++) { - if (i > 0) res += ','; - if (i in this && this[i] !== undefined && this[i] !== null) res += this[i]; - } - - return res; - }, - indexOf(el, start) { - start = start! | 0; - for (var i = Math.max(0, start); i < this.length; i++) { - if (i in this && this[i] == el) return i; - } - - return -1; - }, - lastIndexOf(el, start) { - start = start! | 0; - for (var i = this.length; i >= start; i--) { - if (i in this && this[i] == el) return i; - } - - return -1; - }, - includes(el, start) { - return this.indexOf(el, start) >= 0; - }, - join(val = ',') { - let res = '', first = true; - - for (let i = 0; i < this.length; i++) { - if (!(i in this)) continue; - if (!first) res += val; - first = false; - res += this[i]; - } - return res; - }, - sort(func) { - func ??= (a, b) => { - const _a = a + ''; - const _b = b + ''; - - if (_a > _b) return 1; - if (_a < _b) return -1; - return 0; - }; - - if (typeof func !== 'function') throw new TypeError('Expected func to be undefined or a function.'); - - internals.sort(this, func); - return this; - }, - splice(start, deleteCount, ...items) { - start = clampI(this.length, wrapI(this.length, start ?? 0)); - deleteCount = (deleteCount ?? Infinity | 0); - if (start + deleteCount >= this.length) deleteCount = this.length - start; - - const res = this.slice(start, start + deleteCount); - const moveN = items.length - deleteCount; - const len = this.length; - - if (moveN < 0) { - for (let i = start - moveN; i < len; i++) { - this[i + moveN] = this[i]; + for (var i = 0; i < this.length; i++) { + if (!func(this[i], i, this)) return false; } - } - else if (moveN > 0) { - for (let i = len - 1; i >= start; i--) { - this[i + moveN] = this[i]; + + return true; + }, + some(func, thisArg) { + if (typeof func !== 'function') throw new TypeError("Given argument not a function."); + func = func.bind(thisArg); + + for (var i = 0; i < this.length; i++) { + if (func(this[i], i, this)) return true; } + + return false; + }, + fill(val, start, end) { + if (arguments.length < 3) end = this.length; + if (arguments.length < 2) start = 0; + + start = clampI(this.length, wrapI(this.length + 1, start ?? 0)); + end = clampI(this.length, wrapI(this.length + 1, end ?? this.length)); + + for (; start < end; start++) { + this[start] = val; + } + + return this; + }, + filter(func, thisArg) { + if (typeof func !== 'function') throw new TypeError("Given argument is not a function."); + + var res = []; + for (var i = 0; i < this.length; i++) { + if (i in this && func.call(thisArg, this[i], i, this)) res.push(this[i]); + } + return res; + }, + find(func, thisArg) { + if (typeof func !== 'function') throw new TypeError("Given argument is not a function."); + + for (var i = 0; i < this.length; i++) { + if (i in this && func.call(thisArg, this[i], i, this)) return this[i]; + } + + return undefined; + }, + findIndex(func, thisArg) { + if (typeof func !== 'function') throw new TypeError("Given argument is not a function."); + + for (var i = 0; i < this.length; i++) { + if (i in this && func.call(thisArg, this[i], i, this)) return i; + } + + return -1; + }, + findLast(func, thisArg) { + if (typeof func !== 'function') throw new TypeError("Given argument is not a function."); + + for (var i = this.length - 1; i >= 0; i--) { + if (i in this && func.call(thisArg, this[i], i, this)) return this[i]; + } + + return undefined; + }, + findLastIndex(func, thisArg) { + if (typeof func !== 'function') throw new TypeError("Given argument is not a function."); + + for (var i = this.length - 1; i >= 0; i--) { + if (i in this && func.call(thisArg, this[i], i, this)) return i; + } + + return -1; + }, + flat(depth) { + var res = [] as any[]; + var buff = []; + res.push(...this); + + for (var i = 0; i < (depth ?? 1); i++) { + var anyArrays = false; + for (var el of res) { + if (el instanceof Array) { + buff.push(...el); + anyArrays = true; + } + else buff.push(el); + } + + res = buff; + buff = []; + if (!anyArrays) break; + } + + return res; + }, + flatMap(func, th) { + return this.map(func, th).flat(); + }, + forEach(func, thisArg) { + for (var i = 0; i < this.length; i++) { + if (i in this) func.call(thisArg, this[i], i, this); + } + }, + map(func, thisArg) { + if (typeof func !== 'function') throw new TypeError("Given argument is not a function."); + + var res = []; + for (var i = 0; i < this.length; i++) { + if (i in this) res[i] = func.call(thisArg, this[i], i, this); + } + return res; + }, + pop() { + if (this.length === 0) return undefined; + var val = this[this.length - 1]; + this.length--; + return val; + }, + push() { + for (var i = 0; i < arguments.length; i++) { + this[this.length] = arguments[i]; + } + return arguments.length; + }, + shift() { + if (this.length === 0) return undefined; + var res = this[0]; + + for (var i = 0; i < this.length - 1; i++) { + this[i] = this[i + 1]; + } + + this.length--; + + return res; + }, + unshift() { + for (var i = this.length - 1; i >= 0; i--) { + this[i + arguments.length] = this[i]; + } + for (var i = 0; i < arguments.length; i++) { + this[i] = arguments[i]; + } + + return arguments.length; + }, + slice(start, end) { + start = clampI(this.length, wrapI(this.length + 1, start ?? 0)); + end = clampI(this.length, wrapI(this.length + 1, end ?? this.length)); + + var res: any[] = []; + var n = end - start; + if (n <= 0) return res; + + for (var i = 0; i < n; i++) { + res[i] = this[start + i]; + } + + return res; + }, + toString() { + let res = ''; + for (let i = 0; i < this.length; i++) { + if (i > 0) res += ','; + if (i in this && this[i] !== undefined && this[i] !== null) res += this[i]; + } + + return res; + }, + indexOf(el, start) { + start = start! | 0; + for (var i = Math.max(0, start); i < this.length; i++) { + if (i in this && this[i] == el) return i; + } + + return -1; + }, + lastIndexOf(el, start) { + start = start! | 0; + for (var i = this.length; i >= start; i--) { + if (i in this && this[i] == el) return i; + } + + return -1; + }, + includes(el, start) { + return this.indexOf(el, start) >= 0; + }, + join(val = ',') { + let res = '', first = true; + + for (let i = 0; i < this.length; i++) { + if (!(i in this)) continue; + if (!first) res += val; + first = false; + res += this[i]; + } + return res; + }, + sort(func) { + func ??= (a, b) => { + const _a = a + ''; + const _b = b + ''; + + if (_a > _b) return 1; + if (_a < _b) return -1; + return 0; + }; + + if (typeof func !== 'function') throw new TypeError('Expected func to be undefined or a function.'); + + env.internals.sort(this, func); + return this; + }, + splice(start, deleteCount, ...items) { + start = clampI(this.length, wrapI(this.length, start ?? 0)); + deleteCount = (deleteCount ?? Infinity | 0); + if (start + deleteCount >= this.length) deleteCount = this.length - start; + + const res = this.slice(start, start + deleteCount); + const moveN = items.length - deleteCount; + const len = this.length; + + if (moveN < 0) { + for (let i = start - moveN; i < len; i++) { + this[i + moveN] = this[i]; + } + } + else if (moveN > 0) { + for (let i = len - 1; i >= start; i--) { + this[i + moveN] = this[i]; + } + } + + for (let i = 0; i < items.length; i++) { + this[i + start] = items[i]; + } + + this.length = len + moveN; + + return res; } - - for (let i = 0; i < items.length; i++) { - this[i + start] = items[i]; - } - - this.length = len + moveN; - - return res; - } -}); - -setProps(Array, { - isArray(val: any) { return internals.isArr(val); } -}); + }); + + setProps(Array, env, { + isArray(val: any) { return env.internals.isArr(val); } + }); +}); \ No newline at end of file diff --git a/lib/values/boolean.ts b/lib/values/boolean.ts index 104d194..a8868a4 100644 --- a/lib/values/boolean.ts +++ b/lib/values/boolean.ts @@ -1,22 +1,12 @@ -interface Boolean { - valueOf(): boolean; - constructor: BooleanConstructor; -} -interface BooleanConstructor { - (val: any): boolean; - new (val: any): Boolean; - prototype: Boolean; -} - -declare var Boolean: BooleanConstructor; - -gt.Boolean = function (this: Boolean | undefined, arg) { - var val; - if (arguments.length === 0) val = false; - else val = !!arg; - if (this === undefined || this === null) return val; - else (this as any).value = val; -} as BooleanConstructor; - -Boolean.prototype = (false as any).__proto__ as Boolean; -setConstr(Boolean.prototype, Boolean); \ No newline at end of file +define("values/boolean", () => { + var Boolean = env.global.Boolean = function (this: Boolean | undefined, arg) { + var val; + if (arguments.length === 0) val = false; + else val = !!arg; + if (this === undefined || this === null) return val; + else (this as any).value = val; + } as BooleanConstructor; + + Boolean.prototype = (false as any).__proto__ as Boolean; + setConstr(Boolean.prototype, Boolean, env); +}); diff --git a/lib/values/errors.ts b/lib/values/errors.ts index 0f16197..95ad33f 100644 --- a/lib/values/errors.ts +++ b/lib/values/errors.ts @@ -1,89 +1,43 @@ -interface Error { - constructor: ErrorConstructor; - name: string; - message: string; - stack: string[]; -} -interface ErrorConstructor { - (msg?: any): Error; - new (msg?: any): Error; - prototype: Error; -} +define("values/errors", () => { + var Error = env.global.Error = function Error(msg: string) { + if (msg === undefined) msg = ''; + else msg += ''; + + return Object.setPrototypeOf({ + message: msg, + stack: [] as string[], + }, Error.prototype); + } as ErrorConstructor; + + Error.prototype = env.internals.err ?? {}; + Error.prototype.name = 'Error'; + setConstr(Error.prototype, Error, env); -interface TypeErrorConstructor extends ErrorConstructor { - (msg?: any): TypeError; - new (msg?: any): TypeError; - prototype: Error; -} -interface TypeError extends Error { - constructor: TypeErrorConstructor; - name: 'TypeError'; -} + Error.prototype.toString = function() { + if (!(this instanceof Error)) return ''; + + if (this.message === '') return this.name; + else return this.name + ': ' + this.message; + }; -interface RangeErrorConstructor extends ErrorConstructor { - (msg?: any): RangeError; - new (msg?: any): RangeError; - prototype: Error; -} -interface RangeError extends Error { - constructor: RangeErrorConstructor; - name: 'RangeError'; -} + function makeError(name: string, proto: any): T { + var err = function (msg: string) { + var res = new Error(msg); + (res as any).__proto__ = err.prototype; + return res; + } as T; -interface SyntaxErrorConstructor extends ErrorConstructor { - (msg?: any): RangeError; - new (msg?: any): RangeError; - prototype: Error; -} -interface SyntaxError extends Error { - constructor: SyntaxErrorConstructor; - name: 'SyntaxError'; -} + err.prototype = proto; + err.prototype.name = name; + setConstr(err.prototype, err as ErrorConstructor, env); + (err.prototype as any).__proto__ = Error.prototype; + (err as any).__proto__ = Error; + env.internals.special(err); + return err; + } -declare var Error: ErrorConstructor; -declare var RangeError: RangeErrorConstructor; -declare var TypeError: TypeErrorConstructor; -declare var SyntaxError: SyntaxErrorConstructor; - -gt.Error = function Error(msg: string) { - if (msg === undefined) msg = ''; - else msg += ''; - - return Object.setPrototypeOf({ - message: msg, - stack: [] as string[], - }, Error.prototype); -} as ErrorConstructor; - -Error.prototype = internals.err ?? {}; -Error.prototype.name = 'Error'; -setConstr(Error.prototype, Error); - -Error.prototype.toString = function() { - if (!(this instanceof Error)) return ''; - - if (this.message === '') return this.name; - else return this.name + ': ' + this.message; -}; - -function makeError(name: string, proto: any): T { - var err = function (msg: string) { - var res = new Error(msg); - (res as any).__proto__ = err.prototype; - return res; - } as T; - - err.prototype = proto; - err.prototype.name = name; - setConstr(err.prototype, err as ErrorConstructor); - (err.prototype as any).__proto__ = Error.prototype; - (err as any).__proto__ = Error; - internals.special(err); - - return err; -} - -gt.RangeError = makeError('RangeError', internals.range ?? {}); -gt.TypeError = makeError('TypeError', internals.type ?? {}); -gt.SyntaxError = makeError('SyntaxError', internals.syntax ?? {}); \ No newline at end of file + env.global.RangeError = makeError('RangeError', env.internals.range ?? {}); + env.global.TypeError = makeError('TypeError', env.internals.type ?? {}); + env.global.SyntaxError = makeError('SyntaxError', env.internals.syntax ?? {}); +}); \ No newline at end of file diff --git a/lib/values/function.ts b/lib/values/function.ts index 7bf7178..e00f5c9 100644 --- a/lib/values/function.ts +++ b/lib/values/function.ts @@ -1,181 +1,140 @@ -interface Function { - apply(this: Function, thisArg: any, argArray?: any): any; - call(this: Function, thisArg: any, ...argArray: any[]): any; - bind(this: Function, thisArg: any, ...argArray: any[]): Function; +define("values/function", () => { + var Function = env.global.Function = function() { + throw 'Using the constructor Function() is forbidden.'; + } as unknown as FunctionConstructor; - toString(): string; + Function.prototype = (Function as any).__proto__ as Function; + setConstr(Function.prototype, Function, env); - prototype: any; - constructor: FunctionConstructor; - readonly length: number; - name: string; -} -interface FunctionConstructor extends Function { - (...args: string[]): (...args: any[]) => any; - new (...args: string[]): (...args: any[]) => any; - prototype: Function; - async( - func: (await: (val: T) => Awaited) => (...args: ArgsT) => RetT - ): (...args: ArgsT) => Promise; - asyncGenerator( - func: (await: (val: T) => Awaited, _yield: (val: T) => void) => (...args: ArgsT) => RetT - ): (...args: ArgsT) => AsyncGenerator; - generator( - func: (_yield: (val: T) => TNext) => (...args: ArgsT) => RetT - ): (...args: ArgsT) => Generator; -} + setProps(Function.prototype, env, { + apply(thisArg, args) { + if (typeof args !== 'object') throw 'Expected arguments to be an array-like object.'; + var len = args.length - 0; + let newArgs: any[]; + if (Array.isArray(args)) newArgs = args; + else { + newArgs = []; -interface CallableFunction extends Function { - (...args: any[]): any; - apply(this: (this: ThisArg, ...args: Args) => RetT, thisArg: ThisArg, argArray?: Args): RetT; - call(this: (this: ThisArg, ...args: Args) => RetT, thisArg: ThisArg, ...argArray: Args): RetT; - bind(this: (this: ThisArg, ...args: [ ...Args, ...Rest ]) => RetT, thisArg: ThisArg, ...argArray: Args): (this: void, ...args: Rest) => RetT; -} -interface NewableFunction extends Function { - new(...args: any[]): any; - apply(this: new (...args: Args) => RetT, thisArg: any, argArray?: Args): RetT; - call(this: new (...args: Args) => RetT, thisArg: any, ...argArray: Args): RetT; - bind(this: new (...args: Args) => RetT, thisArg: any, ...argArray: Args): new (...args: Args) => RetT; -} - -declare var Function: FunctionConstructor; - -gt.Function = function() { - throw 'Using the constructor Function() is forbidden.'; -} as unknown as FunctionConstructor; - -Function.prototype = (Function as any).__proto__ as Function; -setConstr(Function.prototype, Function); - -setProps(Function.prototype, { - apply(thisArg, args) { - if (typeof args !== 'object') throw 'Expected arguments to be an array-like object.'; - var len = args.length - 0; - let newArgs: any[]; - if (Array.isArray(args)) newArgs = args; - else { - newArgs = []; - - while (len >= 0) { - len--; - newArgs[len] = args[len]; - } - } - - return internals.apply(this, thisArg, newArgs); - }, - call(thisArg, ...args) { - return this.apply(thisArg, args); - }, - bind(thisArg, ...args) { - var func = this; - - var res = function() { - var resArgs = []; - - for (var i = 0; i < args.length; i++) { - resArgs[i] = args[i]; - } - for (var i = 0; i < arguments.length; i++) { - resArgs[i + args.length] = arguments[i]; - } - - return func.apply(thisArg, resArgs); - }; - res.name = " " + func.name; - return res; - }, - toString() { - return 'function (...) { ... }'; - }, -}); -setProps(Function, { - async(func) { - if (typeof func !== 'function') throw new TypeError('Expected func to be function.'); - - return function (this: any) { - const args = arguments; - - return new Promise((res, rej) => { - const gen = Function.generator(func as any).apply(this, args as any); - - (function next(type: 'none' | 'err' | 'ret', val?: any) { - try { - let result; - - switch (type) { - case 'err': result = gen.throw(val); break; - case 'ret': result = gen.next(val); break; - case 'none': result = gen.next(); break; - } - if (result.done) res(result.value); - else Promise.resolve(result.value).then( - v => next('ret', v), - v => next('err', v) - ) - } - catch (e) { - rej(e); - } - })('none'); - }); - }; - }, - asyncGenerator(func) { - if (typeof func !== 'function') throw new TypeError('Expected func to be function.'); - - - return function(this: any) { - const gen = Function.generator((_yield) => func( - val => _yield(['await', val]) as any, - val => _yield(['yield', val]) - )).apply(this, arguments as any); - - const next = (resolve: Function, reject: Function, type: 'none' | 'val' | 'ret' | 'err', val?: any) => { - let res; - - try { - switch (type) { - case 'val': res = gen.next(val); break; - case 'ret': res = gen.return(val); break; - case 'err': res = gen.throw(val); break; - default: res = gen.next(); break; - } + while (len >= 0) { + len--; + newArgs[len] = args[len]; } - catch (e) { return reject(e); } + } - if (res.done) return { done: true, res: res }; - else if (res.value[0] === 'await') Promise.resolve(res.value[1]).then( - v => next(resolve, reject, 'val', v), - v => next(resolve, reject, 'err', v), - ) - else resolve({ done: false, value: res.value[1] }); + return env.internals.apply(this, thisArg, newArgs); + }, + call(thisArg, ...args) { + return this.apply(thisArg, args); + }, + bind(thisArg, ...args) { + var func = this; + + var res = function() { + var resArgs = []; + + for (var i = 0; i < args.length; i++) { + resArgs[i] = args[i]; + } + for (var i = 0; i < arguments.length; i++) { + resArgs[i + args.length] = arguments[i]; + } + + return func.apply(thisArg, resArgs); }; + res.name = " " + func.name; + return res; + }, + toString() { + return 'function (...) { ... }'; + }, + }); + setProps(Function, env, { + async(func) { + if (typeof func !== 'function') throw new TypeError('Expected func to be function.'); - return { - next() { - const args = arguments; - if (arguments.length === 0) return new Promise((res, rej) => next(res, rej, 'none')); - else return new Promise((res, rej) => next(res, rej, 'val', args[0])); - }, - return: (value) => new Promise((res, rej) => next(res, rej, 'ret', value)), - throw: (value) => new Promise((res, rej) => next(res, rej, 'err', value)), - [Symbol.asyncIterator]() { return this; } + return function (this: any) { + const args = arguments; + + return new Promise((res, rej) => { + const gen = Function.generator(func as any).apply(this, args as any); + + (function next(type: 'none' | 'err' | 'ret', val?: any) { + try { + let result; + + switch (type) { + case 'err': result = gen.throw(val); break; + case 'ret': result = gen.next(val); break; + case 'none': result = gen.next(); break; + } + if (result.done) res(result.value); + else Promise.resolve(result.value).then( + v => next('ret', v), + v => next('err', v) + ) + } + catch (e) { + rej(e); + } + })('none'); + }); + }; + }, + asyncGenerator(func) { + if (typeof func !== 'function') throw new TypeError('Expected func to be function.'); + + return function(this: any) { + const gen = Function.generator((_yield) => func( + val => _yield(['await', val]) as any, + val => _yield(['yield', val]) + )).apply(this, arguments as any); + + const next = (resolve: Function, reject: Function, type: 'none' | 'val' | 'ret' | 'err', val?: any) => { + let res; + + try { + switch (type) { + case 'val': res = gen.next(val); break; + case 'ret': res = gen.return(val); break; + case 'err': res = gen.throw(val); break; + default: res = gen.next(); break; + } + } + catch (e) { return reject(e); } + + if (res.done) return { done: true, res: res }; + else if (res.value[0] === 'await') Promise.resolve(res.value[1]).then( + v => next(resolve, reject, 'val', v), + v => next(resolve, reject, 'err', v), + ) + else resolve({ done: false, value: res.value[1] }); + }; + + return { + next() { + const args = arguments; + if (arguments.length === 0) return new Promise((res, rej) => next(res, rej, 'none')); + else return new Promise((res, rej) => next(res, rej, 'val', args[0])); + }, + return: (value) => new Promise((res, rej) => next(res, rej, 'ret', value)), + throw: (value) => new Promise((res, rej) => next(res, rej, 'err', value)), + [Symbol.asyncIterator]() { return this; } + } + } + }, + generator(func) { + if (typeof func !== 'function') throw new TypeError('Expected func to be function.'); + const gen = env.internals.makeGenerator(func); + return (...args: any[]) => { + const it = gen(args); + + return { + next: it.next, + return: it.return, + throw: it.throw, + [Symbol.iterator]() { return this; } + } } } - }, - generator(func) { - if (typeof func !== 'function') throw new TypeError('Expected func to be function.'); - const gen = internals.makeGenerator(func); - return (...args: any[]) => { - const it = gen(args); - - return { - next: it.next, - return: it.return, - throw: it.throw, - [Symbol.iterator]() { return this; } - } - } - } -}) \ No newline at end of file + }) +}); \ No newline at end of file diff --git a/lib/values/number.ts b/lib/values/number.ts index 6b1dda6..11366a4 100644 --- a/lib/values/number.ts +++ b/lib/values/number.ts @@ -1,50 +1,33 @@ -interface Number { - toString(): string; - valueOf(): number; - constructor: NumberConstructor; -} -interface NumberConstructor { - (val: any): number; - new (val: any): Number; - prototype: Number; - parseInt(val: unknown): number; - parseFloat(val: unknown): number; -} +define("values/number", () => { + var Number = env.global.Number = function(this: Number | undefined, arg: any) { + var val; + if (arguments.length === 0) val = 0; + else val = arg - 0; + if (this === undefined || this === null) return val; + else (this as any).value = val; + } as NumberConstructor; -declare var Number: NumberConstructor; -declare var parseInt: typeof Number.parseInt; -declare var parseFloat: typeof Number.parseFloat; -declare var NaN: number; -declare var Infinity: number; + Number.prototype = (0 as any).__proto__ as Number; + setConstr(Number.prototype, Number, env); -gt.Number = function(this: Number | undefined, arg: any) { - var val; - if (arguments.length === 0) val = 0; - else val = arg - 0; - if (this === undefined || this === null) return val; - else (this as any).value = val; -} as NumberConstructor; + setProps(Number.prototype, env, { + valueOf() { + if (typeof this === 'number') return this; + else return (this as any).value; + }, + toString() { + if (typeof this === 'number') return this + ''; + else return (this as any).value + ''; + } + }); -Number.prototype = (0 as any).__proto__ as Number; -setConstr(Number.prototype, Number); + setProps(Number, env, { + parseInt(val) { return Math.trunc(Number.parseFloat(val)); }, + parseFloat(val) { return env.internals.parseFloat(val); }, + }); -setProps(Number.prototype, { - valueOf() { - if (typeof this === 'number') return this; - else return (this as any).value; - }, - toString() { - if (typeof this === 'number') return this + ''; - else return (this as any).value + ''; - } -}); - -setProps(Number, { - parseInt(val) { return Math.trunc(Number.parseFloat(val)); }, - parseFloat(val) { return internals.parseFloat(val); }, -}); - -Object.defineProperty(gt, 'parseInt', { value: Number.parseInt, writable: false }); -Object.defineProperty(gt, 'parseFloat', { value: Number.parseFloat, writable: false }); -Object.defineProperty(gt, 'NaN', { value: 0 / 0, writable: false }); -Object.defineProperty(gt, 'Infinity', { value: 1 / 0, writable: false }); + env.global.Object.defineProperty(env.global, 'parseInt', { value: Number.parseInt, writable: false }); + env.global.Object.defineProperty(env.global, 'parseFloat', { value: Number.parseFloat, writable: false }); + env.global.Object.defineProperty(env.global, 'NaN', { value: 0 / 0, writable: false }); + env.global.Object.defineProperty(env.global, 'Infinity', { value: 1 / 0, writable: false }); +}); \ No newline at end of file diff --git a/lib/values/object.ts b/lib/values/object.ts index 6d33f03..4e63a39 100644 --- a/lib/values/object.ts +++ b/lib/values/object.ts @@ -1,234 +1,178 @@ - interface Object { - constructor: NewableFunction; - [Symbol.typeName]: string; +/** @internal */ +define("values/object", () => { + var Object = env.global.Object = function(arg: any) { + if (arg === undefined || arg === null) return {}; + else if (typeof arg === 'boolean') return new Boolean(arg); + else if (typeof arg === 'number') return new Number(arg); + else if (typeof arg === 'string') return new String(arg); + return arg; + } as ObjectConstructor; - valueOf(): this; - toString(): string; - hasOwnProperty(key: any): boolean; -} -interface ObjectConstructor extends Function { - (arg: string): String; - (arg: number): Number; - (arg: boolean): Boolean; - (arg?: undefined | null): {}; - (arg: T): T; + Object.prototype = ({} as any).__proto__ as Object; + setConstr(Object.prototype, Object as any, env); - new (arg: string): String; - new (arg: number): Number; - new (arg: boolean): Boolean; - new (arg?: undefined | null): {}; - new (arg: T): T; - - prototype: Object; - - assign(target: T, ...src: object[]): T; - create(proto: T, props?: { [key: string]: PropertyDescriptor }): T; - - keys(obj: T, onlyString?: true): (keyof T)[]; - keys(obj: T, onlyString: false): any[]; - entries(obj: T, onlyString?: true): [keyof T, T[keyof T]][]; - entries(obj: T, onlyString: false): [any, any][]; - values(obj: T, onlyString?: true): (T[keyof T])[]; - values(obj: T, onlyString: false): any[]; - - fromEntries(entries: Iterable<[any, any]>): object; - - defineProperty(obj: ThisT, key: any, desc: PropertyDescriptor): ThisT; - defineProperties(obj: ThisT, desc: { [key: string]: PropertyDescriptor }): ThisT; - - getOwnPropertyNames(obj: T): (keyof T)[]; - getOwnPropertySymbols(obj: T): (keyof T)[]; - hasOwn(obj: T, key: KeyT): boolean; - - getOwnPropertyDescriptor(obj: T, key: KeyT): PropertyDescriptor; - getOwnPropertyDescriptors(obj: T): { [x in keyof T]: PropertyDescriptor }; - - getPrototypeOf(obj: any): object | null; - setPrototypeOf(obj: T, proto: object | null): T; - - preventExtensions(obj: T): T; - seal(obj: T): T; - freeze(obj: T): T; - - isExtensible(obj: object): boolean; - isSealed(obj: object): boolean; - isFrozen(obj: object): boolean; -} - -declare var Object: ObjectConstructor; - -gt.Object = function(arg: any) { - if (arg === undefined || arg === null) return {}; - else if (typeof arg === 'boolean') return new Boolean(arg); - else if (typeof arg === 'number') return new Number(arg); - else if (typeof arg === 'string') return new String(arg); - return arg; -} as ObjectConstructor; - -Object.prototype = ({} as any).__proto__ as Object; -setConstr(Object.prototype, Object as any); - -function throwNotObject(obj: any, name: string) { - if (obj === null || typeof obj !== 'object' && typeof obj !== 'function') { - throw new TypeError(`Object.${name} may only be used for objects.`); + function throwNotObject(obj: any, name: string) { + if (obj === null || typeof obj !== 'object' && typeof obj !== 'function') { + throw new TypeError(`Object.${name} may only be used for objects.`); + } + } + function check(obj: any) { + return typeof obj === 'object' && obj !== null || typeof obj === 'function'; } -} -function check(obj: any) { - return typeof obj === 'object' && obj !== null || typeof obj === 'function'; -} -setProps(Object, { - assign: function(dst, ...src) { - throwNotObject(dst, 'assign'); - for (let i = 0; i < src.length; i++) { - const obj = src[i]; - throwNotObject(obj, 'assign'); - for (const key of Object.keys(obj)) { - (dst as any)[key] = (obj as any)[key]; + setProps(Object, env, { + assign: function(dst, ...src) { + throwNotObject(dst, 'assign'); + for (let i = 0; i < src.length; i++) { + const obj = src[i]; + throwNotObject(obj, 'assign'); + for (const key of Object.keys(obj)) { + (dst as any)[key] = (obj as any)[key]; + } } + return dst; + }, + create(obj, props) { + props ??= {}; + return Object.defineProperties({ __proto__: obj }, props as any) as any; + }, + + defineProperty(obj, key, attrib) { + throwNotObject(obj, 'defineProperty'); + if (typeof attrib !== 'object') throw new TypeError('Expected attributes to be an object.'); + + if ('value' in attrib) { + if ('get' in attrib || 'set' in attrib) throw new TypeError('Cannot specify a value and accessors for a property.'); + if (!env.internals.defineField( + obj, key, + attrib.value, + !!attrib.writable, + !!attrib.enumerable, + !!attrib.configurable + )) throw new TypeError('Can\'t define property \'' + key + '\'.'); + } + else { + if (typeof attrib.get !== 'function' && attrib.get !== undefined) throw new TypeError('Get accessor must be a function.'); + if (typeof attrib.set !== 'function' && attrib.set !== undefined) throw new TypeError('Set accessor must be a function.'); + + if (!env.internals.defineProp( + obj, key, + attrib.get, + attrib.set, + !!attrib.enumerable, + !!attrib.configurable + )) throw new TypeError('Can\'t define property \'' + key + '\'.'); + } + + return obj; + }, + defineProperties(obj, attrib) { + throwNotObject(obj, 'defineProperties'); + if (typeof attrib !== 'object' && typeof attrib !== 'function') throw 'Expected second argument to be an object.'; + + for (var key in attrib) { + Object.defineProperty(obj, key, attrib[key]); + } + + return obj; + }, + + keys(obj, onlyString) { + onlyString = !!(onlyString ?? true); + return env.internals.keys(obj, onlyString); + }, + entries(obj, onlyString) { + return Object.keys(obj, onlyString).map(v => [ v, (obj as any)[v] ]); + }, + values(obj, onlyString) { + return Object.keys(obj, onlyString).map(v => (obj as any)[v]); + }, + + getOwnPropertyDescriptor(obj, key) { + return env.internals.ownProp(obj, key); + }, + getOwnPropertyDescriptors(obj) { + return Object.fromEntries([ + ...Object.getOwnPropertyNames(obj), + ...Object.getOwnPropertySymbols(obj) + ].map(v => [ v, Object.getOwnPropertyDescriptor(obj, v) ])) as any; + }, + + getOwnPropertyNames(obj) { + return env.internals.ownPropKeys(obj, false); + }, + getOwnPropertySymbols(obj) { + return env.internals.ownPropKeys(obj, true); + }, + hasOwn(obj, key) { + if (Object.getOwnPropertyNames(obj).includes(key)) return true; + if (Object.getOwnPropertySymbols(obj).includes(key)) return true; + return false; + }, + + getPrototypeOf(obj) { + return obj.__proto__; + }, + setPrototypeOf(obj, proto) { + (obj as any).__proto__ = proto; + return obj; + }, + + fromEntries(iterable) { + const res = {} as any; + + for (const el of iterable) { + res[el[0]] = el[1]; + } + + return res; + }, + + preventExtensions(obj) { + throwNotObject(obj, 'preventExtensions'); + env.internals.preventExtensions(obj); + return obj; + }, + seal(obj) { + throwNotObject(obj, 'seal'); + env.internals.seal(obj); + return obj; + }, + freeze(obj) { + throwNotObject(obj, 'freeze'); + env.internals.freeze(obj); + return obj; + }, + + isExtensible(obj) { + if (!check(obj)) return false; + return env.internals.extensible(obj); + }, + isSealed(obj) { + if (!check(obj)) return true; + if (Object.isExtensible(obj)) return false; + return Object.getOwnPropertyNames(obj).every(v => !Object.getOwnPropertyDescriptor(obj, v).configurable); + }, + isFrozen(obj) { + if (!check(obj)) return true; + if (Object.isExtensible(obj)) return false; + return Object.getOwnPropertyNames(obj).every(v => { + var prop = Object.getOwnPropertyDescriptor(obj, v); + if ('writable' in prop && prop.writable) return false; + return !prop.configurable; + }); } - return dst; - }, - create(obj, props) { - props ??= {}; - return Object.defineProperties({ __proto__: obj }, props as any) as any; - }, + }); - defineProperty(obj, key, attrib) { - throwNotObject(obj, 'defineProperty'); - if (typeof attrib !== 'object') throw new TypeError('Expected attributes to be an object.'); - - if ('value' in attrib) { - if ('get' in attrib || 'set' in attrib) throw new TypeError('Cannot specify a value and accessors for a property.'); - if (!internals.defineField( - obj, key, - attrib.value, - !!attrib.writable, - !!attrib.enumerable, - !!attrib.configurable - )) throw new TypeError('Can\'t define property \'' + key + '\'.'); - } - else { - if (typeof attrib.get !== 'function' && attrib.get !== undefined) throw new TypeError('Get accessor must be a function.'); - if (typeof attrib.set !== 'function' && attrib.set !== undefined) throw new TypeError('Set accessor must be a function.'); - - if (!internals.defineProp( - obj, key, - attrib.get, - attrib.set, - !!attrib.enumerable, - !!attrib.configurable - )) throw new TypeError('Can\'t define property \'' + key + '\'.'); - } - - return obj; - }, - defineProperties(obj, attrib) { - throwNotObject(obj, 'defineProperties'); - if (typeof attrib !== 'object' && typeof attrib !== 'function') throw 'Expected second argument to be an object.'; - - for (var key in attrib) { - Object.defineProperty(obj, key, attrib[key]); - } - - return obj; - }, - - keys(obj, onlyString) { - onlyString = !!(onlyString ?? true); - return internals.keys(obj, onlyString); - }, - entries(obj, onlyString) { - return Object.keys(obj, onlyString).map(v => [ v, (obj as any)[v] ]); - }, - values(obj, onlyString) { - return Object.keys(obj, onlyString).map(v => (obj as any)[v]); - }, - - getOwnPropertyDescriptor(obj, key) { - return internals.ownProp(obj, key); - }, - getOwnPropertyDescriptors(obj) { - return Object.fromEntries([ - ...Object.getOwnPropertyNames(obj), - ...Object.getOwnPropertySymbols(obj) - ].map(v => [ v, Object.getOwnPropertyDescriptor(obj, v) ])) as any; - }, - - getOwnPropertyNames(obj) { - return internals.ownPropKeys(obj, false); - }, - getOwnPropertySymbols(obj) { - return internals.ownPropKeys(obj, true); - }, - hasOwn(obj, key) { - if (Object.getOwnPropertyNames(obj).includes(key)) return true; - if (Object.getOwnPropertySymbols(obj).includes(key)) return true; - return false; - }, - - getPrototypeOf(obj) { - return obj.__proto__; - }, - setPrototypeOf(obj, proto) { - (obj as any).__proto__ = proto; - return obj; - }, - - fromEntries(iterable) { - const res = {} as any; - - for (const el of iterable) { - res[el[0]] = el[1]; - } - - return res; - }, - - preventExtensions(obj) { - throwNotObject(obj, 'preventExtensions'); - internals.preventExtensions(obj); - return obj; - }, - seal(obj) { - throwNotObject(obj, 'seal'); - internals.seal(obj); - return obj; - }, - freeze(obj) { - throwNotObject(obj, 'freeze'); - internals.freeze(obj); - return obj; - }, - - isExtensible(obj) { - if (!check(obj)) return false; - return internals.extensible(obj); - }, - isSealed(obj) { - if (!check(obj)) return true; - if (Object.isExtensible(obj)) return false; - return Object.getOwnPropertyNames(obj).every(v => !Object.getOwnPropertyDescriptor(obj, v).configurable); - }, - isFrozen(obj) { - if (!check(obj)) return true; - if (Object.isExtensible(obj)) return false; - return Object.getOwnPropertyNames(obj).every(v => { - var prop = Object.getOwnPropertyDescriptor(obj, v); - if ('writable' in prop && prop.writable) return false; - return !prop.configurable; - }); - } -}); - -setProps(Object.prototype, { - valueOf() { - return this; - }, - toString() { - return '[object ' + (this[Symbol.typeName] ?? 'Unknown') + ']'; - }, - hasOwnProperty(key) { - return Object.hasOwn(this, key); - }, -}); + setProps(Object.prototype, env, { + valueOf() { + return this; + }, + toString() { + return '[object ' + (this[Symbol.typeName] ?? 'Unknown') + ']'; + }, + hasOwnProperty(key) { + return Object.hasOwn(this, key); + }, + }); +}); \ No newline at end of file diff --git a/lib/values/string.ts b/lib/values/string.ts index 8ec19e3..95023ff 100644 --- a/lib/values/string.ts +++ b/lib/values/string.ts @@ -1,261 +1,210 @@ -interface Replacer { - [Symbol.replace](target: string, val: string | ((match: string, ...args: any[]) => string)): string; -} +define("values/string", () => { + var String = env.global.String = function(this: String | undefined, arg: any) { + var val; + if (arguments.length === 0) val = ''; + else val = arg + ''; + if (this === undefined || this === null) return val; + else (this as any).value = val; + } as StringConstructor; -interface String { - [i: number]: string; + String.prototype = ('' as any).__proto__ as String; + setConstr(String.prototype, String, env); - toString(): string; - valueOf(): string; + setProps(String.prototype, env, { + toString() { + if (typeof this === 'string') return this; + else return (this as any).value; + }, + valueOf() { + if (typeof this === 'string') return this; + else return (this as any).value; + }, - charAt(pos: number): string; - charCodeAt(pos: number): number; - substring(start?: number, end?: number): string; - slice(start?: number, end?: number): string; - substr(start?: number, length?: number): string; + substring(start, end) { + if (typeof this !== 'string') { + if (this instanceof String) return (this as any).value.substring(start, end); + else throw new Error('This function may be used only with primitive or object strings.'); + } + start = start ?? 0 | 0; + end = (end ?? this.length) | 0; + return env.internals.substring(this, start, end); + }, + substr(start, length) { + start = start ?? 0 | 0; - startsWith(str: string, pos?: number): string; - endsWith(str: string, pos?: number): string; + if (start >= this.length) start = this.length - 1; + if (start < 0) start = 0; - replace(pattern: string | Replacer, val: string): string; - replaceAll(pattern: string | Replacer, val: string): string; + length = (length ?? this.length - start) | 0; + return this.substring(start, length + start); + }, - match(pattern: string | Matcher): RegExpResult | string[] | null; - matchAll(pattern: string | Matcher): IterableIterator; + toLowerCase() { + return env.internals.toLower(this + ''); + }, + toUpperCase() { + return env.internals.toUpper(this + ''); + }, - split(pattern: string | Splitter, limit?: number, sensible?: boolean): string; + charAt(pos) { + if (typeof this !== 'string') { + if (this instanceof String) return (this as any).value.charAt(pos); + else throw new Error('This function may be used only with primitive or object strings.'); + } - concat(...others: string[]): string; - indexOf(term: string | Searcher, start?: number): number; - lastIndexOf(term: string | Searcher, start?: number): number; + pos = pos | 0; + if (pos < 0 || pos >= this.length) return ''; + return this[pos]; + }, + charCodeAt(pos) { + var res = this.charAt(pos); + if (res === '') return NaN; + else return env.internals.toCharCode(res); + }, - toLowerCase(): string; - toUpperCase(): string; + startsWith(term, pos) { + if (typeof this !== 'string') { + if (this instanceof String) return (this as any).value.startsWith(term, pos); + else throw new Error('This function may be used only with primitive or object strings.'); + } + pos = pos! | 0; + return env.internals.startsWith(this, term + '', pos); + }, + endsWith(term, pos) { + if (typeof this !== 'string') { + if (this instanceof String) return (this as any).value.endsWith(term, pos); + else throw new Error('This function may be used only with primitive or object strings.'); + } + pos = (pos ?? this.length) | 0; + return env.internals.endsWith(this, term + '', pos); + }, - trim(): string; + indexOf(term: any, start) { + if (typeof this !== 'string') { + if (this instanceof String) return (this as any).value.indexOf(term, start); + else throw new Error('This function may be used only with primitive or object strings.'); + } - includes(term: string, start?: number): boolean; + if (typeof term[Symbol.search] !== 'function') term = RegExp.escape(term); - length: number; + return term[Symbol.search](this, false, start); + }, + lastIndexOf(term: any, start) { + if (typeof this !== 'string') { + if (this instanceof String) return (this as any).value.indexOf(term, start); + else throw new Error('This function may be used only with primitive or object strings.'); + } - constructor: StringConstructor; -} -interface StringConstructor { - (val: any): string; - new (val: any): String; + if (typeof term[Symbol.search] !== 'function') term = RegExp.escape(term); - fromCharCode(val: number): string; + return term[Symbol.search](this, true, start); + }, + includes(term, start) { + return this.indexOf(term, start) >= 0; + }, - prototype: String; -} + replace(pattern: any, val) { + if (typeof this !== 'string') { + if (this instanceof String) return (this as any).value.replace(pattern, val); + else throw new Error('This function may be used only with primitive or object strings.'); + } -declare var String: StringConstructor; + if (typeof pattern[Symbol.replace] !== 'function') pattern = RegExp.escape(pattern); -gt.String = function(this: String | undefined, arg: any) { - var val; - if (arguments.length === 0) val = ''; - else val = arg + ''; - if (this === undefined || this === null) return val; - else (this as any).value = val; -} as StringConstructor; + return pattern[Symbol.replace](this, val); + }, + replaceAll(pattern: any, val) { + if (typeof this !== 'string') { + if (this instanceof String) return (this as any).value.replace(pattern, val); + else throw new Error('This function may be used only with primitive or object strings.'); + } -String.prototype = ('' as any).__proto__ as String; -setConstr(String.prototype, String); + if (typeof pattern[Symbol.replace] !== 'function') pattern = RegExp.escape(pattern, "g"); + if (pattern instanceof RegExp && !pattern.global) pattern = new pattern.constructor(pattern.source, pattern.flags + "g"); -setProps(String.prototype, { - toString() { - if (typeof this === 'string') return this; - else return (this as any).value; - }, - valueOf() { - if (typeof this === 'string') return this; - else return (this as any).value; - }, + return pattern[Symbol.replace](this, val); + }, - substring(start, end) { - if (typeof this !== 'string') { - if (this instanceof String) return (this as any).value.substring(start, end); - else throw new Error('This function may be used only with primitive or object strings.'); + match(pattern: any) { + if (typeof this !== 'string') { + if (this instanceof String) return (this as any).value.match(pattern); + else throw new Error('This function may be used only with primitive or object strings.'); + } + + if (typeof pattern[Symbol.match] !== 'function') pattern = RegExp.escape(pattern); + + return pattern[Symbol.match](this); + }, + matchAll(pattern: any) { + if (typeof this !== 'string') { + if (this instanceof String) return (this as any).value.matchAll(pattern); + else throw new Error('This function may be used only with primitive or object strings.'); + } + + if (typeof pattern[Symbol.match] !== 'function') pattern = RegExp.escape(pattern, "g"); + if (pattern instanceof RegExp && !pattern.global) pattern = new pattern.constructor(pattern.source, pattern.flags + "g"); + + return pattern[Symbol.match](this); + }, + + split(pattern: any, lim, sensible) { + if (typeof this !== 'string') { + if (this instanceof String) return (this as any).value.split(pattern, lim, sensible); + else throw new Error('This function may be used only with primitive or object strings.'); + } + + if (typeof pattern[Symbol.split] !== 'function') pattern = RegExp.escape(pattern, "g"); + + return pattern[Symbol.split](this, lim, sensible); + }, + slice(start, end) { + if (typeof this !== 'string') { + if (this instanceof String) return (this as any).value.slice(start, end); + else throw new Error('This function may be used only with primitive or object strings.'); + } + + start = wrapI(this.length, start ?? 0 | 0); + end = wrapI(this.length, end ?? this.length | 0); + + if (start > end) return ''; + + return this.substring(start, end); + }, + + concat(...args) { + if (typeof this !== 'string') { + if (this instanceof String) return (this as any).value.concat(...args); + else throw new Error('This function may be used only with primitive or object strings.'); + } + + var res = this; + for (var arg of args) res += arg; + return res; + }, + + trim() { + return this + .replace(/^\s+/g, '') + .replace(/\s+$/g, ''); } - start = start ?? 0 | 0; - end = (end ?? this.length) | 0; - return internals.substring(this, start, end); - }, - substr(start, length) { - start = start ?? 0 | 0; + }); - if (start >= this.length) start = this.length - 1; - if (start < 0) start = 0; + setProps(String, env, { + fromCharCode(val) { + return env.internals.fromCharCode(val | 0); + }, + }) - length = (length ?? this.length - start) | 0; - return this.substring(start, length + start); - }, + env.global.Object.defineProperty(String.prototype, 'length', { + get() { + if (typeof this !== 'string') { + if (this instanceof String) return (this as any).value.length; + else throw new Error('This function may be used only with primitive or object strings.'); + } - toLowerCase() { - return internals.toLower(this + ''); - }, - toUpperCase() { - return internals.toUpper(this + ''); - }, - - charAt(pos) { - if (typeof this !== 'string') { - if (this instanceof String) return (this as any).value.charAt(pos); - else throw new Error('This function may be used only with primitive or object strings.'); - } - - pos = pos | 0; - if (pos < 0 || pos >= this.length) return ''; - return this[pos]; - }, - charCodeAt(pos) { - var res = this.charAt(pos); - if (res === '') return NaN; - else return internals.toCharCode(res); - }, - - startsWith(term, pos) { - if (typeof this !== 'string') { - if (this instanceof String) return (this as any).value.startsWith(term, pos); - else throw new Error('This function may be used only with primitive or object strings.'); - } - pos = pos! | 0; - return internals.startsWith(this, term + '', pos); - }, - endsWith(term, pos) { - if (typeof this !== 'string') { - if (this instanceof String) return (this as any).value.endsWith(term, pos); - else throw new Error('This function may be used only with primitive or object strings.'); - } - pos = (pos ?? this.length) | 0; - return internals.endsWith(this, term + '', pos); - }, - - indexOf(term: any, start) { - if (typeof this !== 'string') { - if (this instanceof String) return (this as any).value.indexOf(term, start); - else throw new Error('This function may be used only with primitive or object strings.'); - } - - if (typeof term[Symbol.search] !== 'function') term = RegExp.escape(term); - - return term[Symbol.search](this, false, start); - }, - lastIndexOf(term: any, start) { - if (typeof this !== 'string') { - if (this instanceof String) return (this as any).value.indexOf(term, start); - else throw new Error('This function may be used only with primitive or object strings.'); - } - - if (typeof term[Symbol.search] !== 'function') term = RegExp.escape(term); - - return term[Symbol.search](this, true, start); - }, - includes(term, start) { - return this.indexOf(term, start) >= 0; - }, - - replace(pattern: any, val) { - if (typeof this !== 'string') { - if (this instanceof String) return (this as any).value.replace(pattern, val); - else throw new Error('This function may be used only with primitive or object strings.'); - } - - if (typeof pattern[Symbol.replace] !== 'function') pattern = RegExp.escape(pattern); - - return pattern[Symbol.replace](this, val); - }, - replaceAll(pattern: any, val) { - if (typeof this !== 'string') { - if (this instanceof String) return (this as any).value.replace(pattern, val); - else throw new Error('This function may be used only with primitive or object strings.'); - } - - if (typeof pattern[Symbol.replace] !== 'function') pattern = RegExp.escape(pattern, "g"); - if (pattern instanceof RegExp && !pattern.global) pattern = new pattern.constructor(pattern.source, pattern.flags + "g"); - - return pattern[Symbol.replace](this, val); - }, - - match(pattern: any) { - if (typeof this !== 'string') { - if (this instanceof String) return (this as any).value.match(pattern); - else throw new Error('This function may be used only with primitive or object strings.'); - } - - if (typeof pattern[Symbol.match] !== 'function') pattern = RegExp.escape(pattern); - - return pattern[Symbol.match](this); - }, - matchAll(pattern: any) { - if (typeof this !== 'string') { - if (this instanceof String) return (this as any).value.matchAll(pattern); - else throw new Error('This function may be used only with primitive or object strings.'); - } - - if (typeof pattern[Symbol.match] !== 'function') pattern = RegExp.escape(pattern, "g"); - if (pattern instanceof RegExp && !pattern.global) pattern = new pattern.constructor(pattern.source, pattern.flags + "g"); - - return pattern[Symbol.match](this); - }, - - split(pattern: any, lim, sensible) { - if (typeof this !== 'string') { - if (this instanceof String) return (this as any).value.split(pattern, lim, sensible); - else throw new Error('This function may be used only with primitive or object strings.'); - } - - if (typeof pattern[Symbol.split] !== 'function') pattern = RegExp.escape(pattern, "g"); - - return pattern[Symbol.split](this, lim, sensible); - }, - slice(start, end) { - if (typeof this !== 'string') { - if (this instanceof String) return (this as any).value.slice(start, end); - else throw new Error('This function may be used only with primitive or object strings.'); - } - - start = wrapI(this.length, start ?? 0 | 0); - end = wrapI(this.length, end ?? this.length | 0); - - if (start > end) return ''; - - return this.substring(start, end); - }, - - concat(...args) { - if (typeof this !== 'string') { - if (this instanceof String) return (this as any).value.concat(...args); - else throw new Error('This function may be used only with primitive or object strings.'); - } - - var res = this; - for (var arg of args) res += arg; - return res; - }, - - trim() { - return this - .replace(/^\s+/g, '') - .replace(/\s+$/g, ''); - } -}); - -setProps(String, { - fromCharCode(val) { - return internals.fromCharCode(val | 0); - }, -}) - -Object.defineProperty(String.prototype, 'length', { - get() { - if (typeof this !== 'string') { - if (this instanceof String) return (this as any).value.length; - else throw new Error('This function may be used only with primitive or object strings.'); - } - - return internals.strlen(this); - }, - configurable: true, - enumerable: false, -}); + return env.internals.strlen(this); + }, + configurable: true, + enumerable: false, + }); +}); \ No newline at end of file diff --git a/lib/values/symbol.ts b/lib/values/symbol.ts index ef0a02c..0258b75 100644 --- a/lib/values/symbol.ts +++ b/lib/values/symbol.ts @@ -1,38 +1,33 @@ -interface Symbol { - valueOf(): symbol; - constructor: SymbolConstructor; -} -interface SymbolConstructor { - (val?: any): symbol; - prototype: Symbol; - for(key: string): symbol; - keyFor(sym: symbol): string; - readonly typeName: unique symbol; -} +define("values/symbol", () => { + var Symbol = env.global.Symbol = function(this: any, val?: string) { + if (this !== undefined && this !== null) throw new TypeError("Symbol may not be called with 'new'."); + if (typeof val !== 'string' && val !== undefined) throw new TypeError('val must be a string or undefined.'); + return env.internals.symbol(val, true); + } as SymbolConstructor; -declare var Symbol: SymbolConstructor; + Symbol.prototype = env.internals.symbolProto; + setConstr(Symbol.prototype, Symbol, env); + (Symbol as any).typeName = Symbol("Symbol.name"); + (Symbol as any).replace = Symbol('Symbol.replace'); + (Symbol as any).match = Symbol('Symbol.match'); + (Symbol as any).matchAll = Symbol('Symbol.matchAll'); + (Symbol as any).split = Symbol('Symbol.split'); + (Symbol as any).search = Symbol('Symbol.search'); + (Symbol as any).iterator = Symbol('Symbol.iterator'); + (Symbol as any).asyncIterator = Symbol('Symbol.asyncIterator'); -gt.Symbol = function(this: any, val?: string) { - if (this !== undefined && this !== null) throw new TypeError("Symbol may not be called with 'new'."); - if (typeof val !== 'string' && val !== undefined) throw new TypeError('val must be a string or undefined.'); - return internals.symbol(val, true); -} as SymbolConstructor; + setProps(Symbol, env, { + for(key) { + if (typeof key !== 'string' && key !== undefined) throw new TypeError('key must be a string or undefined.'); + return env.internals.symbol(key, false); + }, + keyFor(sym) { + if (typeof sym !== 'symbol') throw new TypeError('sym must be a symbol.'); + return env.internals.symStr(sym); + }, + typeName: Symbol('Symbol.name') as any, + }); -Symbol.prototype = internals.symbolProto; -setConstr(Symbol.prototype, Symbol); -(Symbol as any).typeName = Symbol("Symbol.name"); - -setProps(Symbol, { - for(key) { - if (typeof key !== 'string' && key !== undefined) throw new TypeError('key must be a string or undefined.'); - return internals.symbol(key, false); - }, - keyFor(sym) { - if (typeof sym !== 'symbol') throw new TypeError('sym must be a symbol.'); - return internals.symStr(sym); - }, - typeName: Symbol('Symbol.name') as any, -}); - -Object.defineProperty(Object.prototype, Symbol.typeName, { value: 'Object' }); -Object.defineProperty(gt, Symbol.typeName, { value: 'Window' }); + env.global.Object.defineProperty(Object.prototype, Symbol.typeName, { value: 'Object' }); + env.global.Object.defineProperty(env.global, Symbol.typeName, { value: 'Window' }); +}); \ No newline at end of file diff --git a/src/me/topchetoeu/jscript/Main.java b/src/me/topchetoeu/jscript/Main.java index 34a2426..95f00f2 100644 --- a/src/me/topchetoeu/jscript/Main.java +++ b/src/me/topchetoeu/jscript/Main.java @@ -1,7 +1,6 @@ package me.topchetoeu.jscript; import java.io.BufferedReader; -import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.nio.file.Files; @@ -13,8 +12,6 @@ import me.topchetoeu.jscript.engine.values.Values; import me.topchetoeu.jscript.events.Observer; import me.topchetoeu.jscript.exceptions.EngineException; import me.topchetoeu.jscript.exceptions.SyntaxException; -import me.topchetoeu.jscript.polyfills.PolyfillEngine; -import me.topchetoeu.jscript.polyfills.TypescriptEngine; public class Main { static Thread task; @@ -54,7 +51,7 @@ public class Main { public static void main(String args[]) { var in = new BufferedReader(new InputStreamReader(System.in)); - engine = new TypescriptEngine(new File(".")); + engine = new Engine(); var scope = engine.global().globalChild(); var exited = new boolean[1]; diff --git a/src/me/topchetoeu/jscript/compilation/values/OperationStatement.java b/src/me/topchetoeu/jscript/compilation/values/OperationStatement.java index 114f7b6..ab56757 100644 --- a/src/me/topchetoeu/jscript/compilation/values/OperationStatement.java +++ b/src/me/topchetoeu/jscript/compilation/values/OperationStatement.java @@ -6,7 +6,6 @@ import me.topchetoeu.jscript.Location; import me.topchetoeu.jscript.compilation.Instruction; import me.topchetoeu.jscript.compilation.Statement; import me.topchetoeu.jscript.compilation.control.ThrowStatement; -import me.topchetoeu.jscript.engine.CallContext; import me.topchetoeu.jscript.engine.Operation; import me.topchetoeu.jscript.engine.scope.ScopeRecord; import me.topchetoeu.jscript.engine.values.Values; @@ -52,40 +51,7 @@ public class OperationStatement extends Statement { } try { - var ctx = new CallContext(null); - - switch (operation) { - case ADD: return new ConstantStatement(loc(), Values.add(ctx, vals[0], vals[1])); - case SUBTRACT: return new ConstantStatement(loc(), Values.subtract(ctx, vals[0], vals[1])); - case DIVIDE: return new ConstantStatement(loc(), Values.divide(ctx, vals[0], vals[1])); - case MULTIPLY: return new ConstantStatement(loc(), Values.multiply(ctx, vals[0], vals[1])); - case MODULO: return new ConstantStatement(loc(), Values.modulo(ctx, vals[0], vals[1])); - - case AND: return new ConstantStatement(loc(), Values.and(ctx, vals[0], vals[1])); - case OR: return new ConstantStatement(loc(), Values.or(ctx, vals[0], vals[1])); - case XOR: return new ConstantStatement(loc(), Values.xor(ctx, vals[0], vals[1])); - - case EQUALS: return new ConstantStatement(loc(), Values.strictEquals(vals[0], vals[1])); - case NOT_EQUALS: return new ConstantStatement(loc(), !Values.strictEquals(vals[0], vals[1])); - case LOOSE_EQUALS: return new ConstantStatement(loc(), Values.looseEqual(ctx, vals[0], vals[1])); - case LOOSE_NOT_EQUALS: return new ConstantStatement(loc(), !Values.looseEqual(ctx, vals[0], vals[1])); - - case GREATER: return new ConstantStatement(loc(), Values.compare(ctx, vals[0], vals[1]) < 0); - case GREATER_EQUALS: return new ConstantStatement(loc(), Values.compare(ctx, vals[0], vals[1]) <= 0); - case LESS: return new ConstantStatement(loc(), Values.compare(ctx, vals[0], vals[1]) > 0); - case LESS_EQUALS: return new ConstantStatement(loc(), Values.compare(ctx, vals[0], vals[1]) >= 0); - - case INVERSE: return new ConstantStatement(loc(), Values.bitwiseNot(ctx, vals[0])); - case NOT: return new ConstantStatement(loc(), Values.not(vals[0])); - case POS: return new ConstantStatement(loc(), Values.toNumber(ctx, vals[0])); - case NEG: return new ConstantStatement(loc(), Values.negative(ctx, vals[0])); - - case SHIFT_LEFT: return new ConstantStatement(loc(), Values.shiftLeft(ctx, vals[0], vals[1])); - case SHIFT_RIGHT: return new ConstantStatement(loc(), Values.shiftRight(ctx, vals[0], vals[1])); - case USHIFT_RIGHT: return new ConstantStatement(loc(), Values.unsignedShiftRight(ctx, vals[0], vals[1])); - - default: break; - } + return new ConstantStatement(loc(), Values.operation(null, operation, vals)); } catch (EngineException e) { return new ThrowStatement(loc(), new ConstantStatement(loc(), e.value)); diff --git a/src/me/topchetoeu/jscript/engine/Engine.java b/src/me/topchetoeu/jscript/engine/Engine.java index cb21212..111e66a 100644 --- a/src/me/topchetoeu/jscript/engine/Engine.java +++ b/src/me/topchetoeu/jscript/engine/Engine.java @@ -142,13 +142,6 @@ public class Engine { } } - public void exposeClass(String name, Class clazz) { - global.define(name, true, typeRegister.getConstr(clazz)); - } - public void exposeNamespace(String name, Class clazz) { - global.define(name, true, NativeTypeRegister.makeNamespace(clazz)); - } - public Thread start() { if (this.thread == null) { this.thread = new Thread(this::run, "JavaScript Runner #" + id); @@ -176,6 +169,9 @@ public class Engine { public ObjectValue getPrototype(Class clazz) { return typeRegister.getProto(clazz); } + public FunctionValue getConstructor(Class clazz) { + return typeRegister.getConstr(clazz); + } public CallContext context() { return new CallContext(this).mergeData(callCtxVals); } public Awaitable pushMsg(boolean micro, FunctionValue func, Map, Object> data, Object thisArg, Object... args) { diff --git a/src/me/topchetoeu/jscript/engine/frame/CodeFrame.java b/src/me/topchetoeu/jscript/engine/frame/CodeFrame.java index 1101c25..702a9a4 100644 --- a/src/me/topchetoeu/jscript/engine/frame/CodeFrame.java +++ b/src/me/topchetoeu/jscript/engine/frame/CodeFrame.java @@ -93,13 +93,13 @@ public class CodeFrame { return res; } - public void push(Object val) { + public void push(CallContext ctx, Object val) { if (stack.length <= stackPtr) { var newStack = new Object[stack.length * 2]; System.arraycopy(stack, 0, newStack, 0, stack.length); stack = newStack; } - stack[stackPtr++] = Values.normalize(val); + stack[stackPtr++] = Values.normalize(ctx, val); } public void start(CallContext ctx) { @@ -150,7 +150,7 @@ public class CodeFrame { try { this.jumpFlag = false; - return Runners.exec(debugCmd, instr, this, ctx); + return Runners.exec(ctx, debugCmd, instr, this); } catch (EngineException e) { throw e.add(function.name, prevLoc); @@ -307,13 +307,13 @@ public class CodeFrame { } } - public CodeFrame(Object thisArg, Object[] args, CodeFunction func) { + public CodeFrame(CallContext ctx, Object thisArg, Object[] args, CodeFunction func) { this.args = args.clone(); this.scope = new LocalScope(func.localsN, func.captures); this.scope.get(0).set(null, thisArg); var argsObj = new ArrayValue(); for (var i = 0; i < args.length; i++) { - argsObj.set(i, args[i]); + argsObj.set(ctx, i, args[i]); } this.scope.get(1).value = argsObj; diff --git a/src/me/topchetoeu/jscript/engine/frame/Runners.java b/src/me/topchetoeu/jscript/engine/frame/Runners.java index 1e0511f..c59cb0f 100644 --- a/src/me/topchetoeu/jscript/engine/frame/Runners.java +++ b/src/me/topchetoeu/jscript/engine/frame/Runners.java @@ -18,62 +18,62 @@ import me.topchetoeu.jscript.exceptions.EngineException; public class Runners { public static final Object NO_RETURN = new Object(); - public static Object execReturn(Instruction instr, CodeFrame frame, CallContext ctx) { + public static Object execReturn(CallContext ctx, Instruction instr, CodeFrame frame) { frame.codePtr++; return frame.pop(); } - public static Object execSignal(Instruction instr, CodeFrame frame, CallContext ctx) { + public static Object execSignal(CallContext ctx, Instruction instr, CodeFrame frame) { frame.codePtr++; return new SignalValue(instr.get(0)); } - public static Object execThrow(Instruction instr, CodeFrame frame, CallContext ctx) { + public static Object execThrow(CallContext ctx, Instruction instr, CodeFrame frame) { throw new EngineException(frame.pop()); } - public static Object execThrowSyntax(Instruction instr, CodeFrame frame, CallContext ctx) { + public static Object execThrowSyntax(CallContext ctx, Instruction instr, CodeFrame frame) { throw EngineException.ofSyntax((String)instr.get(0)); } - private static Object call(DebugCommand state, CallContext ctx, Object func, Object thisArg, Object... args) throws InterruptedException { + private static Object call(CallContext ctx, DebugCommand state, Object func, Object thisArg, Object... args) throws InterruptedException { ctx.setData(CodeFrame.STOP_AT_START_KEY, state == DebugCommand.STEP_INTO); return Values.call(ctx, func, thisArg, args); } - public static Object execCall(DebugCommand state, Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException { + public static Object execCall(CallContext ctx, DebugCommand state, Instruction instr, CodeFrame frame) throws InterruptedException { var callArgs = frame.take(instr.get(0)); var func = frame.pop(); var thisArg = frame.pop(); - frame.push(call(state, ctx, func, thisArg, callArgs)); + frame.push(ctx, call(ctx, state, func, thisArg, callArgs)); frame.codePtr++; return NO_RETURN; } - public static Object execCallNew(DebugCommand state, Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException { + public static Object execCallNew(CallContext ctx, DebugCommand state, Instruction instr, CodeFrame frame) throws InterruptedException { var callArgs = frame.take(instr.get(0)); var funcObj = frame.pop(); if (Values.isFunction(funcObj) && Values.function(funcObj).special) { - frame.push(call(state, ctx, funcObj, null, callArgs)); + frame.push(ctx, call(ctx, state, funcObj, null, callArgs)); } else { var proto = Values.getMember(ctx, funcObj, "prototype"); var obj = new ObjectValue(); obj.setPrototype(ctx, proto); - call(state, ctx, funcObj, obj, callArgs); - frame.push(obj); + call(ctx, state, funcObj, obj, callArgs); + frame.push(ctx, obj); } frame.codePtr++; return NO_RETURN; } - public static Object execMakeVar(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException { + public static Object execMakeVar(CallContext ctx, Instruction instr, CodeFrame frame) throws InterruptedException { var name = (String)instr.get(0); frame.function.globals.define(name); frame.codePtr++; return NO_RETURN; } - public static Object execDefProp(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException { + public static Object execDefProp(CallContext ctx, Instruction instr, CodeFrame frame) throws InterruptedException { var setter = frame.pop(); var getter = frame.pop(); var name = frame.pop(); @@ -82,28 +82,28 @@ public class Runners { if (getter != null && !Values.isFunction(getter)) throw EngineException.ofType("Getter must be a function or undefined."); if (setter != null && !Values.isFunction(setter)) throw EngineException.ofType("Setter must be a function or undefined."); if (!Values.isObject(obj)) throw EngineException.ofType("Property apply target must be an object."); - Values.object(obj).defineProperty(name, Values.function(getter), Values.function(setter), false, false); + Values.object(obj).defineProperty(ctx, name, Values.function(getter), Values.function(setter), false, false); - frame.push(obj); + frame.push(ctx, obj); frame.codePtr++; return NO_RETURN; } - public static Object execInstanceof(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException { + public static Object execInstanceof(CallContext ctx, Instruction instr, CodeFrame frame) throws InterruptedException { var type = frame.pop(); var obj = frame.pop(); if (!Values.isPrimitive(type)) { var proto = Values.getMember(ctx, type, "prototype"); - frame.push(Values.isInstanceOf(ctx, obj, proto)); + frame.push(ctx, Values.isInstanceOf(ctx, obj, proto)); } else { - frame.push(false); + frame.push(ctx, false); } frame.codePtr++; return NO_RETURN; } - public static Object execKeys(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException { + public static Object execKeys(CallContext ctx, Instruction instr, CodeFrame frame) throws InterruptedException { var val = frame.pop(); var arr = new ObjectValue(); @@ -113,81 +113,81 @@ public class Runners { Collections.reverse(members); for (var el : members) { if (el instanceof Symbol) continue; - arr.defineProperty(i++, el); + arr.defineProperty(ctx, i++, el); } - arr.defineProperty("length", i); + arr.defineProperty(ctx, "length", i); - frame.push(arr); + frame.push(ctx, arr); frame.codePtr++; return NO_RETURN; } - public static Object execTry(DebugCommand state, Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException { + public static Object execTry(CallContext ctx, Instruction instr, CodeFrame frame) throws InterruptedException { frame.addTry(instr.get(0), instr.get(1), instr.get(2)); frame.codePtr++; return NO_RETURN; } - public static Object execDup(Instruction instr, CodeFrame frame, CallContext ctx) { + public static Object execDup(CallContext ctx, Instruction instr, CodeFrame frame) { int offset = instr.get(0), count = instr.get(1); for (var i = 0; i < count; i++) { - frame.push(frame.peek(offset + count - 1)); + frame.push(ctx, frame.peek(offset + count - 1)); } frame.codePtr++; return NO_RETURN; } - public static Object execMove(Instruction instr, CodeFrame frame, CallContext ctx) { + public static Object execMove(CallContext ctx, Instruction instr, CodeFrame frame) { int offset = instr.get(0), count = instr.get(1); var tmp = frame.take(offset); var res = frame.take(count); - for (var i = 0; i < offset; i++) frame.push(tmp[i]); - for (var i = 0; i < count; i++) frame.push(res[i]); + for (var i = 0; i < offset; i++) frame.push(ctx, tmp[i]); + for (var i = 0; i < count; i++) frame.push(ctx, res[i]); frame.codePtr++; return NO_RETURN; } - public static Object execLoadUndefined(Instruction instr, CodeFrame frame, CallContext ctx) { - frame.push(null); + public static Object execLoadUndefined(CallContext ctx, Instruction instr, CodeFrame frame) { + frame.push(ctx, null); frame.codePtr++; return NO_RETURN; } - public static Object execLoadValue(Instruction instr, CodeFrame frame, CallContext ctx) { - frame.push(instr.get(0)); + public static Object execLoadValue(CallContext ctx, Instruction instr, CodeFrame frame) { + frame.push(ctx, instr.get(0)); frame.codePtr++; return NO_RETURN; } - public static Object execLoadVar(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException { + public static Object execLoadVar(CallContext ctx, Instruction instr, CodeFrame frame) throws InterruptedException { var i = instr.get(0); - if (i instanceof String) frame.push(frame.function.globals.get(ctx, (String)i)); - else frame.push(frame.scope.get((int)i).get(ctx)); + if (i instanceof String) frame.push(ctx, frame.function.globals.get(ctx, (String)i)); + else frame.push(ctx, frame.scope.get((int)i).get(ctx)); frame.codePtr++; return NO_RETURN; } - public static Object execLoadObj(Instruction instr, CodeFrame frame, CallContext ctx) { - frame.push(new ObjectValue()); + public static Object execLoadObj(CallContext ctx, Instruction instr, CodeFrame frame) { + frame.push(ctx, new ObjectValue()); frame.codePtr++; return NO_RETURN; } - public static Object execLoadGlob(Instruction instr, CodeFrame frame, CallContext ctx) { - frame.push(frame.function.globals.obj); + public static Object execLoadGlob(CallContext ctx, Instruction instr, CodeFrame frame) { + frame.push(ctx, frame.function.globals.obj); frame.codePtr++; return NO_RETURN; } - public static Object execLoadArr(Instruction instr, CodeFrame frame, CallContext ctx) { + public static Object execLoadArr(CallContext ctx, Instruction instr, CodeFrame frame) { var res = new ArrayValue(); res.setSize(instr.get(0)); - frame.push(res); + frame.push(ctx, res); frame.codePtr++; return NO_RETURN; } - public static Object execLoadFunc(Instruction instr, CodeFrame frame, CallContext ctx) { + public static Object execLoadFunc(CallContext ctx, Instruction instr, CodeFrame frame) { int n = (Integer)instr.get(0); int localsN = (Integer)instr.get(1); int len = (Integer)instr.get(2); @@ -203,18 +203,18 @@ public class Runners { System.arraycopy(frame.function.body, start, body, 0, end - start); var func = new CodeFunction("", localsN, len, frame.function.globals, captures, body); - frame.push(func); + frame.push(ctx, func); frame.codePtr += n; return NO_RETURN; } - public static Object execLoadMember(DebugCommand state, Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException { + public static Object execLoadMember(CallContext ctx, DebugCommand state, Instruction instr, CodeFrame frame) throws InterruptedException { var key = frame.pop(); var obj = frame.pop(); try { ctx.setData(CodeFrame.STOP_AT_START_KEY, state == DebugCommand.STEP_INTO); - frame.push(Values.getMember(ctx, obj, key)); + frame.push(ctx, Values.getMember(ctx, obj, key)); } catch (IllegalArgumentException e) { throw EngineException.ofType(e.getMessage()); @@ -222,33 +222,33 @@ public class Runners { frame.codePtr++; return NO_RETURN; } - public static Object execLoadKeyMember(DebugCommand state, Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException { - frame.push(instr.get(0)); - return execLoadMember(state, instr, frame, ctx); + public static Object execLoadKeyMember(CallContext ctx, DebugCommand state, Instruction instr, CodeFrame frame) throws InterruptedException { + frame.push(ctx, instr.get(0)); + return execLoadMember(ctx, state, instr, frame); } - public static Object execLoadRegEx(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException { - frame.push(ctx.engine().makeRegex(instr.get(0), instr.get(1))); + public static Object execLoadRegEx(CallContext ctx, Instruction instr, CodeFrame frame) throws InterruptedException { + frame.push(ctx, ctx.engine().makeRegex(instr.get(0), instr.get(1))); frame.codePtr++; return NO_RETURN; } - public static Object execDiscard(Instruction instr, CodeFrame frame, CallContext ctx) { + public static Object execDiscard(CallContext ctx, Instruction instr, CodeFrame frame) { frame.pop(); frame.codePtr++; return NO_RETURN; } - public static Object execStoreMember(DebugCommand state, Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException { + public static Object execStoreMember(CallContext ctx, DebugCommand state, Instruction instr, CodeFrame frame) throws InterruptedException { var val = frame.pop(); var key = frame.pop(); var obj = frame.pop(); ctx.setData(CodeFrame.STOP_AT_START_KEY, state == DebugCommand.STEP_INTO); if (!Values.setMember(ctx, obj, key, val)) throw EngineException.ofSyntax("Can't set member '" + key + "'."); - if ((boolean)instr.get(0)) frame.push(val); + if ((boolean)instr.get(0)) frame.push(ctx, val); frame.codePtr++; return NO_RETURN; } - public static Object execStoreVar(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException { + public static Object execStoreVar(CallContext ctx, Instruction instr, CodeFrame frame) throws InterruptedException { var val = (boolean)instr.get(1) ? frame.peek() : frame.pop(); var i = instr.get(0); @@ -258,18 +258,18 @@ public class Runners { frame.codePtr++; return NO_RETURN; } - public static Object execStoreSelfFunc(Instruction instr, CodeFrame frame, CallContext ctx) { + public static Object execStoreSelfFunc(CallContext ctx, Instruction instr, CodeFrame frame) { frame.scope.locals[(int)instr.get(0)].set(ctx, frame.function); frame.codePtr++; return NO_RETURN; } - public static Object execJmp(Instruction instr, CodeFrame frame, CallContext ctx) { + public static Object execJmp(CallContext ctx, Instruction instr, CodeFrame frame) { frame.codePtr += (int)instr.get(0); frame.jumpFlag = true; return NO_RETURN; } - public static Object execJmpIf(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException { + public static Object execJmpIf(CallContext ctx, Instruction instr, CodeFrame frame) throws InterruptedException { if (Values.toBoolean(frame.pop())) { frame.codePtr += (int)instr.get(0); frame.jumpFlag = true; @@ -277,7 +277,7 @@ public class Runners { else frame.codePtr ++; return NO_RETURN; } - public static Object execJmpIfNot(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException { + public static Object execJmpIfNot(CallContext ctx, Instruction instr, CodeFrame frame) throws InterruptedException { if (Values.not(frame.pop())) { frame.codePtr += (int)instr.get(0); frame.jumpFlag = true; @@ -286,15 +286,15 @@ public class Runners { return NO_RETURN; } - public static Object execIn(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException { + public static Object execIn(CallContext ctx, Instruction instr, CodeFrame frame) throws InterruptedException { var obj = frame.pop(); var index = frame.pop(); - frame.push(Values.hasMember(ctx, obj, index, false)); + frame.push(ctx, Values.hasMember(ctx, obj, index, false)); frame.codePtr++; return NO_RETURN; } - public static Object execTypeof(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException { + public static Object execTypeof(CallContext ctx, Instruction instr, CodeFrame frame) throws InterruptedException { String name = instr.get(0); Object obj; @@ -306,12 +306,12 @@ public class Runners { } else obj = frame.pop(); - frame.push(Values.type(obj)); + frame.push(ctx, Values.type(obj)); frame.codePtr++; return NO_RETURN; } - public static Object execNop(Instruction instr, CodeFrame frame, CallContext ctx) { + public static Object execNop(CallContext ctx, Instruction instr, CodeFrame frame) { if (instr.is(0, "dbg_names")) { var names = new String[instr.params.length - 1]; for (var i = 0; i < instr.params.length - 1; i++) { @@ -325,67 +325,67 @@ public class Runners { return NO_RETURN; } - public static Object execDelete(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException { + public static Object execDelete(CallContext ctx, Instruction instr, CodeFrame frame) throws InterruptedException { var key = frame.pop(); var val = frame.pop(); if (!Values.deleteMember(ctx, val, key)) throw EngineException.ofSyntax("Can't delete member '" + key + "'."); - frame.push(true); + frame.push(ctx, true); frame.codePtr++; return NO_RETURN; } - public static Object execOperation(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException { + public static Object execOperation(CallContext ctx, Instruction instr, CodeFrame frame) throws InterruptedException { Operation op = instr.get(0); var args = new Object[op.operands]; for (var i = op.operands - 1; i >= 0; i--) args[i] = frame.pop(); - frame.push(Values.operation(ctx, op, args)); + frame.push(ctx, Values.operation(ctx, op, args)); frame.codePtr++; return NO_RETURN; } - public static Object exec(DebugCommand state, Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException { + public static Object exec(CallContext ctx, DebugCommand state, Instruction instr, CodeFrame frame) throws InterruptedException { // System.out.println(instr + "@" + instr.location); switch (instr.type) { - case NOP: return execNop(instr, frame, ctx); - case RETURN: return execReturn(instr, frame, ctx); - case SIGNAL: return execSignal(instr, frame, ctx); - case THROW: return execThrow(instr, frame, ctx); - case THROW_SYNTAX: return execThrowSyntax(instr, frame, ctx); - case CALL: return execCall(state, instr, frame, ctx); - case CALL_NEW: return execCallNew(state, instr, frame, ctx); - case TRY: return execTry(state, instr, frame, ctx); + case NOP: return execNop(ctx, instr, frame); + case RETURN: return execReturn(ctx, instr, frame); + case SIGNAL: return execSignal(ctx, instr, frame); + case THROW: return execThrow(ctx, instr, frame); + case THROW_SYNTAX: return execThrowSyntax(ctx, instr, frame); + case CALL: return execCall(ctx, state, instr, frame); + case CALL_NEW: return execCallNew(ctx, state, instr, frame); + case TRY: return execTry(ctx, instr, frame); - case DUP: return execDup(instr, frame, ctx); - case MOVE: return execMove(instr, frame, ctx); - case LOAD_VALUE: return execLoadValue(instr, frame, ctx); - case LOAD_VAR: return execLoadVar(instr, frame, ctx); - case LOAD_OBJ: return execLoadObj(instr, frame, ctx); - case LOAD_ARR: return execLoadArr(instr, frame, ctx); - case LOAD_FUNC: return execLoadFunc(instr, frame, ctx); - case LOAD_MEMBER: return execLoadMember(state, instr, frame, ctx); - case LOAD_VAL_MEMBER: return execLoadKeyMember(state, instr, frame, ctx); - case LOAD_REGEX: return execLoadRegEx(instr, frame, ctx); - case LOAD_GLOB: return execLoadGlob(instr, frame, ctx); + case DUP: return execDup(ctx, instr, frame); + case MOVE: return execMove(ctx, instr, frame); + case LOAD_VALUE: return execLoadValue(ctx, instr, frame); + case LOAD_VAR: return execLoadVar(ctx, instr, frame); + case LOAD_OBJ: return execLoadObj(ctx, instr, frame); + case LOAD_ARR: return execLoadArr(ctx, instr, frame); + case LOAD_FUNC: return execLoadFunc(ctx, instr, frame); + case LOAD_MEMBER: return execLoadMember(ctx, state, instr, frame); + case LOAD_VAL_MEMBER: return execLoadKeyMember(ctx, state, instr, frame); + case LOAD_REGEX: return execLoadRegEx(ctx, instr, frame); + case LOAD_GLOB: return execLoadGlob(ctx, instr, frame); - case DISCARD: return execDiscard(instr, frame, ctx); - case STORE_MEMBER: return execStoreMember(state, instr, frame, ctx); - case STORE_VAR: return execStoreVar(instr, frame, ctx); - case STORE_SELF_FUNC: return execStoreSelfFunc(instr, frame, ctx); - case MAKE_VAR: return execMakeVar(instr, frame, ctx); + case DISCARD: return execDiscard(ctx, instr, frame); + case STORE_MEMBER: return execStoreMember(ctx, state, instr, frame); + case STORE_VAR: return execStoreVar(ctx, instr, frame); + case STORE_SELF_FUNC: return execStoreSelfFunc(ctx, instr, frame); + case MAKE_VAR: return execMakeVar(ctx, instr, frame); - case KEYS: return execKeys(instr, frame, ctx); - case DEF_PROP: return execDefProp(instr, frame, ctx); - case TYPEOF: return execTypeof(instr, frame, ctx); - case DELETE: return execDelete(instr, frame, ctx); + case KEYS: return execKeys(ctx, instr, frame); + case DEF_PROP: return execDefProp(ctx, instr, frame); + case TYPEOF: return execTypeof(ctx, instr, frame); + case DELETE: return execDelete(ctx, instr, frame); - case JMP: return execJmp(instr, frame, ctx); - case JMP_IF: return execJmpIf(instr, frame, ctx); - case JMP_IFN: return execJmpIfNot(instr, frame, ctx); + case JMP: return execJmp(ctx, instr, frame); + case JMP_IF: return execJmpIf(ctx, instr, frame); + case JMP_IFN: return execJmpIfNot(ctx, instr, frame); - case OPERATION: return execOperation(instr, frame, ctx); + case OPERATION: return execOperation(ctx, instr, frame); default: throw EngineException.ofSyntax("Invalid instruction " + instr.type.name() + "."); } diff --git a/src/me/topchetoeu/jscript/engine/modules/Module.java b/src/me/topchetoeu/jscript/engine/modules/Module.java index 3959739..44bd681 100644 --- a/src/me/topchetoeu/jscript/engine/modules/Module.java +++ b/src/me/topchetoeu/jscript/engine/modules/Module.java @@ -39,7 +39,7 @@ public class Module { executing = true; var scope = ctx.engine().global().globalChild(); - scope.define("module", true, this); + scope.define(null, "module", true, this); scope.define("exports", new ExportsVariable()); var parent = new File(filename).getParentFile(); diff --git a/src/me/topchetoeu/jscript/engine/scope/GlobalScope.java b/src/me/topchetoeu/jscript/engine/scope/GlobalScope.java index 384ceb8..e318c24 100644 --- a/src/me/topchetoeu/jscript/engine/scope/GlobalScope.java +++ b/src/me/topchetoeu/jscript/engine/scope/GlobalScope.java @@ -38,24 +38,24 @@ public class GlobalScope implements ScopeRecord { Thread.currentThread().interrupt(); return name; } - obj.defineProperty(name, null); + obj.defineProperty(null, name, null); return name; } public void define(String name, Variable val) { - obj.defineProperty(name, + obj.defineProperty(null, name, new NativeFunction("get " + name, (ctx, th, a) -> val.get(ctx)), new NativeFunction("set " + name, (ctx, th, args) -> { val.set(ctx, args.length > 0 ? args[0] : null); return null; }), true, true ); } - public void define(String name, boolean readonly, Object val) { - obj.defineProperty(name, val, readonly, true, true); + public void define(CallContext ctx, String name, boolean readonly, Object val) { + obj.defineProperty(ctx, name, val, readonly, true, true); } public void define(String... names) { for (var n : names) define(n); } public void define(boolean readonly, FunctionValue val) { - define(val.name, readonly, val); + define(null, val.name, readonly, val); } public Object get(CallContext ctx, String name) throws InterruptedException { diff --git a/src/me/topchetoeu/jscript/engine/scope/ValueVariable.java b/src/me/topchetoeu/jscript/engine/scope/ValueVariable.java index ce34b9f..2d68066 100644 --- a/src/me/topchetoeu/jscript/engine/scope/ValueVariable.java +++ b/src/me/topchetoeu/jscript/engine/scope/ValueVariable.java @@ -18,7 +18,7 @@ public class ValueVariable implements Variable { @Override public void set(CallContext ctx, Object val) { if (readonly) return; - this.value = Values.normalize(val); + this.value = Values.normalize(ctx, val); } public ValueVariable(boolean readonly, Object val) { diff --git a/src/me/topchetoeu/jscript/engine/values/ArrayValue.java b/src/me/topchetoeu/jscript/engine/values/ArrayValue.java index b0e8e02..9278ed4 100644 --- a/src/me/topchetoeu/jscript/engine/values/ArrayValue.java +++ b/src/me/topchetoeu/jscript/engine/values/ArrayValue.java @@ -29,14 +29,14 @@ public class ArrayValue extends ObjectValue { if (res == EMPTY) return null; else return res; } - public void set(int i, Object val) { + public void set(CallContext ctx, int i, Object val) { if (i < 0) return; while (values.size() <= i) { values.add(EMPTY); } - values.set(i, Values.normalize(val)); + values.set(i, Values.normalize(ctx, val)); } public boolean has(int i) { return i >= 0 && i < values.size() && values.get(i) != EMPTY; @@ -102,7 +102,7 @@ public class ArrayValue extends ObjectValue { if (key instanceof Number) { var i = Values.number(key); if (i >= 0 && i - Math.floor(i) == 0) { - set((int)i, val); + set(ctx, (int)i, val); return true; } } @@ -149,12 +149,12 @@ public class ArrayValue extends ObjectValue { nonEnumerableSet.add("length"); nonConfigurableSet.add("length"); } - public ArrayValue(Object ...values) { + public ArrayValue(CallContext ctx, Object ...values) { this(); - for (var i = 0; i < values.length; i++) this.values.add(values[i]); + for (var i = 0; i < values.length; i++) this.values.add(Values.normalize(ctx, values[i])); } - public static ArrayValue of(Collection values) { - return new ArrayValue(values.toArray(Object[]::new)); + public static ArrayValue of(CallContext ctx, Collection values) { + return new ArrayValue(ctx, values.toArray(Object[]::new)); } } diff --git a/src/me/topchetoeu/jscript/engine/values/CodeFunction.java b/src/me/topchetoeu/jscript/engine/values/CodeFunction.java index e543728..48a430e 100644 --- a/src/me/topchetoeu/jscript/engine/values/CodeFunction.java +++ b/src/me/topchetoeu/jscript/engine/values/CodeFunction.java @@ -34,7 +34,7 @@ public class CodeFunction extends FunctionValue { @Override public Object call(CallContext ctx, Object thisArg, Object... args) throws InterruptedException { - return new CodeFrame(thisArg, args, this).run(ctx); + return new CodeFrame(ctx, thisArg, args, this).run(ctx); } public CodeFunction(String name, int localsN, int length, GlobalScope globals, ValueVariable[] captures, Instruction[] body) { diff --git a/src/me/topchetoeu/jscript/engine/values/FunctionValue.java b/src/me/topchetoeu/jscript/engine/values/FunctionValue.java index 8a20164..aaf1061 100644 --- a/src/me/topchetoeu/jscript/engine/values/FunctionValue.java +++ b/src/me/topchetoeu/jscript/engine/values/FunctionValue.java @@ -63,8 +63,8 @@ public abstract class FunctionValue extends ObjectValue { nonEnumerableSet.add("length"); var proto = new ObjectValue(); - proto.defineProperty("constructor", this, true, false, false); - this.defineProperty("prototype", proto, true, false, false); + proto.defineProperty(null, "constructor", this, true, false, false); + this.defineProperty(null, "prototype", proto, true, false, false); } } diff --git a/src/me/topchetoeu/jscript/engine/values/ObjectValue.java b/src/me/topchetoeu/jscript/engine/values/ObjectValue.java index de84126..4899448 100644 --- a/src/me/topchetoeu/jscript/engine/values/ObjectValue.java +++ b/src/me/topchetoeu/jscript/engine/values/ObjectValue.java @@ -78,8 +78,8 @@ public class ObjectValue { state = State.FROZEN; } - public final boolean defineProperty(Object key, Object val, boolean writable, boolean configurable, boolean enumerable) { - key = Values.normalize(key); val = Values.normalize(val); + public final boolean defineProperty(CallContext ctx, Object key, Object val, boolean writable, boolean configurable, boolean enumerable) { + key = Values.normalize(ctx, key); val = Values.normalize(ctx, val); boolean reconfigured = writable != memberWritable(key) || configurable != memberConfigurable(key) || @@ -118,11 +118,11 @@ public class ObjectValue { values.put(key, val); return true; } - public final boolean defineProperty(Object key, Object val) { - return defineProperty(Values.normalize(key), Values.normalize(val), true, true, true); + public final boolean defineProperty(CallContext ctx, Object key, Object val) { + return defineProperty(ctx, key, val, true, true, true); } - public final boolean defineProperty(Object key, FunctionValue getter, FunctionValue setter, boolean configurable, boolean enumerable) { - key = Values.normalize(key); + public final boolean defineProperty(CallContext ctx, Object key, FunctionValue getter, FunctionValue setter, boolean configurable, boolean enumerable) { + key = Values.normalize(ctx, key); if ( properties.containsKey(key) && properties.get(key).getter == getter && @@ -162,7 +162,7 @@ public class ObjectValue { return (ObjectValue)prototype; } public final boolean setPrototype(CallContext ctx, Object val) { - val = Values.normalize(val); + val = Values.normalize(ctx, val); if (!extensible()) return false; if (val == null || val == Values.NULL) prototype = null; @@ -228,7 +228,7 @@ public class ObjectValue { } public final Object getMember(CallContext ctx, Object key, Object thisArg) throws InterruptedException { - key = Values.normalize(key); + key = Values.normalize(ctx, key); if (key.equals("__proto__")) { var res = getPrototype(ctx); @@ -239,7 +239,7 @@ public class ObjectValue { if (prop != null) { if (prop.getter == null) return null; - else return prop.getter.call(ctx, Values.normalize(thisArg)); + else return prop.getter.call(ctx, Values.normalize(ctx, thisArg)); } else return getField(ctx, key); } @@ -248,12 +248,12 @@ public class ObjectValue { } public final boolean setMember(CallContext ctx, Object key, Object val, Object thisArg, boolean onlyProps) throws InterruptedException { - key = Values.normalize(key); val = Values.normalize(val); + key = Values.normalize(ctx, key); val = Values.normalize(ctx, val); var prop = getProperty(ctx, key); if (prop != null) { if (prop.setter == null) return false; - prop.setter.call(ctx, Values.normalize(thisArg), val); + prop.setter.call(ctx, Values.normalize(ctx, thisArg), val); return true; } else if (onlyProps) return false; @@ -267,11 +267,11 @@ public class ObjectValue { else return setField(ctx, key, val); } public final boolean setMember(CallContext ctx, Object key, Object val, boolean onlyProps) throws InterruptedException { - return setMember(ctx, Values.normalize(key), Values.normalize(val), this, onlyProps); + return setMember(ctx, Values.normalize(ctx, key), Values.normalize(ctx, val), this, onlyProps); } public final boolean hasMember(CallContext ctx, Object key, boolean own) throws InterruptedException { - key = Values.normalize(key); + key = Values.normalize(ctx, key); if (key != null && key.equals("__proto__")) return true; if (hasField(ctx, key)) return true; @@ -280,7 +280,7 @@ public class ObjectValue { return prototype != null && getPrototype(ctx).hasMember(ctx, key, own); } public final boolean deleteMember(CallContext ctx, Object key) throws InterruptedException { - key = Values.normalize(key); + key = Values.normalize(ctx, key); if (!memberConfigurable(key)) return false; properties.remove(key); @@ -291,21 +291,21 @@ public class ObjectValue { } public final ObjectValue getMemberDescriptor(CallContext ctx, Object key) throws InterruptedException { - key = Values.normalize(key); + key = Values.normalize(ctx, key); var prop = properties.get(key); var res = new ObjectValue(); - res.defineProperty("configurable", memberConfigurable(key)); - res.defineProperty("enumerable", memberEnumerable(key)); + res.defineProperty(ctx, "configurable", memberConfigurable(key)); + res.defineProperty(ctx, "enumerable", memberEnumerable(key)); if (prop != null) { - res.defineProperty("get", prop.getter); - res.defineProperty("set", prop.setter); + res.defineProperty(ctx, "get", prop.getter); + res.defineProperty(ctx, "set", prop.setter); } else if (hasField(ctx, key)) { - res.defineProperty("value", values.get(key)); - res.defineProperty("writable", memberWritable(key)); + res.defineProperty(ctx, "value", values.get(key)); + res.defineProperty(ctx, "writable", memberWritable(key)); } else return null; return res; @@ -326,10 +326,10 @@ public class ObjectValue { return res; } - public ObjectValue(Map values) { + public ObjectValue(CallContext ctx, Map values) { this(PlaceholderProto.OBJECT); for (var el : values.entrySet()) { - defineProperty(el.getKey(), el.getValue()); + defineProperty(ctx, el.getKey(), el.getValue()); } } public ObjectValue(PlaceholderProto proto) { diff --git a/src/me/topchetoeu/jscript/engine/values/Values.java b/src/me/topchetoeu/jscript/engine/values/Values.java index f340f5d..22d4654 100644 --- a/src/me/topchetoeu/jscript/engine/values/Values.java +++ b/src/me/topchetoeu/jscript/engine/values/Values.java @@ -88,7 +88,7 @@ public class Values { } public static Object toPrimitive(CallContext ctx, Object obj, ConvertHint hint) throws InterruptedException { - obj = normalize(obj); + obj = normalize(ctx, obj); if (isPrimitive(obj)) return obj; var first = hint == ConvertHint.VALUEOF ? "valueOf" : "toString"; @@ -231,8 +231,8 @@ public class Values { case OR: return or(ctx, args[0], args[1]); case XOR: return xor(ctx, args[0], args[1]); - case EQUALS: return strictEquals(args[0], args[1]); - case NOT_EQUALS: return !strictEquals(args[0], args[1]); + case EQUALS: return strictEquals(ctx, args[0], args[1]); + case NOT_EQUALS: return !strictEquals(ctx, args[0], args[1]); case LOOSE_EQUALS: return looseEqual(ctx, args[0], args[1]); case LOOSE_NOT_EQUALS: return !looseEqual(ctx, args[0], args[1]); @@ -261,7 +261,7 @@ public class Values { } public static Object getMember(CallContext ctx, Object obj, Object key) throws InterruptedException { - obj = normalize(obj); key = normalize(key); + obj = normalize(ctx, obj); key = normalize(ctx, key); if (obj == null) throw new IllegalArgumentException("Tried to access member of undefined."); if (obj == NULL) throw new IllegalArgumentException("Tried to access member of null."); if (isObject(obj)) return object(obj).getMember(ctx, key); @@ -281,7 +281,7 @@ public class Values { else return proto.getMember(ctx, key, obj); } public static boolean setMember(CallContext ctx, Object obj, Object key, Object val) throws InterruptedException { - obj = normalize(obj); key = normalize(key); val = normalize(val); + obj = normalize(ctx, obj); key = normalize(ctx, key); val = normalize(ctx, val); if (obj == null) throw EngineException.ofType("Tried to access member of undefined."); if (obj == NULL) throw EngineException.ofType("Tried to access member of null."); if (key.equals("__proto__")) return setPrototype(ctx, obj, val); @@ -292,7 +292,7 @@ public class Values { } public static boolean hasMember(CallContext ctx, Object obj, Object key, boolean own) throws InterruptedException { if (obj == null || obj == NULL) return false; - obj = normalize(obj); key = normalize(key); + obj = normalize(ctx, obj); key = normalize(ctx, key); if (key.equals("__proto__")) return true; if (isObject(obj)) return object(obj).hasMember(ctx, key, own); @@ -310,14 +310,14 @@ public class Values { } public static boolean deleteMember(CallContext ctx, Object obj, Object key) throws InterruptedException { if (obj == null || obj == NULL) return false; - obj = normalize(obj); key = normalize(key); + obj = normalize(ctx, obj); key = normalize(ctx, key); if (isObject(obj)) return object(obj).deleteMember(ctx, key); else return false; } public static ObjectValue getPrototype(CallContext ctx, Object obj) throws InterruptedException { if (obj == null || obj == NULL) return null; - obj = normalize(obj); + obj = normalize(ctx, obj); if (isObject(obj)) return object(obj).getPrototype(ctx); if (ctx == null) return null; @@ -329,7 +329,7 @@ public class Values { return null; } public static boolean setPrototype(CallContext ctx, Object obj, Object proto) throws InterruptedException { - obj = normalize(obj); proto = normalize(proto); + obj = normalize(ctx, obj); proto = normalize(ctx, proto); return isObject(obj) && object(obj).setPrototype(ctx, proto); } public static List getMembers(CallContext ctx, Object obj, boolean own, boolean includeNonEnumerable) throws InterruptedException { @@ -359,8 +359,8 @@ public class Values { return function(func).call(ctx, thisArg, args); } - public static boolean strictEquals(Object a, Object b) { - a = normalize(a); b = normalize(b); + public static boolean strictEquals(CallContext ctx, Object a, Object b) { + a = normalize(ctx, a); b = normalize(ctx, b); if (a == null || b == null) return a == null && b == null; if (isNan(a) || isNan(b)) return false; @@ -370,7 +370,7 @@ public class Values { return a == b || a.equals(b); } public static boolean looseEqual(CallContext ctx, Object a, Object b) throws InterruptedException { - a = normalize(a); b = normalize(b); + a = normalize(ctx, a); b = normalize(ctx, b); // In loose equality, null is equivalent to undefined if (a == NULL) a = null; @@ -387,13 +387,13 @@ public class Values { // Compare symbols by reference if (a instanceof Symbol || b instanceof Symbol) return a == b; if (a instanceof Boolean || b instanceof Boolean) return toBoolean(a) == toBoolean(b); - if (a instanceof Number || b instanceof Number) return strictEquals(toNumber(ctx, a), toNumber(ctx, b)); + if (a instanceof Number || b instanceof Number) return strictEquals(ctx, toNumber(ctx, a), toNumber(ctx, b)); // Default to strings return toString(ctx, a).equals(toString(ctx, b)); } - public static Object normalize(Object val) { + public static Object normalize(CallContext ctx, Object val) { if (val instanceof Number) return number(val); if (isPrimitive(val) || val instanceof ObjectValue) return val; if (val instanceof Character) return val + ""; @@ -402,7 +402,7 @@ public class Values { var res = new ObjectValue(); for (var entry : ((Map)val).entrySet()) { - res.defineProperty(entry.getKey(), entry.getValue()); + res.defineProperty(ctx, entry.getKey(), entry.getValue()); } return res; @@ -412,12 +412,17 @@ public class Values { var res = new ArrayValue(); for (var entry : ((Iterable)val)) { - res.set(res.size(), entry); + res.set(ctx, res.size(), entry); } return res; } + if (val instanceof Class) { + if (ctx == null) return null; + else return ctx.engine.getConstructor((Class)val); + } + return new NativeWrapper(val); } @@ -562,14 +567,14 @@ public class Values { var it = iterable.iterator(); try { - var key = getMember(ctx, getMember(ctx, ctx.engine().symbolProto(), "constructor"), "iterable"); - res.defineProperty(key, new NativeFunction("", (_ctx, thisArg, args) -> fromJavaIterable(ctx, iterable))); + var key = getMember(ctx, getMember(ctx, ctx.engine().symbolProto(), "constructor"), "iterator"); + res.defineProperty(ctx, key, new NativeFunction("", (_ctx, thisArg, args) -> thisArg)); } catch (IllegalArgumentException | NullPointerException e) { } - res.defineProperty("next", new NativeFunction("", (_ctx, _th, _args) -> { - if (!it.hasNext()) return new ObjectValue(Map.of("done", true)); - else return new ObjectValue(Map.of("value", it.next())); + res.defineProperty(ctx, "next", new NativeFunction("", (_ctx, _th, _args) -> { + if (!it.hasNext()) return new ObjectValue(ctx, Map.of("done", true)); + else return new ObjectValue(ctx, Map.of("value", it.next())); })); return res; diff --git a/src/me/topchetoeu/jscript/exceptions/EngineException.java b/src/me/topchetoeu/jscript/exceptions/EngineException.java index fcc7cfc..ccdece6 100644 --- a/src/me/topchetoeu/jscript/exceptions/EngineException.java +++ b/src/me/topchetoeu/jscript/exceptions/EngineException.java @@ -41,7 +41,7 @@ public class EngineException extends RuntimeException { private static Object err(String msg, PlaceholderProto proto) { var res = new ObjectValue(proto); - res.defineProperty("message", msg); + res.defineProperty(null, "message", msg); return res; } diff --git a/src/me/topchetoeu/jscript/interop/NativeTypeRegister.java b/src/me/topchetoeu/jscript/interop/NativeTypeRegister.java index c1ed7ea..aceaa79 100644 --- a/src/me/topchetoeu/jscript/interop/NativeTypeRegister.java +++ b/src/me/topchetoeu/jscript/interop/NativeTypeRegister.java @@ -25,7 +25,7 @@ public class NativeTypeRegister { var val = target.values.get(name); if (name.equals("")) name = method.getName(); - if (!(val instanceof OverloadFunction)) target.defineProperty(name, val = new OverloadFunction(name)); + if (!(val instanceof OverloadFunction)) target.defineProperty(null, name, val = new OverloadFunction(name)); ((OverloadFunction)val).overloads.add(Overload.fromMethod(method)); } @@ -40,7 +40,7 @@ public class NativeTypeRegister { else getter = new OverloadFunction("get " + name); getter.overloads.add(Overload.fromMethod(method)); - target.defineProperty(name, getter, setter, true, true); + target.defineProperty(null, name, getter, setter, true, true); } if (set != null) { var name = set.value(); @@ -52,7 +52,7 @@ public class NativeTypeRegister { else setter = new OverloadFunction("set " + name); setter.overloads.add(Overload.fromMethod(method)); - target.defineProperty(name, getter, setter, true, true); + target.defineProperty(null, name, getter, setter, true, true); } } } @@ -67,7 +67,7 @@ public class NativeTypeRegister { if (name.equals("")) name = field.getName(); var getter = new OverloadFunction("get " + name).add(Overload.getterFromField(field)); var setter = new OverloadFunction("set " + name).add(Overload.setterFromField(field)); - target.defineProperty(name, getter, setter, true, false); + target.defineProperty(null, name, getter, setter, true, false); } } } @@ -84,7 +84,7 @@ public class NativeTypeRegister { return ctx.engine().typeRegister().getConstr(cl); })); - target.defineProperty(name, getter, null, true, false); + target.defineProperty(null, name, getter, null, true, false); } } } diff --git a/src/me/topchetoeu/jscript/interop/OverloadFunction.java b/src/me/topchetoeu/jscript/interop/OverloadFunction.java index 38a80ac..e8c78d2 100644 --- a/src/me/topchetoeu/jscript/interop/OverloadFunction.java +++ b/src/me/topchetoeu/jscript/interop/OverloadFunction.java @@ -47,7 +47,7 @@ public class OverloadFunction extends FunctionValue { Object _this = overload.thisArg == null ? null : Values.convert(ctx, thisArg, overload.thisArg); try { - return Values.normalize(overload.runner.run(ctx, _this, newArgs)); + return Values.normalize(ctx, overload.runner.run(ctx, _this, newArgs)); } catch (InstantiationException e) { throw EngineException.ofError("The class may not be instantiated."); diff --git a/src/me/topchetoeu/jscript/polyfills/GeneratorFunction.java b/src/me/topchetoeu/jscript/polyfills/GeneratorFunction.java index b59940b..f27dba7 100644 --- a/src/me/topchetoeu/jscript/polyfills/GeneratorFunction.java +++ b/src/me/topchetoeu/jscript/polyfills/GeneratorFunction.java @@ -22,13 +22,13 @@ public class GeneratorFunction extends FunctionValue { if (done) { if (inducedError != Runners.NO_RETURN) throw new EngineException(inducedError); var res = new ObjectValue(); - res.defineProperty("done", true); - res.defineProperty("value", inducedReturn == Runners.NO_RETURN ? null : inducedReturn); + res.defineProperty(ctx, "done", true); + res.defineProperty(ctx, "value", inducedReturn == Runners.NO_RETURN ? null : inducedReturn); return res; } Object res = null; - if (inducedValue != Runners.NO_RETURN) frame.push(inducedValue); + if (inducedValue != Runners.NO_RETURN) frame.push(ctx, inducedValue); frame.start(ctx); yielding = false; while (!yielding) { @@ -51,8 +51,8 @@ public class GeneratorFunction extends FunctionValue { else res = frame.pop(); var obj = new ObjectValue(); - obj.defineProperty("done", done); - obj.defineProperty("value", res); + obj.defineProperty(ctx, "done", done); + obj.defineProperty(ctx, "value", res); return obj; } @@ -84,11 +84,11 @@ public class GeneratorFunction extends FunctionValue { } @Override - public Object call(CallContext _ctx, Object thisArg, Object... args) throws InterruptedException { + public Object call(CallContext ctx, Object thisArg, Object... args) throws InterruptedException { var handler = new Generator(); - var func = factory.call(_ctx, thisArg, new NativeFunction("yield", handler::yield)); + var func = factory.call(ctx, thisArg, new NativeFunction("yield", handler::yield)); if (!(func instanceof CodeFunction)) throw EngineException.ofType("Return value of argument must be a js function."); - handler.frame = new CodeFrame(thisArg, args, (CodeFunction)func); + handler.frame = new CodeFrame(ctx, thisArg, args, (CodeFunction)func); return handler; } diff --git a/src/me/topchetoeu/jscript/polyfills/Internals.java b/src/me/topchetoeu/jscript/polyfills/Internals.java index 02ed113..da6628a 100644 --- a/src/me/topchetoeu/jscript/polyfills/Internals.java +++ b/src/me/topchetoeu/jscript/polyfills/Internals.java @@ -38,12 +38,12 @@ public class Internals { return func.call(ctx, th, args.toArray()); } @Native - public boolean defineProp(ObjectValue obj, Object key, FunctionValue getter, FunctionValue setter, boolean enumerable, boolean configurable) { - return obj.defineProperty(key, getter, setter, configurable, enumerable); + public boolean defineProp(CallContext ctx, ObjectValue obj, Object key, FunctionValue getter, FunctionValue setter, boolean enumerable, boolean configurable) { + return obj.defineProperty(ctx, key, getter, setter, configurable, enumerable); } @Native - public boolean defineField(ObjectValue obj, Object key, Object val, boolean writable, boolean enumerable, boolean configurable) { - return obj.defineProperty(key, val, writable, configurable, enumerable); + public boolean defineField(CallContext ctx, ObjectValue obj, Object key, Object val, boolean writable, boolean enumerable, boolean configurable) { + return obj.defineProperty(ctx, key, val, writable, configurable, enumerable); } @Native @@ -209,7 +209,7 @@ public class Internals { for (var el : list) { if (el instanceof Symbol && onlyString) continue; - res.set(i++, el); + res.set(ctx, i++, el); } return res; @@ -223,7 +223,7 @@ public class Internals { var list = Values.object(obj).keys(true); for (var el : list) { - if (el instanceof Symbol == symbols) res.set(i++, el); + if (el instanceof Symbol == symbols) res.set(ctx, i++, el); } } diff --git a/src/me/topchetoeu/jscript/polyfills/JSON.java b/src/me/topchetoeu/jscript/polyfills/JSON.java index b9aa27f..755c633 100644 --- a/src/me/topchetoeu/jscript/polyfills/JSON.java +++ b/src/me/topchetoeu/jscript/polyfills/JSON.java @@ -19,11 +19,11 @@ public class JSON { if (val.isBoolean()) return val.bool(); if (val.isString()) return val.string(); if (val.isNumber()) return val.number(); - if (val.isList()) return ArrayValue.of(val.list().stream().map(JSON::toJS).collect(Collectors.toList())); + if (val.isList()) return ArrayValue.of(null, val.list().stream().map(JSON::toJS).collect(Collectors.toList())); if (val.isMap()) { var res = new ObjectValue(); for (var el : val.map().entrySet()) { - res.defineProperty(el.getKey(), toJS(el.getValue())); + res.defineProperty(null, el.getKey(), toJS(el.getValue())); } return res; } diff --git a/src/me/topchetoeu/jscript/polyfills/Map.java b/src/me/topchetoeu/jscript/polyfills/Map.java index e7b22d5..cbb8a2e 100644 --- a/src/me/topchetoeu/jscript/polyfills/Map.java +++ b/src/me/topchetoeu/jscript/polyfills/Map.java @@ -53,7 +53,7 @@ public class Map { return Values.fromJavaIterable(ctx, objs .entrySet() .stream() - .map(v -> new ArrayValue(v.getKey(), v.getValue())) + .map(v -> new ArrayValue(ctx, v.getKey(), v.getValue())) .collect(Collectors.toList()) ); } diff --git a/src/me/topchetoeu/jscript/polyfills/PolyfillEngine.java b/src/me/topchetoeu/jscript/polyfills/PolyfillEngine.java index 07fa886..f3a7706 100644 --- a/src/me/topchetoeu/jscript/polyfills/PolyfillEngine.java +++ b/src/me/topchetoeu/jscript/polyfills/PolyfillEngine.java @@ -8,10 +8,6 @@ import java.io.InputStreamReader; import me.topchetoeu.jscript.engine.Engine; import me.topchetoeu.jscript.engine.modules.ModuleManager; -import me.topchetoeu.jscript.engine.values.FunctionValue; -import me.topchetoeu.jscript.engine.values.NativeFunction; -import me.topchetoeu.jscript.engine.values.Values; -import me.topchetoeu.jscript.parsing.Parsing; public class PolyfillEngine extends Engine { public static String streamToString(InputStream in) { @@ -52,59 +48,58 @@ public class PolyfillEngine extends Engine { this.modules = new ModuleManager(root); - exposeNamespace("Math", Math.class); - exposeNamespace("JSON", JSON.class); - exposeClass("Promise", Promise.class); - exposeClass("RegExp", RegExp.class); - exposeClass("Date", Date.class); - exposeClass("Map", Map.class); - exposeClass("Set", Set.class); + // exposeNamespace("Math", Math.class); + // exposeNamespace("JSON", JSON.class); + // exposeClass("Promise", Promise.class); + // exposeClass("RegExp", RegExp.class); + // exposeClass("Date", Date.class); + // exposeClass("Map", Map.class); + // exposeClass("Set", Set.class); - global().define("Object", "Function", "String", "Number", "Boolean", "Symbol"); - global().define("Array", "require"); - global().define("Error", "SyntaxError", "TypeError", "RangeError"); - global().define("setTimeout", "setInterval", "clearTimeout", "clearInterval"); - // global().define("process", true, "trololo"); - global().define("debugger"); + // global().define("Object", "Function", "String", "Number", "Boolean", "Symbol"); + // global().define("Array", "require"); + // global().define("Error", "SyntaxError", "TypeError", "RangeError"); + // global().define("setTimeout", "setInterval", "clearTimeout", "clearInterval"); + // global().define("debugger"); - global().define(true, new NativeFunction("measure", (ctx, thisArg, values) -> { - var start = System.nanoTime(); - try { - return Values.call(ctx, values[0], ctx); - } - finally { - System.out.println(String.format("Function took %s ms", (System.nanoTime() - start) / 1000000.)); - } - })); - global().define(true, new NativeFunction("isNaN", (ctx, thisArg, args) -> { - if (args.length == 0) return true; - else return Double.isNaN(Values.toNumber(ctx, args[0])); - })); - global().define(true, new NativeFunction("log", (el, t, args) -> { - for (var obj : args) Values.printValue(el, obj); - System.out.println(); - return null; - })); + // global().define(true, new NativeFunction("measure", (ctx, thisArg, values) -> { + // var start = System.nanoTime(); + // try { + // return Values.call(ctx, values[0], ctx); + // } + // finally { + // System.out.println(String.format("Function took %s ms", (System.nanoTime() - start) / 1000000.)); + // } + // })); + // global().define(true, new NativeFunction("isNaN", (ctx, thisArg, args) -> { + // if (args.length == 0) return true; + // else return Double.isNaN(Values.toNumber(ctx, args[0])); + // })); + // global().define(true, new NativeFunction("log", (el, t, args) -> { + // for (var obj : args) Values.printValue(el, obj); + // System.out.println(); + // return null; + // })); - var scope = global().globalChild(); - scope.define("gt", true, global().obj); - scope.define("lgt", true, scope.obj); - scope.define("setProps", "setConstr"); - scope.define("internals", true, new Internals()); - scope.define(true, new NativeFunction("run", (ctx, thisArg, args) -> { - var filename = (String)args[0]; - boolean pollute = args.length > 1 && args[1].equals(true); - FunctionValue func; - var src = resourceToString("js/" + filename); - if (src == null) throw new RuntimeException("The source '" + filename + "' doesn't exist."); + // var scope = global().globalChild(); + // scope.define("gt", true, global().obj); + // scope.define("lgt", true, scope.obj); + // scope.define("setProps", "setConstr"); + // scope.define("internals", true, new Internals()); + // scope.define(true, new NativeFunction("run", (ctx, thisArg, args) -> { + // var filename = (String)args[0]; + // boolean pollute = args.length > 1 && args[1].equals(true); + // FunctionValue func; + // var src = resourceToString("js/" + filename); + // if (src == null) throw new RuntimeException("The source '" + filename + "' doesn't exist."); - if (pollute) func = Parsing.compile(global(), filename, src); - else func = Parsing.compile(scope.globalChild(), filename, src); + // if (pollute) func = Parsing.compile(global(), filename, src); + // else func = Parsing.compile(scope.globalChild(), filename, src); - func.call(ctx); - return null; - })); + // func.call(ctx); + // return null; + // })); - pushMsg(false, scope.globalChild(), java.util.Map.of(), "core.js", resourceToString("js/core.js"), null); + // pushMsg(false, scope.globalChild(), java.util.Map.of(), "core.js", resourceToString("js/core.js"), null); } } diff --git a/src/me/topchetoeu/jscript/polyfills/Promise.java b/src/me/topchetoeu/jscript/polyfills/Promise.java index 91f36ed..6a4481e 100644 --- a/src/me/topchetoeu/jscript/polyfills/Promise.java +++ b/src/me/topchetoeu/jscript/polyfills/Promise.java @@ -27,10 +27,10 @@ public class Promise { } @Native("resolve") - public static Promise ofResolved(CallContext engine, Object val) { + public static Promise ofResolved(CallContext ctx, Object val) { if (Values.isWrapper(val, Promise.class)) return Values.wrapper(val, Promise.class); var res = new Promise(); - res.fulfill(engine, val); + res.fulfill(ctx, val); return res; } public static Promise ofResolved(Object val) { @@ -41,9 +41,9 @@ public class Promise { } @Native("reject") - public static Promise ofRejected(CallContext engine, Object val) { + public static Promise ofRejected(CallContext ctx, Object val) { var res = new Promise(); - res.reject(engine, val); + res.reject(ctx, val); return res; } public static Promise ofRejected(Object val) { @@ -53,7 +53,7 @@ public class Promise { } @Native - public static Promise any(CallContext engine, Object _promises) { + public static Promise any(CallContext ctx, Object _promises) { if (!Values.isArray(_promises)) throw EngineException.ofType("Expected argument for any to be an array."); var promises = Values.array(_promises); if (promises.size() == 0) return ofResolved(new ArrayValue()); @@ -66,17 +66,17 @@ public class Promise { var index = i; var val = promises.get(i); if (Values.isWrapper(val, Promise.class)) Values.wrapper(val, Promise.class).then( - engine, + ctx, new NativeFunction(null, (e, th, args) -> { res.fulfill(e, args[0]); return null; }), new NativeFunction(null, (e, th, args) -> { - errors.set(index, args[0]); + errors.set(ctx, index, args[0]); n[0]--; if (n[0] <= 0) res.reject(e, errors); return null; }) ); else { - res.fulfill(engine, val); + res.fulfill(ctx, val); break; } } @@ -84,7 +84,7 @@ public class Promise { return res; } @Native - public static Promise race(CallContext engine, Object _promises) { + public static Promise race(CallContext ctx, Object _promises) { if (!Values.isArray(_promises)) throw EngineException.ofType("Expected argument for any to be an array."); var promises = Values.array(_promises); if (promises.size() == 0) return ofResolved(new ArrayValue()); @@ -93,7 +93,7 @@ public class Promise { for (var i = 0; i < promises.size(); i++) { var val = promises.get(i); if (Values.isWrapper(val, Promise.class)) Values.wrapper(val, Promise.class).then( - engine, + ctx, new NativeFunction(null, (e, th, args) -> { res.fulfill(e, args[0]); return null; }), new NativeFunction(null, (e, th, args) -> { res.reject(e, args[0]); return null; }) ); @@ -106,7 +106,7 @@ public class Promise { return res; } @Native - public static Promise all(CallContext engine, Object _promises) { + public static Promise all(CallContext ctx, Object _promises) { if (!Values.isArray(_promises)) throw EngineException.ofType("Expected argument for any to be an array."); var promises = Values.array(_promises); if (promises.size() == 0) return ofResolved(new ArrayValue()); @@ -119,9 +119,9 @@ public class Promise { var index = i; var val = promises.get(i); if (Values.isWrapper(val, Promise.class)) Values.wrapper(val, Promise.class).then( - engine, + ctx, new NativeFunction(null, (e, th, args) -> { - result.set(index, args[0]); + result.set(ctx, index, args[0]); n[0]--; if (n[0] <= 0) res.fulfill(e, result); return null; @@ -129,17 +129,17 @@ public class Promise { new NativeFunction(null, (e, th, args) -> { res.reject(e, args[0]); return null; }) ); else { - result.set(i, val); + result.set(ctx, i, val); break; } } - if (n[0] <= 0) res.fulfill(engine, result); + if (n[0] <= 0) res.fulfill(ctx, result); return res; } @Native - public static Promise allSettled(CallContext engine, Object _promises) { + public static Promise allSettled(CallContext ctx, Object _promises) { if (!Values.isArray(_promises)) throw EngineException.ofType("Expected argument for any to be an array."); var promises = Values.array(_promises); if (promises.size() == 0) return ofResolved(new ArrayValue()); @@ -152,9 +152,9 @@ public class Promise { var index = i; var val = promises.get(i); if (Values.isWrapper(val, Promise.class)) Values.wrapper(val, Promise.class).then( - engine, + ctx, new NativeFunction(null, (e, th, args) -> { - result.set(index, new ObjectValue(Map.of( + result.set(ctx, index, new ObjectValue(ctx, Map.of( "status", "fulfilled", "value", args[0] ))); @@ -163,7 +163,7 @@ public class Promise { return null; }), new NativeFunction(null, (e, th, args) -> { - result.set(index, new ObjectValue(Map.of( + result.set(ctx, index, new ObjectValue(ctx, Map.of( "status", "rejected", "reason", args[0] ))); @@ -173,7 +173,7 @@ public class Promise { }) ); else { - result.set(i, new ObjectValue(Map.of( + result.set(ctx, i, new ObjectValue(ctx, Map.of( "status", "fulfilled", "value", val ))); @@ -181,7 +181,7 @@ public class Promise { } } - if (n[0] <= 0) res.fulfill(engine, result); + if (n[0] <= 0) res.fulfill(ctx, result); return res; } diff --git a/src/me/topchetoeu/jscript/polyfills/RegExp.java b/src/me/topchetoeu/jscript/polyfills/RegExp.java index 752f24a..5f7dca6 100644 --- a/src/me/topchetoeu/jscript/polyfills/RegExp.java +++ b/src/me/topchetoeu/jscript/polyfills/RegExp.java @@ -119,7 +119,7 @@ public class RegExp { for (var el : namedGroups) { try { - groups.defineProperty(el, matcher.group(el)); + groups.defineProperty(null, el, matcher.group(el)); } catch (IllegalArgumentException e) { } } @@ -127,23 +127,23 @@ public class RegExp { for (int i = 0; i < matcher.groupCount() + 1; i++) { - obj.set(i, matcher.group(i)); + obj.set(null, i, matcher.group(i)); } - obj.defineProperty("groups", groups); - obj.defineProperty("index", matcher.start()); - obj.defineProperty("input", str); + obj.defineProperty(null, "groups", groups); + obj.defineProperty(null, "index", matcher.start()); + obj.defineProperty(null, "input", str); if (hasIndices) { var indices = new ArrayValue(); for (int i = 0; i < matcher.groupCount() + 1; i++) { - indices.set(i, new ArrayValue(matcher.start(i), matcher.end(i))); + indices.set(null, i, new ArrayValue(null, matcher.start(i), matcher.end(i))); } var groupIndices = new ObjectValue(); for (var el : namedGroups) { - groupIndices.defineProperty(el, new ArrayValue(matcher.start(el), matcher.end(el))); + groupIndices.defineProperty(null, el, new ArrayValue(null, matcher.start(el), matcher.end(el))); } - indices.defineProperty("groups", groupIndices); - obj.defineProperty("indices", indices); + indices.defineProperty(null, "groups", groupIndices); + obj.defineProperty(null, "indices", indices); } return obj; diff --git a/src/me/topchetoeu/jscript/polyfills/Set.java b/src/me/topchetoeu/jscript/polyfills/Set.java index f432e5e..c87b30b 100644 --- a/src/me/topchetoeu/jscript/polyfills/Set.java +++ b/src/me/topchetoeu/jscript/polyfills/Set.java @@ -6,7 +6,6 @@ import java.util.stream.Collectors; import me.topchetoeu.jscript.engine.CallContext; import me.topchetoeu.jscript.engine.values.ArrayValue; import me.topchetoeu.jscript.engine.values.FunctionValue; -import me.topchetoeu.jscript.engine.values.NativeFunction; import me.topchetoeu.jscript.engine.values.ObjectValue; import me.topchetoeu.jscript.engine.values.Values; import me.topchetoeu.jscript.exceptions.EngineException; @@ -44,55 +43,20 @@ public class Set { } @Native - public ObjectValue entries() { - var it = objs.stream().collect(Collectors.toList()).iterator(); - - var next = new NativeFunction("next", (ctx, thisArg, args) -> { - if (it.hasNext()) { - var val = it.next(); - return new ObjectValue(java.util.Map.of( - "value", new ArrayValue(val, val), - "done", false - )); - } - else return new ObjectValue(java.util.Map.of("done", true)); - }); - - return new ObjectValue(java.util.Map.of("next", next)); + public ObjectValue entries(CallContext ctx) throws InterruptedException { + return Values.fromJavaIterable(ctx, objs + .stream() + .map(v -> new ArrayValue(ctx, v, v)) + .collect(Collectors.toList()) + ); } @Native - public ObjectValue keys() { - var it = objs.stream().collect(Collectors.toList()).iterator(); - - var next = new NativeFunction("next", (ctx, thisArg, args) -> { - if (it.hasNext()) { - var val = it.next(); - return new ObjectValue(java.util.Map.of( - "value", val, - "done", false - )); - } - else return new ObjectValue(java.util.Map.of("done", true)); - }); - - return new ObjectValue(java.util.Map.of("next", next)); + public ObjectValue keys(CallContext ctx) throws InterruptedException { + return Values.fromJavaIterable(ctx, objs); } @Native - public ObjectValue values() { - var it = objs.stream().collect(Collectors.toList()).iterator(); - - var next = new NativeFunction("next", (ctx, thisArg, args) -> { - if (it.hasNext()) { - var val = it.next(); - return new ObjectValue(java.util.Map.of( - "value", val, - "done", false - )); - } - else return new ObjectValue(java.util.Map.of("done", true)); - }); - - return new ObjectValue(java.util.Map.of("next", next)); + public ObjectValue values(CallContext ctx) throws InterruptedException { + return Values.fromJavaIterable(ctx, objs); } @NativeGetter("size") diff --git a/src/me/topchetoeu/jscript/polyfills/TypescriptEngine.java b/src/me/topchetoeu/jscript/polyfills/TypescriptEngine.java- similarity index 97% rename from src/me/topchetoeu/jscript/polyfills/TypescriptEngine.java rename to src/me/topchetoeu/jscript/polyfills/TypescriptEngine.java- index 54b677e..3d379ce 100644 --- a/src/me/topchetoeu/jscript/polyfills/TypescriptEngine.java +++ b/src/me/topchetoeu/jscript/polyfills/TypescriptEngine.java- @@ -1,61 +1,61 @@ -package me.topchetoeu.jscript.polyfills; - -import java.io.File; -import java.util.ArrayList; -import java.util.Map; - -import me.topchetoeu.jscript.engine.scope.GlobalScope; -import me.topchetoeu.jscript.engine.values.ArrayValue; -import me.topchetoeu.jscript.engine.values.FunctionValue; -import me.topchetoeu.jscript.engine.values.NativeFunction; -import me.topchetoeu.jscript.engine.values.Values; - -public class TypescriptEngine extends PolyfillEngine { - private FunctionValue ts; - - @Override - public FunctionValue compile(GlobalScope scope, String filename, String raw) throws InterruptedException { - if (ts != null) { - var res = Values.array(ts.call(context(), null, filename, raw)); - var src = Values.toString(context(), res.get(0)); - var func = Values.function(res.get(1)); - - var compiled = super.compile(scope, filename, src); - - return new NativeFunction(null, (ctx, thisArg, args) -> { - return func.call(context(), null, compiled, thisArg, new ArrayValue(args)); - }); - } - return super.compile(scope, filename, raw); - } - - public TypescriptEngine(File root) { - super(root); - var scope = global().globalChild(); - - var decls = new ArrayList(); - decls.add(resourceToString("dts/core.d.ts")); - decls.add(resourceToString("dts/iterators.d.ts")); - decls.add(resourceToString("dts/map.d.ts")); - decls.add(resourceToString("dts/promise.d.ts")); - decls.add(resourceToString("dts/regex.d.ts")); - decls.add(resourceToString("dts/require.d.ts")); - decls.add(resourceToString("dts/set.d.ts")); - decls.add(resourceToString("dts/values/array.d.ts")); - decls.add(resourceToString("dts/values/boolean.d.ts")); - decls.add(resourceToString("dts/values/number.d.ts")); - decls.add(resourceToString("dts/values/errors.d.ts")); - decls.add(resourceToString("dts/values/function.d.ts")); - decls.add(resourceToString("dts/values/object.d.ts")); - decls.add(resourceToString("dts/values/string.d.ts")); - decls.add(resourceToString("dts/values/symbol.d.ts")); - - scope.define("libs", true, ArrayValue.of(decls)); - scope.define(true, new NativeFunction("init", (el, t, args) -> { - ts = Values.function(args[0]); - return null; - })); - - pushMsg(false, scope, Map.of(), "bootstrap.js", resourceToString("js/bootstrap.js"), null); - } -} +package me.topchetoeu.jscript.polyfills; + +import java.io.File; +import java.util.ArrayList; +import java.util.Map; + +import me.topchetoeu.jscript.engine.scope.GlobalScope; +import me.topchetoeu.jscript.engine.values.ArrayValue; +import me.topchetoeu.jscript.engine.values.FunctionValue; +import me.topchetoeu.jscript.engine.values.NativeFunction; +import me.topchetoeu.jscript.engine.values.Values; + +public class TypescriptEngine extends PolyfillEngine { + private FunctionValue ts; + + @Override + public FunctionValue compile(GlobalScope scope, String filename, String raw) throws InterruptedException { + if (ts != null) { + var res = Values.array(ts.call(context(), null, filename, raw)); + var src = Values.toString(context(), res.get(0)); + var func = Values.function(res.get(1)); + + var compiled = super.compile(scope, filename, src); + + return new NativeFunction(null, (ctx, thisArg, args) -> { + return func.call(context(), null, compiled, thisArg, new ArrayValue(args)); + }); + } + return super.compile(scope, filename, raw); + } + + public TypescriptEngine(File root) { + super(root); + var scope = global().globalChild(); + + var decls = new ArrayList(); + decls.add(resourceToString("dts/core.d.ts")); + decls.add(resourceToString("dts/iterators.d.ts")); + decls.add(resourceToString("dts/map.d.ts")); + decls.add(resourceToString("dts/promise.d.ts")); + decls.add(resourceToString("dts/regex.d.ts")); + decls.add(resourceToString("dts/require.d.ts")); + decls.add(resourceToString("dts/set.d.ts")); + decls.add(resourceToString("dts/values/array.d.ts")); + decls.add(resourceToString("dts/values/boolean.d.ts")); + decls.add(resourceToString("dts/values/number.d.ts")); + decls.add(resourceToString("dts/values/errors.d.ts")); + decls.add(resourceToString("dts/values/function.d.ts")); + decls.add(resourceToString("dts/values/object.d.ts")); + decls.add(resourceToString("dts/values/string.d.ts")); + decls.add(resourceToString("dts/values/symbol.d.ts")); + + scope.define("libs", true, ArrayValue.of(decls)); + scope.define(true, new NativeFunction("init", (el, t, args) -> { + ts = Values.function(args[0]); + return null; + })); + + pushMsg(false, scope, Map.of(), "bootstrap.js", resourceToString("js/bootstrap.js"), null); + } +} diff --git a/tsconfig.json b/tsconfig.json index 199cb22..716b087 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,12 +1,29 @@ { - "include": [ "lib/**/*.ts" ], + "files": [ + "lib/lib.d.ts", + "lib/modules.ts", + "lib/utils.ts", + "lib/values/object.ts", + "lib/values/symbol.ts", + "lib/values/function.ts", + "lib/values/errors.ts", + "lib/values/string.ts", + "lib/values/number.ts", + "lib/values/boolean.ts", + "lib/values/array.ts", + "lib/promise.ts", + "lib/map.ts", + "lib/set.ts", + "lib/regex.ts", + "lib/core.ts" + ], "compilerOptions": { - "outDir": "bin/me/topchetoeu/jscript/js", - "declarationDir": "bin/me/topchetoeu/jscript/dts", + "outFile": "bin/me/topchetoeu/jscript/js/core.js", + // "declarationDir": "", + // "declarationDir": "bin/me/topchetoeu/jscript/dts", "target": "ES5", "lib": [], - "module": "CommonJS", - "declaration": true, + "module": "None", "stripInternal": true, "downlevelIteration": true, "esModuleInterop": true,