59 lines
1.6 KiB
TypeScript
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
|