From f3c3a76671409900d5f08332734f9b63884d1e15 Mon Sep 17 00:00:00 2001 From: Dustin Swan Date: Thu, 26 Mar 2026 16:05:22 -0600 Subject: [PATCH] Switching to ML style type annotations. not separate statement from the expression --- src/ast.ts | 6 +++--- src/cg/01-stdlib.cg | 3 +-- src/cg/06-font.cg | 4 ++-- src/compiler.ts | 10 ++++++---- src/parser.ts | 23 +++++++---------------- src/runtime-js.ts | 25 ++++++++++++++++--------- 6 files changed, 35 insertions(+), 36 deletions(-) diff --git a/src/ast.ts b/src/ast.ts index a653112..11e601f 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -325,9 +325,9 @@ export function prettyPrint(ast: AST, indent = 0): string { case 'definition': const ann = ast.annotation - ? `${ast.name} : ${prettyPrintType(ast.annotation.type)};\n` + ? ` : ${prettyPrintType(ast.annotation.type)}` : ''; - return `${ann}${ast.name} = ${prettyPrint(ast.body, indent)};`; + return `${ast.name}${ann} = ${prettyPrint(ast.body, indent)};`; default: return `Unknown AST kind: ${i}${(ast as any).kind}` @@ -373,7 +373,7 @@ function prettyPrintPattern(pattern: Pattern): string { } } -function prettyPrintType(type: TypeAST): string { +export function prettyPrintType(type: TypeAST): string { switch (type.kind) { case 'type-name': case 'type-var': diff --git a/src/cg/01-stdlib.cg b/src/cg/01-stdlib.cg index 83a97fb..a23a6d1 100644 --- a/src/cg/01-stdlib.cg +++ b/src/cg/01-stdlib.cg @@ -8,8 +8,7 @@ Maybe a = None | Some a; # | [0, [x, ...xs]] \ (Some x) # | [n, [x, ...xs]] \ nth (n - 1) xs; -map : (a \ b) \ List a \ List b; -map = f list \ list +map : (a \ b) \ List a \ List b = f list \ list | [] \ [] | [x, ...xs] \ [f x, ...map f xs]; diff --git a/src/cg/06-font.cg b/src/cg/06-font.cg index 1e0035c..22bb108 100644 --- a/src/cg/06-font.cg +++ b/src/cg/06-font.cg @@ -1,4 +1,4 @@ -myFontBackup = { glyphs = { +myFont = { glyphs = { "0" = { w = 7, h = 12, @@ -5836,7 +5836,7 @@ myFontBackup = { glyphs = { } } }; -myFont2Backup = { glyphs = { +myFont2 = { glyphs = { "0" = { w = 5, h = 12, diff --git a/src/compiler.ts b/src/compiler.ts index f9bfc15..36b1d61 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -10,7 +10,7 @@ type CompileCtx = { }; const defaultCtx: CompileCtx = { useStore: true, bound: new Set(), topLevel: new Set() }; -export const definitions: Map = new Map(); +export const definitions: Map = new Map(); export const dependencies: Map> = new Map(); export const dependents: Map> = new Map(); export const astRegistry = new Map(); @@ -226,7 +226,7 @@ export function compileAndRun(defs: Definition[]) { const topLevel = new Set(defs.map(d => d.name)); for (const def of defs) { - definitions.set(def.name, def.body); + definitions.set(def.name, def); const free = freeVars(def.body); const deps = new Set([...free].filter(v => topLevel.has(v))); dependencies.set(def.name, deps); @@ -364,7 +364,9 @@ function patternVars(pattern: Pattern): string[] { } export function recompile(name: string, newAst: AST) { - definitions.set(name, newAst); + const existing = definitions.get(name); + definitions.set(name, { kind: 'definition', name, body: newAst, annotation: existing?.annotation });; + // definitions.set(name, newAst); const topLevel = new Set(definitions.keys()); const free = freeVars(newAst); @@ -394,7 +396,7 @@ export function recompile(name: string, newAst: AST) { collectDependents(name); for (const defName of toRecompile) { - const ast = definitions.get(defName)!; + const ast = definitions.get(defName)!.body; const compiled = compile(ast); const fn = new Function('store', `return ${compiled}`); diff --git a/src/parser.ts b/src/parser.ts index f1ecc9c..61a88ef 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -160,21 +160,6 @@ export class Parser { continue; } - // type annotation - if (this.current().kind === 'ident' && this.peek().kind === 'colon') { - this.advance(); // eat ident - - this.advance(); - const type = this.parseType(); - this.expect('semicolon'); - - // parse definition - const def = this.parseDefinition(); - def.annotation = { constraints: [], type }; - - definitions.push(def); - continue; - } definitions.push(this.parseDefinition()); } @@ -185,6 +170,12 @@ export class Parser { const nameToken = this.expect('ident'); const name = (nameToken as { value: string }).value; + let annotation: Annotation | undefined; + if (this.current().kind === 'colon') { + this.advance(); + annotation = { constraints: [], type: this.parseType() }; + } + this.expect('equals'); const body = this.parseExpression(); @@ -193,7 +184,7 @@ export class Parser { this.expect('semicolon'); } - return { kind: 'definition', name, body, ...this.getPos(nameToken) }; + return { kind: 'definition', name, body, annotation, ...this.getPos(nameToken) }; } private parseExpression(): AST { diff --git a/src/runtime-js.ts b/src/runtime-js.ts index 4b1ba41..dac4249 100644 --- a/src/runtime-js.ts +++ b/src/runtime-js.ts @@ -1,7 +1,7 @@ import { tokenize } from './lexer' import { Parser } from './parser' import { compile, recompile, definitions, freeVars, dependencies, dependents, astRegistry } from './compiler' -import { prettyPrint } from './ast' +import { prettyPrint, prettyPrintType } from './ast' import type { AST } from './ast' import { measure } from './ui'; @@ -118,10 +118,9 @@ export const _rt = { return obj === undefined ? { _tag: 'None' } : { _tag: 'Some', _0: obj }; }, getSource: (name: string) => { - const ast = definitions.get(name); - if (!ast) return ""; - const printed = prettyPrint(ast); - return printed; + const def = definitions.get(name); + if (!def) return ""; + return prettyPrint(def); }, "saveImage!": () => { const saved: Record = {}; @@ -259,8 +258,8 @@ export const _rt = { export function saveDefinitions() { const saved: Record = {}; - for (const [name, ast] of definitions) { - const source = prettyPrint({ kind: 'definition', name, body: ast }); + for (const [name, def] of definitions) { + const source = prettyPrint(def); saved[name] = source; } localStorage.setItem(STORAGE_KEY, JSON.stringify(saved)); @@ -356,8 +355,16 @@ function valueToAst(value: any): AST { export function syncToAst(name: string) { // if (definitions.has(name)) { if (name in store) { - definitions.set(name, valueToAst(store[name])); - const source = prettyPrint({ kind: 'definition', name, body: definitions.get(name)! }); + const existing = definitions.get(name); + const newDef: Definition = { + kind: 'definition', + name, + body: valueToAst(store[name]), + annotation: existing?.annotation, + }; + definitions.set(name, newDef); // valueToAst(store[name])); + // const source = prettyPrint({ kind: 'definition', name, body: definitions.get(name)! }); + const source = prettyPrint(definitions.get(name)!); appendChangeLog(name, source); saveDefinitions(); }