///|
// Validate the original numeric token with decimal digits, so IEEE-754
// rounding/underflow cannot turn a fraction into
// an apparently valid integer cost, timestamp or limit.
fn exact_integer(source : String, path : String) -> Int32 raise InputError {
  if source.length() > 64 {
    invalid(path, "numeric spelling exceeds 64 units")
  }
  let digits : Array[Int32] = []
  let mut fraction = 0
  let mut after_dot = false
  let mut exponent = 0
  let mut exp_negative = false
  let mut in_exponent = false
  let mut negative = false
  for i in 0..= 48 && c <= 57 {
      let digit = c.to_int() - 48
      if in_exponent {
        exponent = (exponent * 10 + digit).min(1001)
      } else {
        digits.push(digit)
        if after_dot {
          fraction += 1
        }
      }
    } else {
      invalid(path, "invalid numeric spelling")
    }
  }
  if digits.all(d => d == 0) {
    return 0
  }
  if negative {
    invalid(path, "expected nonnegative integer")
  }
  let shift = (if exp_negative { -exponent } else { exponent }) - fraction
  let mut keep = digits.length()
  if shift < 0 {
    if -shift >= digits.length() {
      invalid(path, "expected exact integer")
    }
    keep += shift
    for i in keep.. (2147483647 - digit) / 10 {
      invalid(path, "integer exceeds 2147483647")
    }
    value = value * 10 + digit
  }
  if shift > 0 {
    if shift > 10 {
      invalid(path, "integer exceeds 2147483647")
    }
    for _ in 0.. 2147483647 / 10 {
        invalid(path, "integer exceeds 2147483647")
      }
      value *= 10
    }
  }
  value
}