From 6e8b5afd3b8ef41893ed9cc649a715463385ea26 Mon Sep 17 00:00:00 2001 From: Dustin Swan Date: Sun, 1 Feb 2026 01:01:48 -0700 Subject: [PATCH] parsing lambdas --- src/ast.ts | 4 +++ src/main.ts | 2 +- src/parser.ts | 89 ++++++++++++++++++++++----------------------------- 3 files changed, 43 insertions(+), 52 deletions(-) diff --git a/src/ast.ts b/src/ast.ts index 376c587..8edfa59 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -154,6 +154,10 @@ export function prettyPrint(ast: AST, indent = 0): string { .join(', '); return `${i}{${fields}}`; + case 'lambda': + const params = ast.params.join(', ') + return `${i}(${params}) => ${prettyPrint(ast.body)}` + default: return `${i}${ast.kind}` } diff --git a/src/main.ts b/src/main.ts index 91f2902..a0c63de 100644 --- a/src/main.ts +++ b/src/main.ts @@ -25,7 +25,7 @@ console.log(tokenize(str)); // 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('x = (y = 1; y + 1); x * 2'); +const tokens2 = tokenize(`a b \\ a + b`); const p2 = new Parser(tokens2); const ast3 = p2.parse(); console.log(ast3); diff --git a/src/parser.ts b/src/parser.ts index dd843c1..359a0c7 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -68,11 +68,35 @@ export class Parser { kind === 'open-brace'; } + private isLambdaStart(): boolean { + const kind = this.current().kind; + + if (kind === 'backslash') { + return true; + } + + if (kind !== 'ident') { + return false; + } + + let offset = 1; + while (true) { + const token = this.peek(offset); + if (token.kind === 'backslash') return true; + if (token.kind !== 'ident') return false; + offset++; + } + } + parse(): AST { return this.parseExpression(); } private parseExpression(): AST { + if (this.isLambdaStart()) { + return this.parseLambda(); + } + if (this.current().kind === 'ident' && this.peek().kind === 'equals') { return this.parseLet(); } @@ -80,6 +104,20 @@ export class Parser { return this.parseInfix(); } + private parseLambda(): AST { + const params: string[] = []; + + while (this.current().kind === 'ident') { + const param = this.advance(); + params.push((param as { value: string }).value); + } + + this.expect('backslash'); + const body = this.parseExpression(); + + return { kind: 'lambda', params, body }; + } + private parseLet(): AST { const nameToken = this.expect('ident'); const name = (nameToken as { value: string }).value; @@ -198,55 +236,4 @@ export class Parser { throw new Error(`Unexpected token: ${token.kind}`); } - - /* - private parseLambda(): AST { - this.expect('open-paren'); - - const params: string[] = []; - - if (this.current().kind !== 'close-paren') { - const first = this.expect('ident'); - params.push((first as { value: string }).value); - - while (this.current().kind === 'comma') { - this.advance(); - const param = this.expect('ident'); - params.push((param as { value: string }).value); - } - } - - this.expect('close-paren'); - this.expect('arrow'); - - const body = this.parseExpression(); - - return { kind: 'lambda', params, body } - } - - private parsePostfix(): AST { - let expr = this.parsePrimary(); - - while (this.current().kind === 'open-paren') { - this.advance(); - - const args: AST[] = []; - if (this.current().kind !== 'close-paren') { - args.push(this.parseExpression()); - - while (this.current().kind === 'comma') { - this.advance(); - args.push(this.parseExpression()); - } - } - - this.expect('close-paren'); - - expr = { kind: 'apply', func: expr, args }; - } - - return expr; - } - */ - }