106 lines
2.6 KiB
TypeScript
106 lines
2.6 KiB
TypeScript
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};
|
|
}
|