feat: implement async generators

This commit is contained in:
TopchetoEU 2023-08-26 00:41:28 +03:00
parent 8a0d309f0f
commit 7a745faacf
No known key found for this signature in database
GPG Key ID: 24E57B2E9C61AD19
2 changed files with 58 additions and 11 deletions

View File

@ -20,7 +20,7 @@ interface FunctionConstructor extends Function {
asyncGenerator<ArgsT extends any[], RetT>( asyncGenerator<ArgsT extends any[], RetT>(
func: (await: <T>(val: T) => Awaited<T>, _yield: <T>(val: T) => void) => (...args: ArgsT) => RetT func: (await: <T>(val: T) => Awaited<T>, _yield: <T>(val: T) => void) => (...args: ArgsT) => RetT
): (...args: ArgsT) => AsyncGenerator<RetT>; ): (...args: ArgsT) => AsyncGenerator<RetT>;
generator<ArgsT extends any[], T, RetT, TNext>( generator<ArgsT extends any[], T = unknown, RetT = unknown, TNext = unknown>(
func: (_yield: <T>(val: T) => TNext) => (...args: ArgsT) => RetT func: (_yield: <T>(val: T) => TNext) => (...args: ArgsT) => RetT
): (...args: ArgsT) => Generator<T, RetT, TNext>; ): (...args: ArgsT) => Generator<T, RetT, TNext>;
} }
@ -90,7 +90,7 @@ setProps(Function.prototype, {
}, },
}); });
setProps(Function, { setProps(Function, {
async<ArgsT extends any[], RetT>(func: (_yield: <T>(val: T) => Awaited<T>) => (...args: ArgsT) => RetT) { 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.');
return function (this: any) { return function (this: any) {
@ -121,8 +121,53 @@ setProps(Function, {
}); });
}; };
}, },
asyncGenerator(func) {
if (typeof func !== 'function') throw new TypeError('Expected func to be function.');
return function(this: any) {
const gen = Function.generator<any[], ['await' | 'yield', any]>((_yield) => func(
val => _yield(['await', val]) as any,
val => _yield(['yield', val])
)).apply(this, arguments as any);
const next = (resolve: Function, reject: Function, type: 'none' | 'val' | 'ret' | 'err', val?: any) => {
let res;
try {
switch (type) {
case 'val': res = gen.next(val); break;
case 'ret': res = gen.return(val); break;
case 'err': res = gen.throw(val); break;
default: res = gen.next(); break;
}
}
catch (e) { return reject(e); }
if (res.done) return { done: true, res: <any>res };
else if (res.value[0] === 'await') Promise.resolve(res.value[1]).then(
v => next(resolve, reject, 'val', v),
v => next(resolve, reject, 'err', v),
)
else resolve({ done: false, value: res.value[1] });
};
return {
next() {
const args = arguments;
if (arguments.length === 0) return new Promise((res, rej) => next(res, rej, 'none'));
else return new Promise((res, rej) => next(res, rej, 'val', args[0]));
},
return: (value) => new Promise((res, rej) => next(res, rej, 'ret', value)),
throw: (value) => new Promise((res, rej) => next(res, rej, 'err', value)),
[Symbol.asyncIterator]() { return this; }
}
}
},
generator(func) { 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.');
return internals.makeGenerator(func); return Object.assign(internals.makeGenerator(func), {
[Symbol.iterator]() { return this; }
});
} }
}) })

View File

@ -981,7 +981,14 @@ public class Parsing {
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public static ParseRes<? extends Statement> parseSimple(String filename, List<Token> tokens, int i, boolean statement) { public static ParseRes<? extends Statement> parseSimple(String filename, List<Token> tokens, int i, boolean statement) {
var res = new ArrayList<>(List.of( var res = new ArrayList<>();
if (!statement) {
res.add(parseObject(filename, tokens, i));
res.add(parseFunction(filename, tokens, i, false));
}
res.addAll(List.of(
parseVariable(filename, tokens, i), parseVariable(filename, tokens, i),
parseLiteral(filename, tokens, i), parseLiteral(filename, tokens, i),
parseString(filename, tokens, i), parseString(filename, tokens, i),
@ -997,11 +1004,6 @@ public class Parsing {
parseDelete(filename, tokens, i) parseDelete(filename, tokens, i)
)); ));
if (!statement) {
res.add(parseObject(filename, tokens, i));
res.add(parseFunction(filename, tokens, i, false));
}
return ParseRes.any(res.toArray(ParseRes[]::new)); return ParseRes.any(res.toArray(ParseRes[]::new));
} }
@ -1795,7 +1797,6 @@ public class Parsing {
parseContinue(filename, tokens, i), parseContinue(filename, tokens, i),
parseBreak(filename, tokens, i), parseBreak(filename, tokens, i),
parseDebug(filename, tokens, i), parseDebug(filename, tokens, i),
parseValueStatement(filename, tokens, i),
parseIf(filename, tokens, i), parseIf(filename, tokens, i),
parseWhile(filename, tokens, i), parseWhile(filename, tokens, i),
parseSwitch(filename, tokens, i), parseSwitch(filename, tokens, i),
@ -1804,7 +1805,8 @@ public class Parsing {
parseDoWhile(filename, tokens, i), parseDoWhile(filename, tokens, i),
parseCatch(filename, tokens, i), parseCatch(filename, tokens, i),
parseCompound(filename, tokens, i), parseCompound(filename, tokens, i),
parseFunction(filename, tokens, i, true) parseFunction(filename, tokens, i, true),
parseValueStatement(filename, tokens, i)
); );
} }