///|
/// Results of semantic predicates: `Bool`, or a `Value` judged by JavaScript
/// truthiness (as in PEG.js).
pub(open) trait Truthy {
  fn truthy(Self) -> Bool
}

///|
pub impl Truthy for Bool with fn truthy(self) {
  self
}

///|
pub impl[T] Truthy for Value[T] with fn truthy(self) {
  Value::truthy(self)
}

///|
/// The truthiness of a predicate result.
pub fn[R : Truthy] truthy(result : R) -> Bool {
  result.truthy()
}

///|
/// Runs one parse the way PEG.js' `peg$parse` does, shared by the bytecode
/// interpreter and generated parsers:
///
/// 1. selects the start rule from `options["startRule"]` (raising
///    `InvalidStartRule` if it is not allowed);
/// 2. sets up tracing (`tracer`, else the default tracer or a no-op one);
/// 3. creates the parse state and calls `run(state, start_rule)`, which must
///    run the initializer, call `state.begin()` and parse the start rule;
/// 4. checks that all input was consumed, raising `SyntaxError` otherwise.
pub fn[T] drive(
  input : String,
  options : Map[String, Value[T]],
  tracer : Tracer[T]?,
  allowed_start_rules~ : ArrayView[String],
  trace~ : Bool,
  features~ : Features,
  run~ : (State[T], String) -> Slot[T] raise,
) -> Value[T] raise {
  let start = match options.get("startRule") {
    Some(Str(name)) =>
      if allowed_start_rules.contains(name) {
        name
      } else {
        raise InvalidStartRule(name)
      }
    Some(other) => raise InvalidStartRule(other.js_string())
    None => allowed_start_rules[0]
  }
  let tracer = if trace {
    match tracer {
      Some(t) => Some(t)
      None =>
        if features.default_tracer {
          Some(Tracer::default())
        } else {
          Some(Tracer::{ trace: _ => (), })
        }
    }
  } else {
    None
  }
  let state = State::new(input, options~, features~, tracer?)
  let result = run(state, start)
  state.finish(result)
}