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

///|
pub fn Number::parse(token : String) -> Result[Number, Diagnostic] {
  let chars = token.code_units()
  let mut i = 0
  if i < chars.length() && chars[i] == 45 {
    i += 1
  }
  if i >= chars.length() {
    return Err(Diagnostic::new(InvalidNumber, "Expected a JSON number"))
  }
  if chars[i] == 48 {
    i += 1
  } else if chars[i] >= 49 && chars[i] <= 57 {
    while i < chars.length() && digit(chars[i]) {
      i += 1
    }
  } else {
    return Err(Diagnostic::new(InvalidNumber, "Expected an integer part"))
  }
  if i < chars.length() && chars[i] == 46 {
    i += 1
    let start = i
    while i < chars.length() && digit(chars[i]) {
      i += 1
    }
    if i == start {
      return Err(Diagnostic::new(InvalidNumber, "Expected fractional digits"))
    }
  }
  if i < chars.length() && (chars[i] == 69 || chars[i] == 101) {
    i += 1
    if i < chars.length() && (chars[i] == 43 || chars[i] == 45) {
      i += 1
    }
    let start = i
    while i < chars.length() && digit(chars[i]) {
      i += 1
    }
    if i == start {
      return Err(Diagnostic::new(InvalidNumber, "Expected exponent digits"))
    }
  }
  if i != chars.length() {
    Err(Diagnostic::new(InvalidNumber, "Unexpected number suffix"))
  } else {
    Ok({ token, })
  }
}

///|
fn Number::normalized(self : Number) -> (Bool, String, @bigint.BigInt) {
  let negative = self.token.has_prefix("-")
  let parts = self.token.to_lower().split("e").collect()
  let mantissa = parts[0].to_owned()
  let mut exponent = if parts.length() == 2 {
    let raw = parts[1].to_owned()
    @bigint.BigInt::from_string(
      if raw.has_prefix("+") {
        raw[1:].to_owned()
      } else {
        raw
      },
    )
  } else {
    @bigint.BigInt::from_int(0)
  }
  let digits = StringBuilder()
  let mut after_dot = false
  let mut fraction = 0
  for c in mantissa.code_units() {
    if c == 46 {
      after_dot = true
    } else if digit(c) {
      digits.write_char(c.to_int().unsafe_to_char())
      if after_dot {
        fraction += 1
      }
    }
  }
  exponent = exponent - @bigint.BigInt::from_int(fraction)
  let all = digits.to_string()
  let mut start = 0
  let mut end = all.length()
  while start < end && all.code_unit_at(start) == 48 {
    start += 1
  }
  if start == end {
    return (false, "0", @bigint.BigInt::from_int(0))
  }
  while end > start && all.code_unit_at(end - 1) == 48 {
    end -= 1
    exponent = exponent + @bigint.BigInt::from_int(1)
  }
  (negative, all[start:end].to_owned(), exponent)
}

///|
/// A key that is equal exactly when the numbers are numerically equal, for
/// hashing many values without pairwise comparison.
pub fn Number::numeric_key(self : Number) -> String {
  let (negative, digits, exponent) = self.normalized()
  (if negative { "-" } else { "" }) + digits + "e" + exponent.to_string()
}

///|
pub fn Number::numeric_equal(self : Number, other : Number) -> Bool {
  let a = self.normalized()
  let b = other.normalized()
  a.0 == b.0 && a.1 == b.1 && a.2 == b.2
}

///|
pub fn Number::is_integer(self : Number) -> Bool {
  self.normalized().2.compare_int(0) >= 0
}

///|
/// Compare mathematical values without converting to binary floating point.
pub fn Number::numeric_compare(self : Number, other : Number) -> Int32 {
  let a = self.normalized()
  let b = other.normalized()
  if a.0 != b.0 {
    return if a.0 { -1 } else { 1 }
  }
  if a.1 == "0" {
    return if b.1 == "0" { 0 } else { -1 }
  }
  if b.1 == "0" {
    return 1
  }
  let sign = if a.0 { -1 } else { 1 }
  let order = (a.2 + @bigint.BigInt::from_int(a.1.length())).compare(
    b.2 + @bigint.BigInt::from_int(b.1.length()),
  )
  if order != 0 {
    return sign * order
  }
  let length = if a.1.length() > b.1.length() {
    a.1.length()
  } else {
    b.1.length()
  }
  for i in 0..