1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
import { callFn, emptyStackFrame, evaluate, lex, parse } from "../js-lang";
import {
Evaluate,
FnPrim,
Lex,
Parse,
EvalError,
CallFn,
EmptyStackFrame,
ASTNode,
} from "../ts-lang";
export type TransformArgs<Args extends readonly ASTNode[]> = {
[Idx in keyof Args]: any;
};
export type AssertArgs<
Args extends readonly ASTNode[],
ArgsConstraint extends readonly any[]
> = TransformArgs<Args> extends ArgsConstraint ? ArgsConstraint : never;
export const createFn =
<ArgsConstraint extends any[]>() =>
<Program extends string>(
program: Program
): Evaluate<Parse<Lex<Program>>> extends infer E
? E extends [infer ProgramFn extends FnPrim]
? TransformArgs<ProgramFn["args"]> extends ArgsConstraint
? <const Args extends ArgsConstraint>(
...args: Args
) => CallFn<ProgramFn, Args, EmptyStackFrame, []>
: EvalError<`Program's args do not extend args constraint`>
: E extends readonly [
readonly [infer Prim extends FnPrim, infer StackFrame, infer Name]
]
? TransformArgs<Prim["args"]> extends ArgsConstraint
? <const Args extends ArgsConstraint>(
...args: Args
) => CallFn<E[0], Args, EmptyStackFrame, []>
: EvalError<`Program's args do not extend args constraint`>
: EvalError<"Cannot create a function from a program that does not eval to a function">
: never => {
const [programFn] = evaluate(parse(lex(program))) as Array<FnPrim>;
if (!programFn.fn) {
throw new Error(
"Cannot create a function from a program that does not eval to a function"
);
}
return ((...args: any[]) =>
callFn(programFn, args, emptyStackFrame)) as any;
};
|