// The slow scanner scans one token, or a bounded piece of one, per `lexscan`
// call. It implements the same state transitions as the fast scanner. It runs
// when the fast scanner's fallback is taken, to find and report the error, and
// for everything when `max_string_length` is set, since its pieces are
// bounded: at most 64 characters of whitespace, string or digits per scan.

///|
async fn Parser::slow_step(self : Parser) -> Unit {
  match self.state {
    Value => {
      let ws = self.slow_ws()
      self.slow_value(ws)
    }
    ArrayFirst => {
      self.slow_ws() |> ignore
      if self.slow_close_bracket() {
        self.close()
      } else {
        self.slow_value(1)
      }
    }
    ArrayNext => {
      self.slow_ws() |> ignore
      let pos = self.pos()
      match self.slow_punct() {
        ']' => self.close()
        ',' => {
          self.slow_ws() |> ignore
          self.slow_value(1)
        }
        c => self.unexpected(pos, c)
      }
    }
    ObjectFirst => {
      self.slow_ws() |> ignore
      let pos = self.pos()
      match self.slow_punct() {
        '}' => self.close()
        '"' => self.slow_member(pos)
        c => self.unexpected(pos, c)
      }
    }
    ObjectNext => {
      self.slow_ws() |> ignore
      let pos = self.pos()
      match self.slow_punct() {
        '}' => self.close()
        ',' => {
          self.slow_ws() |> ignore
          let pos = self.pos()
          match self.slow_punct() {
            '"' => self.slow_member(pos)
            c => self.unexpected(pos, c)
          }
        }
        c => self.unexpected(pos, c)
      }
    }
    TopEnd =>
      if self.multiple_values {
        self.state = Value
      } else {
        self.slow_ws() |> ignore
        if self.slow_eof() {
          self.state = Finished
        } else {
          self.fail_here()
        }
      }
    Finished => ()
  }
}

///|
/// Reports `c`, consumed by `slow_punct` at `pos`, as unexpected; or, if
/// `slow_punct` consumed nothing (`c` is -1), the next character.
async fn[T] Parser::unexpected(self : Parser, pos : Position, c : Int32) -> T {
  if c < 0 {
    self.fail_here()
  } else {
    raise UnexpectedChar(pos, c.unsafe_to_char())
  }
}

///|
/// Raises the error for the next character, or for the end of the input.
async fn[T] Parser::fail_here(self : Parser) -> T {
  let pos = self.pos()
  let c = lexscan self.lexbuf with longest {
    re"^[\u{0}-\u{10FFFF}]" as c => Some(c)
    _ => None
  }
  match c {
    Some(c) => raise UnexpectedChar(pos, c)
    None => raise UnexpectedEof(pos)
  }
}

///|
/// Skips whitespace and returns the number of code units skipped.
async fn Parser::slow_ws(self : Parser) -> Int32 {
  let start = self.offset
  for ;; {
    let more = lexscan self.lexbuf with longest {
      re"^[ \t\r]{1,64}" as w => {
        self.advance(w.length())
        true
      }
      re"^\n" => {
        self.advance_text("\n")
        true
      }
      _ => false
    }
    if !more {
      break
    }
  }
  self.offset - start
}

///|
async fn Parser::slow_eof(self : Parser) -> Bool {
  lexscan self.lexbuf with longest {
    re"^$" => true
    _ => false
  }
}

///|
async fn Parser::slow_close_bracket(self : Parser) -> Bool {
  lexscan self.lexbuf with longest {
    re"^\]" => {
      self.advance(1)
      true
    }
    _ => false
  }
}

///|
/// Consumes one of `,:]}"` and returns it, or returns -1 and consumes nothing.
async fn Parser::slow_punct(self : Parser) -> Int32 {
  let c = lexscan self.lexbuf with longest {
    re"^," => ','.to_int()
    re"^:" => ':'.to_int()
    re"^\]" => ']'.to_int()
    re"^[}]" => '}'.to_int()
    re"^\"" => '"'.to_int()
    _ => -1
  }
  if c >= 0 {
    self.advance(1)
  }
  c
}

