///|
priv struct RonParser {
  source : Array[Char]
  mut offset : Int32
  max_nesting_depth : Int32
}

///|
fn RonParser::new(source : StringView, max_nesting_depth : Int32) -> RonParser {
  { source: source.to_array(), offset: 0, max_nesting_depth, }
}

///|
fn RonParser::position(self : RonParser) -> RonPosition {
  let mut line = 1
  let mut column = 0
  for i = 0; i < self.offset && i < self.source.length(); i = i + 1 {
    if self.source[i] == '\n' {
      line = line + 1
      column = 0
    } else {
      column = column + 1
    }
  }
  { index: self.offset, line, column, }
}

///|
fn RonParser::error_char(self : RonParser, char : Char) -> RonError {
  UnexpectedChar(self.position(), char)
}

///|
fn RonParser::error_eof(self : RonParser) -> RonError {
  UnexpectedEof(self.position())
}

///|
fn RonParser::error_escape(self : RonParser) -> RonError {
  InvalidEscape(self.position())
}

///|
fn RonParser::error_number(self : RonParser, token : String) -> RonError {
  InvalidNumber(self.position(), token)
}

///|
fn RonParser::error_value(self : RonParser, message : String) -> RonError {
  InvalidValue(self.position(), message)
}

///|
fn RonParser::peek(self : RonParser) -> Char? {
  self.source.get(self.offset)
}

///|
fn RonParser::peek_at(self : RonParser, distance : Int32) -> Char? {
  self.source.get(self.offset + distance)
}

///|
fn RonParser::advance(self : RonParser) -> Char? {
  let char = self.peek()
  match char {
    Some(_) => self.offset = self.offset + 1
    None => ()
  }
  char
}

///|
fn RonParser::expect(self : RonParser, expected : Char) -> Unit raise RonError {
  match self.advance() {
    Some(char) if char == expected => ()
    Some(char) => raise self.error_char(char)
    None => raise self.error_eof()
  }
}

///|
fn RonParser::skip_trivia(self : RonParser) -> Unit raise RonError {
  while self.offset < self.source.length() {
    let char = self.source[self.offset]
    if char.is_whitespace() {
      self.offset = self.offset + 1
      continue
    }
    if char == '/' {
      match self.peek_at(1) {
        Some('/') => {
          self.offset = self.offset + 2
          while self.offset < self.source.length() &&
                self.source[self.offset] != '\n' {
            self.offset = self.offset + 1
          }
          continue
        }
        Some('*') => {
          self.offset = self.offset + 2
          self.skip_block_comment()
          continue
        }
        _ => ()
      }
    }
    break
  }
}

///|
fn RonParser::skip_block_comment(self : RonParser) -> Unit raise RonError {
  let mut nesting = 1
  while nesting > 0 {
    if self.offset >= self.source.length() {
      raise self.error_eof()
    }
    let char = self.source[self.offset]
    if char == '#' {
      self.offset = self.offset + 1
      continue
    }
    if char == '/' && self.peek_at(1) == Some('*') {
      nesting = nesting + 1
      self.offset = self.offset + 2
      continue
    }
    if char == '*' && self.peek_at(1) == Some('/') {
      nesting = nesting - 1
      self.offset = self.offset + 2
      continue
    }
    self.offset = self.offset + 1
  }
}

///|
fn is_identifier_start(char : Char) -> Bool {
  char.is_ascii_alphabetic() || char == '_'
}

///|
fn is_identifier_continue(char : Char) -> Bool {
  char.is_ascii_alphabetic() || char.is_ascii_digit() || char == '_'
}

///|
fn is_number_start(char : Char) -> Bool {
  char.is_ascii_digit() || char == '-' || char == '+'
}

///|
fn RonParser::try_identifier(self : RonParser) -> String? {
  match self.peek() {
    Some(char) if is_identifier_start(char) => {
      let buffer = StringBuilder()
      buffer.write_char(char)
      self.offset = self.offset + 1
      while self.offset < self.source.length() &&
            is_identifier_continue(self.source[self.offset]) {
        buffer.write_char(self.source[self.offset])
        self.offset = self.offset + 1
      }
      Some(buffer.to_string())
    }
    _ => None
  }
}

///|
fn RonParser::parse_identifier(self : RonParser) -> String raise RonError {
  match self.try_identifier() {
    Some(name) => name
    None =>
      match self.peek() {
        Some(char) => raise self.error_char(char)
        None => raise self.error_eof()
      }
  }
}

