Create environments #4
9
.gitattributes
vendored
9
.gitattributes
vendored
@ -1,9 +0,0 @@
|
|||||||
#
|
|
||||||
# https://help.github.com/articles/dealing-with-line-endings/
|
|
||||||
#
|
|
||||||
# Linux start script should use lf
|
|
||||||
/gradlew text eol=lf
|
|
||||||
|
|
||||||
# These are Windows script files and should use crlf
|
|
||||||
*.bat text eol=crlf
|
|
||||||
|
|
8
.github/workflows/tagged-release.yml
vendored
8
.github/workflows/tagged-release.yml
vendored
@ -18,13 +18,7 @@ jobs:
|
|||||||
repository: 'java-jscript'
|
repository: 'java-jscript'
|
||||||
- name: "Build"
|
- name: "Build"
|
||||||
run: |
|
run: |
|
||||||
cd java-jscript;
|
cd java-jscript; node ./build.js release ${{ github.ref }}
|
||||||
ls;
|
|
||||||
mkdir -p dst/classes;
|
|
||||||
rsync -av --exclude='*.java' src/ dst/classes;
|
|
||||||
tsc --outDir dst/classes/me/topchetoeu/jscript/js --declarationDir dst/classes/me/topchetoeu/jscript/dts;
|
|
||||||
find src -name "*.java" | xargs javac -d dst/classes;
|
|
||||||
jar -c -f dst/jscript.jar -e me.topchetoeu.jscript.Main -C dst/classes .
|
|
||||||
|
|
||||||
- uses: "marvinpinto/action-automatic-releases@latest"
|
- uses: "marvinpinto/action-automatic-releases@latest"
|
||||||
with:
|
with:
|
||||||
|
11
.gitignore
vendored
11
.gitignore
vendored
@ -1,8 +1,11 @@
|
|||||||
.vscode
|
.vscode
|
||||||
.gradle
|
.gradle
|
||||||
.ignore
|
.ignore
|
||||||
out
|
/out
|
||||||
build
|
/build
|
||||||
bin
|
/bin
|
||||||
dst
|
/dst
|
||||||
/*.js
|
/*.js
|
||||||
|
!/build.js
|
||||||
|
/dead-code
|
||||||
|
/Metadata.java
|
80
build.js
Normal file
80
build.js
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
const { spawn } = require('child_process');
|
||||||
|
const fs = require('fs/promises');
|
||||||
|
const pt = require('path');
|
||||||
|
const { argv } = require('process');
|
||||||
|
|
||||||
|
const conf = {
|
||||||
|
name: "java-jscript",
|
||||||
|
author: "TopchetoEU",
|
||||||
|
javahome: "",
|
||||||
|
version: argv[3]
|
||||||
|
};
|
||||||
|
|
||||||
|
if (conf.version.startsWith('refs/tags/')) conf.version = conf.version.substring(10);
|
||||||
|
if (conf.version.startsWith('v')) conf.version = conf.version.substring(1);
|
||||||
|
|
||||||
|
async function* find(src, dst, wildcard) {
|
||||||
|
const stat = await fs.stat(src);
|
||||||
|
|
||||||
|
if (stat.isDirectory()) {
|
||||||
|
for (const el of await fs.readdir(src)) {
|
||||||
|
for await (const res of find(pt.join(src, el), dst ? pt.join(dst, el) : undefined, wildcard)) yield res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (stat.isFile() && wildcard(src)) yield dst ? { src, dst } : src;
|
||||||
|
}
|
||||||
|
async function copy(src, dst, wildcard) {
|
||||||
|
const promises = [];
|
||||||
|
|
||||||
|
for await (const el of find(src, dst, wildcard)) {
|
||||||
|
promises.push((async () => {
|
||||||
|
await fs.mkdir(pt.dirname(el.dst), { recursive: true });
|
||||||
|
await fs.copyFile(el.src, el.dst);
|
||||||
|
})());
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all(promises);
|
||||||
|
}
|
||||||
|
|
||||||
|
function run(cmd, ...args) {
|
||||||
|
return new Promise((res, rej) => {
|
||||||
|
const proc = spawn(cmd, args, { stdio: 'inherit' });
|
||||||
|
proc.once('exit', code => {
|
||||||
|
if (code === 0) res(code);
|
||||||
|
else rej(new Error(`Process ${cmd} exited with code ${code}.`));
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function compileJava() {
|
||||||
|
try {
|
||||||
|
await fs.writeFile('Metadata.java', (await fs.readFile('src/me/topchetoeu/jscript/Metadata.java')).toString()
|
||||||
|
.replace('${VERSION}', conf.version)
|
||||||
|
.replace('${NAME}', conf.name)
|
||||||
|
.replace('${AUTHOR}', conf.author)
|
||||||
|
);
|
||||||
|
const args = ['--release', '11', ];
|
||||||
|
if (argv[1] === 'debug') args.push('-g');
|
||||||
|
args.push('-d', 'dst/classes', 'Metadata.java');
|
||||||
|
|
||||||
|
for await (const path of find('src', undefined, v => v.endsWith('.java') && !v.endsWith('Metadata.java'))) args.push(path);
|
||||||
|
await run(conf.javahome + 'javac', ...args);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
await fs.rm('Metadata.java');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
try { await fs.rm('dst', { recursive: true }); } catch {}
|
||||||
|
await copy('src', 'dst/classes', v => !v.endsWith('.java'));
|
||||||
|
await run('tsc', '-p', 'lib/tsconfig.json', '--outFile', 'dst/classes/me/topchetoeu/jscript/js/core.js'),
|
||||||
|
await compileJava();
|
||||||
|
await run('jar', '-c', '-f', 'dst/jscript.jar', '-e', 'me.topchetoeu.jscript.Main', '-C', 'dst/classes', '.');
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
if (argv[2] === 'debug') throw e;
|
||||||
|
else console.log(e.toString());
|
||||||
|
}
|
||||||
|
})();
|
@ -39,7 +39,7 @@ public class Module {
|
|||||||
|
|
||||||
executing = true;
|
executing = true;
|
||||||
var scope = ctx.engine().global().globalChild();
|
var scope = ctx.engine().global().globalChild();
|
||||||
scope.define("module", true, this);
|
scope.define(null, "module", true, this);
|
||||||
scope.define("exports", new ExportsVariable());
|
scope.define("exports", new ExportsVariable());
|
||||||
|
|
||||||
var parent = new File(filename).getParentFile();
|
var parent = new File(filename).getParentFile();
|
220
lib/core.ts
220
lib/core.ts
@ -1,191 +1,71 @@
|
|||||||
type PropertyDescriptor<T, ThisT> = {
|
interface Environment {
|
||||||
value: any;
|
global: typeof globalThis & Record<string, any>;
|
||||||
writable?: boolean;
|
proto(name: string): object;
|
||||||
enumerable?: boolean;
|
setProto(name: string, val: object): void;
|
||||||
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, U> = T extends U ? never : T;
|
|
||||||
type Extract<T, U> = T extends U ? T : never;
|
|
||||||
type Record<KeyT extends string | number | symbol, ValT> = { [x in KeyT]: ValT }
|
|
||||||
|
|
||||||
interface IArguments {
|
|
||||||
[i: number]: any;
|
|
||||||
length: number;
|
|
||||||
}
|
}
|
||||||
|
interface Internals {
|
||||||
|
markSpecial(...funcs: Function[]): void;
|
||||||
|
getEnv(func: Function): Environment | undefined;
|
||||||
|
setEnv<T>(func: T, env: Environment): T;
|
||||||
|
apply(func: Function, thisArg: any, args: any[]): any;
|
||||||
|
delay(timeout: number, callback: Function): () => void;
|
||||||
|
pushMessage(micro: boolean, func: Function, thisArg: any, args: any[]): void;
|
||||||
|
|
||||||
interface MathObject {
|
strlen(val: string): number;
|
||||||
readonly E: number;
|
char(val: string): number;
|
||||||
readonly PI: number;
|
stringFromStrings(arr: string[]): string;
|
||||||
readonly SQRT2: number;
|
stringFromChars(arr: number[]): string;
|
||||||
readonly SQRT1_2: number;
|
symbol(name?: string): symbol;
|
||||||
readonly LN2: number;
|
symbolToString(sym: symbol): string;
|
||||||
readonly LN10: number;
|
|
||||||
readonly LOG2E: number;
|
|
||||||
readonly LOG10E: number;
|
|
||||||
|
|
||||||
asin(x: number): number;
|
isArray(obj: any): boolean;
|
||||||
acos(x: number): number;
|
generator(func: (_yield: <T>(val: T) => unknown) => (...args: any[]) => unknown): GeneratorFunction;
|
||||||
atan(x: number): number;
|
defineField(obj: object, key: any, val: any, writable: boolean, enumerable: boolean, configurable: boolean): boolean;
|
||||||
atan2(y: number, x: number): number;
|
defineProp(obj: object, key: any, get: Function | undefined, set: Function | undefined, enumerable: boolean, configurable: boolean): boolean;
|
||||||
asinh(x: number): number;
|
keys(obj: object, onlyString: boolean): any[];
|
||||||
acosh(x: number): number;
|
ownProp(obj: any, key: string): PropertyDescriptor<any, any>;
|
||||||
atanh(x: number): number;
|
ownPropKeys(obj: any): any[];
|
||||||
sin(x: number): number;
|
lock(obj: object, type: 'ext' | 'seal' | 'freeze'): void;
|
||||||
cos(x: number): number;
|
extensible(obj: object): boolean;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
sort(arr: any[], comaprator: (a: any, b: any) => number): void;
|
||||||
|
|
||||||
//@ts-ignore
|
constructor: {
|
||||||
declare const arguments: IArguments;
|
log(...args: any[]): void;
|
||||||
declare const Math: MathObject;
|
|
||||||
|
|
||||||
declare var setTimeout: <T extends any[]>(handle: (...args: [ ...T, ...any[] ]) => void, delay?: number, ...args: T) => number;
|
|
||||||
declare var setInterval: <T extends any[]>(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, ThisT> = 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<keyof TargetT, 'constructor'> ]?: ReplaceThis<TargetT[x], TargetT> }
|
|
||||||
>(target: TargetT, desc: DescT) => void;
|
|
||||||
/** @internal */
|
|
||||||
declare var setConstr: <ConstrT, T extends { constructor: ConstrT }>(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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var env: Environment = arguments[0], internals: Internals = arguments[1];
|
||||||
|
globalThis.log = internals.constructor.log;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
lgt.setProps = (target, desc) => {
|
run('values/object');
|
||||||
var props = internals.keys(desc, false);
|
run('values/symbol');
|
||||||
for (var i = 0; i < props.length; i++) {
|
run('values/function');
|
||||||
var key = props[i];
|
run('values/errors');
|
||||||
internals.defineField(
|
run('values/string');
|
||||||
target, key, (desc as any)[key],
|
run('values/number');
|
||||||
true, // writable
|
run('values/boolean');
|
||||||
false, // enumerable
|
run('values/array');
|
||||||
true // configurable
|
run('promise');
|
||||||
);
|
run('map');
|
||||||
}
|
run('set');
|
||||||
}
|
run('regex');
|
||||||
lgt.setConstr = (target, constr) => {
|
run('timeout');
|
||||||
internals.defineField(
|
|
||||||
target, 'constructor', constr,
|
|
||||||
true, // writable
|
|
||||||
false, // enumerable
|
|
||||||
true // configurable
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
run('values/object.js');
|
env.global.log = log;
|
||||||
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!');
|
log('Loaded polyfills!');
|
||||||
}
|
}
|
||||||
catch (e: any) {
|
catch (e: any) {
|
||||||
var err = 'Uncaught error while loading polyfills: ';
|
let err = 'Uncaught error while loading polyfills: ';
|
||||||
|
|
||||||
if (typeof Error !== 'undefined' && e instanceof Error && e.toString !== {}.toString) err += e;
|
if (typeof Error !== 'undefined' && e instanceof Error && e.toString !== {}.toString) err += e;
|
||||||
else if ('message' in e) {
|
else if ('message' in e) {
|
||||||
if ('name' in e) err += e.name + ": " + e.message;
|
if ('name' in e) err += e.name + ": " + e.message;
|
||||||
else err += 'Error: ' + e.message;
|
else err += 'Error: ' + e.message;
|
||||||
}
|
}
|
||||||
else err += e;
|
else err += e;
|
||||||
|
|
||||||
|
log(e);
|
||||||
}
|
}
|
216
lib/iterators.ts
216
lib/iterators.ts
@ -1,216 +0,0 @@
|
|||||||
interface SymbolConstructor {
|
|
||||||
readonly iterator: unique symbol;
|
|
||||||
readonly asyncIterator: unique symbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
type IteratorYieldResult<TReturn> =
|
|
||||||
{ done?: false; } &
|
|
||||||
(TReturn extends undefined ? { value?: undefined; } : { value: TReturn; });
|
|
||||||
|
|
||||||
type IteratorReturnResult<TReturn> =
|
|
||||||
{ done: true } &
|
|
||||||
(TReturn extends undefined ? { value?: undefined; } : { value: TReturn; });
|
|
||||||
|
|
||||||
type IteratorResult<T, TReturn = any> = IteratorYieldResult<T> | IteratorReturnResult<TReturn>;
|
|
||||||
|
|
||||||
interface Iterator<T, TReturn = any, TNext = undefined> {
|
|
||||||
next(...args: [] | [TNext]): IteratorResult<T, TReturn>;
|
|
||||||
return?(value?: TReturn): IteratorResult<T, TReturn>;
|
|
||||||
throw?(e?: any): IteratorResult<T, TReturn>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Iterable<T> {
|
|
||||||
[Symbol.iterator](): Iterator<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IterableIterator<T> extends Iterator<T> {
|
|
||||||
[Symbol.iterator](): IterableIterator<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Generator<T = unknown, TReturn = any, TNext = unknown> extends Iterator<T, TReturn, TNext> {
|
|
||||||
// NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places.
|
|
||||||
next(...args: [] | [TNext]): IteratorResult<T, TReturn>;
|
|
||||||
return(value: TReturn): IteratorResult<T, TReturn>;
|
|
||||||
throw(e: any): IteratorResult<T, TReturn>;
|
|
||||||
[Symbol.iterator](): Generator<T, TReturn, TNext>;
|
|
||||||
}
|
|
||||||
|
|
||||||
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<T, TReturn = any, TNext = undefined> {
|
|
||||||
// NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places.
|
|
||||||
next(...args: [] | [TNext]): Promise<IteratorResult<T, TReturn>>;
|
|
||||||
return?(value?: TReturn | Thenable<TReturn>): Promise<IteratorResult<T, TReturn>>;
|
|
||||||
throw?(e?: any): Promise<IteratorResult<T, TReturn>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AsyncIterable<T> {
|
|
||||||
[Symbol.asyncIterator](): AsyncIterator<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AsyncIterableIterator<T> extends AsyncIterator<T> {
|
|
||||||
[Symbol.asyncIterator](): AsyncIterableIterator<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AsyncGenerator<T = unknown, TReturn = any, TNext = unknown> extends AsyncIterator<T, TReturn, TNext> {
|
|
||||||
// NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places.
|
|
||||||
next(...args: [] | [TNext]): Promise<IteratorResult<T, TReturn>>;
|
|
||||||
return(value: TReturn | Thenable<TReturn>): Promise<IteratorResult<T, TReturn>>;
|
|
||||||
throw(e: any): Promise<IteratorResult<T, TReturn>>;
|
|
||||||
[Symbol.asyncIterator](): AsyncGenerator<T, TReturn, TNext>;
|
|
||||||
}
|
|
||||||
|
|
||||||
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<T> extends IterableIterator<T> {
|
|
||||||
entries(): IterableIterator<[number, T]>;
|
|
||||||
values(): IterableIterator<T>;
|
|
||||||
keys(): IterableIterator<number>;
|
|
||||||
}
|
|
||||||
|
|
||||||
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; }
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
586
lib/lib.d.ts
vendored
Normal file
586
lib/lib.d.ts
vendored
Normal file
@ -0,0 +1,586 @@
|
|||||||
|
type PropertyDescriptor<T, ThisT> = {
|
||||||
|
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, U> = T extends U ? never : T;
|
||||||
|
type Extract<T, U> = T extends U ? T : never;
|
||||||
|
type Record<KeyT extends string | number | symbol, ValT> = { [x in KeyT]: ValT }
|
||||||
|
type ReplaceFunc = (match: string, ...args: any[]) => string;
|
||||||
|
|
||||||
|
type PromiseFulfillFunc<T> = (val: T) => void;
|
||||||
|
type PromiseThenFunc<T, NextT> = (val: T) => NextT;
|
||||||
|
type PromiseRejectFunc = (err: unknown) => void;
|
||||||
|
type PromiseFunc<T> = (resolve: PromiseFulfillFunc<T>, reject: PromiseRejectFunc) => void;
|
||||||
|
|
||||||
|
type PromiseResult<T> ={ type: 'fulfilled'; value: T; } | { type: 'rejected'; reason: any; }
|
||||||
|
|
||||||
|
// wippidy-wine, this code is now mine :D
|
||||||
|
type Awaited<T> =
|
||||||
|
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<V> : // recursively unwrap the value
|
||||||
|
never : // the argument to `then` was not callable
|
||||||
|
T;
|
||||||
|
|
||||||
|
type IteratorYieldResult<TReturn> =
|
||||||
|
{ done?: false; } &
|
||||||
|
(TReturn extends undefined ? { value?: undefined; } : { value: TReturn; });
|
||||||
|
|
||||||
|
type IteratorReturnResult<TReturn> =
|
||||||
|
{ done: true } &
|
||||||
|
(TReturn extends undefined ? { value?: undefined; } : { value: TReturn; });
|
||||||
|
|
||||||
|
type IteratorResult<T, TReturn = any> = IteratorYieldResult<T> | IteratorReturnResult<TReturn>;
|
||||||
|
|
||||||
|
interface Thenable<T> {
|
||||||
|
then<NextT>(onFulfilled: PromiseThenFunc<T, NextT>, onRejected?: PromiseRejectFunc): Promise<Awaited<NextT>>;
|
||||||
|
then(onFulfilled: undefined, onRejected?: PromiseRejectFunc): Promise<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RegExpResultIndices extends Array<[number, number]> {
|
||||||
|
groups?: { [name: string]: [number, number]; };
|
||||||
|
}
|
||||||
|
interface RegExpResult extends Array<string> {
|
||||||
|
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<RegExpResult>;
|
||||||
|
}
|
||||||
|
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<Arr, Depth extends number> = {
|
||||||
|
"done": Arr,
|
||||||
|
"recur": Arr extends Array<infer InnerArr>
|
||||||
|
? FlatArray<InnerArr, [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20][Depth]>
|
||||||
|
: Arr
|
||||||
|
}[Depth extends -1 ? "done" : "recur"];
|
||||||
|
|
||||||
|
interface IArguments {
|
||||||
|
[i: number]: any;
|
||||||
|
length: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Iterator<T, TReturn = any, TNext = undefined> {
|
||||||
|
next(...args: [] | [TNext]): IteratorResult<T, TReturn>;
|
||||||
|
return?(value?: TReturn): IteratorResult<T, TReturn>;
|
||||||
|
throw?(e?: any): IteratorResult<T, TReturn>;
|
||||||
|
}
|
||||||
|
interface Iterable<T> {
|
||||||
|
[Symbol.iterator](): Iterator<T>;
|
||||||
|
}
|
||||||
|
interface IterableIterator<T> extends Iterator<T> {
|
||||||
|
[Symbol.iterator](): IterableIterator<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AsyncIterator<T, TReturn = any, TNext = undefined> {
|
||||||
|
next(...args: [] | [TNext]): Promise<IteratorResult<T, TReturn>>;
|
||||||
|
return?(value?: TReturn | Thenable<TReturn>): Promise<IteratorResult<T, TReturn>>;
|
||||||
|
throw?(e?: any): Promise<IteratorResult<T, TReturn>>;
|
||||||
|
}
|
||||||
|
interface AsyncIterable<T> {
|
||||||
|
[Symbol.asyncIterator](): AsyncIterator<T>;
|
||||||
|
}
|
||||||
|
interface AsyncIterableIterator<T> extends AsyncIterator<T> {
|
||||||
|
[Symbol.asyncIterator](): AsyncIterableIterator<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Generator<T = unknown, TReturn = unknown, TNext = unknown> extends Iterator<T, TReturn, TNext> {
|
||||||
|
[Symbol.iterator](): Generator<T, TReturn, TNext>;
|
||||||
|
return(value: TReturn): IteratorResult<T, TReturn>;
|
||||||
|
throw(e: any): IteratorResult<T, TReturn>;
|
||||||
|
}
|
||||||
|
interface GeneratorFunction {
|
||||||
|
new (...args: any[]): Generator;
|
||||||
|
(...args: any[]): Generator;
|
||||||
|
readonly length: number;
|
||||||
|
readonly name: string;
|
||||||
|
readonly prototype: Generator;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AsyncGenerator<T = unknown, TReturn = unknown, TNext = unknown> extends AsyncIterator<T, TReturn, TNext> {
|
||||||
|
return(value: TReturn | Thenable<TReturn>): Promise<IteratorResult<T, TReturn>>;
|
||||||
|
throw(e: any): Promise<IteratorResult<T, TReturn>>;
|
||||||
|
[Symbol.asyncIterator](): AsyncGenerator<T, TReturn, TNext>;
|
||||||
|
}
|
||||||
|
interface AsyncGeneratorFunction {
|
||||||
|
new (...args: any[]): AsyncGenerator;
|
||||||
|
(...args: any[]): AsyncGenerator;
|
||||||
|
readonly length: number;
|
||||||
|
readonly name: string;
|
||||||
|
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<T> extends IterableIterator<T> {
|
||||||
|
[i: number]: T;
|
||||||
|
|
||||||
|
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<U>(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<D extends number = 1>(depth?: D): FlatArray<T, D>;
|
||||||
|
flatMap(func: (val: T, i: number, arr: T[]) => T | T[], thisAarg?: any): FlatArray<T[], 1>;
|
||||||
|
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<U>(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<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U;
|
||||||
|
|
||||||
|
entries(): IterableIterator<[number, T]>;
|
||||||
|
values(): IterableIterator<T>;
|
||||||
|
keys(): IterableIterator<number>;
|
||||||
|
}
|
||||||
|
interface ArrayConstructor {
|
||||||
|
new <T>(arrayLength?: number): T[];
|
||||||
|
new <T>(...items: T[]): T[];
|
||||||
|
<T>(arrayLength?: number): T[];
|
||||||
|
<T>(...items: T[]): T[];
|
||||||
|
isArray(arg: any): arg is any[];
|
||||||
|
prototype: Array<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Boolean {
|
||||||
|
valueOf(): boolean;
|
||||||
|
}
|
||||||
|
interface BooleanConstructor {
|
||||||
|
(val: any): boolean;
|
||||||
|
new (val: any): Boolean;
|
||||||
|
prototype: Boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Error {
|
||||||
|
name: string;
|
||||||
|
message: string;
|
||||||
|
stack: string[];
|
||||||
|
toString(): 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 {
|
||||||
|
name: 'TypeError';
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RangeErrorConstructor extends ErrorConstructor {
|
||||||
|
(msg?: any): RangeError;
|
||||||
|
new (msg?: any): RangeError;
|
||||||
|
prototype: Error;
|
||||||
|
}
|
||||||
|
interface RangeError extends Error {
|
||||||
|
name: 'RangeError';
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SyntaxErrorConstructor extends ErrorConstructor {
|
||||||
|
(msg?: any): RangeError;
|
||||||
|
new (msg?: any): RangeError;
|
||||||
|
prototype: Error;
|
||||||
|
}
|
||||||
|
interface SyntaxError extends Error {
|
||||||
|
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;
|
||||||
|
readonly length: number;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
interface CallableFunction extends Function {
|
||||||
|
(...args: any[]): any;
|
||||||
|
apply<ThisArg, Args extends any[], RetT>(this: (this: ThisArg, ...args: Args) => RetT, thisArg: ThisArg, argArray?: Args): RetT;
|
||||||
|
call<ThisArg, Args extends any[], RetT>(this: (this: ThisArg, ...args: Args) => RetT, thisArg: ThisArg, ...argArray: Args): RetT;
|
||||||
|
bind<ThisArg, Args extends any[], Rest extends any[], RetT>(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<Args extends any[], RetT>(this: new (...args: Args) => RetT, thisArg: any, argArray?: Args): RetT;
|
||||||
|
call<Args extends any[], RetT>(this: new (...args: Args) => RetT, thisArg: any, ...argArray: Args): RetT;
|
||||||
|
bind<Args extends any[], RetT>(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<ArgsT extends any[], RetT>(
|
||||||
|
func: (await: <T>(val: T) => Awaited<T>) => (...args: ArgsT) => RetT
|
||||||
|
): (...args: ArgsT) => Promise<RetT>;
|
||||||
|
asyncGenerator<ArgsT extends any[], RetT>(
|
||||||
|
func: (await: <T>(val: T) => Awaited<T>, _yield: <T>(val: T) => void) => (...args: ArgsT) => RetT
|
||||||
|
): (...args: ArgsT) => AsyncGenerator<RetT>;
|
||||||
|
generator<ArgsT extends any[], T = unknown, RetT = unknown, TNext = unknown>(
|
||||||
|
func: (_yield: <T>(val: T) => TNext) => (...args: ArgsT) => RetT
|
||||||
|
): (...args: ArgsT) => Generator<T, RetT, TNext>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Number {
|
||||||
|
toString(): string;
|
||||||
|
valueOf(): number;
|
||||||
|
}
|
||||||
|
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): {};
|
||||||
|
<T extends object>(arg: T): T;
|
||||||
|
|
||||||
|
new (arg: string): String;
|
||||||
|
new (arg: number): Number;
|
||||||
|
new (arg: boolean): Boolean;
|
||||||
|
new (arg?: undefined | null): {};
|
||||||
|
new <T extends object>(arg: T): T;
|
||||||
|
|
||||||
|
prototype: Object;
|
||||||
|
|
||||||
|
assign<T extends object>(target: T, ...src: object[]): T;
|
||||||
|
create<T extends object>(proto: T, props?: { [key: string]: PropertyDescriptor<any, T> }): T;
|
||||||
|
|
||||||
|
keys<T extends object>(obj: T, onlyString?: true): (keyof T)[];
|
||||||
|
keys<T extends object>(obj: T, onlyString: false): any[];
|
||||||
|
entries<T extends object>(obj: T, onlyString?: true): [keyof T, T[keyof T]][];
|
||||||
|
entries<T extends object>(obj: T, onlyString: false): [any, any][];
|
||||||
|
values<T extends object>(obj: T, onlyString?: true): (T[keyof T])[];
|
||||||
|
values<T extends object>(obj: T, onlyString: false): any[];
|
||||||
|
|
||||||
|
fromEntries(entries: Iterable<[any, any]>): object;
|
||||||
|
|
||||||
|
defineProperty<T, ThisT extends object>(obj: ThisT, key: any, desc: PropertyDescriptor<T, ThisT>): ThisT;
|
||||||
|
defineProperties<ThisT extends object>(obj: ThisT, desc: { [key: string]: PropertyDescriptor<any, ThisT> }): ThisT;
|
||||||
|
|
||||||
|
getOwnPropertyNames<T extends object>(obj: T): (keyof T)[];
|
||||||
|
getOwnPropertySymbols<T extends object>(obj: T): (keyof T)[];
|
||||||
|
hasOwn<T extends object, KeyT>(obj: T, key: KeyT): boolean;
|
||||||
|
|
||||||
|
getOwnPropertyDescriptor<T extends object, KeyT extends keyof T>(obj: T, key: KeyT): PropertyDescriptor<T[KeyT], T>;
|
||||||
|
getOwnPropertyDescriptors<T extends object>(obj: T): { [x in keyof T]: PropertyDescriptor<T[x], T> };
|
||||||
|
|
||||||
|
getPrototypeOf(obj: any): object | null;
|
||||||
|
setPrototypeOf<T>(obj: T, proto: object | null): T;
|
||||||
|
|
||||||
|
preventExtensions<T extends object>(obj: T): T;
|
||||||
|
seal<T extends object>(obj: T): T;
|
||||||
|
freeze<T extends object>(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<RegExpResult>;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
interface StringConstructor {
|
||||||
|
(val: any): string;
|
||||||
|
new (val: any): String;
|
||||||
|
|
||||||
|
fromCharCode(val: number): string;
|
||||||
|
|
||||||
|
prototype: String;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Symbol {
|
||||||
|
valueOf(): symbol;
|
||||||
|
}
|
||||||
|
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<T> extends Thenable<T> {
|
||||||
|
catch(func: PromiseRejectFunc): Promise<T>;
|
||||||
|
finally(func: () => void): Promise<T>;
|
||||||
|
}
|
||||||
|
interface PromiseConstructor {
|
||||||
|
prototype: Promise<any>;
|
||||||
|
|
||||||
|
new <T>(func: PromiseFunc<T>): Promise<Awaited<T>>;
|
||||||
|
resolve<T>(val: T): Promise<Awaited<T>>;
|
||||||
|
reject(val: any): Promise<never>;
|
||||||
|
|
||||||
|
isAwaitable(val: unknown): val is Thenable<any>;
|
||||||
|
any<T>(promises: T[]): Promise<Awaited<T>>;
|
||||||
|
race<T>(promises: (Promise<T>|T)[]): Promise<T>;
|
||||||
|
all<T extends any[]>(promises: T): Promise<{ [Key in keyof T]: Awaited<T[Key]> }>;
|
||||||
|
allSettled<T extends any[]>(...promises: T): Promise<[...{ [P in keyof T]: PromiseResult<Awaited<T[P]>>}]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var String: StringConstructor;
|
||||||
|
//@ts-ignore
|
||||||
|
declare const arguments: IArguments;
|
||||||
|
declare var NaN: number;
|
||||||
|
declare var Infinity: number;
|
||||||
|
|
||||||
|
declare var setTimeout: <T extends any[]>(handle: (...args: [ ...T, ...any[] ]) => void, delay?: number, ...args: T) => number;
|
||||||
|
declare var setInterval: <T extends any[]>(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 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<KeyT, ValueT> {
|
||||||
|
public [Symbol.iterator](): IterableIterator<[KeyT, ValueT]>;
|
||||||
|
|
||||||
|
public clear(): void;
|
||||||
|
public delete(key: KeyT): boolean;
|
||||||
|
|
||||||
|
public entries(): IterableIterator<[KeyT, ValueT]>;
|
||||||
|
public keys(): IterableIterator<KeyT>;
|
||||||
|
public values(): IterableIterator<ValueT>;
|
||||||
|
|
||||||
|
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<KeyT, ValueT>) => void, thisArg?: any): void;
|
||||||
|
|
||||||
|
public constructor();
|
||||||
|
}
|
||||||
|
declare class Set<T> {
|
||||||
|
public [Symbol.iterator](): IterableIterator<T>;
|
||||||
|
|
||||||
|
public entries(): IterableIterator<[T, T]>;
|
||||||
|
public keys(): IterableIterator<T>;
|
||||||
|
public values(): IterableIterator<T>;
|
||||||
|
|
||||||
|
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<T>) => 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<RegExpResult>;
|
||||||
|
[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);
|
||||||
|
}
|
127
lib/map.ts
127
lib/map.ts
@ -1,44 +1,93 @@
|
|||||||
declare class Map<KeyT, ValueT> {
|
define("map", () => {
|
||||||
public [Symbol.iterator](): IterableIterator<[KeyT, ValueT]>;
|
const syms = { values: internals.symbol('Map.values') } as { readonly values: unique symbol };
|
||||||
|
const Object = env.global.Object;
|
||||||
|
|
||||||
public clear(): void;
|
class Map<KeyT, ValueT> {
|
||||||
public delete(key: KeyT): boolean;
|
[syms.values]: any = {};
|
||||||
|
|
||||||
public entries(): IterableIterator<[KeyT, ValueT]>;
|
public [env.global.Symbol.iterator](): IterableIterator<[KeyT, ValueT]> {
|
||||||
public keys(): IterableIterator<KeyT>;
|
|
||||||
public values(): IterableIterator<ValueT>;
|
|
||||||
|
|
||||||
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<KeyT, ValueT>) => void, thisArg?: any): void;
|
|
||||||
|
|
||||||
public constructor();
|
|
||||||
}
|
|
||||||
|
|
||||||
Map.prototype[Symbol.iterator] = function() {
|
|
||||||
return this.entries();
|
return this.entries();
|
||||||
};
|
}
|
||||||
|
|
||||||
var entries = Map.prototype.entries;
|
public clear() {
|
||||||
var keys = Map.prototype.keys;
|
this[syms.values] = {};
|
||||||
var values = Map.prototype.values;
|
}
|
||||||
|
public delete(key: KeyT) {
|
||||||
|
if ((key as any) in this[syms.values]) {
|
||||||
|
delete this[syms.values];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
Map.prototype.entries = function() {
|
public entries(): IterableIterator<[KeyT, ValueT]> {
|
||||||
var it = entries.call(this);
|
const keys = internals.ownPropKeys(this[syms.values]);
|
||||||
it[Symbol.iterator] = () => it;
|
let i = 0;
|
||||||
return it;
|
|
||||||
};
|
return {
|
||||||
Map.prototype.keys = function() {
|
next: () => {
|
||||||
var it = keys.call(this);
|
if (i >= keys.length) return { done: true };
|
||||||
it[Symbol.iterator] = () => it;
|
else return { done: false, value: [ keys[i], this[syms.values][keys[i++]] ] }
|
||||||
return it;
|
},
|
||||||
};
|
[env.global.Symbol.iterator]() { return this; }
|
||||||
Map.prototype.values = function() {
|
}
|
||||||
var it = values.call(this);
|
}
|
||||||
it[Symbol.iterator] = () => it;
|
public keys(): IterableIterator<KeyT> {
|
||||||
return it;
|
const keys = internals.ownPropKeys(this[syms.values]);
|
||||||
};
|
let i = 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
next: () => {
|
||||||
|
if (i >= keys.length) return { done: true };
|
||||||
|
else return { done: false, value: keys[i] }
|
||||||
|
},
|
||||||
|
[env.global.Symbol.iterator]() { return this; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public values(): IterableIterator<ValueT> {
|
||||||
|
const keys = internals.ownPropKeys(this[syms.values]);
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
next: () => {
|
||||||
|
if (i >= keys.length) return { done: true };
|
||||||
|
else return { done: false, value: this[syms.values][keys[i++]] }
|
||||||
|
},
|
||||||
|
[env.global.Symbol.iterator]() { return this; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public get(key: KeyT) {
|
||||||
|
return this[syms.values][key];
|
||||||
|
}
|
||||||
|
public set(key: KeyT, val: ValueT) {
|
||||||
|
this[syms.values][key] = val;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public has(key: KeyT) {
|
||||||
|
return (key as any) in this[syms.values][key];
|
||||||
|
}
|
||||||
|
|
||||||
|
public get size() {
|
||||||
|
return internals.ownPropKeys(this[syms.values]).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public forEach(func: (key: KeyT, val: ValueT, map: Map<KeyT, ValueT>) => void, thisArg?: any) {
|
||||||
|
const keys = internals.ownPropKeys(this[syms.values]);
|
||||||
|
|
||||||
|
for (let i = 0; i < keys.length; i++) {
|
||||||
|
func(keys[i], this[syms.values][keys[i]], this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public constructor(iterable: Iterable<[KeyT, ValueT]>) {
|
||||||
|
const it = iterable[env.global.Symbol.iterator]();
|
||||||
|
|
||||||
|
for (let el = it.next(); !el.done; el = it.next()) {
|
||||||
|
this[syms.values][el.value[0]] = el.value[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
env.global.Map = Map;
|
||||||
|
});
|
||||||
|
13
lib/modules.ts
Normal file
13
lib/modules.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
var { define, run } = (() => {
|
||||||
|
const modules: Record<string, Function> = {};
|
||||||
|
|
||||||
|
function define(name: string, func: Function) {
|
||||||
|
modules[name] = func;
|
||||||
|
}
|
||||||
|
function run(name: string) {
|
||||||
|
if (typeof modules[name] === 'function') return modules[name]();
|
||||||
|
else throw "The module '" + name + "' doesn't exist.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return { define, run };
|
||||||
|
})();
|
228
lib/promise.ts
228
lib/promise.ts
@ -1,43 +1,203 @@
|
|||||||
type PromiseFulfillFunc<T> = (val: T) => void;
|
define("promise", () => {
|
||||||
type PromiseThenFunc<T, NextT> = (val: T) => NextT;
|
const syms = {
|
||||||
type PromiseRejectFunc = (err: unknown) => void;
|
callbacks: internals.symbol('Promise.callbacks'),
|
||||||
type PromiseFunc<T> = (resolve: PromiseFulfillFunc<T>, reject: PromiseRejectFunc) => void;
|
state: internals.symbol('Promise.state'),
|
||||||
|
value: internals.symbol('Promise.value'),
|
||||||
|
handled: internals.symbol('Promise.handled'),
|
||||||
|
} as {
|
||||||
|
readonly callbacks: unique symbol,
|
||||||
|
readonly state: unique symbol,
|
||||||
|
readonly value: unique symbol,
|
||||||
|
readonly handled: unique symbol,
|
||||||
|
}
|
||||||
|
|
||||||
type PromiseResult<T> ={ type: 'fulfilled'; value: T; } | { type: 'rejected'; reason: any; }
|
type Callback<T> = [ PromiseFulfillFunc<T>, PromiseRejectFunc ];
|
||||||
|
enum State {
|
||||||
|
Pending,
|
||||||
|
Fulfilled,
|
||||||
|
Rejected,
|
||||||
|
}
|
||||||
|
|
||||||
interface Thenable<T> {
|
function isAwaitable(val: unknown): val is Thenable<any> {
|
||||||
then<NextT>(this: Promise<T>, onFulfilled: PromiseThenFunc<T, NextT>, onRejected?: PromiseRejectFunc): Promise<Awaited<NextT>>;
|
return (
|
||||||
then(this: Promise<T>, onFulfilled: undefined, onRejected?: PromiseRejectFunc): Promise<T>;
|
typeof val === 'object' &&
|
||||||
}
|
val !== null &&
|
||||||
|
'then' in val &&
|
||||||
|
typeof val.then === 'function'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function resolve(promise: Promise<any>, v: any, state: State) {
|
||||||
|
if (promise[syms.state] === State.Pending) {
|
||||||
|
if (typeof v === 'object' && v !== null && 'then' in v && typeof v.then === 'function') {
|
||||||
|
v.then(
|
||||||
|
(res: any) => resolve(promise, res, state),
|
||||||
|
(res: any) => resolve(promise, res, State.Rejected)
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
promise[syms.value] = v;
|
||||||
|
promise[syms.state] = state;
|
||||||
|
|
||||||
// wippidy-wine, this code is now mine :D
|
for (let i = 0; i < promise[syms.callbacks]!.length; i++) {
|
||||||
type Awaited<T> =
|
promise[syms.handled] = true;
|
||||||
T extends null | undefined ? T : // special case for `null | undefined` when not in `--strictNullChecks` mode
|
promise[syms.callbacks]![i][state - 1](v);
|
||||||
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<V> : // recursively unwrap the value
|
|
||||||
never : // the argument to `then` was not callable
|
|
||||||
T;
|
|
||||||
|
|
||||||
interface PromiseConstructor {
|
promise[syms.callbacks] = undefined;
|
||||||
prototype: Promise<any>;
|
|
||||||
|
|
||||||
new <T>(func: PromiseFunc<T>): Promise<Awaited<T>>;
|
internals.pushMessage(true, internals.setEnv(() => {
|
||||||
resolve<T>(val: T): Promise<Awaited<T>>;
|
if (!promise[syms.handled] && state === State.Rejected) {
|
||||||
reject(val: any): Promise<never>;
|
log('Uncaught (in promise) ' + promise[syms.value]);
|
||||||
|
}
|
||||||
|
}, env), undefined, []);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
any<T>(promises: (Promise<T>|T)[]): Promise<T>;
|
class Promise<T> {
|
||||||
race<T>(promises: (Promise<T>|T)[]): Promise<T>;
|
public static isAwaitable(val: unknown): val is Thenable<any> {
|
||||||
all<T extends any[]>(promises: T): Promise<{ [Key in keyof T]: Awaited<T[Key]> }>;
|
return isAwaitable(val);
|
||||||
allSettled<T extends any[]>(...promises: T): Promise<[...{ [P in keyof T]: PromiseResult<Awaited<T[P]>>}]>;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
interface Promise<T> extends Thenable<T> {
|
public static resolve<T>(val: T): Promise<Awaited<T>> {
|
||||||
constructor: PromiseConstructor;
|
return new Promise(res => res(val as any));
|
||||||
catch(func: PromiseRejectFunc): Promise<T>;
|
}
|
||||||
finally(func: () => void): Promise<T>;
|
public static reject<T>(val: T): Promise<Awaited<T>> {
|
||||||
}
|
return new Promise((_, rej) => rej(val as any));
|
||||||
|
}
|
||||||
|
|
||||||
declare var Promise: PromiseConstructor;
|
public static race<T>(vals: T[]): Promise<Awaited<T>> {
|
||||||
|
if (typeof vals.length !== 'number') throw new TypeError('vals must be an array. Note that Promise.race is not variadic.');
|
||||||
|
return new Promise((res, rej) => {
|
||||||
|
for (let i = 0; i < vals.length; i++) {
|
||||||
|
const val = vals[i];
|
||||||
|
if (this.isAwaitable(val)) val.then(res, rej);
|
||||||
|
else res(val as any);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static any<T>(vals: T[]): Promise<Awaited<T>> {
|
||||||
|
if (typeof vals.length !== 'number') throw new TypeError('vals must be an array. Note that Promise.any is not variadic.');
|
||||||
|
return new Promise((res, rej) => {
|
||||||
|
let n = 0;
|
||||||
|
|
||||||
(Promise.prototype as any)[Symbol.typeName] = 'Promise';
|
for (let i = 0; i < vals.length; i++) {
|
||||||
|
const val = vals[i];
|
||||||
|
if (this.isAwaitable(val)) val.then(res, (err) => {
|
||||||
|
n++;
|
||||||
|
if (n === vals.length) throw Error('No promise resolved.');
|
||||||
|
});
|
||||||
|
else res(val as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vals.length === 0) throw Error('No promise resolved.');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static all(vals: any[]): Promise<any[]> {
|
||||||
|
if (typeof vals.length !== 'number') throw new TypeError('vals must be an array. Note that Promise.all is not variadic.');
|
||||||
|
return new Promise((res, rej) => {
|
||||||
|
const result: any[] = [];
|
||||||
|
let n = 0;
|
||||||
|
|
||||||
|
for (let i = 0; i < vals.length; i++) {
|
||||||
|
const val = vals[i];
|
||||||
|
if (this.isAwaitable(val)) val.then(
|
||||||
|
val => {
|
||||||
|
n++;
|
||||||
|
result[i] = val;
|
||||||
|
if (n === vals.length) res(result);
|
||||||
|
},
|
||||||
|
rej
|
||||||
|
);
|
||||||
|
else {
|
||||||
|
n++;
|
||||||
|
result[i] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vals.length === n) res(result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static allSettled(vals: any[]): Promise<any[]> {
|
||||||
|
if (typeof vals.length !== 'number') throw new TypeError('vals must be an array. Note that Promise.allSettled is not variadic.');
|
||||||
|
return new Promise((res, rej) => {
|
||||||
|
const result: any[] = [];
|
||||||
|
let n = 0;
|
||||||
|
|
||||||
|
for (let i = 0; i < vals.length; i++) {
|
||||||
|
const value = vals[i];
|
||||||
|
if (this.isAwaitable(value)) value.then(
|
||||||
|
value => {
|
||||||
|
n++;
|
||||||
|
result[i] = { status: 'fulfilled', value };
|
||||||
|
if (n === vals.length) res(result);
|
||||||
|
},
|
||||||
|
reason => {
|
||||||
|
n++;
|
||||||
|
result[i] = { status: 'rejected', reason };
|
||||||
|
if (n === vals.length) res(result);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
else {
|
||||||
|
n++;
|
||||||
|
result[i] = { status: 'fulfilled', value };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vals.length === n) res(result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[syms.callbacks]?: Callback<T>[] = [];
|
||||||
|
[syms.handled] = false;
|
||||||
|
[syms.state] = State.Pending;
|
||||||
|
[syms.value]?: T | unknown;
|
||||||
|
|
||||||
|
public then(onFulfil?: PromiseFulfillFunc<T>, onReject?: PromiseRejectFunc) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
onFulfil ??= v => v;
|
||||||
|
onReject ??= v => v;
|
||||||
|
|
||||||
|
const callback = (func: (val: any) => any) => (v: any) => {
|
||||||
|
try { resolve(func(v)); }
|
||||||
|
catch (e) { reject(e); }
|
||||||
|
}
|
||||||
|
switch (this[syms.state]) {
|
||||||
|
case State.Pending:
|
||||||
|
this[syms.callbacks]![this[syms.callbacks]!.length] = [callback(onFulfil), callback(onReject)];
|
||||||
|
break;
|
||||||
|
case State.Fulfilled:
|
||||||
|
this[syms.handled] = true;
|
||||||
|
callback(onFulfil)(this[syms.value]);
|
||||||
|
break;
|
||||||
|
case State.Rejected:
|
||||||
|
this[syms.handled] = true;
|
||||||
|
callback(onReject)(this[syms.value]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
public catch(func: PromiseRejectFunc) {
|
||||||
|
return this.then(undefined, func);
|
||||||
|
}
|
||||||
|
public finally(func: () => void) {
|
||||||
|
return this.then(
|
||||||
|
v => {
|
||||||
|
func();
|
||||||
|
return v;
|
||||||
|
},
|
||||||
|
v => {
|
||||||
|
func();
|
||||||
|
throw v;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public constructor(func: PromiseFunc<T>) {
|
||||||
|
internals.pushMessage(true, func, undefined, [
|
||||||
|
((v) => resolve(this, v, State.Fulfilled)) as PromiseFulfillFunc<T>,
|
||||||
|
((err) => resolve(this, err, State.Rejected)) as PromiseRejectFunc
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
env.global.Promise = Promise as any;
|
||||||
|
});
|
||||||
|
312
lib/regex.ts
312
lib/regex.ts
@ -1,211 +1,143 @@
|
|||||||
interface RegExpResultIndices extends Array<[number, number]> {
|
define("regex", () => {
|
||||||
groups?: { [name: string]: [number, number]; };
|
// var RegExp = env.global.RegExp = env.internals.RegExp;
|
||||||
}
|
|
||||||
interface RegExpResult extends Array<string> {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
type ReplaceFunc = (match: string, ...args: any[]) => string;
|
// setProps(RegExp.prototype as RegExp, env, {
|
||||||
|
// [Symbol.typeName]: 'RegExp',
|
||||||
|
|
||||||
interface Matcher {
|
// test(val) {
|
||||||
[Symbol.match](target: string): RegExpResult | string[] | null;
|
// return !!this.exec(val);
|
||||||
[Symbol.matchAll](target: string): IterableIterator<RegExpResult>;
|
// },
|
||||||
}
|
// toString() {
|
||||||
interface Splitter {
|
// return '/' + this.source + '/' + this.flags;
|
||||||
[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 {
|
// [Symbol.match](target) {
|
||||||
static escape(raw: any, flags?: string): RegExp;
|
// 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;
|
||||||
|
|
||||||
prototype: RegExp;
|
// return {
|
||||||
|
// next: (): IteratorResult<RegExpResult, undefined> => {
|
||||||
|
// const val = pattern?.exec(target);
|
||||||
|
|
||||||
exec(val: string): RegExpResult | null;
|
// if (val === null || val === undefined) {
|
||||||
test(val: string): boolean;
|
// pattern = undefined;
|
||||||
toString(): string;
|
// 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[] = [];
|
||||||
|
|
||||||
[Symbol.match](target: string): RegExpResult | string[] | null;
|
// while ((match = pattern.exec(target)) !== null) {
|
||||||
[Symbol.matchAll](target: string): IterableIterator<RegExpResult>;
|
// let added: string[] = [];
|
||||||
[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;
|
// if (match.index >= target.length) break;
|
||||||
readonly global: boolean;
|
|
||||||
readonly hasIndices: boolean;
|
|
||||||
readonly ignoreCase: boolean;
|
|
||||||
readonly multiline: boolean;
|
|
||||||
readonly sticky: boolean;
|
|
||||||
readonly unicode: boolean;
|
|
||||||
|
|
||||||
readonly source: string;
|
// if (match[0].length === 0) {
|
||||||
readonly flags: string;
|
// 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];
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
lastIndex: number;
|
// 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]);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
constructor(pattern?: string, flags?: string);
|
// lastEnd = pattern.lastIndex;
|
||||||
constructor(pattern?: RegExp, flags?: string);
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
(Symbol as any).replace = Symbol('Symbol.replace');
|
// if (lastEnd < target.length) {
|
||||||
(Symbol as any).match = Symbol('Symbol.match');
|
// res.push(target.substring(lastEnd));
|
||||||
(Symbol as any).matchAll = Symbol('Symbol.matchAll');
|
// }
|
||||||
(Symbol as any).split = Symbol('Symbol.split');
|
|
||||||
(Symbol as any).search = Symbol('Symbol.search');
|
|
||||||
|
|
||||||
setProps(RegExp.prototype, {
|
// return res;
|
||||||
[Symbol.typeName]: 'RegExp',
|
// },
|
||||||
|
// [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[] = [];
|
||||||
|
|
||||||
test(val) {
|
// // log(pattern.toString());
|
||||||
return !!this.exec(val);
|
|
||||||
},
|
|
||||||
toString() {
|
|
||||||
return '/' + this.source + '/' + this.flags;
|
|
||||||
},
|
|
||||||
|
|
||||||
[Symbol.match](target) {
|
// while ((match = pattern.exec(target)) !== null) {
|
||||||
if (this.global) {
|
// const indices = match.indices![0];
|
||||||
const res: string[] = [];
|
// res.push(target.substring(lastEnd, indices[0]));
|
||||||
let val;
|
// if (replacement instanceof Function) {
|
||||||
while (val = this.exec(target)) {
|
// res.push(replacement(target.substring(indices[0], indices[1]), ...match.slice(1), indices[0], target));
|
||||||
res.push(val[0]);
|
// }
|
||||||
}
|
// else {
|
||||||
this.lastIndex = 0;
|
// res.push(replacement);
|
||||||
return res;
|
// }
|
||||||
}
|
// lastEnd = indices[1];
|
||||||
else {
|
// if (!pattern.global) break;
|
||||||
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 {
|
// if (lastEnd < target.length) {
|
||||||
next: (): IteratorResult<RegExpResult, undefined> => {
|
// res.push(target.substring(lastEnd));
|
||||||
const val = pattern?.exec(target);
|
// }
|
||||||
|
|
||||||
if (val === null || val === undefined) {
|
// return res.join('');
|
||||||
pattern = undefined;
|
// },
|
||||||
return { done: true };
|
// [Symbol.search](target, reverse, start) {
|
||||||
}
|
// const pattern: RegExp | undefined = new this.constructor(this, this.flags + "g") as RegExp;
|
||||||
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 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
// if (!reverse) {
|
||||||
pattern.lastIndex = (start as any) | 0;
|
// pattern.lastIndex = (start as any) | 0;
|
||||||
const res = pattern.exec(target);
|
// const res = pattern.exec(target);
|
||||||
if (res) return res.index;
|
// if (res) return res.index;
|
||||||
else return -1;
|
// else return -1;
|
||||||
}
|
// }
|
||||||
else {
|
// else {
|
||||||
start ??= target.length;
|
// start ??= target.length;
|
||||||
start |= 0;
|
// start |= 0;
|
||||||
let res: RegExpResult | null = null;
|
// let res: RegExpResult | null = null;
|
||||||
|
|
||||||
while (true) {
|
// while (true) {
|
||||||
const tmp = pattern.exec(target);
|
// const tmp = pattern.exec(target);
|
||||||
if (tmp === null || tmp.index > start) break;
|
// if (tmp === null || tmp.index > start) break;
|
||||||
res = tmp;
|
// res = tmp;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (res && res.index <= start) return res.index;
|
// if (res && res.index <= start) return res.index;
|
||||||
else return -1;
|
// else return -1;
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
|
// });
|
||||||
});
|
});
|
@ -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);
|
|
||||||
};
|
|
108
lib/set.ts
108
lib/set.ts
@ -1,45 +1,81 @@
|
|||||||
declare class Set<T> {
|
define("set", () => {
|
||||||
public [Symbol.iterator](): IterableIterator<T>;
|
const syms = { values: internals.symbol('Map.values') } as { readonly values: unique symbol };
|
||||||
|
const Object = env.global.Object;
|
||||||
|
|
||||||
public entries(): IterableIterator<[T, T]>;
|
class Set<T> {
|
||||||
public keys(): IterableIterator<T>;
|
[syms.values]: any = {};
|
||||||
public values(): IterableIterator<T>;
|
|
||||||
|
|
||||||
public clear(): void;
|
public [env.global.Symbol.iterator](): IterableIterator<[T, T]> {
|
||||||
|
return this.entries();
|
||||||
|
}
|
||||||
|
|
||||||
public add(val: T): this;
|
public clear() {
|
||||||
public delete(val: T): boolean;
|
this[syms.values] = {};
|
||||||
public has(key: T): boolean;
|
}
|
||||||
|
public delete(key: T) {
|
||||||
|
if ((key as any) in this[syms.values]) {
|
||||||
|
delete this[syms.values];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
public get size(): number;
|
public entries(): IterableIterator<[T, T]> {
|
||||||
|
const keys = internals.ownPropKeys(this[syms.values]);
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
public forEach(func: (key: T, set: Set<T>) => void, thisArg?: any): void;
|
return {
|
||||||
|
next: () => {
|
||||||
|
if (i >= keys.length) return { done: true };
|
||||||
|
else return { done: false, value: [ keys[i], keys[i] ] }
|
||||||
|
},
|
||||||
|
[env.global.Symbol.iterator]() { return this; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public keys(): IterableIterator<T> {
|
||||||
|
const keys = internals.ownPropKeys(this[syms.values]);
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
public constructor();
|
return {
|
||||||
}
|
next: () => {
|
||||||
|
if (i >= keys.length) return { done: true };
|
||||||
|
else return { done: false, value: keys[i] }
|
||||||
|
},
|
||||||
|
[env.global.Symbol.iterator]() { return this; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public values(): IterableIterator<T> {
|
||||||
|
return this.keys();
|
||||||
|
}
|
||||||
|
|
||||||
Set.prototype[Symbol.iterator] = function() {
|
public add(val: T) {
|
||||||
return this.values();
|
this[syms.values][val] = undefined;
|
||||||
};
|
return this;
|
||||||
|
}
|
||||||
|
public has(key: T) {
|
||||||
|
return (key as any) in this[syms.values][key];
|
||||||
|
}
|
||||||
|
|
||||||
(() => {
|
public get size() {
|
||||||
var entries = Set.prototype.entries;
|
return internals.ownPropKeys(this[syms.values]).length;
|
||||||
var keys = Set.prototype.keys;
|
}
|
||||||
var values = Set.prototype.values;
|
|
||||||
|
|
||||||
Set.prototype.entries = function() {
|
public forEach(func: (key: T, val: T, map: Set<T>) => void, thisArg?: any) {
|
||||||
var it = entries.call(this);
|
const keys = internals.ownPropKeys(this[syms.values]);
|
||||||
it[Symbol.iterator] = () => it;
|
|
||||||
return it;
|
for (let i = 0; i < keys.length; i++) {
|
||||||
};
|
func(keys[i], this[syms.values][keys[i]], this);
|
||||||
Set.prototype.keys = function() {
|
}
|
||||||
var it = keys.call(this);
|
}
|
||||||
it[Symbol.iterator] = () => it;
|
|
||||||
return it;
|
public constructor(iterable: Iterable<T>) {
|
||||||
};
|
const it = iterable[env.global.Symbol.iterator]();
|
||||||
Set.prototype.values = function() {
|
|
||||||
var it = values.call(this);
|
for (let el = it.next(); !el.done; el = it.next()) {
|
||||||
it[Symbol.iterator] = () => it;
|
this[syms.values][el.value] = undefined;
|
||||||
return it;
|
}
|
||||||
};
|
}
|
||||||
})();
|
}
|
||||||
|
|
||||||
|
env.global.Set = Set;
|
||||||
|
});
|
||||||
|
38
lib/timeout.ts
Normal file
38
lib/timeout.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
define("timeout", () => {
|
||||||
|
const timeouts: Record<number, () => void> = { };
|
||||||
|
const intervals: Record<number, () => void> = { };
|
||||||
|
let timeoutI = 0, intervalI = 0;
|
||||||
|
|
||||||
|
env.global.setTimeout = (func, delay, ...args) => {
|
||||||
|
if (typeof func !== 'function') throw new TypeError("func must be a function.");
|
||||||
|
delay = (delay ?? 0) - 0;
|
||||||
|
const cancelFunc = internals.delay(delay, () => internals.apply(func, undefined, args));
|
||||||
|
timeouts[++timeoutI] = cancelFunc;
|
||||||
|
return timeoutI;
|
||||||
|
};
|
||||||
|
env.global.setInterval = (func, delay, ...args) => {
|
||||||
|
if (typeof func !== 'function') throw new TypeError("func must be a function.");
|
||||||
|
delay = (delay ?? 0) - 0;
|
||||||
|
|
||||||
|
const i = ++intervalI;
|
||||||
|
intervals[i] = internals.delay(delay, callback);
|
||||||
|
|
||||||
|
return i;
|
||||||
|
|
||||||
|
function callback() {
|
||||||
|
internals.apply(func, undefined, args);
|
||||||
|
intervals[i] = internals.delay(delay!, callback);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
env.global.clearTimeout = (id) => {
|
||||||
|
const func = timeouts[id];
|
||||||
|
if (func) func();
|
||||||
|
timeouts[id] = undefined!;
|
||||||
|
};
|
||||||
|
env.global.clearInterval = (id) => {
|
||||||
|
const func = intervals[id];
|
||||||
|
if (func) func();
|
||||||
|
intervals[id] = undefined!;
|
||||||
|
};
|
||||||
|
});
|
34
lib/tsconfig.json
Normal file
34
lib/tsconfig.json
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"files": [
|
||||||
|
"lib.d.ts",
|
||||||
|
"modules.ts",
|
||||||
|
"utils.ts",
|
||||||
|
"values/object.ts",
|
||||||
|
"values/symbol.ts",
|
||||||
|
"values/function.ts",
|
||||||
|
"values/errors.ts",
|
||||||
|
"values/string.ts",
|
||||||
|
"values/number.ts",
|
||||||
|
"values/boolean.ts",
|
||||||
|
"values/array.ts",
|
||||||
|
"promise.ts",
|
||||||
|
"map.ts",
|
||||||
|
"set.ts",
|
||||||
|
"regex.ts",
|
||||||
|
"timeout.ts",
|
||||||
|
"core.ts"
|
||||||
|
],
|
||||||
|
"compilerOptions": {
|
||||||
|
"outFile": "../bin/me/topchetoeu/jscript/js/core.js",
|
||||||
|
// "declarationDir": "",
|
||||||
|
// "declarationDir": "bin/me/topchetoeu/jscript/dts",
|
||||||
|
"target": "ES5",
|
||||||
|
"lib": [],
|
||||||
|
"module": "None",
|
||||||
|
"stripInternal": true,
|
||||||
|
"downlevelIteration": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"strict": true,
|
||||||
|
}
|
||||||
|
}
|
38
lib/utils.ts
Normal file
38
lib/utils.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
function setProps<
|
||||||
|
TargetT extends object,
|
||||||
|
DescT extends {
|
||||||
|
[x in Exclude<keyof TargetT, 'constructor'> ]?: TargetT[x] extends ((...args: infer ArgsT) => infer RetT) ?
|
||||||
|
((this: TargetT, ...args: ArgsT) => RetT) :
|
||||||
|
TargetT[x]
|
||||||
|
}
|
||||||
|
>(target: TargetT, desc: DescT) {
|
||||||
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function setConstr(target: object, constr: Function) {
|
||||||
|
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;
|
||||||
|
}
|
@ -1,69 +1,5 @@
|
|||||||
// god this is awful
|
define("values/array", () => {
|
||||||
type FlatArray<Arr, Depth extends number> = {
|
var Array = env.global.Array = function(len?: number) {
|
||||||
"done": Arr,
|
|
||||||
"recur": Arr extends Array<infer InnerArr>
|
|
||||||
? FlatArray<InnerArr, [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20][Depth]>
|
|
||||||
: Arr
|
|
||||||
}[Depth extends -1 ? "done" : "recur"];
|
|
||||||
|
|
||||||
interface Array<T> {
|
|
||||||
[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<U>(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<D extends number = 1>(depth?: D): FlatArray<T, D>;
|
|
||||||
flatMap(func: (val: T, i: number, arr: T[]) => T | T[], thisAarg?: any): FlatArray<T[], 1>;
|
|
||||||
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<U>(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<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U;
|
|
||||||
}
|
|
||||||
interface ArrayConstructor {
|
|
||||||
new <T>(arrayLength?: number): T[];
|
|
||||||
new <T>(...items: T[]): T[];
|
|
||||||
<T>(arrayLength?: number): T[];
|
|
||||||
<T>(...items: T[]): T[];
|
|
||||||
isArray(arg: any): arg is any[];
|
|
||||||
prototype: Array<any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare var Array: ArrayConstructor;
|
|
||||||
|
|
||||||
gt.Array = function(len?: number) {
|
|
||||||
var res = [];
|
var res = [];
|
||||||
|
|
||||||
if (typeof len === 'number' && arguments.length === 1) {
|
if (typeof len === 'number' && arguments.length === 1) {
|
||||||
@ -77,28 +13,57 @@ gt.Array = function(len?: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
} as ArrayConstructor;
|
} as ArrayConstructor;
|
||||||
|
|
||||||
Array.prototype = ([] as any).__proto__ as Array<any>;
|
env.setProto('array', Array.prototype);
|
||||||
setConstr(Array.prototype, Array);
|
(Array.prototype as any)[env.global.Symbol.typeName] = "Array";
|
||||||
|
setConstr(Array.prototype, Array);
|
||||||
|
|
||||||
function wrapI(max: number, i: number) {
|
setProps(Array.prototype, {
|
||||||
i |= 0;
|
[env.global.Symbol.iterator]: function() {
|
||||||
if (i < 0) i = max + i;
|
return this.values();
|
||||||
return i;
|
},
|
||||||
}
|
[env.global.Symbol.typeName]: "Array",
|
||||||
function clampI(max: number, i: number) {
|
|
||||||
if (i < 0) i = 0;
|
|
||||||
if (i > max) i = max;
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
lgt.wrapI = wrapI;
|
values() {
|
||||||
lgt.clampI = clampI;
|
var i = 0;
|
||||||
|
|
||||||
(Array.prototype as any)[Symbol.typeName] = "Array";
|
return {
|
||||||
|
next: () => {
|
||||||
|
while (i < this.length) {
|
||||||
|
if (i++ in this) return { done: false, value: this[i - 1] };
|
||||||
|
}
|
||||||
|
return { done: true, value: undefined };
|
||||||
|
},
|
||||||
|
[env.global.Symbol.iterator]() { return this; }
|
||||||
|
};
|
||||||
|
},
|
||||||
|
keys() {
|
||||||
|
var i = 0;
|
||||||
|
|
||||||
setProps(Array.prototype, {
|
return {
|
||||||
|
next: () => {
|
||||||
|
while (i < this.length) {
|
||||||
|
if (i++ in this) return { done: false, value: i - 1 };
|
||||||
|
}
|
||||||
|
return { done: true, value: undefined };
|
||||||
|
},
|
||||||
|
[env.global.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 };
|
||||||
|
},
|
||||||
|
[env.global.Symbol.iterator]() { return this; }
|
||||||
|
};
|
||||||
|
},
|
||||||
concat() {
|
concat() {
|
||||||
var res = [] as any[];
|
var res = [] as any[];
|
||||||
res.push.apply(res, this);
|
res.push.apply(res, this);
|
||||||
@ -362,8 +327,10 @@ setProps(Array.prototype, {
|
|||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setProps(Array, {
|
setProps(Array, {
|
||||||
isArray(val: any) { return internals.isArr(val); }
|
isArray(val: any) { return internals.isArray(val); }
|
||||||
|
});
|
||||||
|
internals.markSpecial(Array);
|
||||||
});
|
});
|
@ -1,22 +1,12 @@
|
|||||||
interface Boolean {
|
define("values/boolean", () => {
|
||||||
valueOf(): boolean;
|
var Boolean = env.global.Boolean = function (this: Boolean | undefined, arg) {
|
||||||
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;
|
var val;
|
||||||
if (arguments.length === 0) val = false;
|
if (arguments.length === 0) val = false;
|
||||||
else val = !!arg;
|
else val = !!arg;
|
||||||
if (this === undefined || this === null) return val;
|
if (this === undefined || this === null) return val;
|
||||||
else (this as any).value = val;
|
else (this as any).value = val;
|
||||||
} as BooleanConstructor;
|
} as BooleanConstructor;
|
||||||
|
|
||||||
Boolean.prototype = (false as any).__proto__ as Boolean;
|
env.setProto('bool', Boolean.prototype);
|
||||||
setConstr(Boolean.prototype, Boolean);
|
setConstr(Boolean.prototype, Boolean);
|
||||||
|
});
|
||||||
|
@ -1,52 +1,5 @@
|
|||||||
interface Error {
|
define("values/errors", () => {
|
||||||
constructor: ErrorConstructor;
|
var Error = env.global.Error = function Error(msg: string) {
|
||||||
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';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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 = '';
|
if (msg === undefined) msg = '';
|
||||||
else msg += '';
|
else msg += '';
|
||||||
|
|
||||||
@ -54,36 +7,40 @@ gt.Error = function Error(msg: string) {
|
|||||||
message: msg,
|
message: msg,
|
||||||
stack: [] as string[],
|
stack: [] as string[],
|
||||||
}, Error.prototype);
|
}, Error.prototype);
|
||||||
} as ErrorConstructor;
|
} as ErrorConstructor;
|
||||||
|
|
||||||
Error.prototype = internals.err ?? {};
|
setConstr(Error.prototype, Error);
|
||||||
Error.prototype.name = 'Error';
|
setProps(Error.prototype, {
|
||||||
setConstr(Error.prototype, Error);
|
name: 'Error',
|
||||||
|
toString: internals.setEnv(function(this: Error) {
|
||||||
Error.prototype.toString = function() {
|
|
||||||
if (!(this instanceof Error)) return '';
|
if (!(this instanceof Error)) return '';
|
||||||
|
|
||||||
if (this.message === '') return this.name;
|
if (this.message === '') return this.name;
|
||||||
else return this.name + ': ' + this.message;
|
else return this.name + ': ' + this.message;
|
||||||
};
|
}, env)
|
||||||
|
});
|
||||||
|
env.setProto('error', Error.prototype);
|
||||||
|
internals.markSpecial(Error);
|
||||||
|
|
||||||
function makeError<T extends ErrorConstructor>(name: string, proto: any): T {
|
function makeError<T1 extends ErrorConstructor>(name: string, proto: string): T1 {
|
||||||
var err = function (msg: string) {
|
function constr (msg: string) {
|
||||||
var res = new Error(msg);
|
var res = new Error(msg);
|
||||||
(res as any).__proto__ = err.prototype;
|
(res as any).__proto__ = constr.prototype;
|
||||||
return res;
|
return res;
|
||||||
} as T;
|
}
|
||||||
|
|
||||||
err.prototype = proto;
|
(constr as any).__proto__ = Error;
|
||||||
err.prototype.name = name;
|
(constr.prototype as any).__proto__ = env.proto('error');
|
||||||
setConstr(err.prototype, err as ErrorConstructor);
|
setConstr(constr.prototype, constr as ErrorConstructor);
|
||||||
(err.prototype as any).__proto__ = Error.prototype;
|
setProps(constr.prototype, { name: name });
|
||||||
(err as any).__proto__ = Error;
|
|
||||||
internals.special(err);
|
|
||||||
|
|
||||||
return err;
|
internals.markSpecial(constr);
|
||||||
}
|
env.setProto(proto, constr.prototype);
|
||||||
|
|
||||||
gt.RangeError = makeError('RangeError', internals.range ?? {});
|
return constr as T1;
|
||||||
gt.TypeError = makeError('TypeError', internals.type ?? {});
|
}
|
||||||
gt.SyntaxError = makeError('SyntaxError', internals.syntax ?? {});
|
|
||||||
|
env.global.RangeError = makeError('RangeError', 'rangeErr');
|
||||||
|
env.global.TypeError = makeError('TypeError', 'typeErr');
|
||||||
|
env.global.SyntaxError = makeError('SyntaxError', 'syntaxErr');
|
||||||
|
});
|
@ -1,58 +1,17 @@
|
|||||||
interface Function {
|
define("values/function", () => {
|
||||||
apply(this: Function, thisArg: any, argArray?: any): any;
|
var Function = env.global.Function = function() {
|
||||||
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 FunctionConstructor extends Function {
|
|
||||||
(...args: string[]): (...args: any[]) => any;
|
|
||||||
new (...args: string[]): (...args: any[]) => any;
|
|
||||||
prototype: Function;
|
|
||||||
async<ArgsT extends any[], RetT>(
|
|
||||||
func: (await: <T>(val: T) => Awaited<T>) => (...args: ArgsT) => RetT
|
|
||||||
): (...args: ArgsT) => Promise<RetT>;
|
|
||||||
asyncGenerator<ArgsT extends any[], RetT>(
|
|
||||||
func: (await: <T>(val: T) => Awaited<T>, _yield: <T>(val: T) => void) => (...args: ArgsT) => RetT
|
|
||||||
): (...args: ArgsT) => AsyncGenerator<RetT>;
|
|
||||||
generator<ArgsT extends any[], T = unknown, RetT = unknown, TNext = unknown>(
|
|
||||||
func: (_yield: <T>(val: T) => TNext) => (...args: ArgsT) => RetT
|
|
||||||
): (...args: ArgsT) => Generator<T, RetT, TNext>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface CallableFunction extends Function {
|
|
||||||
(...args: any[]): any;
|
|
||||||
apply<ThisArg, Args extends any[], RetT>(this: (this: ThisArg, ...args: Args) => RetT, thisArg: ThisArg, argArray?: Args): RetT;
|
|
||||||
call<ThisArg, Args extends any[], RetT>(this: (this: ThisArg, ...args: Args) => RetT, thisArg: ThisArg, ...argArray: Args): RetT;
|
|
||||||
bind<ThisArg, Args extends any[], Rest extends any[], RetT>(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<Args extends any[], RetT>(this: new (...args: Args) => RetT, thisArg: any, argArray?: Args): RetT;
|
|
||||||
call<Args extends any[], RetT>(this: new (...args: Args) => RetT, thisArg: any, ...argArray: Args): RetT;
|
|
||||||
bind<Args extends any[], RetT>(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.';
|
throw 'Using the constructor Function() is forbidden.';
|
||||||
} as unknown as FunctionConstructor;
|
} as unknown as FunctionConstructor;
|
||||||
|
|
||||||
Function.prototype = (Function as any).__proto__ as Function;
|
env.setProto('function', Function.prototype);
|
||||||
setConstr(Function.prototype, Function);
|
setConstr(Function.prototype, Function);
|
||||||
|
|
||||||
setProps(Function.prototype, {
|
setProps(Function.prototype, {
|
||||||
apply(thisArg, args) {
|
apply(thisArg, args) {
|
||||||
if (typeof args !== 'object') throw 'Expected arguments to be an array-like object.';
|
if (typeof args !== 'object') throw 'Expected arguments to be an array-like object.';
|
||||||
var len = args.length - 0;
|
var len = args.length - 0;
|
||||||
let newArgs: any[];
|
let newArgs: any[];
|
||||||
if (Array.isArray(args)) newArgs = args;
|
if (internals.isArray(args)) newArgs = args;
|
||||||
else {
|
else {
|
||||||
newArgs = [];
|
newArgs = [];
|
||||||
|
|
||||||
@ -68,15 +27,14 @@ setProps(Function.prototype, {
|
|||||||
return this.apply(thisArg, args);
|
return this.apply(thisArg, args);
|
||||||
},
|
},
|
||||||
bind(thisArg, ...args) {
|
bind(thisArg, ...args) {
|
||||||
var func = this;
|
const func = this;
|
||||||
|
const res = function() {
|
||||||
|
const resArgs = [];
|
||||||
|
|
||||||
var res = function() {
|
for (let i = 0; i < args.length; i++) {
|
||||||
var resArgs = [];
|
|
||||||
|
|
||||||
for (var i = 0; i < args.length; i++) {
|
|
||||||
resArgs[i] = args[i];
|
resArgs[i] = args[i];
|
||||||
}
|
}
|
||||||
for (var i = 0; i < arguments.length; i++) {
|
for (let i = 0; i < arguments.length; i++) {
|
||||||
resArgs[i + args.length] = arguments[i];
|
resArgs[i + args.length] = arguments[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,8 +46,8 @@ setProps(Function.prototype, {
|
|||||||
toString() {
|
toString() {
|
||||||
return 'function (...) { ... }';
|
return 'function (...) { ... }';
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
setProps(Function, {
|
setProps(Function, {
|
||||||
async(func) {
|
async(func) {
|
||||||
if (typeof func !== 'function') throw new TypeError('Expected func to be function.');
|
if (typeof func !== 'function') throw new TypeError('Expected func to be function.');
|
||||||
|
|
||||||
@ -97,7 +55,7 @@ setProps(Function, {
|
|||||||
const args = arguments;
|
const args = arguments;
|
||||||
|
|
||||||
return new Promise((res, rej) => {
|
return new Promise((res, rej) => {
|
||||||
const gen = Function.generator(func as any).apply(this, args as any);
|
const gen = internals.apply(internals.generator(func as any), this, args as any);
|
||||||
|
|
||||||
(function next(type: 'none' | 'err' | 'ret', val?: any) {
|
(function next(type: 'none' | 'err' | 'ret', val?: any) {
|
||||||
try {
|
try {
|
||||||
@ -124,12 +82,11 @@ setProps(Function, {
|
|||||||
asyncGenerator(func) {
|
asyncGenerator(func) {
|
||||||
if (typeof func !== 'function') throw new TypeError('Expected func to be function.');
|
if (typeof func !== 'function') throw new TypeError('Expected func to be function.');
|
||||||
|
|
||||||
|
return function(this: any, ...args: any[]) {
|
||||||
return function(this: any) {
|
const gen = internals.apply(internals.generator((_yield) => func(
|
||||||
const gen = Function.generator<any[], ['await' | 'yield', any]>((_yield) => func(
|
|
||||||
val => _yield(['await', val]) as any,
|
val => _yield(['await', val]) as any,
|
||||||
val => _yield(['yield', val])
|
val => _yield(['yield', val])
|
||||||
)).apply(this, arguments as any);
|
)), this, args) as Generator<['await' | 'yield', any]>;
|
||||||
|
|
||||||
const next = (resolve: Function, reject: Function, type: 'none' | 'val' | 'ret' | 'err', val?: any) => {
|
const next = (resolve: Function, reject: Function, type: 'none' | 'val' | 'ret' | 'err', val?: any) => {
|
||||||
let res;
|
let res;
|
||||||
@ -160,22 +117,24 @@ setProps(Function, {
|
|||||||
},
|
},
|
||||||
return: (value) => new Promise((res, rej) => next(res, rej, 'ret', value)),
|
return: (value) => new Promise((res, rej) => next(res, rej, 'ret', value)),
|
||||||
throw: (value) => new Promise((res, rej) => next(res, rej, 'err', value)),
|
throw: (value) => new Promise((res, rej) => next(res, rej, 'err', value)),
|
||||||
[Symbol.asyncIterator]() { return this; }
|
[env.global.Symbol.asyncIterator]() { return this; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
generator(func) {
|
generator(func) {
|
||||||
if (typeof func !== 'function') throw new TypeError('Expected func to be function.');
|
if (typeof func !== 'function') throw new TypeError('Expected func to be function.');
|
||||||
const gen = internals.makeGenerator(func);
|
const gen = internals.generator(func);
|
||||||
return (...args: any[]) => {
|
return function(this: any, ...args: any[]) {
|
||||||
const it = gen(args);
|
const it = internals.apply(gen, this, args);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
next: it.next,
|
next: (...args) => internals.apply(it.next, it, args),
|
||||||
return: it.return,
|
return: (val) => internals.apply(it.next, it, [val]),
|
||||||
throw: it.throw,
|
throw: (val) => internals.apply(it.next, it, [val]),
|
||||||
[Symbol.iterator]() { return this; }
|
[env.global.Symbol.iterator]() { return this; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
internals.markSpecial(Function);
|
||||||
|
});
|
@ -1,34 +1,16 @@
|
|||||||
interface Number {
|
define("values/number", () => {
|
||||||
toString(): string;
|
var Number = env.global.Number = function(this: Number | undefined, arg: any) {
|
||||||
valueOf(): number;
|
|
||||||
constructor: NumberConstructor;
|
|
||||||
}
|
|
||||||
interface NumberConstructor {
|
|
||||||
(val: any): number;
|
|
||||||
new (val: any): Number;
|
|
||||||
prototype: Number;
|
|
||||||
parseInt(val: unknown): number;
|
|
||||||
parseFloat(val: unknown): number;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare var Number: NumberConstructor;
|
|
||||||
declare var parseInt: typeof Number.parseInt;
|
|
||||||
declare var parseFloat: typeof Number.parseFloat;
|
|
||||||
declare var NaN: number;
|
|
||||||
declare var Infinity: number;
|
|
||||||
|
|
||||||
gt.Number = function(this: Number | undefined, arg: any) {
|
|
||||||
var val;
|
var val;
|
||||||
if (arguments.length === 0) val = 0;
|
if (arguments.length === 0) val = 0;
|
||||||
else val = arg - 0;
|
else val = arg - 0;
|
||||||
if (this === undefined || this === null) return val;
|
if (this === undefined || this === null) return val;
|
||||||
else (this as any).value = val;
|
else (this as any).value = val;
|
||||||
} as NumberConstructor;
|
} as NumberConstructor;
|
||||||
|
|
||||||
Number.prototype = (0 as any).__proto__ as Number;
|
env.setProto('number', Number.prototype);
|
||||||
setConstr(Number.prototype, Number);
|
setConstr(Number.prototype, Number);
|
||||||
|
|
||||||
setProps(Number.prototype, {
|
setProps(Number.prototype, {
|
||||||
valueOf() {
|
valueOf() {
|
||||||
if (typeof this === 'number') return this;
|
if (typeof this === 'number') return this;
|
||||||
else return (this as any).value;
|
else return (this as any).value;
|
||||||
@ -37,14 +19,15 @@ setProps(Number.prototype, {
|
|||||||
if (typeof this === 'number') return this + '';
|
if (typeof this === 'number') return this + '';
|
||||||
else return (this as any).value + '';
|
else return (this as any).value + '';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setProps(Number, {
|
setProps(Number, {
|
||||||
parseInt(val) { return Math.trunc(Number.parseFloat(val)); },
|
parseInt(val) { return Math.trunc(val as any - 0); },
|
||||||
parseFloat(val) { return internals.parseFloat(val); },
|
parseFloat(val) { return val as any - 0; },
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.defineProperty(gt, 'parseInt', { value: Number.parseInt, writable: false });
|
env.global.parseInt = Number.parseInt;
|
||||||
Object.defineProperty(gt, 'parseFloat', { value: Number.parseFloat, writable: false });
|
env.global.parseFloat = Number.parseFloat;
|
||||||
Object.defineProperty(gt, 'NaN', { value: 0 / 0, writable: false });
|
env.global.Object.defineProperty(env.global, 'NaN', { value: 0 / 0, writable: false });
|
||||||
Object.defineProperty(gt, 'Infinity', { value: 1 / 0, writable: false });
|
env.global.Object.defineProperty(env.global, 'Infinity', { value: 1 / 0, writable: false });
|
||||||
|
});
|
@ -1,84 +1,27 @@
|
|||||||
interface Object {
|
define("values/object", () => {
|
||||||
constructor: NewableFunction;
|
var Object = env.global.Object = function(arg: any) {
|
||||||
[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): {};
|
|
||||||
<T extends object>(arg: T): T;
|
|
||||||
|
|
||||||
new (arg: string): String;
|
|
||||||
new (arg: number): Number;
|
|
||||||
new (arg: boolean): Boolean;
|
|
||||||
new (arg?: undefined | null): {};
|
|
||||||
new <T extends object>(arg: T): T;
|
|
||||||
|
|
||||||
prototype: Object;
|
|
||||||
|
|
||||||
assign<T extends object>(target: T, ...src: object[]): T;
|
|
||||||
create<T extends object>(proto: T, props?: { [key: string]: PropertyDescriptor<any, T> }): T;
|
|
||||||
|
|
||||||
keys<T extends object>(obj: T, onlyString?: true): (keyof T)[];
|
|
||||||
keys<T extends object>(obj: T, onlyString: false): any[];
|
|
||||||
entries<T extends object>(obj: T, onlyString?: true): [keyof T, T[keyof T]][];
|
|
||||||
entries<T extends object>(obj: T, onlyString: false): [any, any][];
|
|
||||||
values<T extends object>(obj: T, onlyString?: true): (T[keyof T])[];
|
|
||||||
values<T extends object>(obj: T, onlyString: false): any[];
|
|
||||||
|
|
||||||
fromEntries(entries: Iterable<[any, any]>): object;
|
|
||||||
|
|
||||||
defineProperty<T, ThisT extends object>(obj: ThisT, key: any, desc: PropertyDescriptor<T, ThisT>): ThisT;
|
|
||||||
defineProperties<ThisT extends object>(obj: ThisT, desc: { [key: string]: PropertyDescriptor<any, ThisT> }): ThisT;
|
|
||||||
|
|
||||||
getOwnPropertyNames<T extends object>(obj: T): (keyof T)[];
|
|
||||||
getOwnPropertySymbols<T extends object>(obj: T): (keyof T)[];
|
|
||||||
hasOwn<T extends object, KeyT>(obj: T, key: KeyT): boolean;
|
|
||||||
|
|
||||||
getOwnPropertyDescriptor<T extends object, KeyT extends keyof T>(obj: T, key: KeyT): PropertyDescriptor<T[KeyT], T>;
|
|
||||||
getOwnPropertyDescriptors<T extends object>(obj: T): { [x in keyof T]: PropertyDescriptor<T[x], T> };
|
|
||||||
|
|
||||||
getPrototypeOf(obj: any): object | null;
|
|
||||||
setPrototypeOf<T>(obj: T, proto: object | null): T;
|
|
||||||
|
|
||||||
preventExtensions<T extends object>(obj: T): T;
|
|
||||||
seal<T extends object>(obj: T): T;
|
|
||||||
freeze<T extends object>(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 {};
|
if (arg === undefined || arg === null) return {};
|
||||||
else if (typeof arg === 'boolean') return new Boolean(arg);
|
else if (typeof arg === 'boolean') return new Boolean(arg);
|
||||||
else if (typeof arg === 'number') return new Number(arg);
|
else if (typeof arg === 'number') return new Number(arg);
|
||||||
else if (typeof arg === 'string') return new String(arg);
|
else if (typeof arg === 'string') return new String(arg);
|
||||||
return arg;
|
return arg;
|
||||||
} as ObjectConstructor;
|
} as ObjectConstructor;
|
||||||
|
|
||||||
Object.prototype = ({} as any).__proto__ as Object;
|
env.setProto('object', Object.prototype);
|
||||||
setConstr(Object.prototype, Object as any);
|
(Object.prototype as any).__proto__ = null;
|
||||||
|
setConstr(Object.prototype, Object as any);
|
||||||
|
|
||||||
function throwNotObject(obj: any, name: string) {
|
function throwNotObject(obj: any, name: string) {
|
||||||
if (obj === null || typeof obj !== 'object' && typeof obj !== 'function') {
|
if (obj === null || typeof obj !== 'object' && typeof obj !== 'function') {
|
||||||
throw new TypeError(`Object.${name} may only be used for objects.`);
|
throw new TypeError(`Object.${name} may only be used for objects.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function check(obj: any) {
|
function check(obj: any) {
|
||||||
return typeof obj === 'object' && obj !== null || typeof obj === 'function';
|
return typeof obj === 'object' && obj !== null || typeof obj === 'function';
|
||||||
}
|
}
|
||||||
|
|
||||||
setProps(Object, {
|
setProps(Object, {
|
||||||
assign: function(dst, ...src) {
|
assign(dst, ...src) {
|
||||||
throwNotObject(dst, 'assign');
|
throwNotObject(dst, 'assign');
|
||||||
for (let i = 0; i < src.length; i++) {
|
for (let i = 0; i < src.length; i++) {
|
||||||
const obj = src[i];
|
const obj = src[i];
|
||||||
@ -135,35 +78,72 @@ setProps(Object, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
keys(obj, onlyString) {
|
keys(obj, onlyString) {
|
||||||
onlyString = !!(onlyString ?? true);
|
return internals.keys(obj, !!(onlyString ?? true));
|
||||||
return internals.keys(obj, onlyString);
|
|
||||||
},
|
},
|
||||||
entries(obj, onlyString) {
|
entries(obj, onlyString) {
|
||||||
return Object.keys(obj, onlyString).map(v => [ v, (obj as any)[v] ]);
|
const res = [];
|
||||||
|
const keys = internals.keys(obj, !!(onlyString ?? true));
|
||||||
|
|
||||||
|
for (let i = 0; i < keys.length; i++) {
|
||||||
|
res[i] = [ keys[i], (obj as any)[keys[i]] ];
|
||||||
|
}
|
||||||
|
|
||||||
|
return keys;
|
||||||
},
|
},
|
||||||
values(obj, onlyString) {
|
values(obj, onlyString) {
|
||||||
return Object.keys(obj, onlyString).map(v => (obj as any)[v]);
|
const res = [];
|
||||||
|
const keys = internals.keys(obj, !!(onlyString ?? true));
|
||||||
|
|
||||||
|
for (let i = 0; i < keys.length; i++) {
|
||||||
|
res[i] = (obj as any)[keys[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return keys;
|
||||||
},
|
},
|
||||||
|
|
||||||
getOwnPropertyDescriptor(obj, key) {
|
getOwnPropertyDescriptor(obj, key) {
|
||||||
return internals.ownProp(obj, key);
|
return internals.ownProp(obj, key) as any;
|
||||||
},
|
},
|
||||||
getOwnPropertyDescriptors(obj) {
|
getOwnPropertyDescriptors(obj) {
|
||||||
return Object.fromEntries([
|
const res = [];
|
||||||
...Object.getOwnPropertyNames(obj),
|
const keys = internals.ownPropKeys(obj);
|
||||||
...Object.getOwnPropertySymbols(obj)
|
|
||||||
].map(v => [ v, Object.getOwnPropertyDescriptor(obj, v) ])) as any;
|
for (let i = 0; i < keys.length; i++) {
|
||||||
|
res[i] = internals.ownProp(obj, keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
},
|
},
|
||||||
|
|
||||||
getOwnPropertyNames(obj) {
|
getOwnPropertyNames(obj) {
|
||||||
return internals.ownPropKeys(obj, false);
|
const arr = internals.ownPropKeys(obj);
|
||||||
|
const res = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
if (typeof arr[i] === 'symbol') continue;
|
||||||
|
res[res.length] = arr[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return res as any;
|
||||||
},
|
},
|
||||||
getOwnPropertySymbols(obj) {
|
getOwnPropertySymbols(obj) {
|
||||||
return internals.ownPropKeys(obj, true);
|
const arr = internals.ownPropKeys(obj);
|
||||||
|
const res = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
if (typeof arr[i] !== 'symbol') continue;
|
||||||
|
res[res.length] = arr[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return res as any;
|
||||||
},
|
},
|
||||||
hasOwn(obj, key) {
|
hasOwn(obj, key) {
|
||||||
if (Object.getOwnPropertyNames(obj).includes(key)) return true;
|
const keys = internals.ownPropKeys(obj);
|
||||||
if (Object.getOwnPropertySymbols(obj).includes(key)) return true;
|
|
||||||
|
for (let i = 0; i < keys.length; i++) {
|
||||||
|
if (keys[i] === key) return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -187,17 +167,17 @@ setProps(Object, {
|
|||||||
|
|
||||||
preventExtensions(obj) {
|
preventExtensions(obj) {
|
||||||
throwNotObject(obj, 'preventExtensions');
|
throwNotObject(obj, 'preventExtensions');
|
||||||
internals.preventExtensions(obj);
|
internals.lock(obj, 'ext');
|
||||||
return obj;
|
return obj;
|
||||||
},
|
},
|
||||||
seal(obj) {
|
seal(obj) {
|
||||||
throwNotObject(obj, 'seal');
|
throwNotObject(obj, 'seal');
|
||||||
internals.seal(obj);
|
internals.lock(obj, 'seal');
|
||||||
return obj;
|
return obj;
|
||||||
},
|
},
|
||||||
freeze(obj) {
|
freeze(obj) {
|
||||||
throwNotObject(obj, 'freeze');
|
throwNotObject(obj, 'freeze');
|
||||||
internals.freeze(obj);
|
internals.lock(obj, 'freeze');
|
||||||
return obj;
|
return obj;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -207,28 +187,40 @@ setProps(Object, {
|
|||||||
},
|
},
|
||||||
isSealed(obj) {
|
isSealed(obj) {
|
||||||
if (!check(obj)) return true;
|
if (!check(obj)) return true;
|
||||||
if (Object.isExtensible(obj)) return false;
|
if (internals.extensible(obj)) return false;
|
||||||
return Object.getOwnPropertyNames(obj).every(v => !Object.getOwnPropertyDescriptor(obj, v).configurable);
|
const keys = internals.ownPropKeys(obj);
|
||||||
|
|
||||||
|
for (let i = 0; i < keys.length; i++) {
|
||||||
|
if (internals.ownProp(obj, keys[i]).configurable) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
isFrozen(obj) {
|
isFrozen(obj) {
|
||||||
if (!check(obj)) return true;
|
if (!check(obj)) return true;
|
||||||
if (Object.isExtensible(obj)) return false;
|
if (internals.extensible(obj)) return false;
|
||||||
return Object.getOwnPropertyNames(obj).every(v => {
|
const keys = internals.ownPropKeys(obj);
|
||||||
var prop = Object.getOwnPropertyDescriptor(obj, v);
|
|
||||||
if ('writable' in prop && prop.writable) return false;
|
|
||||||
return !prop.configurable;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setProps(Object.prototype, {
|
for (let i = 0; i < keys.length; i++) {
|
||||||
|
const prop = internals.ownProp(obj, keys[i]);
|
||||||
|
if (prop.configurable) return false;
|
||||||
|
if ('writable' in prop && prop.writable) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setProps(Object.prototype, {
|
||||||
valueOf() {
|
valueOf() {
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
toString() {
|
toString() {
|
||||||
return '[object ' + (this[Symbol.typeName] ?? 'Unknown') + ']';
|
return '[object ' + (this[env.global.Symbol.typeName] ?? 'Unknown') + ']';
|
||||||
},
|
},
|
||||||
hasOwnProperty(key) {
|
hasOwnProperty(key) {
|
||||||
return Object.hasOwn(this, key);
|
return Object.hasOwn(this, key);
|
||||||
},
|
},
|
||||||
|
});
|
||||||
|
internals.markSpecial(Object);
|
||||||
});
|
});
|
@ -1,68 +1,16 @@
|
|||||||
interface Replacer {
|
define("values/string", () => {
|
||||||
[Symbol.replace](target: string, val: string | ((match: string, ...args: any[]) => string)): string;
|
var String = env.global.String = function(this: String | undefined, arg: any) {
|
||||||
}
|
|
||||||
|
|
||||||
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): string;
|
|
||||||
replaceAll(pattern: string | Replacer, val: string): string;
|
|
||||||
|
|
||||||
match(pattern: string | Matcher): RegExpResult | string[] | null;
|
|
||||||
matchAll(pattern: string | Matcher): IterableIterator<RegExpResult>;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare var String: StringConstructor;
|
|
||||||
|
|
||||||
gt.String = function(this: String | undefined, arg: any) {
|
|
||||||
var val;
|
var val;
|
||||||
if (arguments.length === 0) val = '';
|
if (arguments.length === 0) val = '';
|
||||||
else val = arg + '';
|
else val = arg + '';
|
||||||
if (this === undefined || this === null) return val;
|
if (this === undefined || this === null) return val;
|
||||||
else (this as any).value = val;
|
else (this as any).value = val;
|
||||||
} as StringConstructor;
|
} as StringConstructor;
|
||||||
|
|
||||||
String.prototype = ('' as any).__proto__ as String;
|
env.setProto('string', String.prototype);
|
||||||
setConstr(String.prototype, String);
|
setConstr(String.prototype, String);
|
||||||
|
|
||||||
setProps(String.prototype, {
|
setProps(String.prototype, {
|
||||||
toString() {
|
toString() {
|
||||||
if (typeof this === 'string') return this;
|
if (typeof this === 'string') return this;
|
||||||
else return (this as any).value;
|
else return (this as any).value;
|
||||||
@ -79,7 +27,14 @@ setProps(String.prototype, {
|
|||||||
}
|
}
|
||||||
start = start ?? 0 | 0;
|
start = start ?? 0 | 0;
|
||||||
end = (end ?? this.length) | 0;
|
end = (end ?? this.length) | 0;
|
||||||
return internals.substring(this, start, end);
|
|
||||||
|
const res = [];
|
||||||
|
|
||||||
|
for (let i = start; i < end; i++) {
|
||||||
|
if (i >= 0 && i < this.length) res[res.length] = this[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return internals.stringFromStrings(res);
|
||||||
},
|
},
|
||||||
substr(start, length) {
|
substr(start, length) {
|
||||||
start = start ?? 0 | 0;
|
start = start ?? 0 | 0;
|
||||||
@ -88,14 +43,41 @@ setProps(String.prototype, {
|
|||||||
if (start < 0) start = 0;
|
if (start < 0) start = 0;
|
||||||
|
|
||||||
length = (length ?? this.length - start) | 0;
|
length = (length ?? this.length - start) | 0;
|
||||||
return this.substring(start, length + start);
|
const end = length + start;
|
||||||
|
const res = [];
|
||||||
|
|
||||||
|
for (let i = start; i < end; i++) {
|
||||||
|
if (i >= 0 && i < this.length) res[res.length] = this[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return internals.stringFromStrings(res);
|
||||||
},
|
},
|
||||||
|
|
||||||
toLowerCase() {
|
toLowerCase() {
|
||||||
return internals.toLower(this + '');
|
// TODO: Implement localization
|
||||||
|
const res = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < this.length; i++) {
|
||||||
|
const c = internals.char(this[i]);
|
||||||
|
|
||||||
|
if (c >= 65 && c <= 90) res[i] = c - 65 + 97;
|
||||||
|
else res[i] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return internals.stringFromChars(res);
|
||||||
},
|
},
|
||||||
toUpperCase() {
|
toUpperCase() {
|
||||||
return internals.toUpper(this + '');
|
// TODO: Implement localization
|
||||||
|
const res = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < this.length; i++) {
|
||||||
|
const c = internals.char(this[i]);
|
||||||
|
|
||||||
|
if (c >= 97 && c <= 122) res[i] = c - 97 + 65;
|
||||||
|
else res[i] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return internals.stringFromChars(res);
|
||||||
},
|
},
|
||||||
|
|
||||||
charAt(pos) {
|
charAt(pos) {
|
||||||
@ -109,9 +91,14 @@ setProps(String.prototype, {
|
|||||||
return this[pos];
|
return this[pos];
|
||||||
},
|
},
|
||||||
charCodeAt(pos) {
|
charCodeAt(pos) {
|
||||||
var res = this.charAt(pos);
|
if (typeof this !== 'string') {
|
||||||
if (res === '') return NaN;
|
if (this instanceof String) return (this as any).value.charAt(pos);
|
||||||
else return internals.toCharCode(res);
|
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 0 / 0;
|
||||||
|
return internals.char(this[pos]);
|
||||||
},
|
},
|
||||||
|
|
||||||
startsWith(term, pos) {
|
startsWith(term, pos) {
|
||||||
@ -120,7 +107,15 @@ setProps(String.prototype, {
|
|||||||
else throw new Error('This function may be used only with primitive or object strings.');
|
else throw new Error('This function may be used only with primitive or object strings.');
|
||||||
}
|
}
|
||||||
pos = pos! | 0;
|
pos = pos! | 0;
|
||||||
return internals.startsWith(this, term + '', pos);
|
term = term + "";
|
||||||
|
|
||||||
|
if (pos < 0 || this.length < term.length + pos) return false;
|
||||||
|
|
||||||
|
for (let i = 0; i < term.length; i++) {
|
||||||
|
if (this[i + pos] !== term[i]) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
endsWith(term, pos) {
|
endsWith(term, pos) {
|
||||||
if (typeof this !== 'string') {
|
if (typeof this !== 'string') {
|
||||||
@ -128,7 +123,17 @@ setProps(String.prototype, {
|
|||||||
else throw new Error('This function may be used only with primitive or object strings.');
|
else throw new Error('This function may be used only with primitive or object strings.');
|
||||||
}
|
}
|
||||||
pos = (pos ?? this.length) | 0;
|
pos = (pos ?? this.length) | 0;
|
||||||
return internals.endsWith(this, term + '', pos);
|
term = term + "";
|
||||||
|
|
||||||
|
const start = pos - term.length;
|
||||||
|
|
||||||
|
if (start < 0 || this.length < term.length + start) return false;
|
||||||
|
|
||||||
|
for (let i = 0; i < term.length; i++) {
|
||||||
|
if (this[i + start] !== term[i]) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
indexOf(term: any, start) {
|
indexOf(term: any, start) {
|
||||||
@ -137,9 +142,9 @@ setProps(String.prototype, {
|
|||||||
else throw new Error('This function may be used only with primitive or object strings.');
|
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);
|
if (typeof term[env.global.Symbol.search] !== 'function') term = RegExp.escape(term);
|
||||||
|
|
||||||
return term[Symbol.search](this, false, start);
|
return term[env.global.Symbol.search](this, false, start);
|
||||||
},
|
},
|
||||||
lastIndexOf(term: any, start) {
|
lastIndexOf(term: any, start) {
|
||||||
if (typeof this !== 'string') {
|
if (typeof this !== 'string') {
|
||||||
@ -147,9 +152,9 @@ setProps(String.prototype, {
|
|||||||
else throw new Error('This function may be used only with primitive or object strings.');
|
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);
|
if (typeof term[env.global.Symbol.search] !== 'function') term = RegExp.escape(term);
|
||||||
|
|
||||||
return term[Symbol.search](this, true, start);
|
return term[env.global.Symbol.search](this, true, start);
|
||||||
},
|
},
|
||||||
includes(term, start) {
|
includes(term, start) {
|
||||||
return this.indexOf(term, start) >= 0;
|
return this.indexOf(term, start) >= 0;
|
||||||
@ -161,9 +166,9 @@ setProps(String.prototype, {
|
|||||||
else throw new Error('This function may be used only with primitive or object strings.');
|
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);
|
if (typeof pattern[env.global.Symbol.replace] !== 'function') pattern = RegExp.escape(pattern);
|
||||||
|
|
||||||
return pattern[Symbol.replace](this, val);
|
return pattern[env.global.Symbol.replace](this, val);
|
||||||
},
|
},
|
||||||
replaceAll(pattern: any, val) {
|
replaceAll(pattern: any, val) {
|
||||||
if (typeof this !== 'string') {
|
if (typeof this !== 'string') {
|
||||||
@ -171,10 +176,10 @@ setProps(String.prototype, {
|
|||||||
else throw new Error('This function may be used only with primitive or object strings.');
|
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 (typeof pattern[env.global.Symbol.replace] !== 'function') pattern = RegExp.escape(pattern, "g");
|
||||||
if (pattern instanceof RegExp && !pattern.global) pattern = new pattern.constructor(pattern.source, pattern.flags + "g");
|
if (pattern instanceof RegExp && !pattern.global) pattern = new pattern.constructor(pattern.source, pattern.flags + "g");
|
||||||
|
|
||||||
return pattern[Symbol.replace](this, val);
|
return pattern[env.global.Symbol.replace](this, val);
|
||||||
},
|
},
|
||||||
|
|
||||||
match(pattern: any) {
|
match(pattern: any) {
|
||||||
@ -183,9 +188,9 @@ setProps(String.prototype, {
|
|||||||
else throw new Error('This function may be used only with primitive or object strings.');
|
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);
|
if (typeof pattern[env.global.Symbol.match] !== 'function') pattern = RegExp.escape(pattern);
|
||||||
|
|
||||||
return pattern[Symbol.match](this);
|
return pattern[env.global.Symbol.match](this);
|
||||||
},
|
},
|
||||||
matchAll(pattern: any) {
|
matchAll(pattern: any) {
|
||||||
if (typeof this !== 'string') {
|
if (typeof this !== 'string') {
|
||||||
@ -193,10 +198,10 @@ setProps(String.prototype, {
|
|||||||
else throw new Error('This function may be used only with primitive or object strings.');
|
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 (typeof pattern[env.global.Symbol.match] !== 'function') pattern = RegExp.escape(pattern, "g");
|
||||||
if (pattern instanceof RegExp && !pattern.global) pattern = new pattern.constructor(pattern.source, pattern.flags + "g");
|
if (pattern instanceof RegExp && !pattern.global) pattern = new pattern.constructor(pattern.source, pattern.flags + "g");
|
||||||
|
|
||||||
return pattern[Symbol.match](this);
|
return pattern[env.global.Symbol.match](this);
|
||||||
},
|
},
|
||||||
|
|
||||||
split(pattern: any, lim, sensible) {
|
split(pattern: any, lim, sensible) {
|
||||||
@ -205,9 +210,9 @@ setProps(String.prototype, {
|
|||||||
else throw new Error('This function may be used only with primitive or object strings.');
|
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");
|
if (typeof pattern[env.global.Symbol.split] !== 'function') pattern = RegExp.escape(pattern, "g");
|
||||||
|
|
||||||
return pattern[Symbol.split](this, lim, sensible);
|
return pattern[env.global.Symbol.split](this, lim, sensible);
|
||||||
},
|
},
|
||||||
slice(start, end) {
|
slice(start, end) {
|
||||||
if (typeof this !== 'string') {
|
if (typeof this !== 'string') {
|
||||||
@ -239,15 +244,15 @@ setProps(String.prototype, {
|
|||||||
.replace(/^\s+/g, '')
|
.replace(/^\s+/g, '')
|
||||||
.replace(/\s+$/g, '');
|
.replace(/\s+$/g, '');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setProps(String, {
|
setProps(String, {
|
||||||
fromCharCode(val) {
|
fromCharCode(val) {
|
||||||
return internals.fromCharCode(val | 0);
|
return internals.stringFromChars([val | 0]);
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
Object.defineProperty(String.prototype, 'length', {
|
env.global.Object.defineProperty(String.prototype, 'length', {
|
||||||
get() {
|
get() {
|
||||||
if (typeof this !== 'string') {
|
if (typeof this !== 'string') {
|
||||||
if (this instanceof String) return (this as any).value.length;
|
if (this instanceof String) return (this as any).value.length;
|
||||||
@ -258,4 +263,5 @@ Object.defineProperty(String.prototype, 'length', {
|
|||||||
},
|
},
|
||||||
configurable: true,
|
configurable: true,
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
|
});
|
||||||
});
|
});
|
@ -1,38 +1,36 @@
|
|||||||
interface Symbol {
|
define("values/symbol", () => {
|
||||||
valueOf(): symbol;
|
const symbols: Record<string, symbol> = { };
|
||||||
constructor: SymbolConstructor;
|
|
||||||
}
|
|
||||||
interface SymbolConstructor {
|
|
||||||
(val?: any): symbol;
|
|
||||||
prototype: Symbol;
|
|
||||||
for(key: string): symbol;
|
|
||||||
keyFor(sym: symbol): string;
|
|
||||||
readonly typeName: unique symbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare var Symbol: SymbolConstructor;
|
var Symbol = env.global.Symbol = function(this: any, val?: string) {
|
||||||
|
|
||||||
gt.Symbol = function(this: any, val?: string) {
|
|
||||||
if (this !== undefined && this !== null) throw new TypeError("Symbol may not be called with 'new'.");
|
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.');
|
if (typeof val !== 'string' && val !== undefined) throw new TypeError('val must be a string or undefined.');
|
||||||
return internals.symbol(val, true);
|
return internals.symbol(val);
|
||||||
} as SymbolConstructor;
|
} as SymbolConstructor;
|
||||||
|
|
||||||
Symbol.prototype = internals.symbolProto;
|
env.setProto('symbol', Symbol.prototype);
|
||||||
setConstr(Symbol.prototype, Symbol);
|
setConstr(Symbol.prototype, Symbol);
|
||||||
(Symbol as any).typeName = Symbol("Symbol.name");
|
|
||||||
|
|
||||||
setProps(Symbol, {
|
setProps(Symbol, {
|
||||||
for(key) {
|
for(key) {
|
||||||
if (typeof key !== 'string' && key !== undefined) throw new TypeError('key must be a string or undefined.');
|
if (typeof key !== 'string' && key !== undefined) throw new TypeError('key must be a string or undefined.');
|
||||||
return internals.symbol(key, false);
|
if (key in symbols) return symbols[key];
|
||||||
|
else return symbols[key] = internals.symbol(key);
|
||||||
},
|
},
|
||||||
keyFor(sym) {
|
keyFor(sym) {
|
||||||
if (typeof sym !== 'symbol') throw new TypeError('sym must be a symbol.');
|
if (typeof sym !== 'symbol') throw new TypeError('sym must be a symbol.');
|
||||||
return internals.symStr(sym);
|
return internals.symbolToString(sym);
|
||||||
},
|
},
|
||||||
typeName: Symbol('Symbol.name') as any,
|
|
||||||
});
|
|
||||||
|
|
||||||
Object.defineProperty(Object.prototype, Symbol.typeName, { value: 'Object' });
|
typeName: Symbol("Symbol.name") as any,
|
||||||
Object.defineProperty(gt, Symbol.typeName, { value: 'Window' });
|
replace: Symbol('Symbol.replace') as any,
|
||||||
|
match: Symbol('Symbol.match') as any,
|
||||||
|
matchAll: Symbol('Symbol.matchAll') as any,
|
||||||
|
split: Symbol('Symbol.split') as any,
|
||||||
|
search: Symbol('Symbol.search') as any,
|
||||||
|
iterator: Symbol('Symbol.iterator') as any,
|
||||||
|
asyncIterator: Symbol('Symbol.asyncIterator') as any,
|
||||||
|
});
|
||||||
|
|
||||||
|
internals.defineField(env.global.Object.prototype, Symbol.typeName, 'Object', false, false, false);
|
||||||
|
internals.defineField(env.global, Symbol.typeName, 'Window', false, false, false);
|
||||||
|
});
|
6
package-lock.json
generated
Normal file
6
package-lock.json
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"name": "java-jscript",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {}
|
||||||
|
}
|
1
package.json
Normal file
1
package.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{}
|
@ -1,38 +1,64 @@
|
|||||||
package me.topchetoeu.jscript;
|
package me.topchetoeu.jscript;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.engine.MessageContext;
|
||||||
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.Engine;
|
import me.topchetoeu.jscript.engine.Engine;
|
||||||
|
import me.topchetoeu.jscript.engine.FunctionContext;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
import me.topchetoeu.jscript.events.Observer;
|
import me.topchetoeu.jscript.events.Observer;
|
||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.exceptions.SyntaxException;
|
import me.topchetoeu.jscript.exceptions.SyntaxException;
|
||||||
import me.topchetoeu.jscript.polyfills.PolyfillEngine;
|
import me.topchetoeu.jscript.interop.NativeTypeRegister;
|
||||||
import me.topchetoeu.jscript.polyfills.TypescriptEngine;
|
import me.topchetoeu.jscript.polyfills.Internals;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
static Thread task;
|
static Thread task;
|
||||||
static Engine engine;
|
static Engine engine;
|
||||||
|
static FunctionContext env;
|
||||||
|
|
||||||
|
public static String streamToString(InputStream in) {
|
||||||
|
try {
|
||||||
|
StringBuilder out = new StringBuilder();
|
||||||
|
BufferedReader br = new BufferedReader(new InputStreamReader(in));
|
||||||
|
|
||||||
|
for(var line = br.readLine(); line != null; line = br.readLine()) {
|
||||||
|
out.append(line).append('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
br.close();
|
||||||
|
return out.toString();
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static String resourceToString(String name) {
|
||||||
|
var str = Main.class.getResourceAsStream("/me/topchetoeu/jscript/" + name);
|
||||||
|
if (str == null) return null;
|
||||||
|
return streamToString(str);
|
||||||
|
}
|
||||||
|
|
||||||
private static Observer<Object> valuePrinter = new Observer<Object>() {
|
private static Observer<Object> valuePrinter = new Observer<Object>() {
|
||||||
public void next(Object data) {
|
public void next(Object data) {
|
||||||
try {
|
try {
|
||||||
Values.printValue(engine.context(), data);
|
Values.printValue(null, data);
|
||||||
}
|
}
|
||||||
catch (InterruptedException e) { }
|
catch (InterruptedException e) { }
|
||||||
System.out.println();
|
System.out.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void error(RuntimeException err) {
|
public void error(RuntimeException err) {
|
||||||
|
try {
|
||||||
try {
|
try {
|
||||||
if (err instanceof EngineException) {
|
if (err instanceof EngineException) {
|
||||||
System.out.println("Uncaught " + ((EngineException)err).toString(engine.context()));
|
System.out.println("Uncaught " + ((EngineException)err).toString(new Context(null, new MessageContext(engine))));
|
||||||
}
|
}
|
||||||
else if (err instanceof SyntaxException) {
|
else if (err instanceof SyntaxException) {
|
||||||
System.out.println("Syntax error:" + ((SyntaxException)err).msg);
|
System.out.println("Syntax error:" + ((SyntaxException)err).msg);
|
||||||
@ -44,7 +70,10 @@ public class Main {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (EngineException ex) {
|
catch (EngineException ex) {
|
||||||
System.out.println("Uncaught [error while converting to string]");
|
System.out.println("Uncaught ");
|
||||||
|
Values.printValue(null, ((EngineException)err).value);
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (InterruptedException ex) {
|
catch (InterruptedException ex) {
|
||||||
return;
|
return;
|
||||||
@ -53,19 +82,21 @@ public class Main {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
|
System.out.println(String.format("Running %s v%s by %s", Metadata.NAME, Metadata.VERSION, Metadata.AUTHOR));
|
||||||
var in = new BufferedReader(new InputStreamReader(System.in));
|
var in = new BufferedReader(new InputStreamReader(System.in));
|
||||||
engine = new TypescriptEngine(new File("."));
|
engine = new Engine();
|
||||||
var scope = engine.global().globalChild();
|
env = new FunctionContext(null, null, null);
|
||||||
|
var builderEnv = new FunctionContext(null, new NativeTypeRegister(), null);
|
||||||
var exited = new boolean[1];
|
var exited = new boolean[1];
|
||||||
|
|
||||||
scope.define("exit", ctx -> {
|
env.global.define("exit", ctx -> {
|
||||||
exited[0] = true;
|
exited[0] = true;
|
||||||
task.interrupt();
|
task.interrupt();
|
||||||
throw new InterruptedException();
|
throw new InterruptedException();
|
||||||
});
|
});
|
||||||
scope.define("go", ctx -> {
|
env.global.define("go", ctx -> {
|
||||||
try {
|
try {
|
||||||
var func = engine.compile(scope, "do.js", new String(Files.readAllBytes(Path.of("do.js"))));
|
var func = ctx.compile("do.js", new String(Files.readAllBytes(Path.of("do.js"))));
|
||||||
return func.call(ctx);
|
return func.call(ctx);
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
@ -73,6 +104,8 @@ public class Main {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
engine.pushMsg(false, new Context(builderEnv, new MessageContext(engine)), "core.js", resourceToString("js/core.js"), null, env, new Internals()).toObservable().on(valuePrinter);
|
||||||
|
|
||||||
task = engine.start();
|
task = engine.start();
|
||||||
var reader = new Thread(() -> {
|
var reader = new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
@ -81,11 +114,11 @@ public class Main {
|
|||||||
var raw = in.readLine();
|
var raw = in.readLine();
|
||||||
|
|
||||||
if (raw == null) break;
|
if (raw == null) break;
|
||||||
engine.pushMsg(false, scope, Map.of(), "<stdio>", raw, null).toObservable().once(valuePrinter);
|
engine.pushMsg(false, new Context(env, new MessageContext(engine)), "<stdio>", raw, null).toObservable().once(valuePrinter);
|
||||||
}
|
}
|
||||||
catch (EngineException e) {
|
catch (EngineException e) {
|
||||||
try {
|
try {
|
||||||
System.out.println("Uncaught " + e.toString(engine.context()));
|
System.out.println("Uncaught " + e.toString(null));
|
||||||
}
|
}
|
||||||
catch (EngineException ex) {
|
catch (EngineException ex) {
|
||||||
System.out.println("Uncaught [error while converting to string]");
|
System.out.println("Uncaught [error while converting to string]");
|
||||||
|
7
src/me/topchetoeu/jscript/Metadata.java
Normal file
7
src/me/topchetoeu/jscript/Metadata.java
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package me.topchetoeu.jscript;
|
||||||
|
|
||||||
|
public class Metadata {
|
||||||
|
public static final String VERSION = "${VERSION}";
|
||||||
|
public static final String AUTHOR = "${AUTHOR}";
|
||||||
|
public static final String NAME = "${NAME}";
|
||||||
|
}
|
@ -70,7 +70,7 @@ public class CompoundStatement extends Statement {
|
|||||||
else return new CompoundStatement(loc(), res.toArray(Statement[]::new));
|
else return new CompoundStatement(loc(), res.toArray(Statement[]::new));
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompoundStatement(Location loc, Statement... statements) {
|
public CompoundStatement(Location loc, Statement ...statements) {
|
||||||
super(loc);
|
super(loc);
|
||||||
this.statements = statements;
|
this.statements = statements;
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,7 @@ public class Instruction {
|
|||||||
return params[i].equals(arg);
|
return params[i].equals(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Instruction(Location location, Type type, Object... params) {
|
private Instruction(Location location, Type type, Object ...params) {
|
||||||
this.location = location;
|
this.location = location;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.params = params;
|
this.params = params;
|
||||||
|
@ -66,9 +66,6 @@ public class SwitchStatement extends Statement {
|
|||||||
if (instr.type == Type.NOP && instr.is(0, "break") && instr.get(1) == null) {
|
if (instr.type == Type.NOP && instr.is(0, "break") && instr.get(1) == null) {
|
||||||
target.set(i, Instruction.jmp(target.size() - i).locate(instr.location));
|
target.set(i, Instruction.jmp(target.size() - i).locate(instr.location));
|
||||||
}
|
}
|
||||||
if (instr.type == Type.NOP && instr.is(0, "try_break") && instr.get(1) == null) {
|
|
||||||
target.set(i, Instruction.signal("jmp_" + (target.size() - (Integer)instr.get(2))).locate(instr.location));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (var el : caseMap.entrySet()) {
|
for (var el : caseMap.entrySet()) {
|
||||||
var loc = target.get(el.getKey()).location;
|
var loc = target.get(el.getKey()).location;
|
||||||
|
@ -49,18 +49,6 @@ public class TryStatement extends Statement {
|
|||||||
finN = target.size() - tmp;
|
finN = target.size() - tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// for (int i = start; i < target.size(); i++) {
|
|
||||||
// if (target.get(i).type == Type.NOP) {
|
|
||||||
// var instr = target.get(i);
|
|
||||||
// if (instr.is(0, "break")) {
|
|
||||||
// target.set(i, Instruction.nop("try_break", instr.get(1), target.size()).locate(instr.location));
|
|
||||||
// }
|
|
||||||
// else if (instr.is(0, "cont")) {
|
|
||||||
// target.set(i, Instruction.nop("try_cont", instr.get(1), target.size()).locate(instr.location));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
target.set(start - 1, Instruction.tryInstr(tryN, catchN, finN).locate(loc()));
|
target.set(start - 1, Instruction.tryInstr(tryN, catchN, finN).locate(loc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,14 +81,6 @@ public class WhileStatement extends Statement {
|
|||||||
target.set(i, Instruction.jmp(breakPoint - i));
|
target.set(i, Instruction.jmp(breakPoint - i));
|
||||||
target.get(i).location = instr.location;
|
target.get(i).location = instr.location;
|
||||||
}
|
}
|
||||||
if (instr.type == Type.NOP && instr.is(0, "try_cont") && (instr.get(1) == null || instr.is(1, label))) {
|
|
||||||
target.set(i, Instruction.signal("jmp_" + (continuePoint - (Integer)instr.get(2))));
|
|
||||||
target.get(i).location = instr.location;
|
|
||||||
}
|
|
||||||
if (instr.type == Type.NOP && instr.is(0, "try_break") && (instr.get(1) == null || instr.is(1, label))) {
|
|
||||||
target.set(i, Instruction.signal("jmp_" + (breakPoint - (Integer)instr.get(2))));
|
|
||||||
target.get(i).location = instr.location;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,12 +31,12 @@ public class CallStatement extends Statement {
|
|||||||
target.add(Instruction.call(args.length).locate(loc()).setDebug(true));
|
target.add(Instruction.call(args.length).locate(loc()).setDebug(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public CallStatement(Location loc, Statement func, Statement... args) {
|
public CallStatement(Location loc, Statement func, Statement ...args) {
|
||||||
super(loc);
|
super(loc);
|
||||||
this.func = func;
|
this.func = func;
|
||||||
this.args = args;
|
this.args = args;
|
||||||
}
|
}
|
||||||
public CallStatement(Location loc, Statement obj, Object key, Statement... args) {
|
public CallStatement(Location loc, Statement obj, Object key, Statement ...args) {
|
||||||
super(loc);
|
super(loc);
|
||||||
this.func = new IndexStatement(loc, obj, new ConstantStatement(loc, key));
|
this.func = new IndexStatement(loc, obj, new ConstantStatement(loc, key));
|
||||||
this.args = args;
|
this.args = args;
|
||||||
|
@ -28,10 +28,10 @@ public class FunctionStatement extends Statement {
|
|||||||
public static void checkBreakAndCont(List<Instruction> target, int start) {
|
public static void checkBreakAndCont(List<Instruction> target, int start) {
|
||||||
for (int i = start; i < target.size(); i++) {
|
for (int i = start; i < target.size(); i++) {
|
||||||
if (target.get(i).type == Type.NOP) {
|
if (target.get(i).type == Type.NOP) {
|
||||||
if (target.get(i).is(0, "break") || target.get(i).is(0, "try_break")) {
|
if (target.get(i).is(0, "break") ) {
|
||||||
throw new SyntaxException(target.get(i).location, "Break was placed outside a loop.");
|
throw new SyntaxException(target.get(i).location, "Break was placed outside a loop.");
|
||||||
}
|
}
|
||||||
if (target.get(i).is(0, "cont") || target.get(i).is(0, "try_cont")) {
|
if (target.get(i).is(0, "cont")) {
|
||||||
throw new SyntaxException(target.get(i).location, "Continue was placed outside a loop.");
|
throw new SyntaxException(target.get(i).location, "Continue was placed outside a loop.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ public class NewStatement extends Statement {
|
|||||||
target.add(Instruction.callNew(args.length).locate(loc()).setDebug(true));
|
target.add(Instruction.callNew(args.length).locate(loc()).setDebug(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public NewStatement(Location loc, Statement func, Statement... args) {
|
public NewStatement(Location loc, Statement func, Statement ...args) {
|
||||||
super(loc);
|
super(loc);
|
||||||
this.func = func;
|
this.func = func;
|
||||||
this.args = args;
|
this.args = args;
|
||||||
|
@ -6,7 +6,6 @@ import me.topchetoeu.jscript.Location;
|
|||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Statement;
|
import me.topchetoeu.jscript.compilation.Statement;
|
||||||
import me.topchetoeu.jscript.compilation.control.ThrowStatement;
|
import me.topchetoeu.jscript.compilation.control.ThrowStatement;
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
|
||||||
import me.topchetoeu.jscript.engine.Operation;
|
import me.topchetoeu.jscript.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
import me.topchetoeu.jscript.engine.scope.ScopeRecord;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
@ -52,40 +51,7 @@ public class OperationStatement extends Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var ctx = new CallContext(null);
|
return new ConstantStatement(loc(), Values.operation(null, operation, vals));
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (EngineException e) {
|
catch (EngineException e) {
|
||||||
return new ThrowStatement(loc(), new ConstantStatement(loc(), e.value));
|
return new ThrowStatement(loc(), new ConstantStatement(loc(), e.value));
|
||||||
@ -97,7 +63,7 @@ public class OperationStatement extends Statement {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public OperationStatement(Location loc, Operation operation, Statement... args) {
|
public OperationStatement(Location loc, Operation operation, Statement ...args) {
|
||||||
super(loc);
|
super(loc);
|
||||||
this.operation = operation;
|
this.operation = operation;
|
||||||
this.args = args;
|
this.args = args;
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.engine;
|
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
|
||||||
|
|
||||||
public class BreakpointData {
|
|
||||||
public final Location loc;
|
|
||||||
public final CallContext ctx;
|
|
||||||
|
|
||||||
public BreakpointData(Location loc, CallContext ctx) {
|
|
||||||
this.loc = loc;
|
|
||||||
this.ctx = ctx;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.engine;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Hashtable;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class CallContext {
|
|
||||||
public static final class DataKey<T> {}
|
|
||||||
|
|
||||||
public final Engine engine;
|
|
||||||
private final Map<DataKey<?>, Object> data = new Hashtable<>();
|
|
||||||
|
|
||||||
public Engine engine() { return engine; }
|
|
||||||
public Map<DataKey<?>, Object> data() { return Collections.unmodifiableMap(data); }
|
|
||||||
|
|
||||||
public CallContext copy() {
|
|
||||||
return new CallContext(engine).mergeData(data);
|
|
||||||
}
|
|
||||||
public CallContext mergeData(Map<DataKey<?>, Object> objs) {
|
|
||||||
data.putAll(objs);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
public <T> CallContext setData(DataKey<T> key, T val) {
|
|
||||||
if (val == null) data.remove(key);
|
|
||||||
else data.put(key, val);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <T> T addData(DataKey<T> key, T val) {
|
|
||||||
if (data.containsKey(key)) return (T)data.get(key);
|
|
||||||
else {
|
|
||||||
if (val == null) data.remove(key);
|
|
||||||
else data.put(key, val);
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public boolean hasData(DataKey<?> key) { return data.containsKey(key); }
|
|
||||||
public <T> T getData(DataKey<T> key) {
|
|
||||||
return getData(key, null);
|
|
||||||
}
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <T> T getData(DataKey<T> key, T defaultVal) {
|
|
||||||
if (!hasData(key)) return defaultVal;
|
|
||||||
else return (T)data.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CallContext changeData(DataKey<Integer> key, int n, int start) {
|
|
||||||
return setData(key, getData(key, start) + n);
|
|
||||||
}
|
|
||||||
public CallContext changeData(DataKey<Integer> key, int n) {
|
|
||||||
return changeData(key, n, 0);
|
|
||||||
}
|
|
||||||
public CallContext changeData(DataKey<Integer> key) {
|
|
||||||
return changeData(key, 1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CallContext(Engine engine) {
|
|
||||||
this.engine = engine;
|
|
||||||
}
|
|
||||||
}
|
|
20
src/me/topchetoeu/jscript/engine/Context.java
Normal file
20
src/me/topchetoeu/jscript/engine/Context.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package me.topchetoeu.jscript.engine;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
||||||
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
|
import me.topchetoeu.jscript.parsing.Parsing;
|
||||||
|
|
||||||
|
public class Context {
|
||||||
|
public final FunctionContext function;
|
||||||
|
public final MessageContext message;
|
||||||
|
|
||||||
|
public FunctionValue compile(String filename, String raw) throws InterruptedException {
|
||||||
|
var res = Values.toString(this, function.compile.call(this, null, raw, filename));
|
||||||
|
return Parsing.compile(function, filename, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Context(FunctionContext funcCtx, MessageContext msgCtx) {
|
||||||
|
this.function = funcCtx;
|
||||||
|
this.message = msgCtx;
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.engine;
|
|
||||||
|
|
||||||
public enum DebugCommand {
|
|
||||||
NORMAL,
|
|
||||||
STEP_OVER,
|
|
||||||
STEP_OUT,
|
|
||||||
STEP_INTO,
|
|
||||||
}
|
|
@ -1,116 +1,58 @@
|
|||||||
package me.topchetoeu.jscript.engine;
|
package me.topchetoeu.jscript.engine;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.LinkedBlockingDeque;
|
import java.util.concurrent.LinkedBlockingDeque;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.CallContext.DataKey;
|
|
||||||
import me.topchetoeu.jscript.engine.debug.DebugState;
|
|
||||||
import me.topchetoeu.jscript.engine.modules.ModuleManager;
|
|
||||||
import me.topchetoeu.jscript.engine.scope.GlobalScope;
|
|
||||||
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
||||||
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
|
||||||
import me.topchetoeu.jscript.engine.values.ObjectValue.PlaceholderProto;
|
|
||||||
import me.topchetoeu.jscript.events.Awaitable;
|
import me.topchetoeu.jscript.events.Awaitable;
|
||||||
import me.topchetoeu.jscript.events.DataNotifier;
|
import me.topchetoeu.jscript.events.DataNotifier;
|
||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.interop.NativeTypeRegister;
|
|
||||||
import me.topchetoeu.jscript.parsing.Parsing;
|
|
||||||
|
|
||||||
public class Engine {
|
public class Engine {
|
||||||
private static class RawFunction {
|
private class UncompiledFunction extends FunctionValue {
|
||||||
public final GlobalScope scope;
|
|
||||||
public final String filename;
|
public final String filename;
|
||||||
public final String raw;
|
public final String raw;
|
||||||
|
public final FunctionContext ctx;
|
||||||
|
|
||||||
public RawFunction(GlobalScope scope, String filename, String raw) {
|
@Override
|
||||||
this.scope = scope;
|
public Object call(Context ctx, Object thisArg, Object ...args) throws InterruptedException {
|
||||||
|
ctx = new Context(this.ctx, ctx.message);
|
||||||
|
return ctx.compile(filename, raw).call(ctx, thisArg, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UncompiledFunction(FunctionContext ctx, String filename, String raw) {
|
||||||
|
super(filename, 0);
|
||||||
this.filename = filename;
|
this.filename = filename;
|
||||||
this.raw = raw;
|
this.raw = raw;
|
||||||
|
this.ctx = ctx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Task {
|
private static class Task {
|
||||||
public final Object func;
|
public final FunctionValue func;
|
||||||
public final Object thisArg;
|
public final Object thisArg;
|
||||||
public final Object[] args;
|
public final Object[] args;
|
||||||
public final Map<DataKey<?>, Object> data;
|
|
||||||
public final DataNotifier<Object> notifier = new DataNotifier<>();
|
public final DataNotifier<Object> notifier = new DataNotifier<>();
|
||||||
|
public final MessageContext ctx;
|
||||||
|
|
||||||
public Task(Object func, Map<DataKey<?>, Object> data, Object thisArg, Object[] args) {
|
public Task(MessageContext ctx, FunctionValue func, Object thisArg, Object[] args) {
|
||||||
|
this.ctx = ctx;
|
||||||
this.func = func;
|
this.func = func;
|
||||||
this.data = data;
|
|
||||||
this.thisArg = thisArg;
|
this.thisArg = thisArg;
|
||||||
this.args = args;
|
this.args = args;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final DataKey<DebugState> DEBUG_STATE_KEY = new DataKey<>();
|
|
||||||
private static int nextId = 0;
|
private static int nextId = 0;
|
||||||
|
|
||||||
private Map<DataKey<?>, Object> callCtxVals = new HashMap<>();
|
|
||||||
private GlobalScope global = new GlobalScope();
|
|
||||||
private ObjectValue arrayProto = new ObjectValue();
|
|
||||||
private ObjectValue boolProto = new ObjectValue();
|
|
||||||
private ObjectValue funcProto = new ObjectValue();
|
|
||||||
private ObjectValue numProto = new ObjectValue();
|
|
||||||
private ObjectValue objProto = new ObjectValue(PlaceholderProto.NONE);
|
|
||||||
private ObjectValue strProto = new ObjectValue();
|
|
||||||
private ObjectValue symProto = new ObjectValue();
|
|
||||||
private ObjectValue errProto = new ObjectValue();
|
|
||||||
private ObjectValue syntaxErrProto = new ObjectValue(PlaceholderProto.ERROR);
|
|
||||||
private ObjectValue typeErrProto = new ObjectValue(PlaceholderProto.ERROR);
|
|
||||||
private ObjectValue rangeErrProto = new ObjectValue(PlaceholderProto.ERROR);
|
|
||||||
private NativeTypeRegister typeRegister;
|
|
||||||
private Thread thread;
|
private Thread thread;
|
||||||
|
|
||||||
private LinkedBlockingDeque<Task> macroTasks = new LinkedBlockingDeque<>();
|
private LinkedBlockingDeque<Task> macroTasks = new LinkedBlockingDeque<>();
|
||||||
private LinkedBlockingDeque<Task> microTasks = new LinkedBlockingDeque<>();
|
private LinkedBlockingDeque<Task> microTasks = new LinkedBlockingDeque<>();
|
||||||
|
|
||||||
public final int id = ++nextId;
|
public final int id = ++nextId;
|
||||||
public final DebugState debugState = new DebugState();
|
|
||||||
|
|
||||||
public ObjectValue arrayProto() { return arrayProto; }
|
|
||||||
public ObjectValue booleanProto() { return boolProto; }
|
|
||||||
public ObjectValue functionProto() { return funcProto; }
|
|
||||||
public ObjectValue numberProto() { return numProto; }
|
|
||||||
public ObjectValue objectProto() { return objProto; }
|
|
||||||
public ObjectValue stringProto() { return strProto; }
|
|
||||||
public ObjectValue symbolProto() { return symProto; }
|
|
||||||
public ObjectValue errorProto() { return errProto; }
|
|
||||||
public ObjectValue syntaxErrorProto() { return syntaxErrProto; }
|
|
||||||
public ObjectValue typeErrorProto() { return typeErrProto; }
|
|
||||||
public ObjectValue rangeErrorProto() { return rangeErrProto; }
|
|
||||||
|
|
||||||
public GlobalScope global() { return global; }
|
|
||||||
public NativeTypeRegister typeRegister() { return typeRegister; }
|
|
||||||
|
|
||||||
public void copyFrom(Engine other) {
|
|
||||||
global = other.global;
|
|
||||||
typeRegister = other.typeRegister;
|
|
||||||
arrayProto = other.arrayProto;
|
|
||||||
boolProto = other.boolProto;
|
|
||||||
funcProto = other.funcProto;
|
|
||||||
numProto = other.numProto;
|
|
||||||
objProto = other.objProto;
|
|
||||||
strProto = other.strProto;
|
|
||||||
symProto = other.symProto;
|
|
||||||
errProto = other.errProto;
|
|
||||||
syntaxErrProto = other.syntaxErrProto;
|
|
||||||
typeErrProto = other.typeErrProto;
|
|
||||||
rangeErrProto = other.rangeErrProto;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void runTask(Task task) throws InterruptedException {
|
private void runTask(Task task) throws InterruptedException {
|
||||||
try {
|
try {
|
||||||
FunctionValue func;
|
task.notifier.next(task.func.call(new Context(null, task.ctx), task.thisArg, task.args));
|
||||||
if (task.func instanceof FunctionValue) func = (FunctionValue)task.func;
|
|
||||||
else {
|
|
||||||
var raw = (RawFunction)task.func;
|
|
||||||
func = compile(raw.scope, raw.filename, raw.raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
task.notifier.next(func.call(context().mergeData(task.data), task.thisArg, task.args));
|
|
||||||
}
|
}
|
||||||
catch (InterruptedException e) {
|
catch (InterruptedException e) {
|
||||||
task.notifier.error(new RuntimeException(e));
|
task.notifier.error(new RuntimeException(e));
|
||||||
@ -142,13 +84,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() {
|
public Thread start() {
|
||||||
if (this.thread == null) {
|
if (this.thread == null) {
|
||||||
this.thread = new Thread(this::run, "JavaScript Runner #" + id);
|
this.thread = new Thread(this::run, "JavaScript Runner #" + id);
|
||||||
@ -167,39 +102,17 @@ public class Engine {
|
|||||||
return this.thread != null;
|
return this.thread != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object makeRegex(String pattern, String flags) {
|
public Awaitable<Object> pushMsg(boolean micro, MessageContext ctx, FunctionValue func, Object thisArg, Object ...args) {
|
||||||
throw EngineException.ofError("Regular expressions not supported.");
|
var msg = new Task(ctx, func, thisArg, args);
|
||||||
}
|
|
||||||
public ModuleManager modules() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
public ObjectValue getPrototype(Class<?> clazz) {
|
|
||||||
return typeRegister.getProto(clazz);
|
|
||||||
}
|
|
||||||
public CallContext context() { return new CallContext(this).mergeData(callCtxVals); }
|
|
||||||
|
|
||||||
public Awaitable<Object> pushMsg(boolean micro, FunctionValue func, Map<DataKey<?>, Object> data, Object thisArg, Object... args) {
|
|
||||||
var msg = new Task(func, data, thisArg, args);
|
|
||||||
if (micro) microTasks.addLast(msg);
|
if (micro) microTasks.addLast(msg);
|
||||||
else macroTasks.addLast(msg);
|
else macroTasks.addLast(msg);
|
||||||
return msg.notifier;
|
return msg.notifier;
|
||||||
}
|
}
|
||||||
public Awaitable<Object> pushMsg(boolean micro, GlobalScope scope, Map<DataKey<?>, Object> data, String filename, String raw, Object thisArg, Object... args) {
|
public Awaitable<Object> pushMsg(boolean micro, Context ctx, String filename, String raw, Object thisArg, Object ...args) {
|
||||||
var msg = new Task(new RawFunction(scope, filename, raw), data, thisArg, args);
|
return pushMsg(micro, ctx.message, new UncompiledFunction(ctx.function, filename, raw), thisArg, args);
|
||||||
if (micro) microTasks.addLast(msg);
|
|
||||||
else macroTasks.addLast(msg);
|
|
||||||
return msg.notifier;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public FunctionValue compile(GlobalScope scope, String filename, String raw) throws InterruptedException {
|
// public Engine() {
|
||||||
return Parsing.compile(scope, filename, raw);
|
// this.typeRegister = new NativeTypeRegister();
|
||||||
}
|
// }
|
||||||
|
|
||||||
public Engine(NativeTypeRegister register) {
|
|
||||||
this.typeRegister = register;
|
|
||||||
this.callCtxVals.put(DEBUG_STATE_KEY, debugState);
|
|
||||||
}
|
|
||||||
public Engine() {
|
|
||||||
this(new NativeTypeRegister());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
81
src/me/topchetoeu/jscript/engine/FunctionContext.java
Normal file
81
src/me/topchetoeu/jscript/engine/FunctionContext.java
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package me.topchetoeu.jscript.engine;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.engine.scope.GlobalScope;
|
||||||
|
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.exceptions.EngineException;
|
||||||
|
import me.topchetoeu.jscript.interop.Native;
|
||||||
|
import me.topchetoeu.jscript.interop.NativeGetter;
|
||||||
|
import me.topchetoeu.jscript.interop.NativeSetter;
|
||||||
|
|
||||||
|
public class FunctionContext {
|
||||||
|
private HashMap<String, ObjectValue> prototypes = new HashMap<>();
|
||||||
|
public GlobalScope global;
|
||||||
|
public WrappersProvider wrappersProvider;
|
||||||
|
|
||||||
|
@Native public FunctionValue compile;
|
||||||
|
@Native public FunctionValue regexConstructor = new NativeFunction("RegExp", (ctx, thisArg, args) -> {
|
||||||
|
throw EngineException.ofError("Regular expressions not supported.");
|
||||||
|
});
|
||||||
|
@Native public ObjectValue proto(String name) {
|
||||||
|
return prototypes.get(name);
|
||||||
|
}
|
||||||
|
@Native public void setProto(String name, ObjectValue val) {
|
||||||
|
prototypes.put(name, val);
|
||||||
|
}
|
||||||
|
// @Native public ObjectValue arrayPrototype = new ObjectValue();
|
||||||
|
// @Native public ObjectValue boolPrototype = new ObjectValue();
|
||||||
|
// @Native public ObjectValue functionPrototype = new ObjectValue();
|
||||||
|
// @Native public ObjectValue numberPrototype = new ObjectValue();
|
||||||
|
// @Native public ObjectValue objectPrototype = new ObjectValue(PlaceholderProto.NONE);
|
||||||
|
// @Native public ObjectValue stringPrototype = new ObjectValue();
|
||||||
|
// @Native public ObjectValue symbolPrototype = new ObjectValue();
|
||||||
|
// @Native public ObjectValue errorPrototype = new ObjectValue();
|
||||||
|
// @Native public ObjectValue syntaxErrPrototype = new ObjectValue(PlaceholderProto.ERROR);
|
||||||
|
// @Native public ObjectValue typeErrPrototype = new ObjectValue(PlaceholderProto.ERROR);
|
||||||
|
// @Native public ObjectValue rangeErrPrototype = new ObjectValue(PlaceholderProto.ERROR);
|
||||||
|
|
||||||
|
@NativeGetter("global")
|
||||||
|
public ObjectValue getGlobal() {
|
||||||
|
return global.obj;
|
||||||
|
}
|
||||||
|
@NativeSetter("global")
|
||||||
|
public void setGlobal(ObjectValue val) {
|
||||||
|
global = new GlobalScope(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Native
|
||||||
|
public FunctionContext fork() {
|
||||||
|
var res = new FunctionContext(compile, wrappersProvider, global);
|
||||||
|
res.regexConstructor = regexConstructor;
|
||||||
|
res.prototypes = new HashMap<>(prototypes);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Native
|
||||||
|
public FunctionContext child() {
|
||||||
|
var res = fork();
|
||||||
|
res.global = res.global.globalChild();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FunctionContext(FunctionValue compile, WrappersProvider nativeConverter, GlobalScope global) {
|
||||||
|
if (compile == null) compile = new NativeFunction("compile", (ctx, thisArg, args) -> args.length == 0 ? "" : args[0]);
|
||||||
|
if (nativeConverter == null) nativeConverter = new WrappersProvider() {
|
||||||
|
public ObjectValue getConstr(Class<?> obj) {
|
||||||
|
throw EngineException.ofType("Java objects not passable to Javascript.");
|
||||||
|
}
|
||||||
|
public ObjectValue getProto(Class<?> obj) {
|
||||||
|
throw EngineException.ofType("Java objects not passable to Javascript.");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (global == null) global = new GlobalScope();
|
||||||
|
|
||||||
|
this.wrappersProvider = nativeConverter;
|
||||||
|
this.compile = compile;
|
||||||
|
this.global = global;
|
||||||
|
}
|
||||||
|
}
|
33
src/me/topchetoeu/jscript/engine/MessageContext.java
Normal file
33
src/me/topchetoeu/jscript/engine/MessageContext.java
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package me.topchetoeu.jscript.engine;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.engine.frame.CodeFrame;
|
||||||
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
|
|
||||||
|
public class MessageContext {
|
||||||
|
public final Engine engine;
|
||||||
|
|
||||||
|
private final ArrayList<CodeFrame> frames = new ArrayList<>();
|
||||||
|
public int maxStackFrames = 1000;
|
||||||
|
|
||||||
|
public List<CodeFrame> frames() { return Collections.unmodifiableList(frames); }
|
||||||
|
|
||||||
|
public MessageContext pushFrame(CodeFrame frame) {
|
||||||
|
this.frames.add(frame);
|
||||||
|
if (this.frames.size() > maxStackFrames) throw EngineException.ofRange("Stack overflow!");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public boolean popFrame(CodeFrame frame) {
|
||||||
|
if (this.frames.size() == 0) return false;
|
||||||
|
if (this.frames.get(this.frames.size() - 1) != frame) return false;
|
||||||
|
this.frames.remove(this.frames.size() - 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageContext(Engine engine) {
|
||||||
|
this.engine = engine;
|
||||||
|
}
|
||||||
|
}
|
8
src/me/topchetoeu/jscript/engine/WrappersProvider.java
Normal file
8
src/me/topchetoeu/jscript/engine/WrappersProvider.java
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package me.topchetoeu.jscript.engine;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
||||||
|
|
||||||
|
public interface WrappersProvider {
|
||||||
|
public ObjectValue getProto(Class<?> obj);
|
||||||
|
public ObjectValue getConstr(Class<?> obj);
|
||||||
|
}
|
@ -4,10 +4,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.Location;
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.DebugCommand;
|
|
||||||
import me.topchetoeu.jscript.engine.Engine;
|
|
||||||
import me.topchetoeu.jscript.engine.CallContext.DataKey;
|
|
||||||
import me.topchetoeu.jscript.engine.scope.LocalScope;
|
import me.topchetoeu.jscript.engine.scope.LocalScope;
|
||||||
import me.topchetoeu.jscript.engine.scope.ValueVariable;
|
import me.topchetoeu.jscript.engine.scope.ValueVariable;
|
||||||
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
||||||
@ -45,11 +42,6 @@ public class CodeFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final DataKey<Integer> STACK_N_KEY = new DataKey<>();
|
|
||||||
public static final DataKey<Integer> MAX_STACK_KEY = new DataKey<>();
|
|
||||||
public static final DataKey<Boolean> STOP_AT_START_KEY = new DataKey<>();
|
|
||||||
public static final DataKey<Boolean> STEPPING_TROUGH_KEY = new DataKey<>();
|
|
||||||
|
|
||||||
public final LocalScope scope;
|
public final LocalScope scope;
|
||||||
public final Object thisArg;
|
public final Object thisArg;
|
||||||
public final Object[] args;
|
public final Object[] args;
|
||||||
@ -60,7 +52,6 @@ public class CodeFrame {
|
|||||||
public int stackPtr = 0;
|
public int stackPtr = 0;
|
||||||
public int codePtr = 0;
|
public int codePtr = 0;
|
||||||
public boolean jumpFlag = false;
|
public boolean jumpFlag = false;
|
||||||
private DebugCommand debugCmd = null;
|
|
||||||
private Location prevLoc = null;
|
private Location prevLoc = null;
|
||||||
|
|
||||||
public void addTry(int n, int catchN, int finallyN) {
|
public void addTry(int n, int catchN, int finallyN) {
|
||||||
@ -93,30 +84,16 @@ public class CodeFrame {
|
|||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
public void push(Object val) {
|
public void push(Context ctx, Object val) {
|
||||||
if (stack.length <= stackPtr) {
|
if (stack.length <= stackPtr) {
|
||||||
var newStack = new Object[stack.length * 2];
|
var newStack = new Object[stack.length * 2];
|
||||||
System.arraycopy(stack, 0, newStack, 0, stack.length);
|
System.arraycopy(stack, 0, newStack, 0, stack.length);
|
||||||
stack = newStack;
|
stack = newStack;
|
||||||
}
|
}
|
||||||
stack[stackPtr++] = Values.normalize(val);
|
stack[stackPtr++] = Values.normalize(ctx, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start(CallContext ctx) {
|
private Object nextNoTry(Context ctx) throws InterruptedException {
|
||||||
if (ctx.getData(STACK_N_KEY, 0) >= ctx.addData(MAX_STACK_KEY, 10000)) throw EngineException.ofRange("Stack overflow!");
|
|
||||||
ctx.changeData(STACK_N_KEY);
|
|
||||||
|
|
||||||
var debugState = ctx.getData(Engine.DEBUG_STATE_KEY);
|
|
||||||
if (debugState != null) debugState.pushFrame(this);
|
|
||||||
}
|
|
||||||
public void end(CallContext ctx) {
|
|
||||||
var debugState = ctx.getData(Engine.DEBUG_STATE_KEY);
|
|
||||||
|
|
||||||
if (debugState != null) debugState.popFrame();
|
|
||||||
ctx.changeData(STACK_N_KEY, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object nextNoTry(CallContext ctx) throws InterruptedException {
|
|
||||||
if (Thread.currentThread().isInterrupted()) throw new InterruptedException();
|
if (Thread.currentThread().isInterrupted()) throw new InterruptedException();
|
||||||
if (codePtr < 0 || codePtr >= function.body.length) return null;
|
if (codePtr < 0 || codePtr >= function.body.length) return null;
|
||||||
|
|
||||||
@ -125,39 +102,16 @@ public class CodeFrame {
|
|||||||
var loc = instr.location;
|
var loc = instr.location;
|
||||||
if (loc != null) prevLoc = loc;
|
if (loc != null) prevLoc = loc;
|
||||||
|
|
||||||
// var debugState = ctx.getData(Engine.DEBUG_STATE_KEY);
|
|
||||||
// if (debugCmd == null) {
|
|
||||||
// if (ctx.getData(STOP_AT_START_KEY, false)) debugCmd = DebugCommand.STEP_OVER;
|
|
||||||
// else debugCmd = DebugCommand.NORMAL;
|
|
||||||
|
|
||||||
// if (debugState != null) debugState.pushFrame(this);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (debugState != null && loc != null) {
|
|
||||||
// if (
|
|
||||||
// instr.type == Type.NOP && instr.match("debug") || debugState.breakpoints.contains(loc) || (
|
|
||||||
// ctx.getData(STEPPING_TROUGH_KEY, false) &&
|
|
||||||
// (debugCmd == DebugCommand.STEP_INTO || debugCmd == DebugCommand.STEP_OVER)
|
|
||||||
// )
|
|
||||||
// ) {
|
|
||||||
// ctx.setData(STEPPING_TROUGH_KEY, true);
|
|
||||||
|
|
||||||
// debugState.breakpointNotifier.next(new BreakpointData(loc, ctx));
|
|
||||||
// debugCmd = debugState.commandNotifier.toAwaitable().await();
|
|
||||||
// if (debugCmd == DebugCommand.NORMAL) ctx.setData(STEPPING_TROUGH_KEY, false);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.jumpFlag = false;
|
this.jumpFlag = false;
|
||||||
return Runners.exec(debugCmd, instr, this, ctx);
|
return Runners.exec(ctx, instr, this);
|
||||||
}
|
}
|
||||||
catch (EngineException e) {
|
catch (EngineException e) {
|
||||||
throw e.add(function.name, prevLoc);
|
throw e.add(function.name, prevLoc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object next(CallContext ctx, Object prevReturn, Object prevError) throws InterruptedException {
|
public Object next(Context ctx, Object prevReturn, Object prevError) throws InterruptedException {
|
||||||
TryCtx tryCtx = null;
|
TryCtx tryCtx = null;
|
||||||
if (prevError != Runners.NO_RETURN) prevReturn = Runners.NO_RETURN;
|
if (prevError != Runners.NO_RETURN) prevReturn = Runners.NO_RETURN;
|
||||||
|
|
||||||
@ -257,6 +211,7 @@ public class CodeFrame {
|
|||||||
catch (EngineException e) {
|
catch (EngineException e) {
|
||||||
if (tryCtx.hasCatch) {
|
if (tryCtx.hasCatch) {
|
||||||
tryCtx.state = TryCtx.STATE_CATCH;
|
tryCtx.state = TryCtx.STATE_CATCH;
|
||||||
|
tryCtx.err = e;
|
||||||
codePtr = tryCtx.catchStart;
|
codePtr = tryCtx.catchStart;
|
||||||
scope.catchVars.add(new ValueVariable(false, e.value));
|
scope.catchVars.add(new ValueVariable(false, e.value));
|
||||||
return Runners.NO_RETURN;
|
return Runners.NO_RETURN;
|
||||||
@ -281,6 +236,7 @@ public class CodeFrame {
|
|||||||
else return res;
|
else return res;
|
||||||
}
|
}
|
||||||
catch (EngineException e) {
|
catch (EngineException e) {
|
||||||
|
e.cause = tryCtx.err;
|
||||||
if (tryCtx.hasFinally) {
|
if (tryCtx.hasFinally) {
|
||||||
tryCtx.err = e;
|
tryCtx.err = e;
|
||||||
tryCtx.state = TryCtx.STATE_FINALLY_THREW;
|
tryCtx.state = TryCtx.STATE_FINALLY_THREW;
|
||||||
@ -291,29 +247,38 @@ public class CodeFrame {
|
|||||||
codePtr = tryCtx.finallyStart;
|
codePtr = tryCtx.finallyStart;
|
||||||
return Runners.NO_RETURN;
|
return Runners.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
else if (tryCtx.state == TryCtx.STATE_FINALLY_THREW) {
|
||||||
|
try {
|
||||||
|
return nextNoTry(ctx);
|
||||||
|
}
|
||||||
|
catch (EngineException e) {
|
||||||
|
e.cause = tryCtx.err;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
else return nextNoTry(ctx);
|
else return nextNoTry(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object run(CallContext ctx) throws InterruptedException {
|
public Object run(Context ctx) throws InterruptedException {
|
||||||
try {
|
try {
|
||||||
start(ctx);
|
ctx.message.pushFrame(this);
|
||||||
while (true) {
|
while (true) {
|
||||||
var res = next(ctx, Runners.NO_RETURN, Runners.NO_RETURN);
|
var res = next(ctx, Runners.NO_RETURN, Runners.NO_RETURN);
|
||||||
if (res != Runners.NO_RETURN) return res;
|
if (res != Runners.NO_RETURN) return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
end(ctx);
|
ctx.message.popFrame(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public CodeFrame(Object thisArg, Object[] args, CodeFunction func) {
|
public CodeFrame(Context ctx, Object thisArg, Object[] args, CodeFunction func) {
|
||||||
this.args = args.clone();
|
this.args = args.clone();
|
||||||
this.scope = new LocalScope(func.localsN, func.captures);
|
this.scope = new LocalScope(func.localsN, func.captures);
|
||||||
this.scope.get(0).set(null, thisArg);
|
this.scope.get(0).set(null, thisArg);
|
||||||
var argsObj = new ArrayValue();
|
var argsObj = new ArrayValue();
|
||||||
for (var i = 0; i < args.length; i++) {
|
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;
|
this.scope.get(1).value = argsObj;
|
||||||
|
|
||||||
|
@ -3,8 +3,7 @@ package me.topchetoeu.jscript.engine.frame;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.DebugCommand;
|
|
||||||
import me.topchetoeu.jscript.engine.Operation;
|
import me.topchetoeu.jscript.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.ValueVariable;
|
import me.topchetoeu.jscript.engine.scope.ValueVariable;
|
||||||
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
||||||
@ -18,62 +17,59 @@ import me.topchetoeu.jscript.exceptions.EngineException;
|
|||||||
public class Runners {
|
public class Runners {
|
||||||
public static final Object NO_RETURN = new Object();
|
public static final Object NO_RETURN = new Object();
|
||||||
|
|
||||||
public static Object execReturn(Instruction instr, CodeFrame frame, CallContext ctx) {
|
public static Object execReturn(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
frame.codePtr++;
|
|
||||||
return frame.pop();
|
return frame.pop();
|
||||||
}
|
}
|
||||||
public static Object execSignal(Instruction instr, CodeFrame frame, CallContext ctx) {
|
public static Object execSignal(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
frame.codePtr++;
|
|
||||||
return new SignalValue(instr.get(0));
|
return new SignalValue(instr.get(0));
|
||||||
}
|
}
|
||||||
public static Object execThrow(Instruction instr, CodeFrame frame, CallContext ctx) {
|
public static Object execThrow(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
throw new EngineException(frame.pop());
|
throw new EngineException(frame.pop());
|
||||||
}
|
}
|
||||||
public static Object execThrowSyntax(Instruction instr, CodeFrame frame, CallContext ctx) {
|
public static Object execThrowSyntax(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
throw EngineException.ofSyntax((String)instr.get(0));
|
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(Context ctx, 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);
|
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(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||||
var callArgs = frame.take(instr.get(0));
|
var callArgs = frame.take(instr.get(0));
|
||||||
var func = frame.pop();
|
var func = frame.pop();
|
||||||
var thisArg = frame.pop();
|
var thisArg = frame.pop();
|
||||||
|
|
||||||
frame.push(call(state, ctx, func, thisArg, callArgs));
|
frame.push(ctx, call(ctx, func, thisArg, callArgs));
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execCallNew(DebugCommand state, Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
public static Object execCallNew(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||||
var callArgs = frame.take(instr.get(0));
|
var callArgs = frame.take(instr.get(0));
|
||||||
var funcObj = frame.pop();
|
var funcObj = frame.pop();
|
||||||
|
|
||||||
if (Values.isFunction(funcObj) && Values.function(funcObj).special) {
|
if (Values.isFunction(funcObj) && Values.function(funcObj).special) {
|
||||||
frame.push(call(state, ctx, funcObj, null, callArgs));
|
frame.push(ctx, call(ctx, funcObj, null, callArgs));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var proto = Values.getMember(ctx, funcObj, "prototype");
|
var proto = Values.getMember(ctx, funcObj, "prototype");
|
||||||
var obj = new ObjectValue();
|
var obj = new ObjectValue();
|
||||||
obj.setPrototype(ctx, proto);
|
obj.setPrototype(ctx, proto);
|
||||||
call(state, ctx, funcObj, obj, callArgs);
|
call(ctx, funcObj, obj, callArgs);
|
||||||
frame.push(obj);
|
frame.push(ctx, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object execMakeVar(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
public static Object execMakeVar(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||||
var name = (String)instr.get(0);
|
var name = (String)instr.get(0);
|
||||||
frame.function.globals.define(name);
|
ctx.function.global.define(name);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execDefProp(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
public static Object execDefProp(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||||
var setter = frame.pop();
|
var setter = frame.pop();
|
||||||
var getter = frame.pop();
|
var getter = frame.pop();
|
||||||
var name = frame.pop();
|
var name = frame.pop();
|
||||||
@ -82,28 +78,28 @@ public class Runners {
|
|||||||
if (getter != null && !Values.isFunction(getter)) throw EngineException.ofType("Getter must be a function or undefined.");
|
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 (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.");
|
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++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execInstanceof(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
public static Object execInstanceof(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||||
var type = frame.pop();
|
var type = frame.pop();
|
||||||
var obj = frame.pop();
|
var obj = frame.pop();
|
||||||
|
|
||||||
if (!Values.isPrimitive(type)) {
|
if (!Values.isPrimitive(type)) {
|
||||||
var proto = Values.getMember(ctx, type, "prototype");
|
var proto = Values.getMember(ctx, type, "prototype");
|
||||||
frame.push(Values.isInstanceOf(ctx, obj, proto));
|
frame.push(ctx, Values.isInstanceOf(ctx, obj, proto));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
frame.push(false);
|
frame.push(ctx, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execKeys(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
public static Object execKeys(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||||
var val = frame.pop();
|
var val = frame.pop();
|
||||||
|
|
||||||
var arr = new ObjectValue();
|
var arr = new ObjectValue();
|
||||||
@ -113,81 +109,81 @@ public class Runners {
|
|||||||
Collections.reverse(members);
|
Collections.reverse(members);
|
||||||
for (var el : members) {
|
for (var el : members) {
|
||||||
if (el instanceof Symbol) continue;
|
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++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object execTry(DebugCommand state, Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
public static Object execTry(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||||
frame.addTry(instr.get(0), instr.get(1), instr.get(2));
|
frame.addTry(instr.get(0), instr.get(1), instr.get(2));
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object execDup(Instruction instr, CodeFrame frame, CallContext ctx) {
|
public static Object execDup(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
int offset = instr.get(0), count = instr.get(1);
|
int offset = instr.get(0), count = instr.get(1);
|
||||||
|
|
||||||
for (var i = 0; i < count; i++) {
|
for (var i = 0; i < count; i++) {
|
||||||
frame.push(frame.peek(offset + count - 1));
|
frame.push(ctx, frame.peek(offset + count - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execMove(Instruction instr, CodeFrame frame, CallContext ctx) {
|
public static Object execMove(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
int offset = instr.get(0), count = instr.get(1);
|
int offset = instr.get(0), count = instr.get(1);
|
||||||
|
|
||||||
var tmp = frame.take(offset);
|
var tmp = frame.take(offset);
|
||||||
var res = frame.take(count);
|
var res = frame.take(count);
|
||||||
|
|
||||||
for (var i = 0; i < offset; i++) frame.push(tmp[i]);
|
for (var i = 0; i < offset; i++) frame.push(ctx, tmp[i]);
|
||||||
for (var i = 0; i < count; i++) frame.push(res[i]);
|
for (var i = 0; i < count; i++) frame.push(ctx, res[i]);
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execLoadUndefined(Instruction instr, CodeFrame frame, CallContext ctx) {
|
public static Object execLoadUndefined(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
frame.push(null);
|
frame.push(ctx, null);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execLoadValue(Instruction instr, CodeFrame frame, CallContext ctx) {
|
public static Object execLoadValue(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
frame.push(instr.get(0));
|
frame.push(ctx, instr.get(0));
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execLoadVar(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
public static Object execLoadVar(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||||
var i = instr.get(0);
|
var i = instr.get(0);
|
||||||
|
|
||||||
if (i instanceof String) frame.push(frame.function.globals.get(ctx, (String)i));
|
if (i instanceof String) frame.push(ctx, ctx.function.global.get(ctx, (String)i));
|
||||||
else frame.push(frame.scope.get((int)i).get(ctx));
|
else frame.push(ctx, frame.scope.get((int)i).get(ctx));
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execLoadObj(Instruction instr, CodeFrame frame, CallContext ctx) {
|
public static Object execLoadObj(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
frame.push(new ObjectValue());
|
frame.push(ctx, new ObjectValue());
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execLoadGlob(Instruction instr, CodeFrame frame, CallContext ctx) {
|
public static Object execLoadGlob(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
frame.push(frame.function.globals.obj);
|
frame.push(ctx, ctx.function.global.obj);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execLoadArr(Instruction instr, CodeFrame frame, CallContext ctx) {
|
public static Object execLoadArr(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
var res = new ArrayValue();
|
var res = new ArrayValue();
|
||||||
res.setSize(instr.get(0));
|
res.setSize(instr.get(0));
|
||||||
frame.push(res);
|
frame.push(ctx, res);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execLoadFunc(Instruction instr, CodeFrame frame, CallContext ctx) {
|
public static Object execLoadFunc(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
int n = (Integer)instr.get(0);
|
int n = (Integer)instr.get(0);
|
||||||
int localsN = (Integer)instr.get(1);
|
int localsN = (Integer)instr.get(1);
|
||||||
int len = (Integer)instr.get(2);
|
int len = (Integer)instr.get(2);
|
||||||
@ -202,19 +198,18 @@ public class Runners {
|
|||||||
var body = new Instruction[end - start];
|
var body = new Instruction[end - start];
|
||||||
System.arraycopy(frame.function.body, start, body, 0, end - start);
|
System.arraycopy(frame.function.body, start, body, 0, end - start);
|
||||||
|
|
||||||
var func = new CodeFunction("", localsN, len, frame.function.globals, captures, body);
|
var func = new CodeFunction(ctx.function, "", localsN, len, captures, body);
|
||||||
frame.push(func);
|
frame.push(ctx, func);
|
||||||
|
|
||||||
frame.codePtr += n;
|
frame.codePtr += n;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execLoadMember(DebugCommand state, Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
public static Object execLoadMember(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||||
var key = frame.pop();
|
var key = frame.pop();
|
||||||
var obj = frame.pop();
|
var obj = frame.pop();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ctx.setData(CodeFrame.STOP_AT_START_KEY, state == DebugCommand.STEP_INTO);
|
frame.push(ctx, Values.getMember(ctx, obj, key));
|
||||||
frame.push(Values.getMember(ctx, obj, key));
|
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException e) {
|
catch (IllegalArgumentException e) {
|
||||||
throw EngineException.ofType(e.getMessage());
|
throw EngineException.ofType(e.getMessage());
|
||||||
@ -222,54 +217,53 @@ public class Runners {
|
|||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execLoadKeyMember(DebugCommand state, Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
public static Object execLoadKeyMember(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||||
frame.push(instr.get(0));
|
frame.push(ctx, instr.get(0));
|
||||||
return execLoadMember(state, instr, frame, ctx);
|
return execLoadMember(ctx, instr, frame);
|
||||||
}
|
}
|
||||||
public static Object execLoadRegEx(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
public static Object execLoadRegEx(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||||
frame.push(ctx.engine().makeRegex(instr.get(0), instr.get(1)));
|
frame.push(ctx, ctx.function.regexConstructor.call(ctx, null, instr.get(0), instr.get(1)));
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object execDiscard(Instruction instr, CodeFrame frame, CallContext ctx) {
|
public static Object execDiscard(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
frame.pop();
|
frame.pop();
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execStoreMember(DebugCommand state, Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
public static Object execStoreMember(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||||
var val = frame.pop();
|
var val = frame.pop();
|
||||||
var key = frame.pop();
|
var key = frame.pop();
|
||||||
var obj = 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 (!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++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execStoreVar(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
public static Object execStoreVar(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||||
var val = (boolean)instr.get(1) ? frame.peek() : frame.pop();
|
var val = (boolean)instr.get(1) ? frame.peek() : frame.pop();
|
||||||
var i = instr.get(0);
|
var i = instr.get(0);
|
||||||
|
|
||||||
if (i instanceof String) frame.function.globals.set(ctx, (String)i, val);
|
if (i instanceof String) ctx.function.global.set(ctx, (String)i, val);
|
||||||
else frame.scope.get((int)i).set(ctx, val);
|
else frame.scope.get((int)i).set(ctx, val);
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execStoreSelfFunc(Instruction instr, CodeFrame frame, CallContext ctx) {
|
public static Object execStoreSelfFunc(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
frame.scope.locals[(int)instr.get(0)].set(ctx, frame.function);
|
frame.scope.locals[(int)instr.get(0)].set(ctx, frame.function);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object execJmp(Instruction instr, CodeFrame frame, CallContext ctx) {
|
public static Object execJmp(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
frame.codePtr += (int)instr.get(0);
|
frame.codePtr += (int)instr.get(0);
|
||||||
frame.jumpFlag = true;
|
frame.jumpFlag = true;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execJmpIf(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
public static Object execJmpIf(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||||
if (Values.toBoolean(frame.pop())) {
|
if (Values.toBoolean(frame.pop())) {
|
||||||
frame.codePtr += (int)instr.get(0);
|
frame.codePtr += (int)instr.get(0);
|
||||||
frame.jumpFlag = true;
|
frame.jumpFlag = true;
|
||||||
@ -277,7 +271,7 @@ public class Runners {
|
|||||||
else frame.codePtr ++;
|
else frame.codePtr ++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execJmpIfNot(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
public static Object execJmpIfNot(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||||
if (Values.not(frame.pop())) {
|
if (Values.not(frame.pop())) {
|
||||||
frame.codePtr += (int)instr.get(0);
|
frame.codePtr += (int)instr.get(0);
|
||||||
frame.jumpFlag = true;
|
frame.jumpFlag = true;
|
||||||
@ -286,32 +280,32 @@ public class Runners {
|
|||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object execIn(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
public static Object execIn(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||||
var obj = frame.pop();
|
var obj = frame.pop();
|
||||||
var index = 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++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execTypeof(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
public static Object execTypeof(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||||
String name = instr.get(0);
|
String name = instr.get(0);
|
||||||
Object obj;
|
Object obj;
|
||||||
|
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
if (frame.function.globals.has(ctx, name)) {
|
if (ctx.function.global.has(ctx, name)) {
|
||||||
obj = frame.function.globals.get(ctx, name);
|
obj = ctx.function.global.get(ctx, name);
|
||||||
}
|
}
|
||||||
else obj = null;
|
else obj = null;
|
||||||
}
|
}
|
||||||
else obj = frame.pop();
|
else obj = frame.pop();
|
||||||
|
|
||||||
frame.push(Values.type(obj));
|
frame.push(ctx, Values.type(obj));
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
public static Object execNop(Instruction instr, CodeFrame frame, CallContext ctx) {
|
public static Object execNop(Context ctx, Instruction instr, CodeFrame frame) {
|
||||||
if (instr.is(0, "dbg_names")) {
|
if (instr.is(0, "dbg_names")) {
|
||||||
var names = new String[instr.params.length - 1];
|
var names = new String[instr.params.length - 1];
|
||||||
for (var i = 0; i < instr.params.length - 1; i++) {
|
for (var i = 0; i < instr.params.length - 1; i++) {
|
||||||
@ -325,67 +319,67 @@ public class Runners {
|
|||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object execDelete(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
public static Object execDelete(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||||
var key = frame.pop();
|
var key = frame.pop();
|
||||||
var val = frame.pop();
|
var val = frame.pop();
|
||||||
|
|
||||||
if (!Values.deleteMember(ctx, val, key)) throw EngineException.ofSyntax("Can't delete member '" + key + "'.");
|
if (!Values.deleteMember(ctx, val, key)) throw EngineException.ofSyntax("Can't delete member '" + key + "'.");
|
||||||
frame.push(true);
|
frame.push(ctx, true);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object execOperation(Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
public static Object execOperation(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||||
Operation op = instr.get(0);
|
Operation op = instr.get(0);
|
||||||
var args = new Object[op.operands];
|
var args = new Object[op.operands];
|
||||||
|
|
||||||
for (var i = op.operands - 1; i >= 0; i--) args[i] = frame.pop();
|
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++;
|
frame.codePtr++;
|
||||||
return NO_RETURN;
|
return NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object exec(DebugCommand state, Instruction instr, CodeFrame frame, CallContext ctx) throws InterruptedException {
|
public static Object exec(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||||
// System.out.println(instr + "@" + instr.location);
|
// System.out.println(instr + "@" + instr.location);
|
||||||
switch (instr.type) {
|
switch (instr.type) {
|
||||||
case NOP: return execNop(instr, frame, ctx);
|
case NOP: return execNop(ctx, instr, frame);
|
||||||
case RETURN: return execReturn(instr, frame, ctx);
|
case RETURN: return execReturn(ctx, instr, frame);
|
||||||
case SIGNAL: return execSignal(instr, frame, ctx);
|
case SIGNAL: return execSignal(ctx, instr, frame);
|
||||||
case THROW: return execThrow(instr, frame, ctx);
|
case THROW: return execThrow(ctx, instr, frame);
|
||||||
case THROW_SYNTAX: return execThrowSyntax(instr, frame, ctx);
|
case THROW_SYNTAX: return execThrowSyntax(ctx, instr, frame);
|
||||||
case CALL: return execCall(state, instr, frame, ctx);
|
case CALL: return execCall(ctx, instr, frame);
|
||||||
case CALL_NEW: return execCallNew(state, instr, frame, ctx);
|
case CALL_NEW: return execCallNew(ctx, instr, frame);
|
||||||
case TRY: return execTry(state, instr, frame, ctx);
|
case TRY: return execTry(ctx, instr, frame);
|
||||||
|
|
||||||
case DUP: return execDup(instr, frame, ctx);
|
case DUP: return execDup(ctx, instr, frame);
|
||||||
case MOVE: return execMove(instr, frame, ctx);
|
case MOVE: return execMove(ctx, instr, frame);
|
||||||
case LOAD_VALUE: return execLoadValue(instr, frame, ctx);
|
case LOAD_VALUE: return execLoadValue(ctx, instr, frame);
|
||||||
case LOAD_VAR: return execLoadVar(instr, frame, ctx);
|
case LOAD_VAR: return execLoadVar(ctx, instr, frame);
|
||||||
case LOAD_OBJ: return execLoadObj(instr, frame, ctx);
|
case LOAD_OBJ: return execLoadObj(ctx, instr, frame);
|
||||||
case LOAD_ARR: return execLoadArr(instr, frame, ctx);
|
case LOAD_ARR: return execLoadArr(ctx, instr, frame);
|
||||||
case LOAD_FUNC: return execLoadFunc(instr, frame, ctx);
|
case LOAD_FUNC: return execLoadFunc(ctx, instr, frame);
|
||||||
case LOAD_MEMBER: return execLoadMember(state, instr, frame, ctx);
|
case LOAD_MEMBER: return execLoadMember(ctx, instr, frame);
|
||||||
case LOAD_VAL_MEMBER: return execLoadKeyMember(state, instr, frame, ctx);
|
case LOAD_VAL_MEMBER: return execLoadKeyMember(ctx, instr, frame);
|
||||||
case LOAD_REGEX: return execLoadRegEx(instr, frame, ctx);
|
case LOAD_REGEX: return execLoadRegEx(ctx, instr, frame);
|
||||||
case LOAD_GLOB: return execLoadGlob(instr, frame, ctx);
|
case LOAD_GLOB: return execLoadGlob(ctx, instr, frame);
|
||||||
|
|
||||||
case DISCARD: return execDiscard(instr, frame, ctx);
|
case DISCARD: return execDiscard(ctx, instr, frame);
|
||||||
case STORE_MEMBER: return execStoreMember(state, instr, frame, ctx);
|
case STORE_MEMBER: return execStoreMember(ctx, instr, frame);
|
||||||
case STORE_VAR: return execStoreVar(instr, frame, ctx);
|
case STORE_VAR: return execStoreVar(ctx, instr, frame);
|
||||||
case STORE_SELF_FUNC: return execStoreSelfFunc(instr, frame, ctx);
|
case STORE_SELF_FUNC: return execStoreSelfFunc(ctx, instr, frame);
|
||||||
case MAKE_VAR: return execMakeVar(instr, frame, ctx);
|
case MAKE_VAR: return execMakeVar(ctx, instr, frame);
|
||||||
|
|
||||||
case KEYS: return execKeys(instr, frame, ctx);
|
case KEYS: return execKeys(ctx, instr, frame);
|
||||||
case DEF_PROP: return execDefProp(instr, frame, ctx);
|
case DEF_PROP: return execDefProp(ctx, instr, frame);
|
||||||
case TYPEOF: return execTypeof(instr, frame, ctx);
|
case TYPEOF: return execTypeof(ctx, instr, frame);
|
||||||
case DELETE: return execDelete(instr, frame, ctx);
|
case DELETE: return execDelete(ctx, instr, frame);
|
||||||
|
|
||||||
case JMP: return execJmp(instr, frame, ctx);
|
case JMP: return execJmp(ctx, instr, frame);
|
||||||
case JMP_IF: return execJmpIf(instr, frame, ctx);
|
case JMP_IF: return execJmpIf(ctx, instr, frame);
|
||||||
case JMP_IFN: return execJmpIfNot(instr, frame, ctx);
|
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() + ".");
|
default: throw EngineException.ofSyntax("Invalid instruction " + instr.type.name() + ".");
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ package me.topchetoeu.jscript.engine.scope;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
||||||
import me.topchetoeu.jscript.engine.values.NativeFunction;
|
import me.topchetoeu.jscript.engine.values.NativeFunction;
|
||||||
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
||||||
@ -11,12 +11,11 @@ import me.topchetoeu.jscript.exceptions.EngineException;
|
|||||||
|
|
||||||
public class GlobalScope implements ScopeRecord {
|
public class GlobalScope implements ScopeRecord {
|
||||||
public final ObjectValue obj;
|
public final ObjectValue obj;
|
||||||
public final GlobalScope parent;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GlobalScope parent() { return parent; }
|
public GlobalScope parent() { return null; }
|
||||||
|
|
||||||
public boolean has(CallContext ctx, String name) throws InterruptedException {
|
public boolean has(Context ctx, String name) throws InterruptedException {
|
||||||
return obj.hasMember(ctx, name, false);
|
return obj.hasMember(ctx, name, false);
|
||||||
}
|
}
|
||||||
public Object getKey(String name) {
|
public Object getKey(String name) {
|
||||||
@ -24,7 +23,9 @@ public class GlobalScope implements ScopeRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public GlobalScope globalChild() {
|
public GlobalScope globalChild() {
|
||||||
return new GlobalScope(this);
|
var obj = new ObjectValue();
|
||||||
|
obj.setPrototype(null, this.obj);
|
||||||
|
return new GlobalScope(obj);
|
||||||
}
|
}
|
||||||
public LocalScopeRecord child() {
|
public LocalScopeRecord child() {
|
||||||
return new LocalScopeRecord(this);
|
return new LocalScopeRecord(this);
|
||||||
@ -38,31 +39,31 @@ public class GlobalScope implements ScopeRecord {
|
|||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
obj.defineProperty(name, null);
|
obj.defineProperty(null, name, null);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
public void define(String name, Variable val) {
|
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("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; }),
|
new NativeFunction("set " + name, (ctx, th, args) -> { val.set(ctx, args.length > 0 ? args[0] : null); return null; }),
|
||||||
true, true
|
true, true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public void define(String name, boolean readonly, Object val) {
|
public void define(Context ctx, String name, boolean readonly, Object val) {
|
||||||
obj.defineProperty(name, val, readonly, true, true);
|
obj.defineProperty(ctx, name, val, readonly, true, true);
|
||||||
}
|
}
|
||||||
public void define(String... names) {
|
public void define(String ...names) {
|
||||||
for (var n : names) define(n);
|
for (var n : names) define(n);
|
||||||
}
|
}
|
||||||
public void define(boolean readonly, FunctionValue val) {
|
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 {
|
public Object get(Context ctx, String name) throws InterruptedException {
|
||||||
if (!obj.hasMember(ctx, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
|
if (!obj.hasMember(ctx, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
|
||||||
else return obj.getMember(ctx, name);
|
else return obj.getMember(ctx, name);
|
||||||
}
|
}
|
||||||
public void set(CallContext ctx, String name, Object val) throws InterruptedException {
|
public void set(Context ctx, String name, Object val) throws InterruptedException {
|
||||||
if (!obj.hasMember(ctx, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
|
if (!obj.hasMember(ctx, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
|
||||||
if (!obj.setMember(ctx, name, val, false)) throw EngineException.ofSyntax("The global '" + name + "' is readonly.");
|
if (!obj.setMember(ctx, name, val, false)) throw EngineException.ofSyntax("The global '" + name + "' is readonly.");
|
||||||
}
|
}
|
||||||
@ -78,12 +79,9 @@ public class GlobalScope implements ScopeRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public GlobalScope() {
|
public GlobalScope() {
|
||||||
this.parent = null;
|
|
||||||
this.obj = new ObjectValue();
|
this.obj = new ObjectValue();
|
||||||
}
|
}
|
||||||
public GlobalScope(GlobalScope parent) {
|
public GlobalScope(ObjectValue val) {
|
||||||
this.parent = null;
|
this.obj = val;
|
||||||
this.obj = new ObjectValue();
|
|
||||||
this.obj.setPrototype(null, parent.obj);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import java.util.ArrayList;
|
|||||||
|
|
||||||
public class LocalScope {
|
public class LocalScope {
|
||||||
private String[] names;
|
private String[] names;
|
||||||
private LocalScope parent;
|
|
||||||
public final ValueVariable[] captures;
|
public final ValueVariable[] captures;
|
||||||
public final ValueVariable[] locals;
|
public final ValueVariable[] locals;
|
||||||
public final ArrayList<ValueVariable> catchVars = new ArrayList<>();
|
public final ArrayList<ValueVariable> catchVars = new ArrayList<>();
|
||||||
@ -33,18 +32,11 @@ public class LocalScope {
|
|||||||
return captures.length + locals.length;
|
return captures.length + locals.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlobalScope toGlobal(GlobalScope global) {
|
public void toGlobal(GlobalScope global) {
|
||||||
GlobalScope res;
|
|
||||||
|
|
||||||
if (parent == null) res = new GlobalScope(global);
|
|
||||||
else res = new GlobalScope(parent.toGlobal(global));
|
|
||||||
|
|
||||||
var names = getNames();
|
var names = getNames();
|
||||||
for (var i = 0; i < names.length; i++) {
|
for (var i = 0; i < names.length; i++) {
|
||||||
res.define(names[i], locals[i]);
|
global.define(names[i], locals[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public LocalScope(int n, ValueVariable[] captures) {
|
public LocalScope(int n, ValueVariable[] captures) {
|
||||||
@ -55,8 +47,4 @@ public class LocalScope {
|
|||||||
locals[i] = new ValueVariable(false, null);
|
locals[i] = new ValueVariable(false, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public LocalScope(int n, ValueVariable[] captures, LocalScope parent) {
|
|
||||||
this(n, captures);
|
|
||||||
this.parent = parent;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ package me.topchetoeu.jscript.engine.scope;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
|
|
||||||
public class LocalScopeRecord implements ScopeRecord {
|
public class LocalScopeRecord implements ScopeRecord {
|
||||||
public final LocalScopeRecord parent;
|
public final LocalScopeRecord parent;
|
||||||
@ -59,7 +59,7 @@ public class LocalScopeRecord implements ScopeRecord {
|
|||||||
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
public boolean has(CallContext ctx, String name) throws InterruptedException {
|
public boolean has(Context ctx, String name) throws InterruptedException {
|
||||||
return
|
return
|
||||||
global.has(ctx, name) ||
|
global.has(ctx, name) ||
|
||||||
locals.contains(name) ||
|
locals.contains(name) ||
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package me.topchetoeu.jscript.engine.scope;
|
package me.topchetoeu.jscript.engine.scope;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
|
|
||||||
public class ValueVariable implements Variable {
|
public class ValueVariable implements Variable {
|
||||||
@ -11,14 +11,14 @@ public class ValueVariable implements Variable {
|
|||||||
public boolean readonly() { return readonly; }
|
public boolean readonly() { return readonly; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object get(CallContext ctx) {
|
public Object get(Context ctx) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void set(CallContext ctx, Object val) {
|
public void set(Context ctx, Object val) {
|
||||||
if (readonly) return;
|
if (readonly) return;
|
||||||
this.value = Values.normalize(val);
|
this.value = Values.normalize(ctx, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueVariable(boolean readonly, Object val) {
|
public ValueVariable(boolean readonly, Object val) {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package me.topchetoeu.jscript.engine.scope;
|
package me.topchetoeu.jscript.engine.scope;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
|
|
||||||
public interface Variable {
|
public interface Variable {
|
||||||
Object get(CallContext ctx) throws InterruptedException;
|
Object get(Context ctx) throws InterruptedException;
|
||||||
default boolean readonly() { return true; }
|
default boolean readonly() { return true; }
|
||||||
default void set(CallContext ctx, Object val) throws InterruptedException { }
|
default void set(Context ctx, Object val) throws InterruptedException { }
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import java.util.Collection;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
|
|
||||||
public class ArrayValue extends ObjectValue {
|
public class ArrayValue extends ObjectValue {
|
||||||
private static final Object EMPTY = new Object();
|
private static final Object EMPTY = new Object();
|
||||||
@ -29,14 +29,14 @@ public class ArrayValue extends ObjectValue {
|
|||||||
if (res == EMPTY) return null;
|
if (res == EMPTY) return null;
|
||||||
else return res;
|
else return res;
|
||||||
}
|
}
|
||||||
public void set(int i, Object val) {
|
public void set(Context ctx, int i, Object val) {
|
||||||
if (i < 0) return;
|
if (i < 0) return;
|
||||||
|
|
||||||
while (values.size() <= i) {
|
while (values.size() <= i) {
|
||||||
values.add(EMPTY);
|
values.add(EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
values.set(i, Values.normalize(val));
|
values.set(i, Values.normalize(ctx, val));
|
||||||
}
|
}
|
||||||
public boolean has(int i) {
|
public boolean has(int i) {
|
||||||
return i >= 0 && i < values.size() && values.get(i) != EMPTY;
|
return i >= 0 && i < values.size() && values.get(i) != EMPTY;
|
||||||
@ -83,7 +83,7 @@ public class ArrayValue extends ObjectValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object getField(CallContext ctx, Object key) throws InterruptedException {
|
protected Object getField(Context ctx, Object key) throws InterruptedException {
|
||||||
if (key.equals("length")) return values.size();
|
if (key.equals("length")) return values.size();
|
||||||
if (key instanceof Number) {
|
if (key instanceof Number) {
|
||||||
var i = ((Number)key).doubleValue();
|
var i = ((Number)key).doubleValue();
|
||||||
@ -95,14 +95,14 @@ public class ArrayValue extends ObjectValue {
|
|||||||
return super.getField(ctx, key);
|
return super.getField(ctx, key);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected boolean setField(CallContext ctx, Object key, Object val) throws InterruptedException {
|
protected boolean setField(Context ctx, Object key, Object val) throws InterruptedException {
|
||||||
if (key.equals("length")) {
|
if (key.equals("length")) {
|
||||||
return setSize((int)Values.toNumber(ctx, val));
|
return setSize((int)Values.toNumber(ctx, val));
|
||||||
}
|
}
|
||||||
if (key instanceof Number) {
|
if (key instanceof Number) {
|
||||||
var i = Values.number(key);
|
var i = Values.number(key);
|
||||||
if (i >= 0 && i - Math.floor(i) == 0) {
|
if (i >= 0 && i - Math.floor(i) == 0) {
|
||||||
set((int)i, val);
|
set(ctx, (int)i, val);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -110,7 +110,7 @@ public class ArrayValue extends ObjectValue {
|
|||||||
return super.setField(ctx, key, val);
|
return super.setField(ctx, key, val);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected boolean hasField(CallContext ctx, Object key) throws InterruptedException {
|
protected boolean hasField(Context ctx, Object key) throws InterruptedException {
|
||||||
if (key.equals("length")) return true;
|
if (key.equals("length")) return true;
|
||||||
if (key instanceof Number) {
|
if (key instanceof Number) {
|
||||||
var i = Values.number(key);
|
var i = Values.number(key);
|
||||||
@ -122,7 +122,7 @@ public class ArrayValue extends ObjectValue {
|
|||||||
return super.hasField(ctx, key);
|
return super.hasField(ctx, key);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected void deleteField(CallContext ctx, Object key) throws InterruptedException {
|
protected void deleteField(Context ctx, Object key) throws InterruptedException {
|
||||||
if (key instanceof Number) {
|
if (key instanceof Number) {
|
||||||
var i = Values.number(key);
|
var i = Values.number(key);
|
||||||
if (i >= 0 && i - Math.floor(i) == 0) {
|
if (i >= 0 && i - Math.floor(i) == 0) {
|
||||||
@ -149,12 +149,12 @@ public class ArrayValue extends ObjectValue {
|
|||||||
nonEnumerableSet.add("length");
|
nonEnumerableSet.add("length");
|
||||||
nonConfigurableSet.add("length");
|
nonConfigurableSet.add("length");
|
||||||
}
|
}
|
||||||
public ArrayValue(Object ...values) {
|
public ArrayValue(Context ctx, Object ...values) {
|
||||||
this();
|
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<Object> values) {
|
public static ArrayValue of(Context ctx, Collection<Object> values) {
|
||||||
return new ArrayValue(values.toArray(Object[]::new));
|
return new ArrayValue(ctx, values.toArray(Object[]::new));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,18 @@
|
|||||||
package me.topchetoeu.jscript.engine.values;
|
package me.topchetoeu.jscript.engine.values;
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.Location;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction;
|
import me.topchetoeu.jscript.compilation.Instruction;
|
||||||
import me.topchetoeu.jscript.compilation.Instruction.Type;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.FunctionContext;
|
||||||
import me.topchetoeu.jscript.engine.frame.CodeFrame;
|
import me.topchetoeu.jscript.engine.frame.CodeFrame;
|
||||||
import me.topchetoeu.jscript.engine.scope.GlobalScope;
|
|
||||||
import me.topchetoeu.jscript.engine.scope.ValueVariable;
|
import me.topchetoeu.jscript.engine.scope.ValueVariable;
|
||||||
|
|
||||||
public class CodeFunction extends FunctionValue {
|
public class CodeFunction extends FunctionValue {
|
||||||
public final int localsN;
|
public final int localsN;
|
||||||
public final int length;
|
public final int length;
|
||||||
public final Instruction[] body;
|
public final Instruction[] body;
|
||||||
public final LinkedHashMap<Location, Integer> breakableLocToIndex = new LinkedHashMap<>();
|
|
||||||
public final LinkedHashMap<Integer, Location> breakableIndexToLoc = new LinkedHashMap<>();
|
|
||||||
public final ValueVariable[] captures;
|
public final ValueVariable[] captures;
|
||||||
public final GlobalScope globals;
|
public FunctionContext environment;
|
||||||
|
|
||||||
public Location loc() {
|
public Location loc() {
|
||||||
for (var instr : body) {
|
for (var instr : body) {
|
||||||
@ -33,24 +28,16 @@ public class CodeFunction extends FunctionValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object call(CallContext ctx, Object thisArg, Object... args) throws InterruptedException {
|
public Object call(Context ctx, Object thisArg, Object ...args) throws InterruptedException {
|
||||||
return new CodeFrame(thisArg, args, this).run(ctx);
|
return new CodeFrame(ctx, thisArg, args, this).run(new Context(environment, ctx.message));
|
||||||
}
|
}
|
||||||
|
|
||||||
public CodeFunction(String name, int localsN, int length, GlobalScope globals, ValueVariable[] captures, Instruction[] body) {
|
public CodeFunction(FunctionContext environment, String name, int localsN, int length, ValueVariable[] captures, Instruction[] body) {
|
||||||
super(name, length);
|
super(name, length);
|
||||||
this.captures = captures;
|
this.captures = captures;
|
||||||
this.globals = globals;
|
this.environment = environment;
|
||||||
this.localsN = localsN;
|
this.localsN = localsN;
|
||||||
this.length = length;
|
this.length = length;
|
||||||
this.body = body;
|
this.body = body;
|
||||||
|
|
||||||
for (var i = 0; i < body.length; i++) {
|
|
||||||
if (body[i].type == Type.LOAD_FUNC) i += (int)body[i].get(0);
|
|
||||||
if (body[i].debugged && body[i].location != null) {
|
|
||||||
breakableLocToIndex.put(body[i].location, i);
|
|
||||||
breakableIndexToLoc.put(i, body[i].location);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ package me.topchetoeu.jscript.engine.values;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
|
|
||||||
public abstract class FunctionValue extends ObjectValue {
|
public abstract class FunctionValue extends ObjectValue {
|
||||||
public String name = "";
|
public String name = "";
|
||||||
@ -11,29 +11,29 @@ public abstract class FunctionValue extends ObjectValue {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "function(...) { ... }";
|
return "function(...) { ...}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract Object call(CallContext ctx, Object thisArg, Object... args) throws InterruptedException;
|
public abstract Object call(Context ctx, Object thisArg, Object ...args) throws InterruptedException;
|
||||||
public Object call(CallContext ctx) throws InterruptedException {
|
public Object call(Context ctx) throws InterruptedException {
|
||||||
return call(ctx, null);
|
return call(ctx, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object getField(CallContext ctx, Object key) throws InterruptedException {
|
protected Object getField(Context ctx, Object key) throws InterruptedException {
|
||||||
if (key.equals("name")) return name;
|
if (key.equals("name")) return name;
|
||||||
if (key.equals("length")) return length;
|
if (key.equals("length")) return length;
|
||||||
return super.getField(ctx, key);
|
return super.getField(ctx, key);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected boolean setField(CallContext ctx, Object key, Object val) throws InterruptedException {
|
protected boolean setField(Context ctx, Object key, Object val) throws InterruptedException {
|
||||||
if (key.equals("name")) name = Values.toString(ctx, val);
|
if (key.equals("name")) name = Values.toString(ctx, val);
|
||||||
else if (key.equals("length")) length = (int)Values.toNumber(ctx, val);
|
else if (key.equals("length")) length = (int)Values.toNumber(ctx, val);
|
||||||
else return super.setField(ctx, key, val);
|
else return super.setField(ctx, key, val);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected boolean hasField(CallContext ctx, Object key) throws InterruptedException {
|
protected boolean hasField(Context ctx, Object key) throws InterruptedException {
|
||||||
if (key.equals("name")) return true;
|
if (key.equals("name")) return true;
|
||||||
if (key.equals("length")) return true;
|
if (key.equals("length")) return true;
|
||||||
return super.hasField(ctx, key);
|
return super.hasField(ctx, key);
|
||||||
@ -63,8 +63,8 @@ public abstract class FunctionValue extends ObjectValue {
|
|||||||
nonEnumerableSet.add("length");
|
nonEnumerableSet.add("length");
|
||||||
|
|
||||||
var proto = new ObjectValue();
|
var proto = new ObjectValue();
|
||||||
proto.defineProperty("constructor", this, true, false, false);
|
proto.defineProperty(null, "constructor", this, true, false, false);
|
||||||
this.defineProperty("prototype", proto, true, false, false);
|
this.defineProperty(null, "prototype", proto, true, false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
package me.topchetoeu.jscript.engine.values;
|
package me.topchetoeu.jscript.engine.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
|
|
||||||
public class NativeFunction extends FunctionValue {
|
public class NativeFunction extends FunctionValue {
|
||||||
public static interface NativeFunctionRunner {
|
public static interface NativeFunctionRunner {
|
||||||
Object run(CallContext ctx, Object thisArg, Object[] args) throws InterruptedException;
|
Object run(Context ctx, Object thisArg, Object[] args) throws InterruptedException;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final NativeFunctionRunner action;
|
public final NativeFunctionRunner action;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object call(CallContext ctx, Object thisArg, Object... args) throws InterruptedException {
|
public Object call(Context ctx, Object thisArg, Object ...args) throws InterruptedException {
|
||||||
return action.run(ctx, thisArg, args);
|
return action.run(ctx, thisArg, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
package me.topchetoeu.jscript.engine.values;
|
package me.topchetoeu.jscript.engine.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
|
|
||||||
public class NativeWrapper extends ObjectValue {
|
public class NativeWrapper extends ObjectValue {
|
||||||
private static final Object NATIVE_PROTO = new Object();
|
private static final Object NATIVE_PROTO = new Object();
|
||||||
public final Object wrapped;
|
public final Object wrapped;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ObjectValue getPrototype(CallContext ctx) throws InterruptedException {
|
public ObjectValue getPrototype(Context ctx) throws InterruptedException {
|
||||||
if (prototype == NATIVE_PROTO) return ctx.engine.getPrototype(wrapped.getClass());
|
if (prototype == NATIVE_PROTO) return ctx.function.wrappersProvider.getProto(wrapped.getClass());
|
||||||
else return super.getPrototype(ctx);
|
else return super.getPrototype(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
|
|
||||||
public class ObjectValue {
|
public class ObjectValue {
|
||||||
public static enum PlaceholderProto {
|
public static enum PlaceholderProto {
|
||||||
@ -78,8 +78,8 @@ public class ObjectValue {
|
|||||||
state = State.FROZEN;
|
state = State.FROZEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean defineProperty(Object key, Object val, boolean writable, boolean configurable, boolean enumerable) {
|
public final boolean defineProperty(Context ctx, Object key, Object val, boolean writable, boolean configurable, boolean enumerable) {
|
||||||
key = Values.normalize(key); val = Values.normalize(val);
|
key = Values.normalize(ctx, key); val = Values.normalize(ctx, val);
|
||||||
boolean reconfigured =
|
boolean reconfigured =
|
||||||
writable != memberWritable(key) ||
|
writable != memberWritable(key) ||
|
||||||
configurable != memberConfigurable(key) ||
|
configurable != memberConfigurable(key) ||
|
||||||
@ -118,11 +118,11 @@ public class ObjectValue {
|
|||||||
values.put(key, val);
|
values.put(key, val);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public final boolean defineProperty(Object key, Object val) {
|
public final boolean defineProperty(Context ctx, Object key, Object val) {
|
||||||
return defineProperty(Values.normalize(key), Values.normalize(val), true, true, true);
|
return defineProperty(ctx, key, val, true, true, true);
|
||||||
}
|
}
|
||||||
public final boolean defineProperty(Object key, FunctionValue getter, FunctionValue setter, boolean configurable, boolean enumerable) {
|
public final boolean defineProperty(Context ctx, Object key, FunctionValue getter, FunctionValue setter, boolean configurable, boolean enumerable) {
|
||||||
key = Values.normalize(key);
|
key = Values.normalize(ctx, key);
|
||||||
if (
|
if (
|
||||||
properties.containsKey(key) &&
|
properties.containsKey(key) &&
|
||||||
properties.get(key).getter == getter &&
|
properties.get(key).getter == getter &&
|
||||||
@ -145,15 +145,15 @@ public class ObjectValue {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObjectValue getPrototype(CallContext ctx) throws InterruptedException {
|
public ObjectValue getPrototype(Context ctx) throws InterruptedException {
|
||||||
try {
|
try {
|
||||||
if (prototype == OBJ_PROTO) return ctx.engine().objectProto();
|
if (prototype == OBJ_PROTO) return ctx.function.proto("object");
|
||||||
if (prototype == ARR_PROTO) return ctx.engine().arrayProto();
|
if (prototype == ARR_PROTO) return ctx.function.proto("array");
|
||||||
if (prototype == FUNC_PROTO) return ctx.engine().functionProto();
|
if (prototype == FUNC_PROTO) return ctx.function.proto("function");
|
||||||
if (prototype == ERR_PROTO) return ctx.engine().errorProto();
|
if (prototype == ERR_PROTO) return ctx.function.proto("error");
|
||||||
if (prototype == RANGE_ERR_PROTO) return ctx.engine().rangeErrorProto();
|
if (prototype == RANGE_ERR_PROTO) return ctx.function.proto("rangeErr");
|
||||||
if (prototype == SYNTAX_ERR_PROTO) return ctx.engine().syntaxErrorProto();
|
if (prototype == SYNTAX_ERR_PROTO) return ctx.function.proto("syntaxErr");
|
||||||
if (prototype == TYPE_ERR_PROTO) return ctx.engine().typeErrorProto();
|
if (prototype == TYPE_ERR_PROTO) return ctx.function.proto("typeErr");
|
||||||
}
|
}
|
||||||
catch (NullPointerException e) {
|
catch (NullPointerException e) {
|
||||||
return null;
|
return null;
|
||||||
@ -161,22 +161,25 @@ public class ObjectValue {
|
|||||||
|
|
||||||
return (ObjectValue)prototype;
|
return (ObjectValue)prototype;
|
||||||
}
|
}
|
||||||
public final boolean setPrototype(CallContext ctx, Object val) {
|
public final boolean setPrototype(Context ctx, Object val) {
|
||||||
val = Values.normalize(val);
|
val = Values.normalize(ctx, val);
|
||||||
|
|
||||||
if (!extensible()) return false;
|
if (!extensible()) return false;
|
||||||
if (val == null || val == Values.NULL) prototype = null;
|
if (val == null || val == Values.NULL) {
|
||||||
|
prototype = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
else if (Values.isObject(val)) {
|
else if (Values.isObject(val)) {
|
||||||
var obj = Values.object(val);
|
var obj = Values.object(val);
|
||||||
|
|
||||||
if (ctx != null && ctx.engine() != null) {
|
if (ctx != null && ctx.function != null) {
|
||||||
if (obj == ctx.engine().objectProto()) prototype = OBJ_PROTO;
|
if (obj == ctx.function.proto("object")) prototype = OBJ_PROTO;
|
||||||
else if (obj == ctx.engine().arrayProto()) prototype = ARR_PROTO;
|
else if (obj == ctx.function.proto("array")) prototype = ARR_PROTO;
|
||||||
else if (obj == ctx.engine().functionProto()) prototype = FUNC_PROTO;
|
else if (obj == ctx.function.proto("function")) prototype = FUNC_PROTO;
|
||||||
else if (obj == ctx.engine().errorProto()) prototype = ERR_PROTO;
|
else if (obj == ctx.function.proto("error")) prototype = ERR_PROTO;
|
||||||
else if (obj == ctx.engine().syntaxErrorProto()) prototype = SYNTAX_ERR_PROTO;
|
else if (obj == ctx.function.proto("syntaxErr")) prototype = SYNTAX_ERR_PROTO;
|
||||||
else if (obj == ctx.engine().typeErrorProto()) prototype = TYPE_ERR_PROTO;
|
else if (obj == ctx.function.proto("typeErr")) prototype = TYPE_ERR_PROTO;
|
||||||
else if (obj == ctx.engine().rangeErrorProto()) prototype = RANGE_ERR_PROTO;
|
else if (obj == ctx.function.proto("rangeErr")) prototype = RANGE_ERR_PROTO;
|
||||||
else prototype = obj;
|
else prototype = obj;
|
||||||
}
|
}
|
||||||
else prototype = obj;
|
else prototype = obj;
|
||||||
@ -200,19 +203,19 @@ public class ObjectValue {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Property getProperty(CallContext ctx, Object key) throws InterruptedException {
|
protected Property getProperty(Context ctx, Object key) throws InterruptedException {
|
||||||
if (properties.containsKey(key)) return properties.get(key);
|
if (properties.containsKey(key)) return properties.get(key);
|
||||||
var proto = getPrototype(ctx);
|
var proto = getPrototype(ctx);
|
||||||
if (proto != null) return proto.getProperty(ctx, key);
|
if (proto != null) return proto.getProperty(ctx, key);
|
||||||
else return null;
|
else return null;
|
||||||
}
|
}
|
||||||
protected Object getField(CallContext ctx, Object key) throws InterruptedException {
|
protected Object getField(Context ctx, Object key) throws InterruptedException {
|
||||||
if (values.containsKey(key)) return values.get(key);
|
if (values.containsKey(key)) return values.get(key);
|
||||||
var proto = getPrototype(ctx);
|
var proto = getPrototype(ctx);
|
||||||
if (proto != null) return proto.getField(ctx, key);
|
if (proto != null) return proto.getField(ctx, key);
|
||||||
else return null;
|
else return null;
|
||||||
}
|
}
|
||||||
protected boolean setField(CallContext ctx, Object key, Object val) throws InterruptedException {
|
protected boolean setField(Context ctx, Object key, Object val) throws InterruptedException {
|
||||||
if (val instanceof FunctionValue && ((FunctionValue)val).name.equals("")) {
|
if (val instanceof FunctionValue && ((FunctionValue)val).name.equals("")) {
|
||||||
((FunctionValue)val).name = Values.toString(ctx, key);
|
((FunctionValue)val).name = Values.toString(ctx, key);
|
||||||
}
|
}
|
||||||
@ -220,15 +223,15 @@ public class ObjectValue {
|
|||||||
values.put(key, val);
|
values.put(key, val);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
protected void deleteField(CallContext ctx, Object key) throws InterruptedException {
|
protected void deleteField(Context ctx, Object key) throws InterruptedException {
|
||||||
values.remove(key);
|
values.remove(key);
|
||||||
}
|
}
|
||||||
protected boolean hasField(CallContext ctx, Object key) throws InterruptedException {
|
protected boolean hasField(Context ctx, Object key) throws InterruptedException {
|
||||||
return values.containsKey(key);
|
return values.containsKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final Object getMember(CallContext ctx, Object key, Object thisArg) throws InterruptedException {
|
public final Object getMember(Context ctx, Object key, Object thisArg) throws InterruptedException {
|
||||||
key = Values.normalize(key);
|
key = Values.normalize(ctx, key);
|
||||||
|
|
||||||
if (key.equals("__proto__")) {
|
if (key.equals("__proto__")) {
|
||||||
var res = getPrototype(ctx);
|
var res = getPrototype(ctx);
|
||||||
@ -239,21 +242,21 @@ public class ObjectValue {
|
|||||||
|
|
||||||
if (prop != null) {
|
if (prop != null) {
|
||||||
if (prop.getter == null) return 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);
|
else return getField(ctx, key);
|
||||||
}
|
}
|
||||||
public final Object getMember(CallContext ctx, Object key) throws InterruptedException {
|
public final Object getMember(Context ctx, Object key) throws InterruptedException {
|
||||||
return getMember(ctx, key, this);
|
return getMember(ctx, key, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean setMember(CallContext ctx, Object key, Object val, Object thisArg, boolean onlyProps) throws InterruptedException {
|
public final boolean setMember(Context 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);
|
var prop = getProperty(ctx, key);
|
||||||
if (prop != null) {
|
if (prop != null) {
|
||||||
if (prop.setter == null) return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
else if (onlyProps) return false;
|
else if (onlyProps) return false;
|
||||||
@ -266,21 +269,22 @@ public class ObjectValue {
|
|||||||
else if (nonWritableSet.contains(key)) return false;
|
else if (nonWritableSet.contains(key)) return false;
|
||||||
else return setField(ctx, key, val);
|
else return setField(ctx, key, val);
|
||||||
}
|
}
|
||||||
public final boolean setMember(CallContext ctx, Object key, Object val, boolean onlyProps) throws InterruptedException {
|
public final boolean setMember(Context 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 {
|
public final boolean hasMember(Context 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 (key != null && key.equals("__proto__")) return true;
|
||||||
if (hasField(ctx, key)) return true;
|
if (hasField(ctx, key)) return true;
|
||||||
if (properties.containsKey(key)) return true;
|
if (properties.containsKey(key)) return true;
|
||||||
if (own) return false;
|
if (own) return false;
|
||||||
return prototype != null && getPrototype(ctx).hasMember(ctx, key, own);
|
var proto = getPrototype(ctx);
|
||||||
|
return proto != null && proto.hasMember(ctx, key, own);
|
||||||
}
|
}
|
||||||
public final boolean deleteMember(CallContext ctx, Object key) throws InterruptedException {
|
public final boolean deleteMember(Context ctx, Object key) throws InterruptedException {
|
||||||
key = Values.normalize(key);
|
key = Values.normalize(ctx, key);
|
||||||
|
|
||||||
if (!memberConfigurable(key)) return false;
|
if (!memberConfigurable(key)) return false;
|
||||||
properties.remove(key);
|
properties.remove(key);
|
||||||
@ -290,22 +294,22 @@ public class ObjectValue {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final ObjectValue getMemberDescriptor(CallContext ctx, Object key) throws InterruptedException {
|
public final ObjectValue getMemberDescriptor(Context ctx, Object key) throws InterruptedException {
|
||||||
key = Values.normalize(key);
|
key = Values.normalize(ctx, key);
|
||||||
|
|
||||||
var prop = properties.get(key);
|
var prop = properties.get(key);
|
||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
|
|
||||||
res.defineProperty("configurable", memberConfigurable(key));
|
res.defineProperty(ctx, "configurable", memberConfigurable(key));
|
||||||
res.defineProperty("enumerable", memberEnumerable(key));
|
res.defineProperty(ctx, "enumerable", memberEnumerable(key));
|
||||||
|
|
||||||
if (prop != null) {
|
if (prop != null) {
|
||||||
res.defineProperty("get", prop.getter);
|
res.defineProperty(ctx, "get", prop.getter);
|
||||||
res.defineProperty("set", prop.setter);
|
res.defineProperty(ctx, "set", prop.setter);
|
||||||
}
|
}
|
||||||
else if (hasField(ctx, key)) {
|
else if (hasField(ctx, key)) {
|
||||||
res.defineProperty("value", values.get(key));
|
res.defineProperty(ctx, "value", values.get(key));
|
||||||
res.defineProperty("writable", memberWritable(key));
|
res.defineProperty(ctx, "writable", memberWritable(key));
|
||||||
}
|
}
|
||||||
else return null;
|
else return null;
|
||||||
return res;
|
return res;
|
||||||
@ -326,10 +330,10 @@ public class ObjectValue {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObjectValue(Map<?, ?> values) {
|
public ObjectValue(Context ctx, Map<?, ?> values) {
|
||||||
this(PlaceholderProto.OBJECT);
|
this(PlaceholderProto.OBJECT);
|
||||||
for (var el : values.entrySet()) {
|
for (var el : values.entrySet()) {
|
||||||
defineProperty(el.getKey(), el.getValue());
|
defineProperty(ctx, el.getKey(), el.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public ObjectValue(PlaceholderProto proto) {
|
public ObjectValue(PlaceholderProto proto) {
|
||||||
|
@ -10,7 +10,7 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.Operation;
|
import me.topchetoeu.jscript.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.frame.ConvertHint;
|
import me.topchetoeu.jscript.engine.frame.ConvertHint;
|
||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
@ -65,7 +65,7 @@ public class Values {
|
|||||||
return "object";
|
return "object";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object tryCallConvertFunc(CallContext ctx, Object obj, String name) throws InterruptedException {
|
private static Object tryCallConvertFunc(Context ctx, Object obj, String name) throws InterruptedException {
|
||||||
var func = getMember(ctx, obj, name);
|
var func = getMember(ctx, obj, name);
|
||||||
|
|
||||||
if (func != null) {
|
if (func != null) {
|
||||||
@ -87,8 +87,8 @@ public class Values {
|
|||||||
obj == NULL;
|
obj == NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object toPrimitive(CallContext ctx, Object obj, ConvertHint hint) throws InterruptedException {
|
public static Object toPrimitive(Context ctx, Object obj, ConvertHint hint) throws InterruptedException {
|
||||||
obj = normalize(obj);
|
obj = normalize(ctx, obj);
|
||||||
if (isPrimitive(obj)) return obj;
|
if (isPrimitive(obj)) return obj;
|
||||||
|
|
||||||
var first = hint == ConvertHint.VALUEOF ? "valueOf" : "toString";
|
var first = hint == ConvertHint.VALUEOF ? "valueOf" : "toString";
|
||||||
@ -112,7 +112,7 @@ public class Values {
|
|||||||
if (obj instanceof Boolean) return (Boolean)obj;
|
if (obj instanceof Boolean) return (Boolean)obj;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public static double toNumber(CallContext ctx, Object obj) throws InterruptedException {
|
public static double toNumber(Context ctx, Object obj) throws InterruptedException {
|
||||||
var val = toPrimitive(ctx, obj, ConvertHint.VALUEOF);
|
var val = toPrimitive(ctx, obj, ConvertHint.VALUEOF);
|
||||||
|
|
||||||
if (val instanceof Number) return number(obj);
|
if (val instanceof Number) return number(obj);
|
||||||
@ -125,7 +125,7 @@ public class Values {
|
|||||||
}
|
}
|
||||||
return Double.NaN;
|
return Double.NaN;
|
||||||
}
|
}
|
||||||
public static String toString(CallContext ctx, Object obj) throws InterruptedException {
|
public static String toString(Context ctx, Object obj) throws InterruptedException {
|
||||||
var val = toPrimitive(ctx, obj, ConvertHint.VALUEOF);
|
var val = toPrimitive(ctx, obj, ConvertHint.VALUEOF);
|
||||||
|
|
||||||
if (val == null) return "undefined";
|
if (val == null) return "undefined";
|
||||||
@ -146,47 +146,47 @@ public class Values {
|
|||||||
return "Unknown value";
|
return "Unknown value";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object add(CallContext ctx, Object a, Object b) throws InterruptedException {
|
public static Object add(Context ctx, Object a, Object b) throws InterruptedException {
|
||||||
if (a instanceof String || b instanceof String) return toString(ctx, a) + toString(ctx, b);
|
if (a instanceof String || b instanceof String) return toString(ctx, a) + toString(ctx, b);
|
||||||
else return toNumber(ctx, a) + toNumber(ctx, b);
|
else return toNumber(ctx, a) + toNumber(ctx, b);
|
||||||
}
|
}
|
||||||
public static double subtract(CallContext ctx, Object a, Object b) throws InterruptedException {
|
public static double subtract(Context ctx, Object a, Object b) throws InterruptedException {
|
||||||
return toNumber(ctx, a) - toNumber(ctx, b);
|
return toNumber(ctx, a) - toNumber(ctx, b);
|
||||||
}
|
}
|
||||||
public static double multiply(CallContext ctx, Object a, Object b) throws InterruptedException {
|
public static double multiply(Context ctx, Object a, Object b) throws InterruptedException {
|
||||||
return toNumber(ctx, a) * toNumber(ctx, b);
|
return toNumber(ctx, a) * toNumber(ctx, b);
|
||||||
}
|
}
|
||||||
public static double divide(CallContext ctx, Object a, Object b) throws InterruptedException {
|
public static double divide(Context ctx, Object a, Object b) throws InterruptedException {
|
||||||
return toNumber(ctx, a) / toNumber(ctx, b);
|
return toNumber(ctx, a) / toNumber(ctx, b);
|
||||||
}
|
}
|
||||||
public static double modulo(CallContext ctx, Object a, Object b) throws InterruptedException {
|
public static double modulo(Context ctx, Object a, Object b) throws InterruptedException {
|
||||||
return toNumber(ctx, a) % toNumber(ctx, b);
|
return toNumber(ctx, a) % toNumber(ctx, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double negative(CallContext ctx, Object obj) throws InterruptedException {
|
public static double negative(Context ctx, Object obj) throws InterruptedException {
|
||||||
return -toNumber(ctx, obj);
|
return -toNumber(ctx, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int and(CallContext ctx, Object a, Object b) throws InterruptedException {
|
public static int and(Context ctx, Object a, Object b) throws InterruptedException {
|
||||||
return (int)toNumber(ctx, a) & (int)toNumber(ctx, b);
|
return (int)toNumber(ctx, a) & (int)toNumber(ctx, b);
|
||||||
}
|
}
|
||||||
public static int or(CallContext ctx, Object a, Object b) throws InterruptedException {
|
public static int or(Context ctx, Object a, Object b) throws InterruptedException {
|
||||||
return (int)toNumber(ctx, a) | (int)toNumber(ctx, b);
|
return (int)toNumber(ctx, a) | (int)toNumber(ctx, b);
|
||||||
}
|
}
|
||||||
public static int xor(CallContext ctx, Object a, Object b) throws InterruptedException {
|
public static int xor(Context ctx, Object a, Object b) throws InterruptedException {
|
||||||
return (int)toNumber(ctx, a) ^ (int)toNumber(ctx, b);
|
return (int)toNumber(ctx, a) ^ (int)toNumber(ctx, b);
|
||||||
}
|
}
|
||||||
public static int bitwiseNot(CallContext ctx, Object obj) throws InterruptedException {
|
public static int bitwiseNot(Context ctx, Object obj) throws InterruptedException {
|
||||||
return ~(int)toNumber(ctx, obj);
|
return ~(int)toNumber(ctx, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int shiftLeft(CallContext ctx, Object a, Object b) throws InterruptedException {
|
public static int shiftLeft(Context ctx, Object a, Object b) throws InterruptedException {
|
||||||
return (int)toNumber(ctx, a) << (int)toNumber(ctx, b);
|
return (int)toNumber(ctx, a) << (int)toNumber(ctx, b);
|
||||||
}
|
}
|
||||||
public static int shiftRight(CallContext ctx, Object a, Object b) throws InterruptedException {
|
public static int shiftRight(Context ctx, Object a, Object b) throws InterruptedException {
|
||||||
return (int)toNumber(ctx, a) >> (int)toNumber(ctx, b);
|
return (int)toNumber(ctx, a) >> (int)toNumber(ctx, b);
|
||||||
}
|
}
|
||||||
public static long unsignedShiftRight(CallContext ctx, Object a, Object b) throws InterruptedException {
|
public static long unsignedShiftRight(Context ctx, Object a, Object b) throws InterruptedException {
|
||||||
long _a = (long)toNumber(ctx, a);
|
long _a = (long)toNumber(ctx, a);
|
||||||
long _b = (long)toNumber(ctx, b);
|
long _b = (long)toNumber(ctx, b);
|
||||||
|
|
||||||
@ -195,7 +195,7 @@ public class Values {
|
|||||||
return _a >>> _b;
|
return _a >>> _b;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int compare(CallContext ctx, Object a, Object b) throws InterruptedException {
|
public static int compare(Context ctx, Object a, Object b) throws InterruptedException {
|
||||||
a = toPrimitive(ctx, a, ConvertHint.VALUEOF);
|
a = toPrimitive(ctx, a, ConvertHint.VALUEOF);
|
||||||
b = toPrimitive(ctx, b, ConvertHint.VALUEOF);
|
b = toPrimitive(ctx, b, ConvertHint.VALUEOF);
|
||||||
|
|
||||||
@ -207,7 +207,7 @@ public class Values {
|
|||||||
return !toBoolean(obj);
|
return !toBoolean(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isInstanceOf(CallContext ctx, Object obj, Object proto) throws InterruptedException {
|
public static boolean isInstanceOf(Context ctx, Object obj, Object proto) throws InterruptedException {
|
||||||
if (obj == null || obj == NULL || proto == null || proto == NULL) return false;
|
if (obj == null || obj == NULL || proto == null || proto == NULL) return false;
|
||||||
var val = getPrototype(ctx, obj);
|
var val = getPrototype(ctx, obj);
|
||||||
|
|
||||||
@ -219,7 +219,7 @@ public class Values {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object operation(CallContext ctx, Operation op, Object... args) throws InterruptedException {
|
public static Object operation(Context ctx, Operation op, Object ...args) throws InterruptedException {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case ADD: return add(ctx, args[0], args[1]);
|
case ADD: return add(ctx, args[0], args[1]);
|
||||||
case SUBTRACT: return subtract(ctx, args[0], args[1]);
|
case SUBTRACT: return subtract(ctx, args[0], args[1]);
|
||||||
@ -231,8 +231,8 @@ public class Values {
|
|||||||
case OR: return or(ctx, args[0], args[1]);
|
case OR: return or(ctx, args[0], args[1]);
|
||||||
case XOR: return xor(ctx, args[0], args[1]);
|
case XOR: return xor(ctx, args[0], args[1]);
|
||||||
|
|
||||||
case EQUALS: return strictEquals(args[0], args[1]);
|
case EQUALS: return strictEquals(ctx, args[0], args[1]);
|
||||||
case NOT_EQUALS: return !strictEquals(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_EQUALS: return looseEqual(ctx, args[0], args[1]);
|
||||||
case LOOSE_NOT_EQUALS: return !looseEqual(ctx, args[0], args[1]);
|
case LOOSE_NOT_EQUALS: return !looseEqual(ctx, args[0], args[1]);
|
||||||
|
|
||||||
@ -260,8 +260,8 @@ public class Values {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object getMember(CallContext ctx, Object obj, Object key) throws InterruptedException {
|
public static Object getMember(Context 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 undefined.");
|
||||||
if (obj == NULL) throw new IllegalArgumentException("Tried to access member of null.");
|
if (obj == NULL) throw new IllegalArgumentException("Tried to access member of null.");
|
||||||
if (isObject(obj)) return object(obj).getMember(ctx, key);
|
if (isObject(obj)) return object(obj).getMember(ctx, key);
|
||||||
@ -280,8 +280,8 @@ public class Values {
|
|||||||
else if (key != null && key.equals("__proto__")) return proto;
|
else if (key != null && key.equals("__proto__")) return proto;
|
||||||
else return proto.getMember(ctx, key, obj);
|
else return proto.getMember(ctx, key, obj);
|
||||||
}
|
}
|
||||||
public static boolean setMember(CallContext ctx, Object obj, Object key, Object val) throws InterruptedException {
|
public static boolean setMember(Context 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 undefined.");
|
||||||
if (obj == NULL) throw EngineException.ofType("Tried to access member of null.");
|
if (obj == NULL) throw EngineException.ofType("Tried to access member of null.");
|
||||||
if (key.equals("__proto__")) return setPrototype(ctx, obj, val);
|
if (key.equals("__proto__")) return setPrototype(ctx, obj, val);
|
||||||
@ -290,9 +290,9 @@ public class Values {
|
|||||||
var proto = getPrototype(ctx, obj);
|
var proto = getPrototype(ctx, obj);
|
||||||
return proto.setMember(ctx, key, val, obj, true);
|
return proto.setMember(ctx, key, val, obj, true);
|
||||||
}
|
}
|
||||||
public static boolean hasMember(CallContext ctx, Object obj, Object key, boolean own) throws InterruptedException {
|
public static boolean hasMember(Context ctx, Object obj, Object key, boolean own) throws InterruptedException {
|
||||||
if (obj == null || obj == NULL) return false;
|
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 (key.equals("__proto__")) return true;
|
||||||
if (isObject(obj)) return object(obj).hasMember(ctx, key, own);
|
if (isObject(obj)) return object(obj).hasMember(ctx, key, own);
|
||||||
@ -308,31 +308,31 @@ public class Values {
|
|||||||
var proto = getPrototype(ctx, obj);
|
var proto = getPrototype(ctx, obj);
|
||||||
return proto != null && proto.hasMember(ctx, key, own);
|
return proto != null && proto.hasMember(ctx, key, own);
|
||||||
}
|
}
|
||||||
public static boolean deleteMember(CallContext ctx, Object obj, Object key) throws InterruptedException {
|
public static boolean deleteMember(Context ctx, Object obj, Object key) throws InterruptedException {
|
||||||
if (obj == null || obj == NULL) return false;
|
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);
|
if (isObject(obj)) return object(obj).deleteMember(ctx, key);
|
||||||
else return false;
|
else return false;
|
||||||
}
|
}
|
||||||
public static ObjectValue getPrototype(CallContext ctx, Object obj) throws InterruptedException {
|
public static ObjectValue getPrototype(Context ctx, Object obj) throws InterruptedException {
|
||||||
if (obj == null || obj == NULL) return null;
|
if (obj == null || obj == NULL) return null;
|
||||||
obj = normalize(obj);
|
obj = normalize(ctx, obj);
|
||||||
if (isObject(obj)) return object(obj).getPrototype(ctx);
|
if (isObject(obj)) return object(obj).getPrototype(ctx);
|
||||||
if (ctx == null) return null;
|
if (ctx == null) return null;
|
||||||
|
|
||||||
if (obj instanceof String) return ctx.engine().stringProto();
|
if (obj instanceof String) return ctx.function.proto("string");
|
||||||
else if (obj instanceof Number) return ctx.engine().numberProto();
|
else if (obj instanceof Number) return ctx.function.proto("number");
|
||||||
else if (obj instanceof Boolean) return ctx.engine().booleanProto();
|
else if (obj instanceof Boolean) return ctx.function.proto("bool");
|
||||||
else if (obj instanceof Symbol) return ctx.engine().symbolProto();
|
else if (obj instanceof Symbol) return ctx.function.proto("symbol");
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
public static boolean setPrototype(CallContext ctx, Object obj, Object proto) throws InterruptedException {
|
public static boolean setPrototype(Context ctx, Object obj, Object proto) throws InterruptedException {
|
||||||
obj = normalize(obj); proto = normalize(proto);
|
obj = normalize(ctx, obj);
|
||||||
return isObject(obj) && object(obj).setPrototype(ctx, proto);
|
return isObject(obj) && object(obj).setPrototype(ctx, proto);
|
||||||
}
|
}
|
||||||
public static List<Object> getMembers(CallContext ctx, Object obj, boolean own, boolean includeNonEnumerable) throws InterruptedException {
|
public static List<Object> getMembers(Context ctx, Object obj, boolean own, boolean includeNonEnumerable) throws InterruptedException {
|
||||||
List<Object> res = new ArrayList<>();
|
List<Object> res = new ArrayList<>();
|
||||||
|
|
||||||
if (isObject(obj)) res = object(obj).keys(includeNonEnumerable);
|
if (isObject(obj)) res = object(obj).keys(includeNonEnumerable);
|
||||||
@ -353,14 +353,14 @@ public class Values {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object call(CallContext ctx, Object func, Object thisArg, Object ...args) throws InterruptedException {
|
public static Object call(Context ctx, Object func, Object thisArg, Object ...args) throws InterruptedException {
|
||||||
if (!isFunction(func))
|
if (!isFunction(func))
|
||||||
throw EngineException.ofType("Tried to call a non-function value.");
|
throw EngineException.ofType("Tried to call a non-function value.");
|
||||||
return function(func).call(ctx, thisArg, args);
|
return function(func).call(ctx, thisArg, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean strictEquals(Object a, Object b) {
|
public static boolean strictEquals(Context ctx, Object a, Object b) {
|
||||||
a = normalize(a); b = normalize(b);
|
a = normalize(ctx, a); b = normalize(ctx, b);
|
||||||
|
|
||||||
if (a == null || b == null) return a == null && b == null;
|
if (a == null || b == null) return a == null && b == null;
|
||||||
if (isNan(a) || isNan(b)) return false;
|
if (isNan(a) || isNan(b)) return false;
|
||||||
@ -369,8 +369,8 @@ public class Values {
|
|||||||
|
|
||||||
return a == b || a.equals(b);
|
return a == b || a.equals(b);
|
||||||
}
|
}
|
||||||
public static boolean looseEqual(CallContext ctx, Object a, Object b) throws InterruptedException {
|
public static boolean looseEqual(Context 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
|
// In loose equality, null is equivalent to undefined
|
||||||
if (a == NULL) a = null;
|
if (a == NULL) a = null;
|
||||||
@ -387,13 +387,13 @@ public class Values {
|
|||||||
// Compare symbols by reference
|
// Compare symbols by reference
|
||||||
if (a instanceof Symbol || b instanceof Symbol) return a == b;
|
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 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
|
// Default to strings
|
||||||
return toString(ctx, a).equals(toString(ctx, b));
|
return toString(ctx, a).equals(toString(ctx, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object normalize(Object val) {
|
public static Object normalize(Context ctx, Object val) {
|
||||||
if (val instanceof Number) return number(val);
|
if (val instanceof Number) return number(val);
|
||||||
if (isPrimitive(val) || val instanceof ObjectValue) return val;
|
if (isPrimitive(val) || val instanceof ObjectValue) return val;
|
||||||
if (val instanceof Character) return val + "";
|
if (val instanceof Character) return val + "";
|
||||||
@ -402,7 +402,7 @@ public class Values {
|
|||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
|
|
||||||
for (var entry : ((Map<?, ?>)val).entrySet()) {
|
for (var entry : ((Map<?, ?>)val).entrySet()) {
|
||||||
res.defineProperty(entry.getKey(), entry.getValue());
|
res.defineProperty(ctx, entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -412,17 +412,22 @@ public class Values {
|
|||||||
var res = new ArrayValue();
|
var res = new ArrayValue();
|
||||||
|
|
||||||
for (var entry : ((Iterable<?>)val)) {
|
for (var entry : ((Iterable<?>)val)) {
|
||||||
res.set(res.size(), entry);
|
res.set(ctx, res.size(), entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (val instanceof Class) {
|
||||||
|
if (ctx == null) return null;
|
||||||
|
else return ctx.function.wrappersProvider.getConstr((Class<?>)val);
|
||||||
|
}
|
||||||
|
|
||||||
return new NativeWrapper(val);
|
return new NativeWrapper(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <T> T convert(CallContext ctx, Object obj, Class<T> clazz) throws InterruptedException {
|
public static <T> T convert(Context ctx, Object obj, Class<T> clazz) throws InterruptedException {
|
||||||
if (clazz == Void.class) return null;
|
if (clazz == Void.class) return null;
|
||||||
if (clazz == null || clazz == Object.class) return (T)obj;
|
if (clazz == null || clazz == Object.class) return (T)obj;
|
||||||
|
|
||||||
@ -490,10 +495,10 @@ public class Values {
|
|||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Iterable<Object> toJavaIterable(CallContext ctx, Object obj) throws InterruptedException {
|
public static Iterable<Object> toJavaIterable(Context ctx, Object obj) throws InterruptedException {
|
||||||
return () -> {
|
return () -> {
|
||||||
try {
|
try {
|
||||||
var constr = getMember(ctx, ctx.engine().symbolProto(), "constructor");
|
var constr = getMember(ctx, ctx.function.proto("symbol"), "constructor");
|
||||||
var symbol = getMember(ctx, constr, "iterator");
|
var symbol = getMember(ctx, constr, "iterator");
|
||||||
|
|
||||||
var iteratorFunc = getMember(ctx, obj, symbol);
|
var iteratorFunc = getMember(ctx, obj, symbol);
|
||||||
@ -557,25 +562,25 @@ public class Values {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ObjectValue fromJavaIterable(CallContext ctx, Iterable<?> iterable) throws InterruptedException {
|
public static ObjectValue fromJavaIterable(Context ctx, Iterable<?> iterable) throws InterruptedException {
|
||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
var it = iterable.iterator();
|
var it = iterable.iterator();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var key = getMember(ctx, getMember(ctx, ctx.engine().symbolProto(), "constructor"), "iterable");
|
var key = getMember(ctx, getMember(ctx, ctx.function.proto("symbol"), "constructor"), "iterator");
|
||||||
res.defineProperty(key, new NativeFunction("", (_ctx, thisArg, args) -> fromJavaIterable(ctx, iterable)));
|
res.defineProperty(ctx, key, new NativeFunction("", (_ctx, thisArg, args) -> thisArg));
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException | NullPointerException e) { }
|
catch (IllegalArgumentException | NullPointerException e) { }
|
||||||
|
|
||||||
res.defineProperty("next", new NativeFunction("", (_ctx, _th, _args) -> {
|
res.defineProperty(ctx, "next", new NativeFunction("", (_ctx, _th, _args) -> {
|
||||||
if (!it.hasNext()) return new ObjectValue(Map.of("done", true));
|
if (!it.hasNext()) return new ObjectValue(ctx, Map.of("done", true));
|
||||||
else return new ObjectValue(Map.of("value", it.next()));
|
else return new ObjectValue(ctx, Map.of("value", it.next()));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void printValue(CallContext ctx, Object val, HashSet<Object> passed, int tab) throws InterruptedException {
|
private static void printValue(Context ctx, Object val, HashSet<Object> passed, int tab) throws InterruptedException {
|
||||||
if (passed.contains(val)) {
|
if (passed.contains(val)) {
|
||||||
System.out.print("[circular]");
|
System.out.print("[circular]");
|
||||||
return;
|
return;
|
||||||
@ -647,7 +652,7 @@ public class Values {
|
|||||||
else if (val instanceof String) System.out.print("'" + val + "'");
|
else if (val instanceof String) System.out.print("'" + val + "'");
|
||||||
else System.out.print(Values.toString(ctx, val));
|
else System.out.print(Values.toString(ctx, val));
|
||||||
}
|
}
|
||||||
public static void printValue(CallContext ctx, Object val) throws InterruptedException {
|
public static void printValue(Context ctx, Object val) throws InterruptedException {
|
||||||
printValue(ctx, val, new HashSet<>(), 0);
|
printValue(ctx, val, new HashSet<>(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.Location;
|
import me.topchetoeu.jscript.Location;
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
import me.topchetoeu.jscript.engine.values.ObjectValue.PlaceholderProto;
|
import me.topchetoeu.jscript.engine.values.ObjectValue.PlaceholderProto;
|
||||||
@ -28,9 +28,14 @@ public class EngineException extends RuntimeException {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString(CallContext ctx) throws InterruptedException {
|
public String toString(Context ctx) throws InterruptedException {
|
||||||
var ss = new StringBuilder();
|
var ss = new StringBuilder();
|
||||||
|
try {
|
||||||
ss.append(Values.toString(ctx, value)).append('\n');
|
ss.append(Values.toString(ctx, value)).append('\n');
|
||||||
|
}
|
||||||
|
catch (EngineException e) {
|
||||||
|
ss.append("[Error while stringifying]\n");
|
||||||
|
}
|
||||||
for (var line : stackTrace) {
|
for (var line : stackTrace) {
|
||||||
ss.append(" ").append(line).append('\n');
|
ss.append(" ").append(line).append('\n');
|
||||||
}
|
}
|
||||||
@ -41,7 +46,7 @@ public class EngineException extends RuntimeException {
|
|||||||
|
|
||||||
private static Object err(String msg, PlaceholderProto proto) {
|
private static Object err(String msg, PlaceholderProto proto) {
|
||||||
var res = new ObjectValue(proto);
|
var res = new ObjectValue(proto);
|
||||||
res.defineProperty("message", msg);
|
res.defineProperty(null, "message", msg);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.filesystem;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public interface File {
|
|
||||||
int read(byte[] buff) throws IOException;
|
|
||||||
void write(byte[] buff) throws IOException;
|
|
||||||
long tell() throws IOException;
|
|
||||||
void seek(long offset, int pos) throws IOException;
|
|
||||||
void close() throws IOException;
|
|
||||||
Permissions perms();
|
|
||||||
|
|
||||||
default String readToString() throws IOException {
|
|
||||||
seek(0, 2);
|
|
||||||
long len = tell();
|
|
||||||
if (len < 0) return null;
|
|
||||||
seek(0, 0);
|
|
||||||
byte[] res = new byte[(int)len];
|
|
||||||
if (read(res) < 0) return null;
|
|
||||||
return new String(res);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.filesystem;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
public interface Filesystem extends PermissionsProvider {
|
|
||||||
public static enum EntryType {
|
|
||||||
NONE,
|
|
||||||
FILE,
|
|
||||||
FOLDER,
|
|
||||||
}
|
|
||||||
|
|
||||||
File open(Path path) throws IOException;
|
|
||||||
EntryType type(Path path);
|
|
||||||
boolean mkdir(Path path);
|
|
||||||
boolean rm(Path path) throws IOException;
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.filesystem;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class InaccessibleFile implements File {
|
|
||||||
@Override
|
|
||||||
public int read(byte[] buff) throws IOException {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void write(byte[] buff) throws IOException {
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public long tell() throws IOException {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void seek(long offset, int pos) throws IOException {
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public Permissions perms() {
|
|
||||||
return Permissions.NONE;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.filesystem;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class MemoryFile implements File {
|
|
||||||
public byte[] data;
|
|
||||||
private int ptr = 0;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
data = null;
|
|
||||||
ptr = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int read(byte[] buff) throws IOException {
|
|
||||||
if (data == null) return -1;
|
|
||||||
if (ptr == data.length) return -1;
|
|
||||||
int n = Math.min(buff.length, data.length - ptr);
|
|
||||||
System.arraycopy(data, ptr, buff, 0, n);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void seek(long offset, int pos) throws IOException {
|
|
||||||
if (data == null) return;
|
|
||||||
if (pos == 0) ptr = (int)offset;
|
|
||||||
else if (pos == 1) ptr += (int)offset;
|
|
||||||
else ptr = data.length - (int)offset;
|
|
||||||
|
|
||||||
ptr = (int)Math.max(Math.min(ptr, data.length), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long tell() throws IOException {
|
|
||||||
if (data == null) return -1;
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(byte[] buff) throws IOException { }
|
|
||||||
@Override
|
|
||||||
public Permissions perms() {
|
|
||||||
if (data == null) return Permissions.NONE;
|
|
||||||
else return Permissions.READ;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MemoryFile(byte[] data) {
|
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.filesystem;
|
|
||||||
|
|
||||||
public enum Permissions {
|
|
||||||
NONE("", false, false),
|
|
||||||
READ("r", true, false),
|
|
||||||
READ_WRITE("rw", true, true);
|
|
||||||
|
|
||||||
public final String readMode;
|
|
||||||
public final boolean readable;
|
|
||||||
public final boolean writable;
|
|
||||||
|
|
||||||
private Permissions(String mode, boolean r, boolean w) {
|
|
||||||
this.readMode = mode;
|
|
||||||
this.readable = r;
|
|
||||||
this.writable = w;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.filesystem;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
public interface PermissionsProvider {
|
|
||||||
Permissions perms(Path file);
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.filesystem;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.RandomAccessFile;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
public class PhysicalFile implements File {
|
|
||||||
private RandomAccessFile file;
|
|
||||||
private Permissions perms;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int read(byte[] buff) throws IOException {
|
|
||||||
if (!perms.readable) return -1;
|
|
||||||
return file.read(buff);
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void write(byte[] buff) throws IOException {
|
|
||||||
if (!perms.writable) return;
|
|
||||||
file.write(buff);
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public long tell() throws IOException {
|
|
||||||
if (!perms.readable) return -1;
|
|
||||||
return file.getFilePointer();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void seek(long offset, int pos) throws IOException {
|
|
||||||
if (!perms.readable) return;
|
|
||||||
if (pos == 0) file.seek(offset);
|
|
||||||
else if (pos == 1) file.seek(tell() + offset);
|
|
||||||
else file.seek(file.length() + offset);
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
if (!perms.readable) return;
|
|
||||||
file.close();
|
|
||||||
file = null;
|
|
||||||
perms = Permissions.NONE;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public Permissions perms() {
|
|
||||||
return perms;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PhysicalFile(Path path, Permissions perms) throws IOException {
|
|
||||||
if (!path.toFile().canWrite() && perms.writable) perms = Permissions.READ;
|
|
||||||
if (!path.toFile().canRead() && perms.readable) perms = Permissions.NONE;
|
|
||||||
|
|
||||||
this.perms = perms;
|
|
||||||
if (perms == Permissions.NONE) this.file = null;
|
|
||||||
else this.file = new RandomAccessFile(path.toString(), perms.readMode);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,75 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.filesystem;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class PhysicalFilesystem implements Filesystem {
|
|
||||||
public final Path root;
|
|
||||||
public final PermissionsProvider perms;
|
|
||||||
|
|
||||||
private static Path joinPaths(Path root, Path file) {
|
|
||||||
if (file.isAbsolute()) file = file.getRoot().relativize(file);
|
|
||||||
file = file.normalize();
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (file.startsWith("..")) file = file.subpath(1, file.getNameCount());
|
|
||||||
else if (file.startsWith(".")) file = file.subpath(1, file.getNameCount());
|
|
||||||
else break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Path.of(root.toString(), file.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean mkdir(Path path) {
|
|
||||||
if (!perms(path).writable) return false;
|
|
||||||
path = joinPaths(root, path);
|
|
||||||
return path.toFile().mkdirs();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public File open(Path path) throws IOException {
|
|
||||||
var perms = perms(path);
|
|
||||||
if (perms == Permissions.NONE) return new InaccessibleFile();
|
|
||||||
path = joinPaths(root, path);
|
|
||||||
|
|
||||||
if (path.toFile().isDirectory()) {
|
|
||||||
return new MemoryFile(String.join("\n", Files.list(path).map(Path::toString).collect(Collectors.toList())).getBytes());
|
|
||||||
}
|
|
||||||
else if (path.toFile().isFile()) {
|
|
||||||
return new PhysicalFile(path, perms);
|
|
||||||
}
|
|
||||||
else return new InaccessibleFile();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public boolean rm(Path path) {
|
|
||||||
if (!perms(path).writable) return false;
|
|
||||||
return joinPaths(root, path).toFile().delete();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public EntryType type(Path path) {
|
|
||||||
if (!perms(path).readable) return EntryType.NONE;
|
|
||||||
path = joinPaths(root, path);
|
|
||||||
|
|
||||||
if (!path.toFile().exists()) return EntryType.NONE;
|
|
||||||
if (path.toFile().isFile()) return EntryType.FILE;
|
|
||||||
else return EntryType.FOLDER;
|
|
||||||
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public Permissions perms(Path path) {
|
|
||||||
path = joinPaths(root, path);
|
|
||||||
var res = perms.perms(path);
|
|
||||||
|
|
||||||
if (!path.toFile().canWrite() && res.writable) res = Permissions.READ;
|
|
||||||
if (!path.toFile().canRead() && res.readable) res = Permissions.NONE;
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PhysicalFilesystem(Path root, PermissionsProvider perms) {
|
|
||||||
this.root = root;
|
|
||||||
this.perms = perms;
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,12 +3,13 @@ package me.topchetoeu.jscript.interop;
|
|||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.engine.WrappersProvider;
|
||||||
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
||||||
import me.topchetoeu.jscript.engine.values.NativeFunction;
|
import me.topchetoeu.jscript.engine.values.NativeFunction;
|
||||||
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
|
|
||||||
public class NativeTypeRegister {
|
public class NativeTypeRegister implements WrappersProvider {
|
||||||
private final HashMap<Class<?>, FunctionValue> constructors = new HashMap<>();
|
private final HashMap<Class<?>, FunctionValue> constructors = new HashMap<>();
|
||||||
private final HashMap<Class<?>, ObjectValue> prototypes = new HashMap<>();
|
private final HashMap<Class<?>, ObjectValue> prototypes = new HashMap<>();
|
||||||
|
|
||||||
@ -25,7 +26,7 @@ public class NativeTypeRegister {
|
|||||||
var val = target.values.get(name);
|
var val = target.values.get(name);
|
||||||
|
|
||||||
if (name.equals("")) name = method.getName();
|
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));
|
((OverloadFunction)val).overloads.add(Overload.fromMethod(method));
|
||||||
}
|
}
|
||||||
@ -40,7 +41,7 @@ public class NativeTypeRegister {
|
|||||||
else getter = new OverloadFunction("get " + name);
|
else getter = new OverloadFunction("get " + name);
|
||||||
|
|
||||||
getter.overloads.add(Overload.fromMethod(method));
|
getter.overloads.add(Overload.fromMethod(method));
|
||||||
target.defineProperty(name, getter, setter, true, true);
|
target.defineProperty(null, name, getter, setter, true, true);
|
||||||
}
|
}
|
||||||
if (set != null) {
|
if (set != null) {
|
||||||
var name = set.value();
|
var name = set.value();
|
||||||
@ -52,7 +53,7 @@ public class NativeTypeRegister {
|
|||||||
else setter = new OverloadFunction("set " + name);
|
else setter = new OverloadFunction("set " + name);
|
||||||
|
|
||||||
setter.overloads.add(Overload.fromMethod(method));
|
setter.overloads.add(Overload.fromMethod(method));
|
||||||
target.defineProperty(name, getter, setter, true, true);
|
target.defineProperty(null, name, getter, setter, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -67,7 +68,7 @@ public class NativeTypeRegister {
|
|||||||
if (name.equals("")) name = field.getName();
|
if (name.equals("")) name = field.getName();
|
||||||
var getter = new OverloadFunction("get " + name).add(Overload.getterFromField(field));
|
var getter = new OverloadFunction("get " + name).add(Overload.getterFromField(field));
|
||||||
var setter = new OverloadFunction("set " + name).add(Overload.setterFromField(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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,11 +81,9 @@ public class NativeTypeRegister {
|
|||||||
var name = nat.value();
|
var name = nat.value();
|
||||||
if (name.equals("")) name = cl.getSimpleName();
|
if (name.equals("")) name = cl.getSimpleName();
|
||||||
|
|
||||||
var getter = new OverloadFunction("get " + name).add(Overload.getter(member ? clazz : null, (ctx, thisArg, args) -> {
|
var getter = new NativeFunction("get " + name, (ctx, thisArg, args) -> cl);
|
||||||
return ctx.engine().typeRegister().getConstr(cl);
|
|
||||||
}));
|
|
||||||
|
|
||||||
target.defineProperty(name, getter, null, true, false);
|
target.defineProperty(null, name, getter, null, true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,11 @@ import java.lang.reflect.Field;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
|
|
||||||
public class Overload {
|
public class Overload {
|
||||||
public static interface OverloadRunner {
|
public static interface OverloadRunner {
|
||||||
Object run(CallContext ctx, Object thisArg, Object[] args) throws
|
Object run(Context ctx, Object thisArg, Object[] args) throws
|
||||||
InterruptedException,
|
InterruptedException,
|
||||||
ReflectiveOperationException,
|
ReflectiveOperationException,
|
||||||
IllegalArgumentException;
|
IllegalArgumentException;
|
||||||
|
@ -5,7 +5,7 @@ import java.lang.reflect.InvocationTargetException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
@ -13,9 +13,9 @@ import me.topchetoeu.jscript.exceptions.EngineException;
|
|||||||
public class OverloadFunction extends FunctionValue {
|
public class OverloadFunction extends FunctionValue {
|
||||||
public final List<Overload> overloads = new ArrayList<>();
|
public final List<Overload> overloads = new ArrayList<>();
|
||||||
|
|
||||||
public Object call(CallContext ctx, Object thisArg, Object... args) throws InterruptedException {
|
public Object call(Context ctx, Object thisArg, Object ...args) throws InterruptedException {
|
||||||
for (var overload : overloads) {
|
for (var overload : overloads) {
|
||||||
boolean consumesEngine = overload.params.length > 0 && overload.params[0] == CallContext.class;
|
boolean consumesEngine = overload.params.length > 0 && overload.params[0] == Context.class;
|
||||||
int start = consumesEngine ? 1 : 0;
|
int start = consumesEngine ? 1 : 0;
|
||||||
int end = overload.params.length - (overload.variadic ? 1 : 0);
|
int end = overload.params.length - (overload.variadic ? 1 : 0);
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ public class OverloadFunction extends FunctionValue {
|
|||||||
Object _this = overload.thisArg == null ? null : Values.convert(ctx, thisArg, overload.thisArg);
|
Object _this = overload.thisArg == null ? null : Values.convert(ctx, thisArg, overload.thisArg);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return Values.normalize(overload.runner.run(ctx, _this, newArgs));
|
return Values.normalize(ctx, overload.runner.run(ctx, _this, newArgs));
|
||||||
}
|
}
|
||||||
catch (InstantiationException e) {
|
catch (InstantiationException e) {
|
||||||
throw EngineException.ofError("The class may not be instantiated.");
|
throw EngineException.ofError("The class may not be instantiated.");
|
||||||
|
@ -68,7 +68,7 @@ public class ParseRes<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SafeVarargs
|
@SafeVarargs
|
||||||
public static <T> ParseRes<? extends T> any(ParseRes<? extends T>... parsers) {
|
public static <T> ParseRes<? extends T> any(ParseRes<? extends T> ...parsers) {
|
||||||
ParseRes<? extends T> best = null;
|
ParseRes<? extends T> best = null;
|
||||||
ParseRes<? extends T> error = ParseRes.failed();
|
ParseRes<? extends T> error = ParseRes.failed();
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ public class ParseRes<T> {
|
|||||||
else return error;
|
else return error;
|
||||||
}
|
}
|
||||||
@SafeVarargs
|
@SafeVarargs
|
||||||
public static <T> ParseRes<? extends T> first(String filename, List<Token> tokens, Map<String, Parser<T>> named, Parser<? extends T>... parsers) {
|
public static <T> ParseRes<? extends T> first(String filename, List<Token> tokens, Map<String, Parser<T>> named, Parser<? extends T> ...parsers) {
|
||||||
ParseRes<? extends T> error = ParseRes.failed();
|
ParseRes<? extends T> error = ParseRes.failed();
|
||||||
|
|
||||||
for (var parser : parsers) {
|
for (var parser : parsers) {
|
||||||
|
@ -13,8 +13,8 @@ import me.topchetoeu.jscript.compilation.VariableDeclareStatement.Pair;
|
|||||||
import me.topchetoeu.jscript.compilation.control.*;
|
import me.topchetoeu.jscript.compilation.control.*;
|
||||||
import me.topchetoeu.jscript.compilation.control.SwitchStatement.SwitchCase;
|
import me.topchetoeu.jscript.compilation.control.SwitchStatement.SwitchCase;
|
||||||
import me.topchetoeu.jscript.compilation.values.*;
|
import me.topchetoeu.jscript.compilation.values.*;
|
||||||
|
import me.topchetoeu.jscript.engine.FunctionContext;
|
||||||
import me.topchetoeu.jscript.engine.Operation;
|
import me.topchetoeu.jscript.engine.Operation;
|
||||||
import me.topchetoeu.jscript.engine.scope.GlobalScope;
|
|
||||||
import me.topchetoeu.jscript.engine.scope.ValueVariable;
|
import me.topchetoeu.jscript.engine.scope.ValueVariable;
|
||||||
import me.topchetoeu.jscript.engine.values.CodeFunction;
|
import me.topchetoeu.jscript.engine.values.CodeFunction;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
@ -1842,8 +1842,8 @@ public class Parsing {
|
|||||||
return list.toArray(Statement[]::new);
|
return list.toArray(Statement[]::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CodeFunction compile(GlobalScope scope, Statement... statements) {
|
public static CodeFunction compile(FunctionContext environment, Statement ...statements) {
|
||||||
var target = scope.globalChild();
|
var target = environment.global.globalChild();
|
||||||
var subscope = target.child();
|
var subscope = target.child();
|
||||||
var res = new ArrayList<Instruction>();
|
var res = new ArrayList<Instruction>();
|
||||||
var body = new CompoundStatement(null, statements);
|
var body = new CompoundStatement(null, statements);
|
||||||
@ -1870,14 +1870,14 @@ public class Parsing {
|
|||||||
}
|
}
|
||||||
else res.add(Instruction.ret());
|
else res.add(Instruction.ret());
|
||||||
|
|
||||||
return new CodeFunction("", subscope.localsCount(), 0, scope, new ValueVariable[0], res.toArray(Instruction[]::new));
|
return new CodeFunction(environment, "", subscope.localsCount(), 0, new ValueVariable[0], res.toArray(Instruction[]::new));
|
||||||
}
|
}
|
||||||
public static CodeFunction compile(GlobalScope scope, String filename, String raw) {
|
public static CodeFunction compile(FunctionContext environment, String filename, String raw) {
|
||||||
try {
|
try {
|
||||||
return compile(scope, parse(filename, raw));
|
return compile(environment, parse(filename, raw));
|
||||||
}
|
}
|
||||||
catch (SyntaxException e) {
|
catch (SyntaxException e) {
|
||||||
return new CodeFunction(null, 2, 0, scope, new ValueVariable[0], new Instruction[] { Instruction.throwSyntax(e) });
|
return new CodeFunction(environment, null, 2, 0, new ValueVariable[0], new Instruction[] { Instruction.throwSyntax(e) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ package me.topchetoeu.jscript.polyfills;
|
|||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
import me.topchetoeu.jscript.interop.Native;
|
import me.topchetoeu.jscript.interop.Native;
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ public class Date {
|
|||||||
return normal.get(Calendar.YEAR) - 1900;
|
return normal.get(Calendar.YEAR) - 1900;
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public double setYear(CallContext ctx, Object val) throws InterruptedException {
|
public double setYear(Context ctx, Object val) throws InterruptedException {
|
||||||
var real = Values.toNumber(ctx, val);
|
var real = Values.toNumber(ctx, val);
|
||||||
if (real >= 0 && real <= 99) real = real + 1900;
|
if (real >= 0 && real <= 99) real = real + 1900;
|
||||||
if (Double.isNaN(real)) invalidate();
|
if (Double.isNaN(real)) invalidate();
|
||||||
@ -139,7 +139,7 @@ public class Date {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Native
|
@Native
|
||||||
public double setFullYear(CallContext ctx, Object val) throws InterruptedException {
|
public double setFullYear(Context ctx, Object val) throws InterruptedException {
|
||||||
var real = Values.toNumber(ctx, val);
|
var real = Values.toNumber(ctx, val);
|
||||||
if (Double.isNaN(real)) invalidate();
|
if (Double.isNaN(real)) invalidate();
|
||||||
else normal.set(Calendar.YEAR, (int)real);
|
else normal.set(Calendar.YEAR, (int)real);
|
||||||
@ -147,7 +147,7 @@ public class Date {
|
|||||||
return getTime();
|
return getTime();
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public double setMonth(CallContext ctx, Object val) throws InterruptedException {
|
public double setMonth(Context ctx, Object val) throws InterruptedException {
|
||||||
var real = Values.toNumber(ctx, val);
|
var real = Values.toNumber(ctx, val);
|
||||||
if (Double.isNaN(real)) invalidate();
|
if (Double.isNaN(real)) invalidate();
|
||||||
else normal.set(Calendar.MONTH, (int)real);
|
else normal.set(Calendar.MONTH, (int)real);
|
||||||
@ -155,7 +155,7 @@ public class Date {
|
|||||||
return getTime();
|
return getTime();
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public double setDate(CallContext ctx, Object val) throws InterruptedException {
|
public double setDate(Context ctx, Object val) throws InterruptedException {
|
||||||
var real = Values.toNumber(ctx, val);
|
var real = Values.toNumber(ctx, val);
|
||||||
if (Double.isNaN(real)) invalidate();
|
if (Double.isNaN(real)) invalidate();
|
||||||
else normal.set(Calendar.DAY_OF_MONTH, (int)real);
|
else normal.set(Calendar.DAY_OF_MONTH, (int)real);
|
||||||
@ -163,7 +163,7 @@ public class Date {
|
|||||||
return getTime();
|
return getTime();
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public double setDay(CallContext ctx, Object val) throws InterruptedException {
|
public double setDay(Context ctx, Object val) throws InterruptedException {
|
||||||
var real = Values.toNumber(ctx, val);
|
var real = Values.toNumber(ctx, val);
|
||||||
if (Double.isNaN(real)) invalidate();
|
if (Double.isNaN(real)) invalidate();
|
||||||
else normal.set(Calendar.DAY_OF_WEEK, (int)real);
|
else normal.set(Calendar.DAY_OF_WEEK, (int)real);
|
||||||
@ -171,7 +171,7 @@ public class Date {
|
|||||||
return getTime();
|
return getTime();
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public double setHours(CallContext ctx, Object val) throws InterruptedException {
|
public double setHours(Context ctx, Object val) throws InterruptedException {
|
||||||
var real = Values.toNumber(ctx, val);
|
var real = Values.toNumber(ctx, val);
|
||||||
if (Double.isNaN(real)) invalidate();
|
if (Double.isNaN(real)) invalidate();
|
||||||
else normal.set(Calendar.HOUR_OF_DAY, (int)real);
|
else normal.set(Calendar.HOUR_OF_DAY, (int)real);
|
||||||
@ -179,7 +179,7 @@ public class Date {
|
|||||||
return getTime();
|
return getTime();
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public double setMinutes(CallContext ctx, Object val) throws InterruptedException {
|
public double setMinutes(Context ctx, Object val) throws InterruptedException {
|
||||||
var real = Values.toNumber(ctx, val);
|
var real = Values.toNumber(ctx, val);
|
||||||
if (Double.isNaN(real)) invalidate();
|
if (Double.isNaN(real)) invalidate();
|
||||||
else normal.set(Calendar.MINUTE, (int)real);
|
else normal.set(Calendar.MINUTE, (int)real);
|
||||||
@ -187,7 +187,7 @@ public class Date {
|
|||||||
return getTime();
|
return getTime();
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public double setSeconds(CallContext ctx, Object val) throws InterruptedException {
|
public double setSeconds(Context ctx, Object val) throws InterruptedException {
|
||||||
var real = Values.toNumber(ctx, val);
|
var real = Values.toNumber(ctx, val);
|
||||||
if (Double.isNaN(real)) invalidate();
|
if (Double.isNaN(real)) invalidate();
|
||||||
else normal.set(Calendar.SECOND, (int)real);
|
else normal.set(Calendar.SECOND, (int)real);
|
||||||
@ -195,7 +195,7 @@ public class Date {
|
|||||||
return getTime();
|
return getTime();
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public double setMilliseconds(CallContext ctx, Object val) throws InterruptedException {
|
public double setMilliseconds(Context ctx, Object val) throws InterruptedException {
|
||||||
var real = Values.toNumber(ctx, val);
|
var real = Values.toNumber(ctx, val);
|
||||||
if (Double.isNaN(real)) invalidate();
|
if (Double.isNaN(real)) invalidate();
|
||||||
else normal.set(Calendar.MILLISECOND, (int)real);
|
else normal.set(Calendar.MILLISECOND, (int)real);
|
||||||
@ -204,7 +204,7 @@ public class Date {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Native
|
@Native
|
||||||
public double setUTCFullYear(CallContext ctx, Object val) throws InterruptedException {
|
public double setUTCFullYear(Context ctx, Object val) throws InterruptedException {
|
||||||
var real = Values.toNumber(ctx, val);
|
var real = Values.toNumber(ctx, val);
|
||||||
if (Double.isNaN(real)) invalidate();
|
if (Double.isNaN(real)) invalidate();
|
||||||
else utc.set(Calendar.YEAR, (int)real);
|
else utc.set(Calendar.YEAR, (int)real);
|
||||||
@ -212,7 +212,7 @@ public class Date {
|
|||||||
return getTime();
|
return getTime();
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public double setUTCMonth(CallContext ctx, Object val) throws InterruptedException {
|
public double setUTCMonth(Context ctx, Object val) throws InterruptedException {
|
||||||
var real = Values.toNumber(ctx, val);
|
var real = Values.toNumber(ctx, val);
|
||||||
if (Double.isNaN(real)) invalidate();
|
if (Double.isNaN(real)) invalidate();
|
||||||
else utc.set(Calendar.MONTH, (int)real);
|
else utc.set(Calendar.MONTH, (int)real);
|
||||||
@ -220,7 +220,7 @@ public class Date {
|
|||||||
return getTime();
|
return getTime();
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public double setUTCDate(CallContext ctx, Object val) throws InterruptedException {
|
public double setUTCDate(Context ctx, Object val) throws InterruptedException {
|
||||||
var real = Values.toNumber(ctx, val);
|
var real = Values.toNumber(ctx, val);
|
||||||
if (Double.isNaN(real)) invalidate();
|
if (Double.isNaN(real)) invalidate();
|
||||||
else utc.set(Calendar.DAY_OF_MONTH, (int)real);
|
else utc.set(Calendar.DAY_OF_MONTH, (int)real);
|
||||||
@ -228,7 +228,7 @@ public class Date {
|
|||||||
return getTime();
|
return getTime();
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public double setUTCDay(CallContext ctx, Object val) throws InterruptedException {
|
public double setUTCDay(Context ctx, Object val) throws InterruptedException {
|
||||||
var real = Values.toNumber(ctx, val);
|
var real = Values.toNumber(ctx, val);
|
||||||
if (Double.isNaN(real)) invalidate();
|
if (Double.isNaN(real)) invalidate();
|
||||||
else utc.set(Calendar.DAY_OF_WEEK, (int)real);
|
else utc.set(Calendar.DAY_OF_WEEK, (int)real);
|
||||||
@ -236,7 +236,7 @@ public class Date {
|
|||||||
return getTime();
|
return getTime();
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public double setUTCHours(CallContext ctx, Object val) throws InterruptedException {
|
public double setUTCHours(Context ctx, Object val) throws InterruptedException {
|
||||||
var real = Values.toNumber(ctx, val);
|
var real = Values.toNumber(ctx, val);
|
||||||
if (Double.isNaN(real)) invalidate();
|
if (Double.isNaN(real)) invalidate();
|
||||||
else utc.set(Calendar.HOUR_OF_DAY, (int)real);
|
else utc.set(Calendar.HOUR_OF_DAY, (int)real);
|
||||||
@ -244,7 +244,7 @@ public class Date {
|
|||||||
return getTime();
|
return getTime();
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public double setUTCMinutes(CallContext ctx, Object val) throws InterruptedException {
|
public double setUTCMinutes(Context ctx, Object val) throws InterruptedException {
|
||||||
var real = Values.toNumber(ctx, val);
|
var real = Values.toNumber(ctx, val);
|
||||||
if (Double.isNaN(real)) invalidate();
|
if (Double.isNaN(real)) invalidate();
|
||||||
else utc.set(Calendar.MINUTE, (int)real);
|
else utc.set(Calendar.MINUTE, (int)real);
|
||||||
@ -252,7 +252,7 @@ public class Date {
|
|||||||
return getTime();
|
return getTime();
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public double setUTCSeconds(CallContext ctx, Object val) throws InterruptedException {
|
public double setUTCSeconds(Context ctx, Object val) throws InterruptedException {
|
||||||
var real = Values.toNumber(ctx, val);
|
var real = Values.toNumber(ctx, val);
|
||||||
if (Double.isNaN(real)) invalidate();
|
if (Double.isNaN(real)) invalidate();
|
||||||
else utc.set(Calendar.SECOND, (int)real);
|
else utc.set(Calendar.SECOND, (int)real);
|
||||||
@ -260,7 +260,7 @@ public class Date {
|
|||||||
return getTime();
|
return getTime();
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public double setUTCMilliseconds(CallContext ctx, Object val) throws InterruptedException {
|
public double setUTCMilliseconds(Context ctx, Object val) throws InterruptedException {
|
||||||
var real = Values.toNumber(ctx, val);
|
var real = Values.toNumber(ctx, val);
|
||||||
if (Double.isNaN(real)) invalidate();
|
if (Double.isNaN(real)) invalidate();
|
||||||
else utc.set(Calendar.MILLISECOND, (int)real);
|
else utc.set(Calendar.MILLISECOND, (int)real);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package me.topchetoeu.jscript.polyfills;
|
package me.topchetoeu.jscript.polyfills;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.frame.CodeFrame;
|
import me.topchetoeu.jscript.engine.frame.CodeFrame;
|
||||||
import me.topchetoeu.jscript.engine.frame.Runners;
|
import me.topchetoeu.jscript.engine.frame.Runners;
|
||||||
import me.topchetoeu.jscript.engine.values.CodeFunction;
|
import me.topchetoeu.jscript.engine.values.CodeFunction;
|
||||||
@ -11,25 +11,25 @@ import me.topchetoeu.jscript.exceptions.EngineException;
|
|||||||
import me.topchetoeu.jscript.interop.Native;
|
import me.topchetoeu.jscript.interop.Native;
|
||||||
|
|
||||||
public class GeneratorFunction extends FunctionValue {
|
public class GeneratorFunction extends FunctionValue {
|
||||||
public final CodeFunction factory;
|
public final FunctionValue factory;
|
||||||
|
|
||||||
public static class Generator {
|
public static class Generator {
|
||||||
private boolean yielding = true;
|
private boolean yielding = true;
|
||||||
private boolean done = false;
|
private boolean done = false;
|
||||||
public CodeFrame frame;
|
public CodeFrame frame;
|
||||||
|
|
||||||
private ObjectValue next(CallContext ctx, Object inducedValue, Object inducedReturn, Object inducedError) throws InterruptedException {
|
private ObjectValue next(Context ctx, Object inducedValue, Object inducedReturn, Object inducedError) throws InterruptedException {
|
||||||
if (done) {
|
if (done) {
|
||||||
if (inducedError != Runners.NO_RETURN) throw new EngineException(inducedError);
|
if (inducedError != Runners.NO_RETURN) throw new EngineException(inducedError);
|
||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
res.defineProperty("done", true);
|
res.defineProperty(ctx, "done", true);
|
||||||
res.defineProperty("value", inducedReturn == Runners.NO_RETURN ? null : inducedReturn);
|
res.defineProperty(ctx, "value", inducedReturn == Runners.NO_RETURN ? null : inducedReturn);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object res = null;
|
Object res = null;
|
||||||
if (inducedValue != Runners.NO_RETURN) frame.push(inducedValue);
|
if (inducedValue != Runners.NO_RETURN) frame.push(ctx, inducedValue);
|
||||||
frame.start(ctx);
|
ctx.message.pushFrame(frame);
|
||||||
yielding = false;
|
yielding = false;
|
||||||
while (!yielding) {
|
while (!yielding) {
|
||||||
try {
|
try {
|
||||||
@ -46,27 +46,27 @@ public class GeneratorFunction extends FunctionValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
frame.end(ctx);
|
ctx.message.popFrame(frame);
|
||||||
if (done) frame = null;
|
if (done) frame = null;
|
||||||
else res = frame.pop();
|
else res = frame.pop();
|
||||||
|
|
||||||
var obj = new ObjectValue();
|
var obj = new ObjectValue();
|
||||||
obj.defineProperty("done", done);
|
obj.defineProperty(ctx, "done", done);
|
||||||
obj.defineProperty("value", res);
|
obj.defineProperty(ctx, "value", res);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Native
|
@Native
|
||||||
public ObjectValue next(CallContext ctx, Object... args) throws InterruptedException {
|
public ObjectValue next(Context ctx, Object ...args) throws InterruptedException {
|
||||||
if (args.length == 0) return next(ctx, Runners.NO_RETURN, Runners.NO_RETURN, Runners.NO_RETURN);
|
if (args.length == 0) return next(ctx, Runners.NO_RETURN, Runners.NO_RETURN, Runners.NO_RETURN);
|
||||||
else return next(ctx, args[0], Runners.NO_RETURN, Runners.NO_RETURN);
|
else return next(ctx, args[0], Runners.NO_RETURN, Runners.NO_RETURN);
|
||||||
}
|
}
|
||||||
@Native("throw")
|
@Native("throw")
|
||||||
public ObjectValue _throw(CallContext ctx, Object error) throws InterruptedException {
|
public ObjectValue _throw(Context ctx, Object error) throws InterruptedException {
|
||||||
return next(ctx, Runners.NO_RETURN, Runners.NO_RETURN, error);
|
return next(ctx, Runners.NO_RETURN, Runners.NO_RETURN, error);
|
||||||
}
|
}
|
||||||
@Native("return")
|
@Native("return")
|
||||||
public ObjectValue _return(CallContext ctx, Object value) throws InterruptedException {
|
public ObjectValue _return(Context ctx, Object value) throws InterruptedException {
|
||||||
return next(ctx, Runners.NO_RETURN, value, Runners.NO_RETURN);
|
return next(ctx, Runners.NO_RETURN, value, Runners.NO_RETURN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,22 +77,22 @@ public class GeneratorFunction extends FunctionValue {
|
|||||||
return "Generator " + (done ? "[closed]" : "[suspended]");
|
return "Generator " + (done ? "[closed]" : "[suspended]");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object yield(CallContext ctx, Object thisArg, Object[] args) {
|
public Object yield(Context ctx, Object thisArg, Object[] args) {
|
||||||
this.yielding = true;
|
this.yielding = true;
|
||||||
return args.length > 0 ? args[0] : null;
|
return args.length > 0 ? args[0] : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object call(CallContext _ctx, Object thisArg, Object... args) throws InterruptedException {
|
public Object call(Context ctx, Object thisArg, Object ...args) throws InterruptedException {
|
||||||
var handler = new Generator();
|
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.");
|
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;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GeneratorFunction(CodeFunction factory) {
|
public GeneratorFunction(FunctionValue factory) {
|
||||||
super(factory.name, factory.length);
|
super(factory.name, factory.length);
|
||||||
this.factory = factory;
|
this.factory = factory;
|
||||||
}
|
}
|
||||||
|
@ -1,150 +1,137 @@
|
|||||||
package me.topchetoeu.jscript.polyfills;
|
package me.topchetoeu.jscript.polyfills;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
|
import me.topchetoeu.jscript.engine.FunctionContext;
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
|
||||||
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
||||||
import me.topchetoeu.jscript.engine.values.CodeFunction;
|
import me.topchetoeu.jscript.engine.values.CodeFunction;
|
||||||
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
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.ObjectValue;
|
||||||
import me.topchetoeu.jscript.engine.values.Symbol;
|
import me.topchetoeu.jscript.engine.values.Symbol;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
|
||||||
import me.topchetoeu.jscript.interop.Native;
|
import me.topchetoeu.jscript.interop.Native;
|
||||||
import me.topchetoeu.jscript.interop.NativeGetter;
|
|
||||||
|
|
||||||
public class Internals {
|
public class Internals {
|
||||||
private HashMap<Integer, Thread> intervals = new HashMap<>();
|
@Native public void markSpecial(FunctionValue ...funcs) {
|
||||||
private HashMap<Integer, Thread> timeouts = new HashMap<>();
|
for (var func : funcs) {
|
||||||
private HashMap<String, Symbol> symbols = new HashMap<>();
|
func.special = true;
|
||||||
private int nextId = 0;
|
|
||||||
|
|
||||||
@Native
|
|
||||||
public double parseFloat(CallContext ctx, Object val) throws InterruptedException {
|
|
||||||
return Values.toNumber(ctx, val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Native
|
|
||||||
public boolean isArr(Object val) {
|
|
||||||
return val instanceof ArrayValue;
|
|
||||||
}
|
}
|
||||||
|
@Native public FunctionContext getEnv(Object func) {
|
||||||
@NativeGetter("symbolProto")
|
if (func instanceof CodeFunction) return ((CodeFunction)func).environment;
|
||||||
public ObjectValue symbolProto(CallContext ctx) {
|
else return null;
|
||||||
return ctx.engine().symbolProto();
|
|
||||||
}
|
}
|
||||||
@Native
|
@Native public Object setEnv(Object func, FunctionContext env) {
|
||||||
public final Object apply(CallContext ctx, FunctionValue func, Object th, ArrayValue args) throws InterruptedException {
|
if (func instanceof CodeFunction) ((CodeFunction)func).environment = env;
|
||||||
return func.call(ctx, th, args.toArray());
|
return func;
|
||||||
}
|
}
|
||||||
@Native
|
@Native public Object apply(Context ctx, FunctionValue func, Object thisArg, ArrayValue args) throws InterruptedException {
|
||||||
public boolean defineProp(ObjectValue obj, Object key, FunctionValue getter, FunctionValue setter, boolean enumerable, boolean configurable) {
|
return func.call(ctx, thisArg, args.toArray());
|
||||||
return obj.defineProperty(key, getter, setter, configurable, enumerable);
|
|
||||||
}
|
}
|
||||||
@Native
|
@Native public FunctionValue delay(Context ctx, double delay, FunctionValue callback) throws InterruptedException {
|
||||||
public boolean defineField(ObjectValue obj, Object key, Object val, boolean writable, boolean enumerable, boolean configurable) {
|
|
||||||
return obj.defineProperty(key, val, writable, configurable, enumerable);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Native
|
|
||||||
public int strlen(String str) {
|
|
||||||
return str.length();
|
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public String substring(String str, int start, int end) {
|
|
||||||
if (start > end) return substring(str, end, start);
|
|
||||||
|
|
||||||
if (start < 0) start = 0;
|
|
||||||
if (start >= str.length()) return "";
|
|
||||||
|
|
||||||
if (end < 0) end = 0;
|
|
||||||
if (end > str.length()) end = str.length();
|
|
||||||
|
|
||||||
return str.substring(start, end);
|
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public String toLower(String str) {
|
|
||||||
return str.toLowerCase();
|
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public String toUpper(String str) {
|
|
||||||
return str.toUpperCase();
|
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public int toCharCode(String str) {
|
|
||||||
return str.codePointAt(0);
|
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public String fromCharCode(int code) {
|
|
||||||
return Character.toString((char)code);
|
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public boolean startsWith(String str, String term, int offset) {
|
|
||||||
return str.startsWith(term, offset);
|
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public boolean endsWith(String str, String term, int offset) {
|
|
||||||
try {
|
|
||||||
return str.substring(0, offset).endsWith(term);
|
|
||||||
}
|
|
||||||
catch (IndexOutOfBoundsException e) { return false; }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Native
|
|
||||||
public int setInterval(CallContext ctx, FunctionValue func, double delay) {
|
|
||||||
var thread = new Thread((Runnable)() -> {
|
var thread = new Thread((Runnable)() -> {
|
||||||
var ms = (long)delay;
|
var ms = (long)delay;
|
||||||
var ns = (int)((delay - ms) * 10000000);
|
var ns = (int)((delay - ms) * 10000000);
|
||||||
|
|
||||||
while (true) {
|
|
||||||
try {
|
try {
|
||||||
Thread.sleep(ms, ns);
|
Thread.sleep(ms, ns);
|
||||||
}
|
}
|
||||||
catch (InterruptedException e) { return; }
|
catch (InterruptedException e) { return; }
|
||||||
|
|
||||||
ctx.engine().pushMsg(false, func, ctx.data(), null);
|
ctx.message.engine.pushMsg(false, ctx.message, callback, null);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
thread.start();
|
thread.start();
|
||||||
|
|
||||||
intervals.put(++nextId, thread);
|
return new NativeFunction((_ctx, thisArg, args) -> {
|
||||||
|
thread.interrupt();
|
||||||
return nextId;
|
return null;
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public int setTimeout(CallContext ctx, FunctionValue func, double delay) {
|
|
||||||
var thread = new Thread((Runnable)() -> {
|
|
||||||
var ms = (long)delay;
|
|
||||||
var ns = (int)((delay - ms) * 1000000);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(ms, ns);
|
|
||||||
}
|
|
||||||
catch (InterruptedException e) { return; }
|
|
||||||
|
|
||||||
ctx.engine().pushMsg(false, func, ctx.data(), null);
|
|
||||||
});
|
});
|
||||||
thread.start();
|
}
|
||||||
|
@Native public void pushMessage(Context ctx, boolean micro, FunctionValue func, Object thisArg, Object[] args) {
|
||||||
timeouts.put(++nextId, thread);
|
ctx.message.engine.pushMsg(micro, ctx.message, func, thisArg, args);
|
||||||
|
|
||||||
return nextId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Native
|
@Native public int strlen(String str) {
|
||||||
public void clearInterval(int id) {
|
return str.length();
|
||||||
var thread = intervals.remove(id);
|
|
||||||
if (thread != null) thread.interrupt();
|
|
||||||
}
|
}
|
||||||
@Native
|
@Native("char") public int _char(String str) {
|
||||||
public void clearTimeout(int id) {
|
return str.charAt(0);
|
||||||
var thread = timeouts.remove(id);
|
}
|
||||||
if (thread != null) thread.interrupt();
|
@Native public String stringFromChars(char[] str) {
|
||||||
|
return new String(str);
|
||||||
|
}
|
||||||
|
@Native public String stringFromStrings(String[] str) {
|
||||||
|
var res = new char[str.length];
|
||||||
|
|
||||||
|
for (var i = 0; i < str.length; i++) res[i] = str[i].charAt(0);
|
||||||
|
|
||||||
|
return stringFromChars(res);
|
||||||
|
}
|
||||||
|
@Native public Symbol symbol(String str) {
|
||||||
|
return new Symbol(str);
|
||||||
|
}
|
||||||
|
@Native public String symbolToString(Symbol str) {
|
||||||
|
return str.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Native
|
@Native public static void log(Context ctx, Object ...args) throws InterruptedException {
|
||||||
public void sort(CallContext ctx, ArrayValue arr, FunctionValue cmp) {
|
for (var arg : args) {
|
||||||
|
Values.printValue(ctx, arg);
|
||||||
|
}
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Native public boolean isArray(Object obj) {
|
||||||
|
return obj instanceof ArrayValue;
|
||||||
|
}
|
||||||
|
@Native public GeneratorFunction generator(FunctionValue obj) {
|
||||||
|
return new GeneratorFunction(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Native public boolean defineField(Context ctx, ObjectValue obj, Object key, Object val, boolean writable, boolean enumerable, boolean configurable) {
|
||||||
|
return obj.defineProperty(ctx, key, val, writable, configurable, enumerable);
|
||||||
|
}
|
||||||
|
@Native public boolean defineProp(Context ctx, ObjectValue obj, Object key, FunctionValue getter, FunctionValue setter, boolean enumerable, boolean configurable) {
|
||||||
|
return obj.defineProperty(ctx, key, getter, setter, configurable, enumerable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Native public ArrayValue keys(Context ctx, Object obj, boolean onlyString) throws InterruptedException {
|
||||||
|
var res = new ArrayValue();
|
||||||
|
|
||||||
|
var i = 0;
|
||||||
|
var list = Values.getMembers(ctx, obj, true, false);
|
||||||
|
|
||||||
|
for (var el : list) res.set(ctx, i++, el);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
@Native public ArrayValue ownPropKeys(Context ctx, Object obj, boolean symbols) throws InterruptedException {
|
||||||
|
var res = new ArrayValue();
|
||||||
|
|
||||||
|
if (Values.isObject(obj)) {
|
||||||
|
var i = 0;
|
||||||
|
var list = Values.object(obj).keys(true);
|
||||||
|
|
||||||
|
for (var el : list) res.set(ctx, i++, el);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
@Native public ObjectValue ownProp(Context ctx, ObjectValue val, Object key) throws InterruptedException {
|
||||||
|
return val.getMemberDescriptor(ctx, key);
|
||||||
|
}
|
||||||
|
@Native public void lock(ObjectValue val, String type) {
|
||||||
|
switch (type) {
|
||||||
|
case "ext": val.preventExtensions(); break;
|
||||||
|
case "seal": val.seal(); break;
|
||||||
|
case "freeze": val.freeze(); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Native public boolean extensible(ObjectValue val) {
|
||||||
|
return val.extensible();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Native public void sort(Context ctx, ArrayValue arr, FunctionValue cmp) {
|
||||||
arr.sort((a, b) -> {
|
arr.sort((a, b) -> {
|
||||||
try {
|
try {
|
||||||
var res = Values.toNumber(ctx, cmp.call(ctx, null, a, b));
|
var res = Values.toNumber(ctx, cmp.call(ctx, null, a, b));
|
||||||
@ -158,109 +145,4 @@ public class Internals {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Native
|
|
||||||
public void special(FunctionValue... funcs) {
|
|
||||||
for (var func : funcs) {
|
|
||||||
func.special = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Native
|
|
||||||
public Symbol symbol(String name, boolean unique) {
|
|
||||||
if (!unique && symbols.containsKey(name)) {
|
|
||||||
return symbols.get(name);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var val = new Symbol(name);
|
|
||||||
if (!unique) symbols.put(name, val);
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public String symStr(Symbol symbol) {
|
|
||||||
return symbol.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Native
|
|
||||||
public void freeze(ObjectValue val) {
|
|
||||||
val.freeze();
|
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public void seal(ObjectValue val) {
|
|
||||||
val.seal();
|
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public void preventExtensions(ObjectValue val) {
|
|
||||||
val.preventExtensions();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Native
|
|
||||||
public boolean extensible(Object val) {
|
|
||||||
return Values.isObject(val) && Values.object(val).extensible();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Native
|
|
||||||
public ArrayValue keys(CallContext ctx, Object obj, boolean onlyString) throws InterruptedException {
|
|
||||||
var res = new ArrayValue();
|
|
||||||
|
|
||||||
var i = 0;
|
|
||||||
var list = Values.getMembers(ctx, obj, true, false);
|
|
||||||
|
|
||||||
for (var el : list) {
|
|
||||||
if (el instanceof Symbol && onlyString) continue;
|
|
||||||
res.set(i++, el);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public ArrayValue ownPropKeys(CallContext ctx, Object obj, boolean symbols) throws InterruptedException {
|
|
||||||
var res = new ArrayValue();
|
|
||||||
|
|
||||||
if (Values.isObject(obj)) {
|
|
||||||
var i = 0;
|
|
||||||
var list = Values.object(obj).keys(true);
|
|
||||||
|
|
||||||
for (var el : list) {
|
|
||||||
if (el instanceof Symbol == symbols) res.set(i++, el);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public ObjectValue ownProp(CallContext ctx, ObjectValue val, Object key) throws InterruptedException {
|
|
||||||
return val.getMemberDescriptor(ctx, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Native
|
|
||||||
public Object require(CallContext ctx, Object name) throws InterruptedException {
|
|
||||||
var res = ctx.engine().modules().tryLoad(ctx, Values.toString(ctx, name));
|
|
||||||
if (res == null) throw EngineException.ofError("The module '" + name + "' doesn\'t exist.");
|
|
||||||
return res.exports();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Native
|
|
||||||
public GeneratorFunction makeGenerator(FunctionValue func) {
|
|
||||||
if (func instanceof CodeFunction) return new GeneratorFunction((CodeFunction)func);
|
|
||||||
else throw EngineException.ofType("Can't create a generator with a non-js function.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@NativeGetter("err")
|
|
||||||
public ObjectValue errProto(CallContext ctx) {
|
|
||||||
return ctx.engine.errorProto();
|
|
||||||
}
|
|
||||||
@NativeGetter("syntax")
|
|
||||||
public ObjectValue syntaxProto(CallContext ctx) {
|
|
||||||
return ctx.engine.syntaxErrorProto();
|
|
||||||
}
|
|
||||||
@NativeGetter("range")
|
|
||||||
public ObjectValue rangeProto(CallContext ctx) {
|
|
||||||
return ctx.engine.rangeErrorProto();
|
|
||||||
}
|
|
||||||
@NativeGetter("type")
|
|
||||||
public ObjectValue typeProto(CallContext ctx) {
|
|
||||||
return ctx.engine.typeErrorProto();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ package me.topchetoeu.jscript.polyfills;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
||||||
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.engine.values.Values;
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
@ -19,18 +19,18 @@ public class JSON {
|
|||||||
if (val.isBoolean()) return val.bool();
|
if (val.isBoolean()) return val.bool();
|
||||||
if (val.isString()) return val.string();
|
if (val.isString()) return val.string();
|
||||||
if (val.isNumber()) return val.number();
|
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()) {
|
if (val.isMap()) {
|
||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
for (var el : val.map().entrySet()) {
|
for (var el : val.map().entrySet()) {
|
||||||
res.defineProperty(el.getKey(), toJS(el.getValue()));
|
res.defineProperty(null, el.getKey(), toJS(el.getValue()));
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
if (val.isNull()) return Values.NULL;
|
if (val.isNull()) return Values.NULL;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
private static JSONElement toJSON(CallContext ctx, Object val, HashSet<Object> prev) throws InterruptedException {
|
private static JSONElement toJSON(Context ctx, Object val, HashSet<Object> prev) throws InterruptedException {
|
||||||
if (val instanceof Boolean) return JSONElement.bool((boolean)val);
|
if (val instanceof Boolean) return JSONElement.bool((boolean)val);
|
||||||
if (val instanceof Number) return JSONElement.number(((Number)val).doubleValue());
|
if (val instanceof Number) return JSONElement.number(((Number)val).doubleValue());
|
||||||
if (val instanceof String) return JSONElement.string((String)val);
|
if (val instanceof String) return JSONElement.string((String)val);
|
||||||
@ -70,7 +70,7 @@ public class JSON {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Native
|
@Native
|
||||||
public static Object parse(CallContext ctx, String val) throws InterruptedException {
|
public static Object parse(Context ctx, String val) throws InterruptedException {
|
||||||
try {
|
try {
|
||||||
return toJS(me.topchetoeu.jscript.json.JSON.parse("<value>", val));
|
return toJS(me.topchetoeu.jscript.json.JSON.parse("<value>", val));
|
||||||
}
|
}
|
||||||
@ -79,7 +79,7 @@ public class JSON {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static String stringify(CallContext ctx, Object val) throws InterruptedException {
|
public static String stringify(Context ctx, Object val) throws InterruptedException {
|
||||||
return me.topchetoeu.jscript.json.JSON.stringify(toJSON(ctx, val, new HashSet<>()));
|
return me.topchetoeu.jscript.json.JSON.stringify(toJSON(ctx, val, new HashSet<>()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,86 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.polyfills;
|
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
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.Values;
|
|
||||||
import me.topchetoeu.jscript.interop.Native;
|
|
||||||
import me.topchetoeu.jscript.interop.NativeGetter;
|
|
||||||
|
|
||||||
public class Map {
|
|
||||||
private LinkedHashMap<Object, Object> objs = new LinkedHashMap<>();
|
|
||||||
|
|
||||||
@Native
|
|
||||||
public Object get(Object key) {
|
|
||||||
return objs.get(key);
|
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public Map set(Object key, Object val) {
|
|
||||||
objs.put(key, val);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public boolean delete(Object key) {
|
|
||||||
if (objs.containsKey(key)) {
|
|
||||||
objs.remove(key);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else return false;
|
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public boolean has(Object key) {
|
|
||||||
return objs.containsKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Native
|
|
||||||
public void clear() {
|
|
||||||
objs.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Native
|
|
||||||
public void forEach(CallContext ctx, FunctionValue func, Object thisArg) throws InterruptedException {
|
|
||||||
|
|
||||||
for (var el : objs.entrySet().stream().collect(Collectors.toList())) {
|
|
||||||
func.call(ctx, thisArg, el.getValue(), el.getKey(), this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Native
|
|
||||||
public Object entries(CallContext ctx) throws InterruptedException {
|
|
||||||
return Values.fromJavaIterable(ctx, objs
|
|
||||||
.entrySet()
|
|
||||||
.stream()
|
|
||||||
.map(v -> new ArrayValue(v.getKey(), v.getValue()))
|
|
||||||
.collect(Collectors.toList())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public Object keys(CallContext ctx) throws InterruptedException {
|
|
||||||
return Values.fromJavaIterable(ctx, objs.keySet().stream().collect(Collectors.toList()));
|
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public Object values(CallContext ctx) throws InterruptedException {
|
|
||||||
return Values.fromJavaIterable(ctx, objs.values().stream().collect(Collectors.toList()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@NativeGetter("size")
|
|
||||||
public int size() {
|
|
||||||
return objs.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Native
|
|
||||||
public Map(CallContext ctx, Object iterable) throws InterruptedException {
|
|
||||||
if (Values.isPrimitive(iterable)) return;
|
|
||||||
|
|
||||||
for (var val : Values.toJavaIterable(ctx, iterable)) {
|
|
||||||
var first = Values.getMember(ctx, val, 0);
|
|
||||||
var second = Values.getMember(ctx, val, 1);
|
|
||||||
|
|
||||||
set(first, second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public Map() { }
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
package me.topchetoeu.jscript.polyfills;
|
package me.topchetoeu.jscript.polyfills;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.MessageContext;
|
||||||
import me.topchetoeu.jscript.interop.Native;
|
import me.topchetoeu.jscript.interop.Native;
|
||||||
|
|
||||||
public class Math {
|
public class Math {
|
||||||
@ -22,19 +22,19 @@ public class Math {
|
|||||||
public static final double LOG10E = java.lang.Math.log10(java.lang.Math.E);
|
public static final double LOG10E = java.lang.Math.log10(java.lang.Math.E);
|
||||||
|
|
||||||
@Native
|
@Native
|
||||||
public static double asin(CallContext ctx, double x) throws InterruptedException {
|
public static double asin(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return java.lang.Math.asin(x);
|
return java.lang.Math.asin(x);
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static double acos(CallContext ctx, double x) throws InterruptedException {
|
public static double acos(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return java.lang.Math.acos(x);
|
return java.lang.Math.acos(x);
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static double atan(CallContext ctx, double x) throws InterruptedException {
|
public static double atan(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return java.lang.Math.atan(x);
|
return java.lang.Math.atan(x);
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static double atan2(CallContext ctx, double y, double x) throws InterruptedException {
|
public static double atan2(MessageContext ctx, double y, double x) throws InterruptedException {
|
||||||
double _y = y;
|
double _y = y;
|
||||||
double _x = x;
|
double _x = x;
|
||||||
if (_x == 0) {
|
if (_x == 0) {
|
||||||
@ -51,59 +51,59 @@ public class Math {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Native
|
@Native
|
||||||
public static double asinh(CallContext ctx, double x) throws InterruptedException {
|
public static double asinh(MessageContext ctx, double x) throws InterruptedException {
|
||||||
double _x = x;
|
double _x = x;
|
||||||
return java.lang.Math.log(_x + java.lang.Math.sqrt(_x * _x + 1));
|
return java.lang.Math.log(_x + java.lang.Math.sqrt(_x * _x + 1));
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static double acosh(CallContext ctx, double x) throws InterruptedException {
|
public static double acosh(MessageContext ctx, double x) throws InterruptedException {
|
||||||
double _x = x;
|
double _x = x;
|
||||||
return java.lang.Math.log(_x + java.lang.Math.sqrt(_x * _x - 1));
|
return java.lang.Math.log(_x + java.lang.Math.sqrt(_x * _x - 1));
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static double atanh(CallContext ctx, double x) throws InterruptedException {
|
public static double atanh(MessageContext ctx, double x) throws InterruptedException {
|
||||||
double _x = x;
|
double _x = x;
|
||||||
if (_x <= -1 || _x >= 1) return Double.NaN;
|
if (_x <= -1 || _x >= 1) return Double.NaN;
|
||||||
return .5 * java.lang.Math.log((1 + _x) / (1 - _x));
|
return .5 * java.lang.Math.log((1 + _x) / (1 - _x));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Native
|
@Native
|
||||||
public static double sin(CallContext ctx, double x) throws InterruptedException {
|
public static double sin(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return java.lang.Math.sin(x);
|
return java.lang.Math.sin(x);
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static double cos(CallContext ctx, double x) throws InterruptedException {
|
public static double cos(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return java.lang.Math.cos(x);
|
return java.lang.Math.cos(x);
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static double tan(CallContext ctx, double x) throws InterruptedException {
|
public static double tan(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return java.lang.Math.tan(x);
|
return java.lang.Math.tan(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Native
|
@Native
|
||||||
public static double sinh(CallContext ctx, double x) throws InterruptedException {
|
public static double sinh(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return java.lang.Math.sinh(x);
|
return java.lang.Math.sinh(x);
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static double cosh(CallContext ctx, double x) throws InterruptedException {
|
public static double cosh(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return java.lang.Math.cosh(x);
|
return java.lang.Math.cosh(x);
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static double tanh(CallContext ctx, double x) throws InterruptedException {
|
public static double tanh(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return java.lang.Math.tanh(x);
|
return java.lang.Math.tanh(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Native
|
@Native
|
||||||
public static double sqrt(CallContext ctx, double x) throws InterruptedException {
|
public static double sqrt(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return java.lang.Math.sqrt(x);
|
return java.lang.Math.sqrt(x);
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static double cbrt(CallContext ctx, double x) throws InterruptedException {
|
public static double cbrt(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return java.lang.Math.cbrt(x);
|
return java.lang.Math.cbrt(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Native
|
@Native
|
||||||
public static double hypot(CallContext ctx, double... vals) throws InterruptedException {
|
public static double hypot(MessageContext ctx, double ...vals) throws InterruptedException {
|
||||||
var res = 0.;
|
var res = 0.;
|
||||||
for (var el : vals) {
|
for (var el : vals) {
|
||||||
var val = el;
|
var val = el;
|
||||||
@ -112,68 +112,68 @@ public class Math {
|
|||||||
return java.lang.Math.sqrt(res);
|
return java.lang.Math.sqrt(res);
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static int imul(CallContext ctx, double a, double b) throws InterruptedException {
|
public static int imul(MessageContext ctx, double a, double b) throws InterruptedException {
|
||||||
return (int)a * (int)b;
|
return (int)a * (int)b;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Native
|
@Native
|
||||||
public static double exp(CallContext ctx, double x) throws InterruptedException {
|
public static double exp(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return java.lang.Math.exp(x);
|
return java.lang.Math.exp(x);
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static double expm1(CallContext ctx, double x) throws InterruptedException {
|
public static double expm1(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return java.lang.Math.expm1(x);
|
return java.lang.Math.expm1(x);
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static double pow(CallContext ctx, double x, double y) throws InterruptedException {
|
public static double pow(MessageContext ctx, double x, double y) throws InterruptedException {
|
||||||
return java.lang.Math.pow(x, y);
|
return java.lang.Math.pow(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Native
|
@Native
|
||||||
public static double log(CallContext ctx, double x) throws InterruptedException {
|
public static double log(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return java.lang.Math.log(x);
|
return java.lang.Math.log(x);
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static double log10(CallContext ctx, double x) throws InterruptedException {
|
public static double log10(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return java.lang.Math.log10(x);
|
return java.lang.Math.log10(x);
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static double log1p(CallContext ctx, double x) throws InterruptedException {
|
public static double log1p(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return java.lang.Math.log1p(x);
|
return java.lang.Math.log1p(x);
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static double log2(CallContext ctx, double x) throws InterruptedException {
|
public static double log2(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return java.lang.Math.log(x) / LN2;
|
return java.lang.Math.log(x) / LN2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Native
|
@Native
|
||||||
public static double ceil(CallContext ctx, double x) throws InterruptedException {
|
public static double ceil(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return java.lang.Math.ceil(x);
|
return java.lang.Math.ceil(x);
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static double floor(CallContext ctx, double x) throws InterruptedException {
|
public static double floor(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return java.lang.Math.floor(x);
|
return java.lang.Math.floor(x);
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static double round(CallContext ctx, double x) throws InterruptedException {
|
public static double round(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return java.lang.Math.round(x);
|
return java.lang.Math.round(x);
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static float fround(CallContext ctx, double x) throws InterruptedException {
|
public static float fround(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return (float)x;
|
return (float)x;
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static double trunc(CallContext ctx, double x) throws InterruptedException {
|
public static double trunc(MessageContext ctx, double x) throws InterruptedException {
|
||||||
var _x = x;
|
var _x = x;
|
||||||
return java.lang.Math.floor(java.lang.Math.abs(_x)) * java.lang.Math.signum(_x);
|
return java.lang.Math.floor(java.lang.Math.abs(_x)) * java.lang.Math.signum(_x);
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static double abs(CallContext ctx, double x) throws InterruptedException {
|
public static double abs(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return java.lang.Math.abs(x);
|
return java.lang.Math.abs(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Native
|
@Native
|
||||||
public static double max(CallContext ctx, double... vals) throws InterruptedException {
|
public static double max(MessageContext ctx, double ...vals) throws InterruptedException {
|
||||||
var res = Double.NEGATIVE_INFINITY;
|
var res = Double.NEGATIVE_INFINITY;
|
||||||
|
|
||||||
for (var el : vals) {
|
for (var el : vals) {
|
||||||
@ -184,7 +184,7 @@ public class Math {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static double min(CallContext ctx, double... vals) throws InterruptedException {
|
public static double min(MessageContext ctx, double ...vals) throws InterruptedException {
|
||||||
var res = Double.POSITIVE_INFINITY;
|
var res = Double.POSITIVE_INFINITY;
|
||||||
|
|
||||||
for (var el : vals) {
|
for (var el : vals) {
|
||||||
@ -196,7 +196,7 @@ public class Math {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Native
|
@Native
|
||||||
public static double sign(CallContext ctx, double x) throws InterruptedException {
|
public static double sign(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return java.lang.Math.signum(x);
|
return java.lang.Math.signum(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,7 +205,7 @@ public class Math {
|
|||||||
return java.lang.Math.random();
|
return java.lang.Math.random();
|
||||||
}
|
}
|
||||||
@Native
|
@Native
|
||||||
public static int clz32(CallContext ctx, double x) throws InterruptedException {
|
public static int clz32(MessageContext ctx, double x) throws InterruptedException {
|
||||||
return Integer.numberOfLeadingZeros((int)x);
|
return Integer.numberOfLeadingZeros((int)x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,110 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.polyfills;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
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) {
|
|
||||||
try {
|
|
||||||
StringBuilder out = new StringBuilder();
|
|
||||||
BufferedReader br = new BufferedReader(new InputStreamReader(in));
|
|
||||||
|
|
||||||
for(var line = br.readLine(); line != null; line = br.readLine()) {
|
|
||||||
out.append(line).append('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
br.close();
|
|
||||||
return out.toString();
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static String resourceToString(String name) {
|
|
||||||
var str = PolyfillEngine.class.getResourceAsStream("/me/topchetoeu/jscript/" + name);
|
|
||||||
if (str == null) return null;
|
|
||||||
return streamToString(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final ModuleManager modules;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object makeRegex(String pattern, String flags) {
|
|
||||||
return new RegExp(pattern, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ModuleManager modules() {
|
|
||||||
return modules;
|
|
||||||
}
|
|
||||||
public PolyfillEngine(File root) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
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(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.");
|
|
||||||
|
|
||||||
if (pollute) func = Parsing.compile(global(), filename, src);
|
|
||||||
else func = Parsing.compile(scope.globalChild(), filename, src);
|
|
||||||
|
|
||||||
func.call(ctx);
|
|
||||||
return null;
|
|
||||||
}));
|
|
||||||
|
|
||||||
pushMsg(false, scope.globalChild(), java.util.Map.of(), "core.js", resourceToString("js/core.js"), null);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,360 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.polyfills;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
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;
|
|
||||||
import me.topchetoeu.jscript.interop.Native;
|
|
||||||
|
|
||||||
public class Promise {
|
|
||||||
private static class Handle {
|
|
||||||
public final CallContext ctx;
|
|
||||||
public final FunctionValue fulfilled;
|
|
||||||
public final FunctionValue rejected;
|
|
||||||
|
|
||||||
public Handle(CallContext ctx, FunctionValue fulfilled, FunctionValue rejected) {
|
|
||||||
this.ctx = ctx;
|
|
||||||
this.fulfilled = fulfilled;
|
|
||||||
this.rejected = rejected;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Native("resolve")
|
|
||||||
public static Promise ofResolved(CallContext engine, Object val) {
|
|
||||||
if (Values.isWrapper(val, Promise.class)) return Values.wrapper(val, Promise.class);
|
|
||||||
var res = new Promise();
|
|
||||||
res.fulfill(engine, val);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
public static Promise ofResolved(Object val) {
|
|
||||||
if (Values.isWrapper(val, Promise.class)) return Values.wrapper(val, Promise.class);
|
|
||||||
var res = new Promise();
|
|
||||||
res.fulfill(val);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Native("reject")
|
|
||||||
public static Promise ofRejected(CallContext engine, Object val) {
|
|
||||||
var res = new Promise();
|
|
||||||
res.reject(engine, val);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
public static Promise ofRejected(Object val) {
|
|
||||||
var res = new Promise();
|
|
||||||
res.fulfill(val);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Native
|
|
||||||
public static Promise any(CallContext engine, 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());
|
|
||||||
var n = new int[] { promises.size() };
|
|
||||||
var res = new Promise();
|
|
||||||
|
|
||||||
var errors = new ArrayValue();
|
|
||||||
|
|
||||||
for (var i = 0; i < promises.size(); i++) {
|
|
||||||
var index = i;
|
|
||||||
var val = promises.get(i);
|
|
||||||
if (Values.isWrapper(val, Promise.class)) Values.wrapper(val, Promise.class).then(
|
|
||||||
engine,
|
|
||||||
new NativeFunction(null, (e, th, args) -> { res.fulfill(e, args[0]); return null; }),
|
|
||||||
new NativeFunction(null, (e, th, args) -> {
|
|
||||||
errors.set(index, args[0]);
|
|
||||||
n[0]--;
|
|
||||||
if (n[0] <= 0) res.reject(e, errors);
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
else {
|
|
||||||
res.fulfill(engine, val);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public static Promise race(CallContext engine, 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());
|
|
||||||
var res = new 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,
|
|
||||||
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; })
|
|
||||||
);
|
|
||||||
else {
|
|
||||||
res.fulfill(val);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public static Promise all(CallContext engine, 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());
|
|
||||||
var n = new int[] { promises.size() };
|
|
||||||
var res = new Promise();
|
|
||||||
|
|
||||||
var result = new ArrayValue();
|
|
||||||
|
|
||||||
for (var i = 0; i < promises.size(); i++) {
|
|
||||||
var index = i;
|
|
||||||
var val = promises.get(i);
|
|
||||||
if (Values.isWrapper(val, Promise.class)) Values.wrapper(val, Promise.class).then(
|
|
||||||
engine,
|
|
||||||
new NativeFunction(null, (e, th, args) -> {
|
|
||||||
result.set(index, args[0]);
|
|
||||||
n[0]--;
|
|
||||||
if (n[0] <= 0) res.fulfill(e, result);
|
|
||||||
return null;
|
|
||||||
}),
|
|
||||||
new NativeFunction(null, (e, th, args) -> { res.reject(e, args[0]); return null; })
|
|
||||||
);
|
|
||||||
else {
|
|
||||||
result.set(i, val);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n[0] <= 0) res.fulfill(engine, result);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public static Promise allSettled(CallContext engine, 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());
|
|
||||||
var n = new int[] { promises.size() };
|
|
||||||
var res = new Promise();
|
|
||||||
|
|
||||||
var result = new ArrayValue();
|
|
||||||
|
|
||||||
for (var i = 0; i < promises.size(); i++) {
|
|
||||||
var index = i;
|
|
||||||
var val = promises.get(i);
|
|
||||||
if (Values.isWrapper(val, Promise.class)) Values.wrapper(val, Promise.class).then(
|
|
||||||
engine,
|
|
||||||
new NativeFunction(null, (e, th, args) -> {
|
|
||||||
result.set(index, new ObjectValue(Map.of(
|
|
||||||
"status", "fulfilled",
|
|
||||||
"value", args[0]
|
|
||||||
)));
|
|
||||||
n[0]--;
|
|
||||||
if (n[0] <= 0) res.fulfill(e, result);
|
|
||||||
return null;
|
|
||||||
}),
|
|
||||||
new NativeFunction(null, (e, th, args) -> {
|
|
||||||
result.set(index, new ObjectValue(Map.of(
|
|
||||||
"status", "rejected",
|
|
||||||
"reason", args[0]
|
|
||||||
)));
|
|
||||||
n[0]--;
|
|
||||||
if (n[0] <= 0) res.fulfill(e, result);
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
else {
|
|
||||||
result.set(i, new ObjectValue(Map.of(
|
|
||||||
"status", "fulfilled",
|
|
||||||
"value", val
|
|
||||||
)));
|
|
||||||
n[0]--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n[0] <= 0) res.fulfill(engine, result);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Handle> handles = new ArrayList<>();
|
|
||||||
|
|
||||||
private static final int STATE_PENDING = 0;
|
|
||||||
private static final int STATE_FULFILLED = 1;
|
|
||||||
private static final int STATE_REJECTED = 2;
|
|
||||||
|
|
||||||
private int state = STATE_PENDING;
|
|
||||||
private Object val;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Thread safe - call from any thread
|
|
||||||
*/
|
|
||||||
public void fulfill(Object val) {
|
|
||||||
if (Values.isWrapper(val, Promise.class)) throw new IllegalArgumentException("A promise may not be a fulfil value.");
|
|
||||||
if (state != STATE_PENDING) return;
|
|
||||||
|
|
||||||
this.state = STATE_FULFILLED;
|
|
||||||
this.val = val;
|
|
||||||
for (var el : handles) el.ctx.engine().pushMsg(true, el.fulfilled, el.ctx.data(), null, val);
|
|
||||||
handles = null;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Thread safe - call from any thread
|
|
||||||
*/
|
|
||||||
public void fulfill(CallContext ctx, Object val) {
|
|
||||||
if (Values.isWrapper(val, Promise.class)) Values.wrapper(val, Promise.class).then(ctx,
|
|
||||||
new NativeFunction(null, (e, th, args) -> {
|
|
||||||
this.fulfill(e, args[0]);
|
|
||||||
return null;
|
|
||||||
}),
|
|
||||||
new NativeFunction(null, (e, th, args) -> {
|
|
||||||
this.reject(e, args[0]);
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
else this.fulfill(val);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Thread safe - call from any thread
|
|
||||||
*/
|
|
||||||
public void reject(Object val) {
|
|
||||||
if (Values.isWrapper(val, Promise.class)) throw new IllegalArgumentException("A promise may not be a reject value.");
|
|
||||||
if (state != STATE_PENDING) return;
|
|
||||||
|
|
||||||
this.state = STATE_REJECTED;
|
|
||||||
this.val = val;
|
|
||||||
for (var el : handles) el.ctx.engine().pushMsg(true, el.rejected, el.ctx.data(), null, val);
|
|
||||||
handles = null;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Thread safe - call from any thread
|
|
||||||
*/
|
|
||||||
public void reject(CallContext ctx, Object val) {
|
|
||||||
if (Values.isWrapper(val, Promise.class)) Values.wrapper(val, Promise.class).then(ctx,
|
|
||||||
new NativeFunction(null, (e, th, args) -> {
|
|
||||||
this.reject(e, args[0]);
|
|
||||||
return null;
|
|
||||||
}),
|
|
||||||
new NativeFunction(null, (e, th, args) -> {
|
|
||||||
this.reject(e, args[0]);
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
else this.reject(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handle(CallContext ctx, FunctionValue fulfill, FunctionValue reject) {
|
|
||||||
if (state == STATE_FULFILLED) ctx.engine().pushMsg(true, fulfill, ctx.data(), null, val);
|
|
||||||
else if (state == STATE_REJECTED) ctx.engine().pushMsg(true, reject, ctx.data(), null, val);
|
|
||||||
else handles.add(new Handle(ctx, fulfill, reject));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Thread safe - you can call this from anywhere
|
|
||||||
* HOWEVER, it's strongly recommended to use this only in javascript
|
|
||||||
*/
|
|
||||||
@Native
|
|
||||||
public Promise then(CallContext ctx, Object onFulfill, Object onReject) {
|
|
||||||
if (!(onFulfill instanceof FunctionValue)) onFulfill = null;
|
|
||||||
if (!(onReject instanceof FunctionValue)) onReject = null;
|
|
||||||
|
|
||||||
var res = new Promise();
|
|
||||||
|
|
||||||
var fulfill = (FunctionValue)onFulfill;
|
|
||||||
var reject = (FunctionValue)onReject;
|
|
||||||
|
|
||||||
handle(ctx,
|
|
||||||
new NativeFunction(null, (e, th, args) -> {
|
|
||||||
if (fulfill == null) res.fulfill(e, args[0]);
|
|
||||||
else {
|
|
||||||
try { res.fulfill(e, fulfill.call(e, null, args[0])); }
|
|
||||||
catch (EngineException err) { res.reject(e, err.value); }
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}),
|
|
||||||
new NativeFunction(null, (e, th, args) -> {
|
|
||||||
if (reject == null) res.reject(e, args[0]);
|
|
||||||
else {
|
|
||||||
try { res.fulfill(e, reject.call(e, null, args[0])); }
|
|
||||||
catch (EngineException err) { res.reject(e, err.value); }
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Thread safe - you can call this from anywhere
|
|
||||||
* HOWEVER, it's strongly recommended to use this only in javascript
|
|
||||||
*/
|
|
||||||
@Native("catch")
|
|
||||||
public Promise _catch(CallContext ctx, Object onReject) {
|
|
||||||
return then(ctx, null, onReject);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Thread safe - you can call this from anywhere
|
|
||||||
* HOWEVER, it's strongly recommended to use this only in javascript
|
|
||||||
*/
|
|
||||||
@Native("finally")
|
|
||||||
public Promise _finally(CallContext ctx, Object handle) {
|
|
||||||
return then(ctx,
|
|
||||||
new NativeFunction(null, (e, th, args) -> {
|
|
||||||
if (handle instanceof FunctionValue) ((FunctionValue)handle).call(ctx);
|
|
||||||
return args[0];
|
|
||||||
}),
|
|
||||||
new NativeFunction(null, (e, th, args) -> {
|
|
||||||
if (handle instanceof FunctionValue) ((FunctionValue)handle).call(ctx);
|
|
||||||
throw new EngineException(args[0]);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* NOT THREAD SAFE - must be called from the engine executor thread
|
|
||||||
*/
|
|
||||||
@Native
|
|
||||||
public Promise(CallContext ctx, FunctionValue func) throws InterruptedException {
|
|
||||||
if (!(func instanceof FunctionValue)) throw EngineException.ofType("A function must be passed to the promise constructor.");
|
|
||||||
try {
|
|
||||||
func.call(
|
|
||||||
ctx, null,
|
|
||||||
new NativeFunction(null, (e, th, args) -> {
|
|
||||||
fulfill(e, args.length > 0 ? args[0] : null);
|
|
||||||
return null;
|
|
||||||
}),
|
|
||||||
new NativeFunction(null, (e, th, args) -> {
|
|
||||||
reject(e, args.length > 0 ? args[0] : null);
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
catch (EngineException e) {
|
|
||||||
reject(ctx, e.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override @Native
|
|
||||||
public String toString() {
|
|
||||||
if (state == STATE_PENDING) return "Promise (pending)";
|
|
||||||
else if (state == STATE_FULFILLED) return "Promise (fulfilled)";
|
|
||||||
else return "Promise (rejected)";
|
|
||||||
}
|
|
||||||
|
|
||||||
private Promise(int state, Object val) {
|
|
||||||
this.state = state;
|
|
||||||
this.val = val;
|
|
||||||
}
|
|
||||||
public Promise() {
|
|
||||||
this(STATE_PENDING, null);
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,7 +3,7 @@ package me.topchetoeu.jscript.polyfills;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.engine.CallContext;
|
import me.topchetoeu.jscript.engine.Context;
|
||||||
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
||||||
import me.topchetoeu.jscript.engine.values.NativeWrapper;
|
import me.topchetoeu.jscript.engine.values.NativeWrapper;
|
||||||
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
||||||
@ -17,7 +17,7 @@ public class RegExp {
|
|||||||
private static final Pattern NAMED_PATTERN = Pattern.compile("\\(\\?<([^=!].*?)>", Pattern.DOTALL);
|
private static final Pattern NAMED_PATTERN = Pattern.compile("\\(\\?<([^=!].*?)>", Pattern.DOTALL);
|
||||||
private static final Pattern ESCAPE_PATTERN = Pattern.compile("[/\\-\\\\^$*+?.()|\\[\\]{}]");
|
private static final Pattern ESCAPE_PATTERN = Pattern.compile("[/\\-\\\\^$*+?.()|\\[\\]{}]");
|
||||||
|
|
||||||
private static String cleanupPattern(CallContext ctx, Object val) throws InterruptedException {
|
private static String cleanupPattern(Context ctx, Object val) throws InterruptedException {
|
||||||
if (val == null) return "(?:)";
|
if (val == null) return "(?:)";
|
||||||
if (val instanceof RegExp) return ((RegExp)val).source;
|
if (val instanceof RegExp) return ((RegExp)val).source;
|
||||||
if (val instanceof NativeWrapper && ((NativeWrapper)val).wrapped instanceof RegExp) {
|
if (val instanceof NativeWrapper && ((NativeWrapper)val).wrapped instanceof RegExp) {
|
||||||
@ -27,7 +27,7 @@ public class RegExp {
|
|||||||
if (res.equals("")) return "(?:)";
|
if (res.equals("")) return "(?:)";
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
private static String cleanupFlags(CallContext ctx, Object val) throws InterruptedException {
|
private static String cleanupFlags(Context ctx, Object val) throws InterruptedException {
|
||||||
if (val == null) return "";
|
if (val == null) return "";
|
||||||
return Values.toString(ctx, val);
|
return Values.toString(ctx, val);
|
||||||
}
|
}
|
||||||
@ -46,7 +46,7 @@ public class RegExp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Native
|
@Native
|
||||||
public static RegExp escape(CallContext ctx, Object raw, Object flags) throws InterruptedException {
|
public static RegExp escape(Context ctx, Object raw, Object flags) throws InterruptedException {
|
||||||
return escape(Values.toString(ctx, raw), cleanupFlags(ctx, flags));
|
return escape(Values.toString(ctx, raw), cleanupFlags(ctx, flags));
|
||||||
}
|
}
|
||||||
public static RegExp escape(String raw, String flags) {
|
public static RegExp escape(String raw, String flags) {
|
||||||
@ -79,7 +79,7 @@ public class RegExp {
|
|||||||
@NativeGetter("lastIndex")
|
@NativeGetter("lastIndex")
|
||||||
public int lastIndex() { return lastI; }
|
public int lastIndex() { return lastI; }
|
||||||
@NativeSetter("lastIndex")
|
@NativeSetter("lastIndex")
|
||||||
public void setLastIndex(CallContext ctx, Object i) throws InterruptedException {
|
public void setLastIndex(Context ctx, Object i) throws InterruptedException {
|
||||||
lastI = (int)Values.toNumber(ctx, i);
|
lastI = (int)Values.toNumber(ctx, i);
|
||||||
}
|
}
|
||||||
public void setLastIndex(int i) {
|
public void setLastIndex(int i) {
|
||||||
@ -100,7 +100,7 @@ public class RegExp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Native
|
@Native
|
||||||
public Object exec(CallContext ctx, Object str) throws InterruptedException {
|
public Object exec(Context ctx, Object str) throws InterruptedException {
|
||||||
return exec(Values.toString(ctx, str));
|
return exec(Values.toString(ctx, str));
|
||||||
}
|
}
|
||||||
public Object exec(String str) {
|
public Object exec(String str) {
|
||||||
@ -119,7 +119,7 @@ public class RegExp {
|
|||||||
|
|
||||||
for (var el : namedGroups) {
|
for (var el : namedGroups) {
|
||||||
try {
|
try {
|
||||||
groups.defineProperty(el, matcher.group(el));
|
groups.defineProperty(null, el, matcher.group(el));
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException e) { }
|
catch (IllegalArgumentException e) { }
|
||||||
}
|
}
|
||||||
@ -127,30 +127,30 @@ public class RegExp {
|
|||||||
|
|
||||||
|
|
||||||
for (int i = 0; i < matcher.groupCount() + 1; i++) {
|
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(null, "groups", groups);
|
||||||
obj.defineProperty("index", matcher.start());
|
obj.defineProperty(null, "index", matcher.start());
|
||||||
obj.defineProperty("input", str);
|
obj.defineProperty(null, "input", str);
|
||||||
|
|
||||||
if (hasIndices) {
|
if (hasIndices) {
|
||||||
var indices = new ArrayValue();
|
var indices = new ArrayValue();
|
||||||
for (int i = 0; i < matcher.groupCount() + 1; i++) {
|
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();
|
var groupIndices = new ObjectValue();
|
||||||
for (var el : namedGroups) {
|
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);
|
indices.defineProperty(null, "groups", groupIndices);
|
||||||
obj.defineProperty("indices", indices);
|
obj.defineProperty(null, "indices", indices);
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Native
|
@Native
|
||||||
public RegExp(CallContext ctx, Object pattern, Object flags) throws InterruptedException {
|
public RegExp(Context ctx, Object pattern, Object flags) throws InterruptedException {
|
||||||
this(cleanupPattern(ctx, pattern), cleanupFlags(ctx, flags));
|
this(cleanupPattern(ctx, pattern), cleanupFlags(ctx, flags));
|
||||||
}
|
}
|
||||||
public RegExp(String pattern, String flags) {
|
public RegExp(String pattern, String flags) {
|
||||||
|
@ -1,112 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.polyfills;
|
|
||||||
|
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
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;
|
|
||||||
import me.topchetoeu.jscript.interop.Native;
|
|
||||||
import me.topchetoeu.jscript.interop.NativeGetter;
|
|
||||||
|
|
||||||
public class Set {
|
|
||||||
private LinkedHashSet<Object> objs = new LinkedHashSet<>();
|
|
||||||
|
|
||||||
@Native
|
|
||||||
public Set add(Object key) {
|
|
||||||
objs.add(key);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public boolean delete(Object key) {
|
|
||||||
return objs.remove(key);
|
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public boolean has(Object key) {
|
|
||||||
return objs.contains(key);
|
|
||||||
}
|
|
||||||
@Native
|
|
||||||
public void clear() {
|
|
||||||
objs.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Native
|
|
||||||
public void forEach(CallContext ctx, Object func, Object thisArg) throws InterruptedException {
|
|
||||||
if (!(func instanceof FunctionValue)) throw EngineException.ofType("func must be a function.");
|
|
||||||
|
|
||||||
for (var el : objs.stream().collect(Collectors.toList())) {
|
|
||||||
((FunctionValue)func).call(ctx, thisArg, el, el, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@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));
|
|
||||||
}
|
|
||||||
@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));
|
|
||||||
}
|
|
||||||
@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));
|
|
||||||
}
|
|
||||||
|
|
||||||
@NativeGetter("size")
|
|
||||||
public int size() {
|
|
||||||
return objs.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Native
|
|
||||||
public Set(CallContext ctx, Object iterable) throws InterruptedException {
|
|
||||||
if (Values.isPrimitive(iterable)) return;
|
|
||||||
|
|
||||||
for (var val : Values.toJavaIterable(ctx, iterable)) {
|
|
||||||
add(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public Set() { }
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
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<Object>();
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"include": [ "lib/**/*.ts" ],
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "bin/me/topchetoeu/jscript/js",
|
|
||||||
"declarationDir": "bin/me/topchetoeu/jscript/dts",
|
|
||||||
"target": "ES5",
|
|
||||||
"lib": [],
|
|
||||||
"module": "CommonJS",
|
|
||||||
"declaration": true,
|
|
||||||
"stripInternal": true,
|
|
||||||
"downlevelIteration": true,
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"forceConsistentCasingInFileNames": true,
|
|
||||||
"strict": true,
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user