syntax-lab/src/syntax.ts
2026-04-25 01:10:49 +02:00

59 lines
1.6 KiB
TypeScript

import type { CodePointSpan } from 'source-region';
export type ConcreteSyntax = Expr<{ span: CodePointSpan }>
export type Expr<A> =
| { tag: "literal", value: Literal } & A
| { tag: "list", values: Expr<A>[] } & A
export namespace ConcreteSyntax {
export function number(value: number, span: CodePointSpan): ConcreteSyntax {
return { tag: "literal", value: { tag: "number", value }, span };
}
export function identifier(value: Identifier, span: CodePointSpan): ConcreteSyntax {
return { tag: "literal", value: { tag: "identifier", value }, span };
}
export function list(values: ConcreteSyntax[], span: CodePointSpan): ConcreteSyntax {
return { tag: "list", values, span };
}
}
export namespace Expr {
export function number(value: number): Expr<void> {
return { tag: "literal", value: { tag: "number", value } };
}
export function identifier(value: Identifier): Expr<void> {
return { tag: "literal", value: { tag: "identifier", value } };
}
export function list(values: Expr<void>[]): Expr<void> {
return { tag: "list", values };
}
export function show<A>(e: Expr<A>): string {
switch (e.tag) {
case "literal":
return showLiteral(e.value);
case "list":
return `(${e.values.map(show).join(" ")})`;
}
}
function showLiteral(e: Literal): string {
switch (e.tag) {
case "number":
return `${e.value}`;
case "identifier":
return `${e.value}`;
}
}
}
type Literal =
| { tag: "number", value: number }
| { tag: "identifier", value: Identifier }
type Identifier = string