///|
fn RonParser::parse_path(self : RonParser) -> String raise RonError {
  let buffer = StringBuilder()
  buffer.write_string(self.parse_identifier())
  while self.peek() == Some(':') && self.peek_at(1) == Some(':') {
    self.offset = self.offset + 2
    buffer.write_string("::")
    buffer.write_string(self.parse_identifier())
  }
  buffer.to_string()
}

///|
fn split_path(path : String) -> (String, String)? {
  match path.rev_find("::") {
    Some(index) => {
      let owner = path.unsafe_substring(start=0, end=index)
      let variant = path.unsafe_substring(start=index + 2, end=path.length())
      Some((owner, variant))
    }
    None => None
  }
}

///|
fn is_type_name(path : String) -> Bool {
  match path.get_char(0) {
    Some(char) => char.is_ascii_uppercase()
    None => false
  }
}

///|
fn RonParser::parse_value(
  self : RonParser,
  depth : Int32,
) -> RonValue raise RonError {
  self.skip_trivia()
  if self.peek() == Some('.') && self.peek_at(1) == Some('.') {
    return self.parse_open_range(depth)
  }
  let value = self.parse_value_non_range(depth)
  self.skip_trivia()
  if self.peek() == Some('.') && self.peek_at(1) == Some('.') {
    return self.parse_range_from(value, depth)
  }
  value
}

///|
fn RonParser::parse_value_non_range(
  self : RonParser,
  depth : Int32,
) -> RonValue raise RonError {
  if depth > self.max_nesting_depth {
    raise DepthLimitExceeded(self.max_nesting_depth)
  }
  self.skip_trivia()
  match self.peek() {
    Some('(') => self.parse_tuple(depth)
    Some('[') => self.parse_sequence(depth)
    Some('{') => self.parse_map(depth)
    Some('"') => RonValue::String(self.parse_string_literal())
    Some('\'') => RonValue::Char(self.parse_char_literal())
    Some('b') =>
      match self.peek_at(1) {
        Some('"') => RonValue::Bytes(self.parse_byte_string())
        Some('r') => RonValue::Bytes(self.parse_raw_byte_string())
        Some('\'') => RonValue::Byte(self.parse_byte_char())
        _ => self.parse_identifier_value(depth)
      }
    Some('r') =>
      match self.peek_at(1) {
        Some('"') | Some('#') => RonValue::String(self.parse_raw_string())
        _ => self.parse_identifier_value(depth)
      }
    Some(char) if is_number_start(char) => self.parse_number()
    Some(char) if is_identifier_start(char) =>
      self.parse_identifier_value(depth)
    Some(char) => raise self.error_char(char)
    None => raise self.error_eof()
  }
}

///|
fn is_range_terminator(char : Char?) -> Bool {
  match char {
    None => true
    Some(',') | Some(')') | Some(']') | Some('}') | Some(':') => true
    _ => false
  }
}

///|
fn RonParser::parse_range_from(
  self : RonParser,
  start : RonValue,
  depth : Int32,
) -> RonValue raise RonError {
  self.offset = self.offset + 2
  let inclusive = if self.peek() == Some('=') {
    self.offset = self.offset + 1
    true
  } else {
    false
  }
  self.skip_trivia()
  if is_range_terminator(self.peek()) {
    if inclusive {
      raise self.error_eof()
    }
    return RonValue::Range({ start: Some(start), end: None, inclusive: false, })
  }
  let end = self.parse_value(depth + 1)
  RonValue::Range({ start: Some(start), end: Some(end), inclusive, })
}

///|
fn RonParser::parse_open_range(
  self : RonParser,
  depth : Int32,
) -> RonValue raise RonError {
  self.expect('.')
  self.expect('.')
  let inclusive = if self.peek() == Some('=') {
    self.offset = self.offset + 1
    true
  } else {
    false
  }
  self.skip_trivia()
  if is_range_terminator(self.peek()) {
    if inclusive {
      raise self.error_eof()
    }
    return RonValue::Range({ start: None, end: None, inclusive: false, })
  }
  let end = self.parse_value(depth + 1)
  RonValue::Range({ start: None, end: Some(end), inclusive, })
}

