code: function makeLexer() {
    const mooLexer = moo.compile(tokens);
  
    return {
      current: null,
      lines: [],
      get line() {
        return mooLexer.line;
      },
      get col() {
        return mooLexer.col;
      },
      save() {
        return mooLexer.save();
      },
      reset(chunk, info) {
        this.lines = chunk.split('\n');
        return mooLexer.reset(chunk, info);
      },
      next() {
        // It's a cruel and unusual punishment to implement comments with nearly
        let token = mooLexer.next();
        // Drop all comment tokens found
        while (token && token.type === 'comment') {
          token = mooLexer.next();
        }
        this.current = token;
        return this.current;
      },
      formatError(token) {
        return mooLexer.formatError(token);
      },
      has(name) {
        return mooLexer.has(name);
      },
    };
  }
docs: Returns a custom lexer. This wrapper API is necessary to ignore comments
  in all of the subsequent compiler phases, unfortunately.
  
  TODO: Maybe consider adding comment nodes back to the AST. IIRC this causes
  lots of ambiguous grammar for whatever reason.