import Parser from "../Parser";
import { anyOf, into, matchChar, named, opt, regex, seq, zeroOrMore } from "../Parsers";
interface Id {
value: string;
}
interface Num {
value: number;
}
interface List {
value: Expr[];
}
interface Ws {
value: string;
}
type Expr = Id | Num | List | Ws;
export function id(value: string): Id {
return { value };
}
export function num(value: number): Num {
return { value };
}
export function list(value: Expr[]): Expr {
return { value };
}
export const identifierParser: () => Parser<Id>
= () => named("id", () => into(
() => regex(/^[^\s\d()"'`,][^\s()"'`,]*/),
(s) => ({ value: s })));
export const numberParser: () => Parser<Num>
= () => named("num", () => into(
() => regex(/^[-+]?(?:\d*\.?\d+|\d+\.?\d*)(?:[eE][-+]?\d+)?/),
(s) => ({ value: parseFloat(s) })));
export const whitespaceParser: () => Parser<Ws>
= () => named("ws", () => into(
() => regex(/\s*/),
(s) => ({ value: s })));
export const nakedListParser: (subtype: () => Parser<Expr>) => Parser<List>
= (subtype) => named(`naked-list(${subtype().name})`,
() => into<Expr[], List>(
() => zeroOrMore(
() => into(
() => seq([
subtype,
() => into(() => opt(whitespaceParser), (r) => {
if (r === null) {
return { value: "" };
} else {
return r;
}
})]),
(e: Expr[]) => e[0])),
(es) => ({ value: es })));
export const listParser: (subtype: () => Parser<Expr>) => Parser<List>
= (subtype) => named(`list(${subtype().name})`, () => into<Expr[][], List>(() => seq<Expr[]>([
/* opening parenthesis */
() => into<string, Expr[]>(
() => matchChar("("),
(s) => ([{ value: s }])),
/* content */
() => zeroOrMore(
() => into(
() => seq([
subtype,
() => into(() => opt(whitespaceParser), (r) => {
if (r === null) {
return { value: "" };
} else {
return r;
}
})]),
(e: Expr[]) => e[0])),
/* closing parenthesis */
() => into<string, Expr[]>(
() => matchChar(")"),
(s) => ([{ value: s }]))]),
(es) => ({ value: es[1] })));
export const exprParser: () => Parser<Expr>
= () => named("expr",
() => anyOf<Expr>([identifierParser, numberParser, () => listParser(exprParser)]));