///|
fn RonParser::parse_identifier_value(
  self : RonParser,
  depth : Int32,
) -> RonValue raise RonError {
  let path = self.parse_path()
  self.skip_trivia()
  if self.peek() == Some('(') {
    let (fields, values) = self.parse_payload(depth)
    if path == "Some" {
      if fields.length() == 0 && values.length() == 1 {
        return RonValue::Option(Some(values[0]))
      }
      raise self.error_value("Some expects exactly one positional value")
    }
    match split_path(path) {
      Some((owner, variant)) =>
        if fields.length() == 0 && values.length() == 0 {
          RonValue::Enum(owner, variant, [])
        } else if fields.length() == 0 {
          RonValue::EnumTuple(owner, variant, values)
        } else {
          RonValue::Enum(owner, variant, fields)
        }
      None =>
        if fields.length() == 0 && values.length() == 0 {
          RonValue::Struct(path, [])
        } else if fields.length() == 0 {
          RonValue::TupleStruct(path, values)
        } else {
          RonValue::Struct(path, fields)
        }
    }
  } else {
    match path {
      "true" => RonValue::Bool(true)
      "false" => RonValue::Bool(false)
      "None" => RonValue::Option(None)
      "NaN" | "nan" => RonValue::Number(NaN)
      "inf" | "Infinity" | "infinity" => RonValue::Number(Infinity)
      _ =>
        match split_path(path) {
          Some((owner, variant)) => RonValue::Enum(owner, variant, [])
          None if is_type_name(path) => RonValue::Struct(path, [])
          None => RonValue::Identifier(path)
        }
    }
  }
}

///|
fn RonParser::parse_comma_or_end(
  self : RonParser,
  end : Char,
) -> Bool raise RonError {
  self.skip_trivia()
  match self.peek() {
    Some(char) if char == ',' => {
      self.offset = self.offset + 1
      self.skip_trivia()
      if self.peek() == Some(end) {
        self.offset = self.offset + 1
        true
      } else {
        false
      }
    }
    Some(char) if char == end => {
      self.offset = self.offset + 1
      true
    }
    Some(char) => raise self.error_char(char)
    None => raise self.error_eof()
  }
}

///|
fn RonParser::parse_tuple(
  self : RonParser,
  depth : Int32,
) -> RonValue raise RonError {
  self.expect('(')
  self.skip_trivia()
  if self.peek() == Some(')') {
    self.offset = self.offset + 1
    return RonValue::Unit
  }
  if self.looks_like_named_field() {
    let fields = []
    while true {
      let name = self.parse_identifier()
      self.skip_trivia()
      self.expect(':')
      fields.push((name, self.parse_value(depth + 1)))
      if self.parse_comma_or_end(')') {
        break
      }
    }
    return RonValue::Struct("", fields)
  }
  let values = []
  while true {
    values.push(self.parse_value(depth + 1))
    if self.parse_comma_or_end(')') {
      break
    }
  }
  RonValue::Tuple(values)
}

///|
fn RonParser::parse_sequence(
  self : RonParser,
  depth : Int32,
) -> RonValue raise RonError {
  self.expect('[')
  self.skip_trivia()
  let values = []
  if self.peek() == Some(']') {
    self.offset = self.offset + 1
    return RonValue::Sequence(values)
  }
  while true {
    values.push(self.parse_value(depth + 1))
    if self.parse_comma_or_end(']') {
      break
    }
  }
  RonValue::Sequence(values)
}

///|
fn RonParser::parse_map(
  self : RonParser,
  depth : Int32,
) -> RonValue raise RonError {
  self.expect('{')
  self.skip_trivia()
  let entries = []
  if self.peek() == Some('}') {
    self.offset = self.offset + 1
    return RonValue::Map(entries)
  }
  while true {
    let key = self.parse_value(depth + 1)
    self.skip_trivia()
    self.expect(':')
    let value = self.parse_value(depth + 1)
    entries.push((key, value))
    if self.parse_comma_or_end('}') {
      break
    }
  }
  RonValue::Map(entries)
}

///|
fn RonParser::looks_like_named_field(self : RonParser) -> Bool {
  let saved = self.offset
  let result = try {
    self.try_identifier() |> ignore
    self.skip_trivia()
    self.peek() == Some(':')
  } catch {
    _ => false
  }
  self.offset = saved
  result
}

