interpreting record update, and > (func application pipe thing). cleaning up main.ts test code
This commit is contained in:
parent
59b718619c
commit
c44a6858ff
3 changed files with 53 additions and 42 deletions
|
|
@ -7,11 +7,14 @@ export function evaluate(ast: AST, env: Env): Value {
|
|||
case 'literal':
|
||||
return ast.value;
|
||||
|
||||
case 'variable':
|
||||
case 'variable': {
|
||||
const val = env.get(ast.name);
|
||||
|
||||
if (val === undefined)
|
||||
throw new Error(`Unknown variable: ${ast.name}`);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
case 'list':
|
||||
return {
|
||||
|
|
@ -28,7 +31,7 @@ export function evaluate(ast: AST, env: Env): Value {
|
|||
|
||||
return { kind: 'record', fields };
|
||||
|
||||
case 'record-access':
|
||||
case 'record-access': {
|
||||
const record = evaluate(ast.record, env);
|
||||
|
||||
if (record.kind !== 'record')
|
||||
|
|
@ -41,6 +44,22 @@ export function evaluate(ast: AST, env: Env): Value {
|
|||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
case 'record-update': {
|
||||
const record = evaluate(ast.record, env);
|
||||
|
||||
if (record.kind !== 'record')
|
||||
throw new Error('Not a record');
|
||||
|
||||
const newFields: { [key: string]: Value } = { ...record.fields };
|
||||
|
||||
for (const [field, expr] of Object.entries(ast.updates)) {
|
||||
newFields[field] = evaluate(expr, env);
|
||||
}
|
||||
|
||||
return { kind: 'record', fields: newFields };
|
||||
}
|
||||
|
||||
case 'constructor':
|
||||
return {
|
||||
|
|
@ -49,10 +68,11 @@ export function evaluate(ast: AST, env: Env): Value {
|
|||
args: [] // TODO: constructors args
|
||||
};
|
||||
|
||||
case 'let':
|
||||
const val2 = evaluate(ast.value, env);
|
||||
const newEnv = new Map(env).set(ast.name, val2);
|
||||
case 'let': {
|
||||
const val = evaluate(ast.value, env);
|
||||
const newEnv = new Map(env).set(ast.name, val);
|
||||
return evaluate(ast.body, newEnv);
|
||||
}
|
||||
|
||||
case 'lambda':
|
||||
return {
|
||||
|
|
@ -62,7 +82,7 @@ export function evaluate(ast: AST, env: Env): Value {
|
|||
env
|
||||
}
|
||||
|
||||
case 'apply':
|
||||
case 'apply': {
|
||||
// Operators
|
||||
if (ast.func.kind === 'variable') {
|
||||
const name = ast.func.name;
|
||||
|
|
@ -114,10 +134,10 @@ export function evaluate(ast: AST, env: Env): Value {
|
|||
}
|
||||
|
||||
return evaluate(func.body, callEnv);
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error('Syntax Error');
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -155,8 +175,18 @@ function evaluateBuiltIn(op: string, left: Value, right: Value): Value {
|
|||
return evaluateBinaryOp(op, left, right);
|
||||
}
|
||||
|
||||
if (op === '>')
|
||||
throw new Error('TODO Not implemented yet');
|
||||
if (op === '>') {
|
||||
// x > f means f(x)
|
||||
if (right.kind !== 'closure')
|
||||
throw new Error('Right side of > must be a function');
|
||||
|
||||
if (right.params.length !== 1)
|
||||
throw new Error('Pipe only works with 1-arg functions for now..');
|
||||
|
||||
const callEnv = new Map(right.env);
|
||||
callEnv.set(right.params[0], left);
|
||||
return evaluate(right.body, callEnv);
|
||||
}
|
||||
|
||||
if (op === '&')
|
||||
throw new Error('TODO Not implemented yet');
|
||||
|
|
|
|||
46
src/main.ts
46
src/main.ts
|
|
@ -1,39 +1,21 @@
|
|||
import { evaluate } from './interpreter'
|
||||
// import type { AST } from './ast'
|
||||
import type { Env } from './env'
|
||||
import { tokenize } from './lexer'
|
||||
import { Parser } from './parser'
|
||||
import { prettyPrint } from './ast';
|
||||
|
||||
// const env: Env = new Map();
|
||||
function e(str: string) {
|
||||
const tokens = tokenize(str);
|
||||
const p = new Parser(tokens);
|
||||
const ast = p.parse();
|
||||
const env: Env = new Map();
|
||||
console.log(str, tokens, prettyPrint(ast), evaluate(ast, env));
|
||||
}
|
||||
|
||||
// const res = evaluate(ast, env);
|
||||
|
||||
// console.log(res);
|
||||
|
||||
const str = `
|
||||
# This is a comment
|
||||
double = x \\ x * 2
|
||||
read_line! : Unit \\ String
|
||||
`;
|
||||
console.log(tokenize(str));
|
||||
|
||||
// const tokens = tokenize("x");
|
||||
// const p = new Parser(tokens);
|
||||
// console.log(p.parse());
|
||||
|
||||
// const tokens2 = tokenize("let x = (y) => 5 + y in x(3)");
|
||||
// const tokens2 = tokenize("let x = 5 in x * 4");
|
||||
// const tokens2 = tokenize("(x, y) => x + y");
|
||||
// const tokens2 = tokenize('point { x = 3 }');
|
||||
// const tokens2 = tokenize('add1 = (x \\ x + 1); add1 3');
|
||||
// const tokens2 = tokenize('sum = x y \\ x + y; sum 5 3');
|
||||
// const tokens2 = tokenize('[1, 2, 3]');
|
||||
// const tokens2 = tokenize('c = 5; { a = 3, b = c }');
|
||||
const tokens2 = tokenize('rec = { a = 3, b = 5 }; rec.a');
|
||||
const p2 = new Parser(tokens2);
|
||||
const ast3 = p2.parse();
|
||||
console.log(ast3);
|
||||
console.log(prettyPrint(ast3));
|
||||
const env3: Env = new Map();
|
||||
console.log(evaluate(ast3, env3));
|
||||
e('add1 = (x \\ x + 1); add1 3');
|
||||
e('sum = x y \\ x + y; sum 5 3');
|
||||
e('[1, 2, 3]');
|
||||
e('c = 5; { a = 3, b = c }');
|
||||
e('rec = { a = 3, b = 5 }; rec.a');
|
||||
e('rec = { a = 3, b = 5 }; rec{ a = 10 }');
|
||||
e('add1 = (x \\ x + 1); 3 > add1');
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ export class Parser {
|
|||
|
||||
constructor(tokens: Token[]) {
|
||||
this.tokens = tokens;
|
||||
console.log("tokens", tokens);
|
||||
}
|
||||
|
||||
private current(): Token {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue