git.dumitru.net fructose / master src / parser / language / Language.ts
master

Tree @master (Download .tar.gz)

Language.ts @masterraw · history · blame

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)]));