diff --git a/src/ast.ts b/src/ast.ts index 8edfa59..f755a11 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -158,6 +158,13 @@ export function prettyPrint(ast: AST, indent = 0): string { const params = ast.params.join(', ') return `${i}(${params}) => ${prettyPrint(ast.body)}` + case 'record-access': + return `${i}${prettyPrint(ast.record)}.${ast.field}` + + case 'record-update': + const updates = Object.entries(ast.updates).map(([k, v]) => `${k} = ${prettyPrint(v, 0)}`).join(', '); + return `${i}${prettyPrint(ast.record)} { ${updates} }` + default: return `${i}${ast.kind}` } diff --git a/src/main.ts b/src/main.ts index a0c63de..e696ddc 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(`a b \\ a + b`); +const tokens2 = tokenize('point { x = 3 }'); const p2 = new Parser(tokens2); const ast3 = p2.parse(); console.log(ast3); diff --git a/src/parser.ts b/src/parser.ts index 359a0c7..8a37c6b 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -148,16 +148,54 @@ export class Parser { } private parseApplication(): AST { - let func = this.parsePrimary(); + let func = this.parsePostfix(); while (this.canStartPrimary()) { - const arg = this.parsePrimary(); + const arg = this.parsePostfix(); func = { kind: 'apply', func, args: [arg] }; } return func; } + private parsePostfix(): AST { + let expr = this.parsePrimary(); + + while (true) { + if (this.current().kind === 'dot') { + // Record access + this.advance(); + const fieldToken = this.expect('ident'); + const field = (fieldToken as { value: string }).value; + expr = { kind: 'record-access', record: expr, field }; + } else if (this.current().kind === 'open-brace') { + // Record update + this.advance(); + const updates: { [key: string]: AST } = {}; + let first = true; + + while (this.current().kind !== 'close-brace') { + if (!first) { + this.expect('comma'); + } + first = false; + + const keyToken = this.expect('ident'); + const key = (keyToken as { value: string }).value; + this.expect('equals'); + updates[key] = this.parseExpression(); + } + + this.expect('close-brace'); + expr = { kind: 'record-update', record: expr, updates } + } else { + break; + } + } + + return expr; + } + private parsePrimary(): AST { const token = this.current();