Core library reprogramming #5

Merged
TopchetoEU merged 23 commits from TopchetoEU/corelib-reprogramming into master 2023-10-04 05:50:26 +00:00
9 changed files with 102 additions and 228 deletions
Showing only changes of commit 63b04019cf - Show all commits

View File

@ -22,10 +22,18 @@ interface Internals {
map: typeof Map;
set: typeof Set;
timers: {
setTimeout: <T extends any[]>(handle: (...args: [ ...T, ...any[] ]) => void, delay?: number, ...args: T) => number,
setInterval: <T extends any[]>(handle: (...args: [ ...T, ...any[] ]) => void, delay?: number, ...args: T) => number,
clearTimeout: (id: number) => void,
clearInterval: (id: number) => void,
}
markSpecial(...funcs: Function[]): void;
getEnv(func: Function): Environment | undefined;
setEnv<T>(func: T, env: Environment): T;
apply(func: Function, thisArg: any, args: any[], env?: Environment): any;
bind(func: Function, thisArg: any): any;
delay(timeout: number, callback: Function): () => void;
pushMessage(micro: boolean, func: Function, thisArg: any, args: any[]): void;
@ -54,24 +62,26 @@ interface Internals {
var env: Environment = arguments[0], internals: Internals = arguments[1];
try {
const values = {
Object: env.global.Object = internals.object,
Function: env.global.Function = internals.function,
Array: env.global.Array = internals.array,
Promise: env.global.Promise = internals.promise,
Boolean: env.global.Boolean = internals.bool,
Number: env.global.Number = internals.number,
String: env.global.String = internals.string,
Symbol: env.global.Symbol = internals.symbol,
Error: env.global.Error = internals.error,
SyntaxError: env.global.SyntaxError = internals.syntax,
TypeError: env.global.TypeError = internals.type,
RangeError: env.global.RangeError = internals.range,
RegExp: env.global.RegExp = internals.regexp,
Map: env.global.Map = internals.map,
Set: env.global.Set = internals.set,
}
const Array = values.Array;
const Array = env.global.Array = internals.array;
env.global.Object = internals.object;
env.global.Function = internals.function;
env.global.Promise = internals.promise;
env.global.Boolean = internals.bool;
env.global.Number = internals.number;
env.global.String = internals.string;
env.global.Symbol = internals.symbol;
env.global.Error = internals.error;
env.global.SyntaxError = internals.syntax;
env.global.TypeError = internals.type;
env.global.RangeError = internals.range;
env.global.RegExp = internals.regexp;
env.global.Map = internals.map;
env.global.Set = internals.set;
env.global.setInterval = internals.bind(internals.timers.setInterval, internals.timers);
env.global.setTimeout = internals.bind(internals.timers.setTimeout, internals.timers);
env.global.clearInterval = internals.bind(internals.timers.clearInterval, internals.timers);
env.global.clearTimeout = internals.bind(internals.timers.clearTimeout, internals.timers);
const log = env.global.log = internals.bind(internals.log, internals);
env.setProto('object', env.global.Object.prototype);
env.setProto('function', env.global.Function.prototype);
@ -88,14 +98,6 @@ try {
(env.global.Object.prototype as any).__proto__ = null;
internals.getEnv(run)?.setProto('array', Array.prototype);
globalThis.log = (...args) => internals.apply(internals.log, internals, args);
run('timeout');
env.global.log = log;
env.global.NewObject = internals.object;
log('Loaded polyfills!');
}
catch (e: any) {

View File

@ -1,13 +0,0 @@
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 };
})();

View File

@ -1,143 +0,0 @@
define("regex", () => {
// var RegExp = env.global.RegExp = env.internals.RegExp;
// setProps(RegExp.prototype as RegExp, env, {
// [Symbol.typeName]: 'RegExp',
// test(val) {
// return !!this.exec(val);
// },
// toString() {
// return '/' + this.source + '/' + this.flags;
// },
// [Symbol.match](target) {
// if (this.global) {
// const res: string[] = [];
// let val;
// while (val = this.exec(target)) {
// res.push(val[0]);
// }
// this.lastIndex = 0;
// return res;
// }
// else {
// const res = this.exec(target);
// if (!this.sticky) this.lastIndex = 0;
// return res;
// }
// },
// [Symbol.matchAll](target) {
// let pattern: RegExp | undefined = new this.constructor(this, this.flags + "g") as RegExp;
// return {
// next: (): IteratorResult<RegExpResult, undefined> => {
// const val = pattern?.exec(target);
// if (val === null || val === undefined) {
// pattern = undefined;
// return { done: true };
// }
// else return { value: val };
// },
// [Symbol.iterator]() { return this; }
// }
// },
// [Symbol.split](target, limit, sensible) {
// const pattern = new this.constructor(this, this.flags + "g") as RegExp;
// let match: RegExpResult | null;
// let lastEnd = 0;
// const res: string[] = [];
// 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) {
// pattern.lastIndex = (start as any) | 0;
// const res = pattern.exec(target);
// if (res) return res.index;
// else return -1;
// }
// else {
// start ??= target.length;
// start |= 0;
// let res: RegExpResult | null = null;
// while (true) {
// const tmp = pattern.exec(target);
// if (tmp === null || tmp.index > start) break;
// res = tmp;
// }
// if (res && res.index <= start) return res.index;
// else return -1;
// }
// },
// });
});

View File

@ -1,38 +0,0 @@
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 env.global.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 env.global.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!;
};
});

