///|
pub fn[T, A] Parser::or_else(
  self : Parser[T, A],
  fallback : Parser[T, A],
) -> Parser[T, A] {
  {
    execute: state => {
      match (self.execute)(state) {
        Failure(first_error, false, false) =>
          match (fallback.execute)(state) {
            Failure(second_error, consumed, committed) =>
              Failure(first_error.furthest(second_error), consumed, committed)
            result => result
          }
        result => result
      }
    },
  }
}

///|
pub fn[T, A] Parser::attempt(self : Parser[T, A]) -> Parser[T, A] {
  {
    execute: state => {
      match (self.execute)(state) {
        Failure(error, _, committed) => Failure(error, false, committed)
        result => result
      }
    },
  }
}

///|
pub fn[T] Parser::cut() -> Parser[T, Unit] {
  { execute: state => Success((), state, false, true) }
}

///|
pub fn[T, A] Parser::label(self : Parser[T, A], label : String) -> Parser[T, A] {
  {
    execute: state => {
      match (self.execute)(state) {
        Failure(_, false, false) =>
          Failure(Expected(label~, offset=state.offset()), false, false)
        result => result
      }
    },
  }
}

///|
pub fn[T, A] Parser::context(
  self : Parser[T, A],
  label : String,
) -> Parser[T, A] {
  {
    execute: state => {
      match (self.execute)(state) {
        Failure(error, consumed, committed) =>
          Failure(Context(label~, cause=error), consumed, committed)
        result => result
      }
    },
  }
}

///|
pub fn[T, A] Parser::choice(parsers : Array[Parser[T, A]]) -> Parser[T, A] {
  {
    execute: state => {
      for index = 0, best_error = EmptyChoice(offset=state.offset()); index <
         parsers.length(); {
        match (parsers[index].execute)(state) {
          Failure(error, false, false) =>
            continue index + 1, best_error.furthest(error)
          result => break result
        }
      } nobreak {
        Failure(best_error, false, false)
      }
    },
  }
}