lambdas and application now in AST, types and interpreter

master
Dustin Swan 1 week ago
parent d60e5aa29f
commit 920151f49c
Signed by: dustinswan
GPG Key ID: 30D46587E2100467

@ -1,4 +1,4 @@
import type { Value } from './types'; import type { Value, Closure } from './types';
export type Literal = { export type Literal = {
kind: 'literal' kind: 'literal'
@ -31,4 +31,16 @@ export type If = {
else: AST else: AST
} }
export type AST = Literal | BinaryOp | Variable | Let | If export type Lambda = {
kind: 'lambda'
params: string[]
body: AST
}
export type Apply = {
kind: 'apply'
func: AST
args: AST[]
}
export type AST = Literal | BinaryOp | Variable | Let | If | Lambda | Apply

@ -1,6 +1,6 @@
import type { AST } from './ast'; import type { AST } from './ast';
import type { Env } from './env'; import type { Env } from './env';
import type { Value } from './types'; import type { Value, Closure } from './types';
export function evaluate(ast: AST, env: Env): Value { export function evaluate(ast: AST, env: Env): Value {
switch (ast.kind) { switch (ast.kind) {
@ -34,6 +34,38 @@ export function evaluate(ast: AST, env: Env): Value {
} else { } else {
return evaluate(ast.else, env); 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');
} }
} }

@ -28,3 +28,47 @@ const env: Env = new Map();
const res = evaluate(ast, env); const res = evaluate(ast, env);
console.log(res); console.log(res);
const ast2: AST = {
kind: 'let',
name: 'add',
value: {
kind: 'lambda',
params: ['x', 'y'],
body: {
kind: 'binaryop',
operator: '+',
left: {
kind: 'variable',
name: 'x',
},
right: {
kind: 'variable',
name: 'y',
}
}
},
body: {
kind: 'apply',
func: {
kind: 'variable',
name: 'add'
},
args: [
{
kind: 'literal',
value: { kind: 'int', value: 2 }
},
{
kind: 'literal',
value: { kind: 'int', value: 3 }
},
]
}
};
const env2: Env = new Map();
const res2 = evaluate(ast2, env2);
console.log(res2);

@ -1,3 +1,6 @@
import type { AST } from './ast'
import type { Env } from './env'
export type IntValue = { export type IntValue = {
kind: 'int' kind: 'int'
value: number value: number
@ -18,4 +21,11 @@ export type BoolValue = {
value: boolean value: boolean
} }
export type Value = IntValue | FloatValue | StringValue | BoolValue; export type Closure = {
kind: 'closure'
params: string[]
body: AST
env: Env
}
export type Value = IntValue | FloatValue | StringValue | BoolValue | Closure;

Loading…
Cancel
Save