///|
fn RonParser::parse_payload(
  self : RonParser,
  depth : Int32,
) -> (Array[(String, RonValue)], Array[RonValue]) raise RonError {
  self.expect('(')
  self.skip_trivia()
  let fields = []
  let values = []
  if self.peek() == Some(')') {
    self.offset = self.offset + 1
    return (fields, values)
  }
  if self.looks_like_named_field() {
    while true {
      let name = self.parse_identifier()
      self.skip_trivia()
      self.expect(':')
      fields.push((name, self.parse_value(depth + 1)))
      if self.parse_comma_or_end(')') {
        break
      }
    }
  } else {
    while true {
      values.push(self.parse_value(depth + 1))
      if self.parse_comma_or_end(')') {
        break
      }
    }
  }
  (fields, values)
}

///|
fn RonParser::parse_escape(self : RonParser) -> Char raise RonError {
  match self.advance() {
    Some('n') => '\n'
    Some('r') => '\r'
    Some('t') => '\t'
    Some('0') => '\u{0}'
    Some('\\') => '\\'
    Some('"') => '"'
    Some('\'') => '\''
    Some('/') => '/'
    Some('x') => {
      let value = self.parse_hex_digits(2)
      if value > 0xff {
        raise self.error_escape()
      }
      value.unsafe_to_char()
    }
    Some('u') => {
      self.expect('{')
      let value = self.parse_variable_hex_digits()
      self.expect('}')
      if value > 0x10ffff || (value >= 0xd800 && value <= 0xdfff) {
        raise self.error_escape()
      }
      value.unsafe_to_char()
    }
    Some(_) => raise self.error_escape()
    None => raise self.error_eof()
  }
}

///|
fn RonParser::parse_hex_digits(
  self : RonParser,
  count : Int32,
) -> Int32 raise RonError {
  let mut value = 0
  for i = 0; i < count; i = i + 1 {
    let digit = match self.advance() {
      Some('0'..<='9' as char) => char.to_int() - '0'.to_int()
      Some('a'..<='f' as char) => char.to_int() - 'a'.to_int() + 10
      Some('A'..<='F' as char) => char.to_int() - 'A'.to_int() + 10
      Some(_) => raise self.error_escape()
      None => raise self.error_eof()
    }
    value = (value << 4) | digit
  }
  value
}

///|
fn RonParser::parse_variable_hex_digits(
  self : RonParser,
) -> Int32 raise RonError {
  let mut value = 0
  let mut digits = 0
  while self.peek() != Some('}') {
    if digits == 6 {
      raise self.error_escape()
    }
    let digit = match self.advance() {
      Some('0'..<='9' as char) => char.to_int() - '0'.to_int()
      Some('a'..<='f' as char) => char.to_int() - 'a'.to_int() + 10
      Some('A'..<='F' as char) => char.to_int() - 'A'.to_int() + 10
      Some(_) => raise self.error_escape()
      None => raise self.error_eof()
    }
    value = (value << 4) | digit
    digits = digits + 1
  }
  if digits == 0 {
    raise self.error_escape()
  }
  value
}

///|
fn RonParser::parse_string_literal(self : RonParser) -> String raise RonError {
  self.expect('"')
  let buffer = StringBuilder()
  while true {
    match self.advance() {
      Some('"') => return buffer.to_string()
      Some('\\') => buffer.write_char(self.parse_escape())
      Some(char) if char.to_int() < 0x20 => raise self.error_char(char)
      Some(char) => buffer.write_char(char)
      None => raise self.error_eof()
    }
  }
  abort("unreachable")
}

///|
fn RonParser::parse_char_literal(self : RonParser) -> Char raise RonError {
  self.expect('\'')
  let char = match self.advance() {
    Some('\\') => self.parse_escape()
    Some('\'') => raise self.error_escape()
    Some(char) if char.to_int() < 0x20 => raise self.error_char(char)
    Some(char) => char
    None => raise self.error_eof()
  }
  self.expect('\'')
  char
}

///|
fn RonParser::parse_byte_escape(self : RonParser) -> Byte raise RonError {
  match self.advance() {
    Some('n') => '\n'.to_int().to_byte()
    Some('r') => '\r'.to_int().to_byte()
    Some('t') => '\t'.to_int().to_byte()
    Some('0') => Byte::default()
    Some('\\') => '\\'.to_int().to_byte()
    Some('"') => '"'.to_int().to_byte()
    Some('\'') => '\''.to_int().to_byte()
    Some('/') => '/'.to_int().to_byte()
    Some('x') => self.parse_hex_digits(2).to_byte()
    Some(_) => raise self.error_escape()
    None => raise self.error_eof()
  }
}

