import type { Value } from './types'; // Literals and Variables export type Literal = { kind: 'literal' value: Value } export type Variable = { kind: 'variable' name: string } export type Constructor = { kind: 'constructor' name: string } // Functions export type Lambda = { kind: 'lambda' params: string[] body: AST } export type Apply = { kind: 'apply' func: AST args: AST[] } // Bindings export type Let = { kind: 'let' name: string value: AST body: AST } // Matching export type Match = { kind: 'match' expr: AST cases: MatchCase[] } export type MatchCase = { pattern: Pattern result: AST } export type Pattern = | { kind: 'wildcard' } | { kind: 'var', name: string } | { kind: 'literal', value: number | string } | { kind: 'constructor', name: string, args: Pattern[] } | { kind: 'list', elements: Pattern[] } | { kind: 'record', fields: { [key: string]: Pattern } } // Data Structures export type Record = { kind: 'record' fields: { [key: string]: AST } } export type RecordAccess = { kind: 'record-access' record: AST field: string } export type RecordUpdate = { kind: 'record-update' record: AST updates: { [key: string]: AST } } export type List = { kind: 'list' elements: AST[] } // Top-level constructs export type Definition = { kind: 'definition' name: string body: AST // type?: string // TODO } export type TypeDef = { kind: 'typedef' name: string variants: Array<{ name: string, args: string[] }> } export type Import = { kind: 'import' module: string items: string[] | 'all' } export type AST = | Literal | Variable | Constructor | Lambda | Apply | Let | Match | Record | RecordAccess | RecordUpdate | List | Definition | TypeDef | Import export function prettyPrint(ast: AST, indent = 0): string { const i = ' '.repeat(indent); switch (ast.kind) { case 'literal': return `${i}${ast.value.value}`; case 'variable': return `${i}${ast.name}`; case 'constructor': return `${i}${ast.name}`; case 'apply': const func = prettyPrint(ast.func, 0); const args = ast.args.map(a => prettyPrint(a, 0)).join(' '); return `${i}(${func} ${args})` case 'let': return `${i}let ${ast.name} = \n${prettyPrint(ast.value, indent + 1)}\n${i}in\n${prettyPrint(ast.body, indent + 1)}` case 'list': const elems = ast.elements.map(e => prettyPrint(e, 0)).join(', '); return `${i}[${elems}]`; case 'record': const fields = Object.entries(ast.fields) .map(([k, v]) => `${k} = ${prettyPrint(v, 0)}`) .join(', '); return `${i}{${fields}}`; case 'lambda': 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}` } }