Starting to add types

This commit is contained in:
Dustin Swan 2026-03-25 19:58:37 -06:00
parent a8e879289d
commit 3132b79aae
No known key found for this signature in database
GPG key ID: 30D46587E2100467
5 changed files with 203 additions and 9 deletions

View file

@ -146,6 +146,7 @@ export type Definition = {
line?: number
column?: number
start?: number
annotation?: Annotation
}
export type Rebind = {
@ -157,6 +158,35 @@ export type Rebind = {
start?: number
}
export type TypeAST =
| { kind: 'type-name', name: string } // Int, String, Bool
| { kind: 'type-var', name: string } // a, b
| { kind: 'type-function', param: TypeAST, result: TypeAST } // a \ b
| { kind: 'type-apply', constructor: TypeAST, args: TypeAST[] } // List a, Maybe Int
| { kind: 'type-record', fields: { name: string, type: TypeAST }[] } // { x: Int }
export type TypeConstructor = { name: string, args: TypeAST[] }
export type TypeDefinition = {
kind: 'type-definition'
name: string
params: string[]
constructors: TypeConstructor[]
line?: number
column?: number
start?: number
}
export type Annotation = {
constraints: Constraint[]
type: TypeAST
}
export type Constraint = {
className: string
typeVar: string
}
export type AST =
| Literal
| Variable
@ -292,7 +322,10 @@ export function prettyPrint(ast: AST, indent = 0): string {
return `...${prettyPrint(ast.spread, indent)}`;
case 'definition':
return `${ast.name} = ${prettyPrint(ast.body, indent)};`;
const ann = ast.annotation
? `${ast.name} : ${prettyPrintType(ast.annotation.type)};\n`
: '';
return `${ann}${ast.name} = ${prettyPrint(ast.body, indent)};`;
default:
return `Unknown AST kind: ${i}${(ast as any).kind}`
@ -338,6 +371,44 @@ function prettyPrintPattern(pattern: Pattern): string {
}
}
function prettyPrintType(type: TypeAST): string {
switch (type.kind) {
case 'type-name':
case 'type-var':
return type.name;
case 'type-function':
const param = type.param.kind === 'type-function'
? `(${prettyPrintType(type.param)})`
: prettyPrintType(type.param);
return `${param} \\ ${prettyPrintType(type.result)}`;
case 'type-apply':
const args = type.args.map(a =>
a.kind === 'type-function' || a.kind === 'type-apply'
? `(${prettyPrintType(a)})`
: prettyPrintType(a)
).join(' ');
return `${prettyPrintType(type.constructor)} ${args}`;
case 'type-record':
const fields = type.fields
.map(f => `${f.name} : ${prettyPrintType(f.type)}`)
.join(', ');
return `{ ${fields} }`;
}
}
function prettyPrintTypeDefinition(td: TypeDefinition): string {
const params = td.params.length > 0 ? ' ' + td.params.join(' ') : '';
const ctors = td.constructors.map(c => {
const args = c.args.map(a =>
a.kind === 'type-function' || a.kind === 'type-apply'
? `(${prettyPrintType(a)})`
: prettyPrintType(a)
).join(' ');
return args ? `${c.name} ${args}` : c.name;
}).join(' | ');
return `${td.name}${params} = ${ctors};`;
}
function needsQuotes(key: string): boolean {
return key === '_' || !/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key);
}