feat: implement basic promises

This commit is contained in:
TopchetoEU 2024-12-27 19:17:07 +02:00
parent 7423e3f283
commit 1ac68425af
Signed by: topchetoeu
GPG Key ID: 6531B8583E5F6ED4
4 changed files with 185 additions and 1 deletions

View File

@ -14,6 +14,7 @@ import { Math as _Math } from "./math.ts";
import { Set, WeakSet } from "./set.ts"; import { Set, WeakSet } from "./set.ts";
import { JSON } from "./json.ts"; import { JSON } from "./json.ts";
import { encodeURI, encodeURIComponent } from "./url.ts"; import { encodeURI, encodeURIComponent } from "./url.ts";
import { Promise } from "./promise.ts";
declare global { declare global {
function print(...args: any[]): void; function print(...args: any[]): void;
@ -22,7 +23,7 @@ declare global {
function fixup<T extends Function>(clazz: T) { function fixup<T extends Function>(clazz: T) {
object.setPrototype(clazz, Function.prototype); object.setPrototype(clazz, Function.prototype);
object.setPrototype(clazz.prototype, Object.prototype); object.setPrototype(clazz.prototype as any, Object.prototype);
return clazz; return clazz;
} }
@ -48,6 +49,7 @@ target.Set = fixup(Set);
target.WeakSet = fixup(WeakSet); target.WeakSet = fixup(WeakSet);
target.RegExp = fixup(RegExp); target.RegExp = fixup(RegExp);
target.Date = fixup(Date); target.Date = fixup(Date);
target.Promise = fixup(Promise);
target.Math = object.setPrototype(_Math, Object.prototype); target.Math = object.setPrototype(_Math, Object.prototype);
target.JSON = object.setPrototype(JSON, Object.prototype); target.JSON = object.setPrototype(JSON, Object.prototype);

View File

@ -79,6 +79,8 @@ export interface Primordials {
compile(src: string): Function; compile(src: string): Function;
setGlobalPrototypes(prototype: Record<string, any>): void; setGlobalPrototypes(prototype: Record<string, any>): void;
now(): number; now(): number;
next(func: () => void): void;
schedule(func: () => void, delay: number): () => void;
} }
globalThis.undefined = void 0; globalThis.undefined = void 0;
@ -97,6 +99,8 @@ export const {
setGlobalPrototypes, setGlobalPrototypes,
compile, compile,
now, now,
next,
schedule,
} = primordials; } = primordials;
export type regex = InstanceType<typeof regex>; export type regex = InstanceType<typeof regex>;

154
src/lib/libs/promise.ts Normal file
View File

@ -0,0 +1,154 @@
import { func, next, object, symbol } from "./primordials.ts";
enum PromiseState {
Pending = "pend",
Fulfilled = "ful",
Rejected = "rej",
}
const pState: unique symbol = symbol.makeSymbol("Promise.state") as any;
const pValue: unique symbol = symbol.makeSymbol("Promise.value") as any;
const pFulHandles: unique symbol = symbol.makeSymbol("Promise.fulfillHandles") as any;
const pRejHandles: unique symbol = symbol.makeSymbol("Promise.rejectHandles") as any;
function makePromise<T>(): Promise<T> {
return object.setPrototype({
[pState]: PromiseState.Pending,
[pFulHandles]: [],
[pRejHandles]: [],
}, Promise.prototype) as Promise<T>;
}
function fulfill(self: Promise<any>, val: any) {
if (self[pState] !== PromiseState.Pending) return;
if (self === val) throw new Error("A promise may not be fulfilled with itself");
if (val != null && typeof val.then === "function") {
val.then(
(val: any) => fulfill(self, val),
(err: any) => reject(self, err),
);
}
else {
self[pValue] = val;
self[pState] = PromiseState.Fulfilled;
const handles = self[pFulHandles]!;
for (let i = 0; i < handles.length; i++) {
handles[i](val);
}
self[pFulHandles] = undefined;
self[pRejHandles] = undefined;
}
}
function reject(self: Promise<any>, val: any) {
if (self[pState] !== PromiseState.Pending) return;
if (self === val) throw new Error("A promise may not be rejected with itself");
if (val != null && typeof val.then === "function") {
val.then(
(val: any) => reject(self, val),
(err: any) => reject(self, err),
);
}
else {
self[pValue] = val;
self[pState] = PromiseState.Rejected;
const handles = self[pRejHandles]!;
for (let i = 0; i < handles.length; i++) {
handles[i](val);
}
self[pFulHandles] = undefined;
self[pRejHandles] = undefined;
}
}
function handle<T>(self: Promise<T>, ful?: (val: T) => void, rej?: (err: any) => void) {
if (self[pState] === PromiseState.Pending) {
if (ful != null) {
self[pFulHandles]![self[pFulHandles]!.length] = ful;
}
if (rej != null) {
self[pRejHandles]![self[pRejHandles]!.length] = rej;
}
}
else if (self[pState] === PromiseState.Fulfilled) {
if (ful != null) ful(self[pValue] as T);
}
else if (self[pState] === PromiseState.Rejected) {
if (rej != null) rej(self[pValue]);
}
}
export class Promise<T> {
public [pState]: PromiseState;
public [pValue]?: T | unknown;
public [pFulHandles]?: ((val: T) => void)[] = [];
public [pRejHandles]?: ((val: T) => void)[] = [];
public then<Res>(ful?: (val: T) => Res, rej?: (err: any) => Res) {
if (typeof ful !== "function") ful = undefined;
if (typeof rej !== "function") rej = undefined;
const promise = makePromise<Res>();
handle(this,
val => next(() => {
if (ful == null) fulfill(promise, val);
else {
try { fulfill(promise, ful(val)); }
catch (e) { reject(promise, e); }
}
}),
err => next(() => {
if (rej == null) reject(promise, err);
else {
try { fulfill(promise, rej(err)); }
catch (e) { reject(promise, e); }
}
}),
);
return promise;
}
public catch<Res>(rej?: (err: any) => Res) {
return this.then(undefined, rej);
}
public finally(fn?: () => void) {
if (typeof fn !== "function") return this["then"]();
return this.then(
v => {
fn();
return v;
},
v => {
fn();
throw v;
},
)
}
public constructor(fn: (fulfil: (val: T) => void, reject: (err: unknown) => void) => void) {
this[pState] = PromiseState.Pending;
fn(val => fulfill(this, val), err => reject(this, err));
}
public static resolve(val: any) {
const res = makePromise();
fulfill(res, val);
return res;
}
public static reject(val: any) {
const res = makePromise();
reject(res, val);
return res;
}
}
func.setCallable(Promise, false);

24
src/main/resources/lib/async.d.ts vendored Normal file
View File

@ -0,0 +1,24 @@
declare type Timer = number;
declare function setTimeout(func: () => void, time: number): Timer;
declare function setTimer(func: () => void, time: number): Timer;
declare function setImmediate(func: () => void): void;
declare function clearTimeout(timer: Timer): void;
declare function clearTimer(timer: Timer): void;
declare type Awaited<T> = T extends { then(fn?: (val: infer Res) => void) } ? Awaited<Res> : T;
declare interface Thenable<T> {
then<Res = T, Rej = never>(onFulfill?: (val: T) => Res, onReject?: (err: any) => Rej): Promise<Res | Rej>;
}
declare interface Promise<T> extends Thenable<T> {
catch<Res = T>(onReject?: (err: any) => Res): Promise<Res>;
finally(fn?: () => void): Promise<T>;
}
declare interface PromiseConstructor {
new <T>(fn: (res: (val: T) => void, rej: (err: any) => void) => void): Promise<T>;
resolve<T>(val: T): Promise<Awaited<T>>;
reject<T>(err: unknown): Promise<T>;
}