From 31ef279f166e6bf72bd3576a7f5591e4bc9fbdda Mon Sep 17 00:00:00 2001 From: Dustin Swan Date: Fri, 6 Feb 2026 17:33:00 -0700 Subject: [PATCH] Language now supports top level definitions. no more last-expression-is-a-value thing, it's also a def. Host knows to run the special `os` def --- src/ast.ts | 1 + src/main.ts | 14 ++++++++++---- src/parser.ts | 27 ++++++++++++++++++++++++--- src/textinput-test.cg | 2 +- 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/ast.ts b/src/ast.ts index 9a09b38..fb028dc 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -2,6 +2,7 @@ import type { Value } from './types'; // Literals and Variables + export type Literal = { kind: 'literal' value: Value diff --git a/src/main.ts b/src/main.ts index cfcb386..59cfc50 100644 --- a/src/main.ts +++ b/src/main.ts @@ -25,14 +25,20 @@ const cgCode = stdlibCode + '\n' + try { const tokens = tokenize(cgCode); const parser = new Parser(tokens, cgCode); - const ast = parser.parse(); + const definitions = parser.parse(); // console.log(ast); const env: Env = new Map(Object.entries(builtins)); - const appRecord = evaluate(ast, env, cgCode); - // console.log("appRecord", appRecord); - if (appRecord.kind !== 'record') + for (const def of definitions) { + const value = evaluate(def.body, env, cgCode); + env.set(def.name, value); + } + + const appRecord = env.get('os'); + console.log("appRecord", appRecord); + + if (!appRecord || appRecord.kind !== 'record') throw new Error('Expected record'); const init = appRecord.fields.init; diff --git a/src/parser.ts b/src/parser.ts index 8c83bdf..181199a 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -1,5 +1,5 @@ import type { Token } from './lexer' -import type { AST, MatchCase, Pattern } from './ast' +import type { AST, MatchCase, Pattern, Definition } from './ast' import { ParseError } from './error' export class Parser { @@ -114,8 +114,29 @@ export class Parser { } } - parse(): AST { - return this.parseExpression(); + parse(): Definition[] { + const definitions: Definition[] = []; + + while (this.current().kind !== 'eof') { + definitions.push(this.parseDefinition()); + } + + return definitions; + } + + private parseDefinition(): Definition { + const nameToken = this.expect('ident'); + const name = (nameToken as { value: string }).value; + + this.expect('equals'); + + const body = this.parseExpression(); + + if (this.current().kind !== 'eof') { + this.expect('semicolon'); + } + + return { kind: 'definition', name, body, ...this.getPos(nameToken) }; } private parseExpression(): AST { diff --git a/src/textinput-test.cg b/src/textinput-test.cg index 7e24c2e..d979487 100644 --- a/src/textinput-test.cg +++ b/src/textinput-test.cg @@ -37,4 +37,4 @@ view = state viewport \ } }; -{ init = init, update = update, view = view } +os = { init = init, update = update, view = view }