View File

@ -1,9 +1,6 @@
{
"files": [
"lib.d.ts",
"modules.ts",
"regex.ts",
"timeout.ts",
"core.ts"
],
"compilerOptions": {

View File

@ -24,9 +24,14 @@ public class FunctionPolyfill {
if (!(func instanceof FunctionValue)) throw EngineException.ofError("Expected this to be a function.");
return new NativeFunction(func.name + " (bound)", (callCtx, _0, callArgs) -> {
var resArgs = new Object[args.length + callArgs.length];
Object[] resArgs;
if (args.length == 0) resArgs = callArgs;
else {
resArgs = new Object[args.length + callArgs.length];
System.arraycopy(args, 0, resArgs, 0, args.length);
System.arraycopy(callArgs, 0, resArgs, args.length, callArgs.length);
}
return func.call(ctx, thisArg, resArgs);
});

View File

@ -1,7 +1,6 @@
package me.topchetoeu.jscript.polyfills;
import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.Environment;
import me.topchetoeu.jscript.engine.frame.CodeFrame;
import me.topchetoeu.jscript.engine.frame.Runners;
import me.topchetoeu.jscript.engine.values.CodeFunction;

View File

@ -20,6 +20,8 @@ public class Internals {
promise, map, set, regexp,
error, syntax, type, range;
@Native public final TimerPolyfills timers = new TimerPolyfills();
@Native public void markSpecial(FunctionValue ...funcs) {
for (var func : funcs) {
func.special = true;
@ -37,6 +39,9 @@ public class Internals {
if (env != null) ctx = new Context(env, ctx.message);
return func.call(ctx, thisArg, args.toArray());
}
@Native public FunctionValue bind(Context ctx, FunctionValue func, Object thisArg) throws InterruptedException {
return FunctionPolyfill.bind(ctx, func, thisArg);
}
@Native public FunctionValue delay(Context ctx, double delay, FunctionValue callback) throws InterruptedException {
var thread = new Thread((Runnable)() -> {
var ms = (long)delay;

View File

@ -0,0 +1,60 @@
package me.topchetoeu.jscript.polyfills;
import java.util.HashMap;
import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.values.FunctionValue;
import me.topchetoeu.jscript.interop.Native;
public class TimerPolyfills {
private HashMap<Integer, Thread> threads = new HashMap<>();
private int i = 0;
@Native public int setTimeout(Context ctx, FunctionValue func, int delay, Object ...args) {
var thread = new Thread(() -> {
var ms = (long)delay;
var ns = (int)((delay - ms) * 10000000);
try {
Thread.sleep(ms, ns);
}
catch (InterruptedException e) { return; }
ctx.message.engine.pushMsg(false, ctx.message, func, null, args);
});
thread.start();
threads.put(++i, thread);
return i;
}
@Native public int setInterval(Context ctx, FunctionValue func, int delay, Object ...args) {
var thread = new Thread(() -> {
var ms = (long)delay;
var ns = (int)((delay - ms) * 10000000);
while (true) {
try {
Thread.sleep(ms, ns);
}
catch (InterruptedException e) { return; }
ctx.message.engine.pushMsg(false, ctx.message, func, null, args);
}
});
thread.start();
threads.put(++i, thread);
return i;
}
@Native public void clearTimeout(Context ctx, int i) {
var thread = threads.remove(i);
if (thread != null) thread.interrupt();
}
@Native public void clearInterval(Context ctx, int i) {
clearTimeout(ctx, i);
}
}