import { trie } from "dope2"; import type { CallBlockState } from "../component/expr/CallBlock"; import type { ExprBlockState } from "../component/expr/ExprBlock"; import type { InputBlockState } from "../component/expr/InputBlock"; import type { LambdaBlockState } from "../component/expr/LambdaBlock"; import type { LetInBlockState } from "../component/expr/LetInBlock"; export interface DynamicEnvironment { names: any; } export interface EvalResult { val?: any; err?: Error; }; export function evalExpr(s: ExprBlockState, env: DynamicEnvironment): EvalResult { if (s.kind === "input") { return evalInput(s, env); } else if (s.kind === "call") { return evalCall(s, env); } else if (s.kind === "let") { return evalLet(s, env); } else { // (s.kind === "lambda") return evalLambda(s, env); } } export function evalInput(s: InputBlockState, env: DynamicEnvironment): EvalResult { if (s.value.kind === "literal") { if (s.text === '') { return { err: new Error('cannot parse empty string as '+s.value.type) }; } const ctor = { Int: BigInt, Double: Number, }[s.value.type] as (s: string) => any; return { val: ctor(s.text) }; } else if (s.value.kind === "name") { const found = trie.get(env.names)(s.text); if (found) { if (found.recursive) { // dirty return found.i(); } return {val: found.i}; } } return { err: new Error(`'${s.text}' not found`), } } export function evalCall(s: CallBlockState, env: DynamicEnvironment): EvalResult { const fn = evalExpr(s.fn, env); const input = evalExpr(s.input, env); if (fn.val !== undefined && input.val !== undefined) { try { const result = fn.val(input.val) return { val: result } ; } catch (e: any) { return { err: e }; } } return {}; } export function evalLet(s: LetInBlockState, env: DynamicEnvironment): EvalResult { const valueEnv = { names: trie.insert(env.names)(s.name)({ recursive: true, i: () => { try { return { val }; } catch (e) { return { err: e }; } }, }), }; const {val} = evalExpr(s.value, valueEnv); const innerEnv = { names: trie.insert(env.names)(s.name)({i: val}), } return evalExpr(s.inner, innerEnv); } export function evalLambda(s: LambdaBlockState, env: DynamicEnvironment): EvalResult { const fn = x => { const innerEnv = { names: trie.insert(env.names)(s.paramName)({i: x}) }; const result = evalExpr(s.expr, innerEnv); return result.val; }; return {val: fn}; }