///|
/// Scans the rest of a member after its opening quote at `quote`: the
/// property name, whitespace and `:`.
async fn Parser::slow_member(self : Parser, quote : Position) -> Unit {
  let key = self.slow_string(quote)
  self.pending.push(Key(key))
  self.slow_ws() |> ignore
  let pos = self.pos()
  match self.slow_punct() {
    ':' => self.state = Value
    c => self.unexpected(pos, c)
  }
}

///|
/// Scans a value after `ws` code units of whitespace. At the top level of a
/// multi-value stream the end of the input is accepted instead.
async fn Parser::slow_value(self : Parser, ws : Int32) -> Unit {
  let pos = self.pos()
  // The length of a literal prefix, consumed only after the separator check.
  let mut partial = 0
  let mut first = 't'
  // A code for what starts here: the character for a container, a string or
  // a number; 't', 'f' or 'n' for a whole literal; 0 for the prefix of a
  // literal; -2 for the end of the input; -1 for anything else.
  let kind = lexscan self.lexbuf with longest {
    re"^[{]" => '{'.to_int()
    re"^\[" => '['.to_int()
    re"^\"" => '"'.to_int()
    re"^true" => 't'.to_int()
    re"^false" => 'f'.to_int()
    re"^null" => 'n'.to_int()
    re"^-" => '-'.to_int()
    re"^[0-9]" as d => d.to_int()
    re"^(?:t(?:ru?)?|f(?:a(?:ls?)?)?|n(?:ul?)?)" as p => {
      partial = p.length()
      first = p.unsafe_get(0).to_int().unsafe_to_char()
      0
    }
    re"^$" => -2
    _ => -1
  }
  if kind == -2 && self.stack.is_empty() && self.multiple_values {
    self.state = Finished
    return
  }
  if self.multiple_values && kind != -2 {
    // A missing separator is reported before anything wrong in the value.
    // For -1 the next character is reported anyway.
    if kind >= 0 {
      self.check_separator(
        ws,
        if kind == 0 {
          first
        } else {
          kind.unsafe_to_char()
        },
      )
    }
  }
  if kind <= 0 {
    self.advance(partial)
    self.fail_here()
  }
  match kind {
    '{' | '[' => {
      self.open(kind == '{', pos)
      self.advance(1)
    }
    '"' => {
      self.advance(1)
      let s = self.slow_string(pos)
      self.scalar(Json::string(s), false)
    }
    't' => {
      self.advance(4)
      self.scalar(Json::boolean(true), true)
    }
    'f' => {
      self.advance(5)
      self.scalar(Json::boolean(false), true)
    }
    'n' => {
      self.advance(4)
      self.scalar(Json::null(), true)
    }
    _ => {
      self.advance(1)
      self.slow_number(pos, kind)
    }
  }
}

///|
/// Checks the length limit for a token starting at `start`.
fn Parser::check_length(
  self : Parser,
  start : Position,
  len : Int32,
) -> Unit raise ParseError {
  if self.max_string_length >= 0 && len > self.max_string_length {
    raise TooLong(start, self.max_string_length)
  }
}

