|
|
|
|
@ -1,6 +1,6 @@
|
|
|
|
|
import type { AST } from './ast';
|
|
|
|
|
import type { Env } from './env';
|
|
|
|
|
import type { Value } from './types';
|
|
|
|
|
import type { Value, Closure } from './types';
|
|
|
|
|
|
|
|
|
|
export function evaluate(ast: AST, env: Env): Value {
|
|
|
|
|
switch (ast.kind) {
|
|
|
|
|
@ -34,6 +34,38 @@ export function evaluate(ast: AST, env: Env): Value {
|
|
|
|
|
} else {
|
|
|
|
|
return evaluate(ast.else, env);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case 'lambda':
|
|
|
|
|
return {
|
|
|
|
|
kind: 'closure',
|
|
|
|
|
params: ast.params,
|
|
|
|
|
body: ast.body,
|
|
|
|
|
env
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case 'apply':
|
|
|
|
|
const func = evaluate(ast.func, env);
|
|
|
|
|
if (func.kind !== 'closure')
|
|
|
|
|
throw new Error('Not a closure');
|
|
|
|
|
|
|
|
|
|
const params = func.params;
|
|
|
|
|
const callEnv = new Map(func.env);
|
|
|
|
|
const args = ast.args;
|
|
|
|
|
|
|
|
|
|
if (args.length !== params.length)
|
|
|
|
|
throw new Error('Parameter argument mismatch');
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < args.length; i++) {
|
|
|
|
|
const arg = evaluate(args[i], env);
|
|
|
|
|
const param = params[i];
|
|
|
|
|
callEnv.set(param, arg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return evaluate(func.body, callEnv);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
throw new Error('Syntax Error');
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|