JSFiddle - React, Tailwind, and code Playground

HTML

<html>
<head>
    <meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
</head>
<body>

</body>
</html>

JavaScript

class MatchError extends Error {}

    class Range {
      constructor(text, position = 0) {
        this.text = text;
        this.position = position;
      }
      get remainder() {
        return this.text.substr(this.position);
      }
      extractRegExp(pattern) {
        let matches = this.remainder.match(pattern);
        if (!matches || matches.index !== 0) throw new MatchError(`Mismatch parsing "${this.remainder.substr(0, 10)}..." with "${pattern}"`);
        this.position += matches[0].length; /**/
        console.debug(`Matched '${matches[0]}'`)
        return matches[0];
      }
      extractString(string) {
        if (!this.remainder.startsWith(string)) throw new MatchError(`Mismatch parsing "${this.remainder.substr(0, 10)}..." with "${string}"`);
        this.position += string.length; /**/
        console.debug(`Matched '${string}'`)
        return string;
      }
      get copy() {
        this.lastCopy = new Range(this.text, this.position);
        return this.lastCopy;
      }
      commitLastCopy = () => {
        this.position = this.lastCopy.position;
      }
    }

    class Choice extends Array {
      map(parse) { //console.log(`Choosing between`)
        for (let option of this) { //console.log(option)
          try {
            return parse(option);
          } catch (e) {
            if (e.constructor !== MatchError) throw e; /**/
            console.debug(e, ` when choosing`);
          }
        }
        throw new Error(`Failed all choices ${this}`);
      }
    }

    function either(...x) {
      return new Choice().concat(x);
    }

    class Repetition {
      constructor(value) {
        this.value = value;
      }
      map(parse) {
        try {
          return [parse(this.value)].concat(this.map(parse));
        } catch (e) {
          if (e.constructor !== MatchError) throw e; /**/
          console.debug(e, ` when iterating`);
          return [];
        }
      }
    }

    function many(x) {
      return new...