From c44a6858ffa80c8ab4bde7d5bf355ed8571b244e Mon Sep 17 00:00:00 2001 From: Dustin Swan Date: Sun, 1 Feb 2026 16:46:18 -0700 Subject: [PATCH] interpreting record update, and > (func application pipe thing). cleaning up main.ts test code --- src/interpreter.ts | 48 +++++++++++++++++++++++++++++++++++++--------- src/main.ts | 46 ++++++++++++++------------------------------ src/parser.ts | 1 - 3 files changed, 53 insertions(+), 42 deletions(-) diff --git a/src/interpreter.ts b/src/interpreter.ts index 6cfc171..2706f25 100644 --- a/src/interpreter.ts +++ b/src/interpreter.ts @@ -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'); diff --git a/src/main.ts b/src/main.ts index 9aee4b3..653f4cf 100644 --- a/src/main.ts +++ b/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'); diff --git a/src/parser.ts b/src/parser.ts index 01a81ac..a210614 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -7,7 +7,6 @@ export class Parser { constructor(tokens: Token[]) { this.tokens = tokens; - console.log("tokens", tokens); } private current(): Token {