lambdas and application now in AST, types and interpreter
This commit is contained in:
parent
d60e5aa29f
commit
920151f49c
4 changed files with 102 additions and 4 deletions
16
src/ast.ts
16
src/ast.ts
|
|
@ -1,4 +1,4 @@
|
|||
import type { Value } from './types';
|
||||
import type { Value, Closure } from './types';
|
||||
|
||||
export type Literal = {
|
||||
kind: 'literal'
|
||||
|
|
@ -31,4 +31,16 @@ export type If = {
|
|||
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 { 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');
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
44
src/main.ts
44
src/main.ts
|
|
@ -28,3 +28,47 @@ const env: Env = new Map();
|
|||
const res = evaluate(ast, env);
|
||||
|
||||
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);
|
||||
|
|
|
|||
12
src/types.ts
12
src/types.ts
|
|
@ -1,3 +1,6 @@
|
|||
import type { AST } from './ast'
|
||||
import type { Env } from './env'
|
||||
|
||||
export type IntValue = {
|
||||
kind: 'int'
|
||||
value: number
|
||||
|
|
@ -18,4 +21,11 @@ export type BoolValue = {
|
|||
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…
Add table
Add a link
Reference in a new issue