import { BUILTIN_Add, BUILTIN_Arr, BUILTIN_Mul, BUILTIN_ToString, SBUILTIN_Call, SBUILTIN_Map, } from "../builtin"; import { ToString } from "../util"; import { ASTNode, EmptyStackFrame, NodeType, StackFrame } from "./common"; import { Lex } from "./lexer"; import { Parse } from "./parser"; export type SENTINEL_NO_BUILTIN = "__NO_BUILTIN__"; export type MapBuiltins< Node extends ASTNode, Frame extends StackFrame > = GetEvaluatedChildren extends infer Args extends readonly any[] ? Node["name"] extends "call" ? SBUILTIN_Call : Node["name"] extends "map" ? SBUILTIN_Map : Node["name"] extends "tostring" ? BUILTIN_ToString : Node["name"] extends "arr" ? BUILTIN_Arr : Node["name"] extends "add" ? BUILTIN_Add : Node["name"] extends "mul" ? BUILTIN_Mul : SENTINEL_NO_BUILTIN : never; export type EvalError = `Eval error: ${T}`; export type FindInStack< Frame extends StackFrame, NameToFind > = NameToFind extends keyof Frame["bindings"] ? Frame["bindings"][NameToFind] : Frame["parent"] extends null ? EvalError<`Can't find name "${ToString}" on the stack`> : FindInStack; export type MapOnStack< Node extends ASTNode, Frame extends StackFrame > = FindInStack; export type FnPrim< Args extends readonly ASTNode[] = readonly ASTNode[], Fn extends ASTNode = ASTNode > = { args: Args; fn: Fn }; export type HandleFn = Node["children"] extends [ ...infer Args extends ASTNode[], infer Fn extends ASTNode ] ? FnPrim : never; export type MapZip< T extends readonly ASTNode[], U extends readonly PropertyKey[] > = { [Idx in Exclude< keyof T, keyof any[] > as T[Idx] extends infer Node extends ASTNode ? Node["name"] : never]: Idx extends keyof U ? U[Idx] : never; }; export type CallFn< Fn extends FnPrim, Values extends readonly any[], Frame extends StackFrame > = Evaluate, Frame>>; export type Evaluate< Node extends ASTNode, Frame extends StackFrame = EmptyStackFrame > = Node["type"] extends NodeType.INT ? Node["value"] : Node["type"] extends NodeType.EXT ? // special builtin Node["name"] extends "fn" ? HandleFn : MapBuiltins extends infer BI ? BI extends SENTINEL_NO_BUILTIN ? MapOnStack : BI : never : EvalError<`Unhandled node type ${Node["type"]}`>; export type GetEvaluatedChildren< Node extends ASTNode, Frame extends StackFrame > = Node["children"] extends infer Children extends readonly ASTNode[] ? { [Idx in keyof Children]: Children[Idx] extends ASTNode ? Evaluate : never; } : never; const input = `map(arr("hello", "world"), fn(s, i, add(tostring(i), ":", s)))` as const; const lex_result = null as unknown as Lex; const parse_result = null as unknown as Parse; const eval_result = null as unknown as Evaluate;