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 = {
|
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');
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
44
src/main.ts
44
src/main.ts
|
|
@ -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);
|
||||||
|
|
|
||||||
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 = {
|
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…
Add table
Add a link
Reference in a new issue