///|
/// Parse the fragment part of a JSON Pointer reference (RFC 6901),
/// e.g. `#/properties/foo` -> `["properties", "foo"]`.
/// Returns None if the fragment is malformed (empty token after `/`,
/// or an invalid escape such as `~2`).
fn parse_pointer_fragment(fragment : String) -> Array[String]? {
  let tokens : Array[String] = []
  let buf = StringBuilder()
  let mut in_escape = false
  let mut pos = 0
  for c in decode_percent(fragment) {
    if pos == 0 && c == '#' {
      pos = pos + 1
      continue // skip the leading '#'
    }
    if pos <= 1 && c != '#' {
      // first significant character must be '/'
      if c != '/' {
        return None // plain name: anchor reference, not a pointer
      }
      pos = 2
      continue
    }
    pos = pos + 1
    if in_escape {
      match c {
        '0' => buf.write_char('~')
        '1' => buf.write_char('/')
        _ => return None // invalid escape
      }
      in_escape = false
    } else if c == '~' {
      in_escape = true
    } else if c == '/' {
      tokens.push(buf.to_string())
      buf.reset()
    } else {
      buf.write_char(c)
    }
  }
  if pos < 2 {
    return None // empty fragment or "#" alone
  }
  if in_escape {
    return None // dangling '~'
  }
  tokens.push(buf.to_string())
  Some(tokens)
}

///|
/// Walk a JSON document along pointer tokens. Array tokens must be
/// canonical decimal indices (no leading zeros, per RFC 6901).
fn resolve_pointer_tokens(doc : Json, tokens : Array[String]) -> Json? {
  let mut cur = doc
  for t in tokens {
    match cur {
      Object(o) =>
        match o.get(t) {
          Some(v) => cur = v
          None => return None
        }
      Array(a) => {
        guard parse_index(t) is Some(i) else { return None }
        guard i < a.length() else { return None }
        cur = a[i]
      }
      _ => return None
    }
  }
  Some(cur)
}

///|
/// Parse a canonical array index (no leading zeros unless "0" itself).
fn parse_index(t : String) -> Int? {
  if t.length() == 0 {
    return None
  }
  let mut n = 0
  for c in t {
    guard c >= '0' && c <= '9' else { return None }
    n = n * 10 + (c.to_int() - '0'.to_int())
  }
  if t.length() > 1 && t.get_char(0) == Some('0') {
    return None
  }
  Some(n)
}