Modularize UI, make it a bit more Lisp independent
This commit is contained in:
parent
e1e1b90579
commit
c3edf193c4
19 changed files with 973 additions and 884 deletions
152
src/languages/lisp/syntax.ts
Normal file
152
src/languages/lisp/syntax.ts
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
import type { CodePointSpan } from 'source-region';
|
||||
import type { ParseError } from './parse_errors';
|
||||
|
||||
export type ConcreteInfo = { span: CodePointSpan };
|
||||
|
||||
export type ConcreteError = ConcreteErrorNode[] // Convention: can't be empty.
|
||||
export type ConcreteErrorNode = {
|
||||
span: CodePointSpan,
|
||||
error: ParseError,
|
||||
panickedOver?: CodePointSpan,
|
||||
}
|
||||
|
||||
export namespace ConcreteError {
|
||||
export function single(node: ConcreteErrorNode): ConcreteError {
|
||||
return [node];
|
||||
}
|
||||
}
|
||||
|
||||
export type DelimiterToken =
|
||||
| { tag: "open-paren"; span: CodePointSpan }
|
||||
| { tag: "close-paren"; span: CodePointSpan }
|
||||
| { tag: "open-bracket"; span: CodePointSpan }
|
||||
| { tag: "close-bracket"; span: CodePointSpan };
|
||||
|
||||
export namespace DelimiterToken {
|
||||
export function openParen(span: CodePointSpan): DelimiterToken {
|
||||
return { tag: "open-paren", span };
|
||||
}
|
||||
|
||||
export function closeParen(span: CodePointSpan): DelimiterToken {
|
||||
return { tag: "close-paren", span };
|
||||
}
|
||||
|
||||
export function openBracket(span: CodePointSpan): DelimiterToken {
|
||||
return { tag: "open-bracket", span };
|
||||
}
|
||||
|
||||
export function closeBracket(span: CodePointSpan): DelimiterToken {
|
||||
return { tag: "close-bracket", span };
|
||||
}
|
||||
}
|
||||
|
||||
export type Program<Info, Error> = {
|
||||
tag: "program",
|
||||
expressions: Expr<Info, Error>[],
|
||||
error?: Error,
|
||||
} & Info
|
||||
|
||||
export type Expr<Info, Error> =
|
||||
| Literal<Info, Error>
|
||||
| List<Info, Error>
|
||||
| { tag: "error-expression", error: Error } & Info // This is for errors that don't really correspond to any sort of node. Unknown errors.
|
||||
|
||||
export type List<Info, Error> =
|
||||
{ tag: "list", open: DelimiterToken, items: ListItem<Info, Error>[], close?: DelimiterToken, error?: Error } & Info
|
||||
|
||||
export type ListItem<Info, Error> =
|
||||
| Expr<Info, Error>
|
||||
| { tag: "error-list-separator", error: Error } & Info
|
||||
|
||||
export type Literal<Info, Error> =
|
||||
// === number ===
|
||||
| { tag: "number", value: number } & Info
|
||||
| { tag: "error-number", error: Error } & Info
|
||||
// === identifier ===
|
||||
| { tag: "identifier", value: Identifier } & Info
|
||||
| { tag: "error-identifier", error: Error } & Info
|
||||
|
||||
export type Identifier = string
|
||||
|
||||
export namespace Program {
|
||||
export function make<Info, Error>(
|
||||
expressions: Expr<Info, Error>[],
|
||||
info: Info,
|
||||
error?: Error,
|
||||
): Program<Info, Error> {
|
||||
return error === undefined
|
||||
? { tag: "program", expressions, ...info }
|
||||
: { tag: "program", expressions, error, ...info };
|
||||
}
|
||||
|
||||
export function show<Info, Error>(program: Program<Info, Error>): string {
|
||||
return program.expressions.map(Expr.show).join(" ");
|
||||
}
|
||||
}
|
||||
|
||||
export namespace Expr {
|
||||
export function number(value: number, span: CodePointSpan): Expr<ConcreteInfo, ConcreteError> {
|
||||
return { tag: "number", value, span };
|
||||
}
|
||||
|
||||
export function errorNumber(error: ConcreteError, span: CodePointSpan): Expr<ConcreteInfo, ConcreteError> {
|
||||
return { tag: "error-number", error, span };
|
||||
}
|
||||
|
||||
export function identifier(value: Identifier, span: CodePointSpan): Expr<ConcreteInfo, ConcreteError> {
|
||||
return { tag: "identifier", value, span };
|
||||
}
|
||||
|
||||
export function errorIdentifier(error: ConcreteError, span: CodePointSpan): Expr<ConcreteInfo, ConcreteError> {
|
||||
return { tag: "error-identifier", error, span };
|
||||
}
|
||||
|
||||
export function list(
|
||||
open: DelimiterToken,
|
||||
items: ListItem<ConcreteInfo, ConcreteError>[],
|
||||
span: CodePointSpan,
|
||||
close?: DelimiterToken,
|
||||
error?: ConcreteError,
|
||||
): Expr<ConcreteInfo, ConcreteError> {
|
||||
return { tag: "list", open, items, close, error, span };
|
||||
}
|
||||
|
||||
export function errorExpression(error: ConcreteError, span: CodePointSpan): Expr<ConcreteInfo, ConcreteError> {
|
||||
return { tag: "error-expression", error, span };
|
||||
}
|
||||
|
||||
export function show<Info, Error>(expr: Expr<Info, Error>): string {
|
||||
switch (expr.tag) {
|
||||
case "number":
|
||||
return `${expr.value}`;
|
||||
case "identifier":
|
||||
return expr.value;
|
||||
case "error-number":
|
||||
return "<error-number>";
|
||||
case "error-identifier":
|
||||
return "<error-identifier>";
|
||||
case "error-expression":
|
||||
return "<error-expression>";
|
||||
case "list":
|
||||
return showList(expr);
|
||||
}
|
||||
}
|
||||
|
||||
function showList<Info, Error>(list: List<Info, Error>): string {
|
||||
const open = list.open.tag === "open-bracket" ? "[" : "(";
|
||||
const close = list.open.tag === "open-bracket" ? "]" : ")";
|
||||
const sep = list.open.tag === "open-bracket" ? ", " : " ";
|
||||
return `${open}${list.items.map(ListItem.show).join(sep)}${close}`;
|
||||
}
|
||||
}
|
||||
|
||||
export namespace ListItem {
|
||||
export function errorSeparator(error: ConcreteError, span: CodePointSpan): ListItem<ConcreteInfo, ConcreteError> {
|
||||
return { tag: "error-list-separator", error, span };
|
||||
}
|
||||
|
||||
export function show<Info, Error>(item: ListItem<Info, Error>): string {
|
||||
if (item.tag === "error-list-separator") return "<error-separator>";
|
||||
return Expr.show(item);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue