///|
fn digit(c : Int32) -> Bool {
  c >= 48 && c <= 57
}

///|
fn decimal_syntax(data : BytesView) -> Bool {
  let mut i = 0
  if data.length() > 0 && (data[0] == b'+' || data[0] == b'-') {
    i += 1
  }
  let start = i
  while i < data.length() && digit(data[i].to_int()) {
    i += 1
  }
  let mut digits = i - start
  if i < data.length() && data[i] == b'.' {
    i += 1
    let fraction = i
    while i < data.length() && digit(data[i].to_int()) {
      i += 1
    }
    digits += i - fraction
  }
  if digits == 0 {
    return false
  }
  if i < data.length() && (data[i] == b'e' || data[i] == b'E') {
    i += 1
    if i < data.length() && (data[i] == b'+' || data[i] == b'-') {
      i += 1
    }
    let exponent = i
    while i < data.length() && digit(data[i].to_int()) {
      i += 1
    }
    if exponent == i {
      return false
    }
  }
  i == data.length()
}

///|
fn Reader::atom(self : Reader) -> Value raise ConfigError {
  let start = self.pos
  while ({
          let c = self.peek()
          (c >= 65 && c <= 90) ||
          (c >= 97 && c <= 122) ||
          digit(c) ||
          c == 43 ||
          c == 45 ||
          c == 46
        }) {
    self.advance()
  }
  let raw = @utf8.decode_lossy(self.data[start:self.pos])
  let lower = raw.to_lower()
  if lower == "true" {
    return Boolean(true)
  }
  if lower == "false" {
    return Boolean(false)
  }
  let long = raw.has_suffix("L") || raw.has_suffix("LL")
  let suffix = if raw.has_suffix("LL") { 2 } else if long { 1 } else { 0 }
  let end = self.pos - suffix
  if end <= start {
    raise self.error("invalid_number", "expected numeric value")
  }
  let number = @utf8.decode_lossy(self.data[start:end]).to_lower()
  let base = if number.has_prefix("0x") {
    16
  } else if number.has_prefix("0b") {
    2
  } else if number.has_prefix("0o") || number.has_prefix("0q") {
    8
  } else {
    10
  }
  if base != 10 {
    let n = end - start - 2
    let max32 = if base == 16 { 8 } else if base == 8 { 10 } else { 32 }
    let max64 = if base == 16 { 16 } else if base == 8 { 21 } else { 64 }
    if n < 1 || n > max64 {
      raise self.error("integer_overflow", "invalid base integer width")
    }
    for i = start + 2; i < end; i = i + 1 {
      let d = hex_digit(self.data[i].to_int())
      if d < 0 || d >= base {
        raise self.error("invalid_number", "invalid digit for base")
      }
    }
    let digits = @utf8.decode_lossy(self.data[start + 2:end])
    let bits = @string.parse_uint64(digits, base~) catch {
      _ => raise self.error("integer_overflow", "integer exceeds 64 bits")
    }
    if long || n > max32 {
      return Integer64(bits.reinterpret_as_int64())
    }
    return Integer(bits.to_int())
  }
  if !decimal_syntax(self.data[start:end]) {
    raise self.error("invalid_number", "invalid decimal or boolean")
  }
  if number.contains(".") || number.contains("e") || number.contains("E") {
    if long {
      raise self.error("invalid_number", "float cannot have integer suffix")
    }
    let v = @string.parse_double(number) catch {
      _ => raise self.error("invalid_number", "invalid floating point number")
    }
    if v.is_inf() || v.is_nan() {
      raise self.error("float_overflow", "non-finite float")
    }
    Float(v)
  } else {
    let v = @string.parse_int64(number) catch {
      _ =>
        raise self.error("integer_overflow", "integer exceeds signed 64 bits")
    }
    if long || v < -2147483648L || v > 2147483647L {
      Integer64(v)
    } else {
      Integer(v.to_int())
    }
  }
}