///|
/// Scans the rest of a string after its opening quote at `quote` and returns
/// its decoded contents.
async fn Parser::slow_string(self : Parser, quote : Position) -> String {
  let sb = StringBuilder()
  let mut len = 0
  for ;; {
    let pos = self.pos()
    // The number of code units added, or -1 at the closing quote, -2 for an
    // error at the current position, -3 for an unpaired surrogate.
    let n = lexscan self.lexbuf with longest {
      re"^[^\"\\\u{0}-\u{1f}]{1,64}" as s => {
        sb.write_view(s)
        self.advance(s.length())
        s.length()
      }
      re"^\"" => {
        self.advance(1)
        -1
      }
      re"^\\[\"\\/bfnrt]" as e => {
        sb.write_char(unescape(e.unsafe_get(1)))
        self.advance(2)
        1
      }
      re"^\\u[0-9a-fA-F]{4}" as u => {
        let c = hex4(u, 2)
        if c is (0xD800..<=0xDFFF) {
          -3
        } else {
          sb.write_char(c.unsafe_to_char())
          self.advance(6)
          1
        }
      }
      re"^\\u[dD][89abAB][0-9a-fA-F]{2}\\u[dD][c-fC-F][0-9a-fA-F]{2}" as u => {
        let c = (hex4(u, 2) << 10) + hex4(u, 8) - 0x35fdc00
        sb.write_char(c.unsafe_to_char())
        self.advance(12)
        2
      }
      re"^\\(?:u[0-9a-fA-F]{0,3})?" as e => {
        self.advance(e.length())
        -2
      }
      _ => -2
    }
    match n {
      -1 => break
      -2 => self.fail_here()
      -3 => raise UnpairedSurrogate(pos)
      _ => {
        len += n
        self.check_length(quote, len)
      }
    }
  }
  sb.to_string()
}

///|
/// Scans the rest of a number starting at `start`, whose first character
/// `first` (`-` or a digit) is consumed.
async fn Parser::slow_number(
  self : Parser,
  start : Position,
  first : Int32,
) -> Unit {
  let sb = StringBuilder()
  sb.write_char(first.unsafe_to_char())
  let mut lead = first
  if first == '-' {
    lead = self.slow_digit()
    if lead < 0 {
      self.fail_here()
    }
    sb.write_char(lead.unsafe_to_char())
  }
  let mut len = sb.to_string().length()
  if lead != '0' {
    len = self.slow_digits(sb, start, len)
  }
  // A fraction or exponent is taken only with its first digit, so a number
  // ends where the fast scanner's longest match ends; `1.` is `1` followed by
  // an unexpected `.`.
  let f = self.slow_fraction(sb)
  if f > 0 {
    len = self.slow_digits(sb, start, len + f)
  }
  let e = self.slow_exponent(sb)
  if e > 0 {
    len = self.slow_digits(sb, start, len + e)
  }
  self.check_length(start, len)
  self.scalar(number_value(sb.to_string()), true)
}

///|
/// Consumes one digit and returns it, or returns -1 and consumes nothing.
async fn Parser::slow_digit(self : Parser) -> Int32 {
  lexscan self.lexbuf with longest {
    re"^[0-9]" as d => {
      self.advance(1)
      d.to_int()
    }
    _ => -1
  }
}

///|
/// Consumes digits into `sb` and returns the token length `len` plus the
/// number of digits.
async fn Parser::slow_digits(
  self : Parser,
  sb : StringBuilder,
  start : Position,
  len : Int32,
) -> Int32 {
  let mut len = len
  for ;; {
    let more = lexscan self.lexbuf with longest {
      re"^[0-9]{1,64}" as d => {
        sb.write_view(d)
        self.advance(d.length())
        len += d.length()
        true
      }
      _ => false
    }
    if !more {
      break
    }
    self.check_length(start, len)
  }
  len
}

///|
/// Consumes `.` and one digit into `sb`; returns how many code units were
/// consumed.
async fn Parser::slow_fraction(self : Parser, sb : StringBuilder) -> Int32 {
  lexscan self.lexbuf with longest {
    re"^\.[0-9]" as f => {
      sb.write_view(f)
      self.advance(2)
      2
    }
    _ => 0
  }
}

///|
/// Consumes `e` or `E`, an optional sign and one digit into `sb`; returns how
/// many code units were consumed.
async fn Parser::slow_exponent(self : Parser, sb : StringBuilder) -> Int32 {
  lexscan self.lexbuf with longest {
    re"^[eE][+\-]?[0-9]" as e => {
      sb.write_view(e)
      self.advance(e.length())
      e.length()
    }
    _ => 0
  }
}