///|
fn RonParser::parse_byte_string(self : RonParser) -> Bytes raise RonError {
  self.expect('b')
  self.expect('"')
  let bytes = []
  while true {
    match self.advance() {
      Some('"') => return Bytes::from_array(bytes)
      Some('\\') => bytes.push(self.parse_byte_escape())
      Some(char) if char.to_int() <= 0x7f => bytes.push(char.to_int().to_byte())
      Some(char) => raise self.error_char(char)
      None => raise self.error_eof()
    }
  }
  abort("unreachable")
}

///|
fn RonParser::parse_byte_char(self : RonParser) -> Byte raise RonError {
  self.expect('b')
  self.expect('\'')
  let byte = match self.advance() {
    Some('\\') => self.parse_byte_escape()
    Some(char) if char.to_int() <= 0x7f => char.to_int().to_byte()
    Some(char) => raise self.error_char(char)
    None => raise self.error_eof()
  }
  self.expect('\'')
  byte
}

///|
fn RonParser::parse_raw_string(self : RonParser) -> String raise RonError {
  self.expect('r')
  let hashes = self.count_raw_hashes()
  self.expect('"')
  let buffer = StringBuilder()
  while true {
    match self.advance() {
      Some('"') if self.consume_hash_suffix(hashes) => return buffer.to_string()
      Some(char) => buffer.write_char(char)
      None => raise self.error_eof()
    }
  }
  abort("unreachable")
}

///|
fn RonParser::parse_raw_byte_string(self : RonParser) -> Bytes raise RonError {
  self.expect('b')
  self.expect('r')
  let hashes = self.count_raw_hashes()
  self.expect('"')
  let bytes = []
  while true {
    match self.advance() {
      Some('"') if self.consume_hash_suffix(hashes) =>
        return Bytes::from_array(bytes)
      Some(char) if char.to_int() <= 0x7f => bytes.push(char.to_int().to_byte())
      Some(char) => raise self.error_char(char)
      None => raise self.error_eof()
    }
  }
  abort("unreachable")
}

///|
fn RonParser::count_raw_hashes(self : RonParser) -> Int32 {
  let mut count = 0
  while self.peek() == Some('#') {
    count = count + 1
    self.offset = self.offset + 1
  }
  count
}

///|
fn RonParser::consume_hash_suffix(self : RonParser, count : Int32) -> Bool {
  if count == 0 {
    return true
  }
  for i = 0; i < count; i = i + 1 {
    if self.peek_at(i) != Some('#') {
      return false
    }
  }
  self.offset = self.offset + count
  true
}

///|
fn is_number_char(char : Char) -> Bool {
  char.is_ascii_alphabetic() ||
  char.is_ascii_digit() ||
  char == '_' ||
  char == '.' ||
  char == '+' ||
  char == '-'
}

///|
fn RonParser::parse_number(self : RonParser) -> RonValue raise RonError {
  let start = self.offset
  let buffer = StringBuilder()
  while self.offset < self.source.length() &&
        is_number_char(self.source[self.offset]) {
    if self.source[self.offset] == '.' && self.peek_at(1) == Some('.') {
      break
    }
    buffer.write_char(self.source[self.offset])
    self.offset = self.offset + 1
  }
  let token = buffer.to_string()
  let lower = token.to_lower()
  if token.length() == 0 {
    raise self.error_eof()
  }
  if lower == "inf" ||
    lower == "+inf" ||
    lower == "infinity" ||
    lower == "+infinity" {
    return RonValue::Number(Infinity)
  }
  if lower == "-inf" || lower == "-infinity" {
    return RonValue::Number(NegativeInfinity)
  }
  if lower == "nan" || lower == "+nan" || lower == "-nan" {
    return RonValue::Number(NaN)
  }
  if token.contains(".") || lower.contains("e") {
    return RonValue::Number(Float(@string.parse_double(token))) catch {
      _ => {
        self.offset = start + token.length()
        raise self.error_number(token)
      }
    }
  }
  try {
    if token.has_prefix("-") {
      RonValue::Number(Signed(@string.parse_int64(token, base=0)))
    } else {
      let value = @string.parse_uint64(token, base=0)
      if value <= 0x7fffffffffffffffUL {
        RonValue::Number(Signed(value.reinterpret_as_int64()))
      } else {
        RonValue::Number(Unsigned(value))
      }
    }
  } catch {
    _ => {
      self.offset = start + token.length()
      raise self.error_number(token)
    }
  }
}