// JsonCursorBox: minimal JSON scanning helpers (Nyash)
// Note: naive and partial; sufficient for MVP patterns (string/int + bracket depth)
static box JsonCursorBox {
  next_non_ws(s, pos) {
    local i = pos
    local n = s.length()
    loop (i < n) {
      local ch = s.substring(i, i+1)
      if ch != " " && ch != "\n" && ch != "\r" && ch != "\t" { return i }
      i = i + 1
    }
    return -1
  }
  read_quoted_from(s, pos) {
    local i = pos
    if s.substring(i, i+1) != "\"" { return "" }
    i = i + 1
    local out = ""
    local n = s.length()
    loop (i < n) {
      local ch = s.substring(i, i+1)
      if ch == "\"" { break }
      if ch == "\\" { i = i + 1  ch = s.substring(i, i+1) }
      out = out + ch
      i = i + 1
    }
    return out
  }
  read_digits_from(s, pos) {
    local out = ""
    local i = pos
    if i == null { return out }
    if i < 0 { return out }
    loop (true) {
      local ch = s.substring(i, i+1)
      if ch == "" { break }
      if ch == "0" || ch == "1" || ch == "2" || ch == "3" || ch == "4" || ch == "5" || ch == "6" || ch == "7" || ch == "8" || ch == "9" { out = out + ch  i = i + 1 } else { break }
    }
    return out
  }
  find_balanced_array_end(s, idx) {
    local n = s.length()
    if s.substring(idx, idx+1) != "[" { return -1 }
    local depth = 0
    local i = idx
    loop (i < n) {
      local ch = s.substring(i, i+1)
      if ch == "[" { depth = depth + 1 }
      if ch == "]" { depth = depth - 1  if depth == 0 { return i } }
      i = i + 1
    }
    return -1
  }
  find_balanced_object_end(s, idx) {
    local n = s.length()
    if s.substring(idx, idx+1) != "{" { return -1 }
    local depth = 0
    local i = idx
    loop (i < n) {
      local ch = s.substring(i, i+1)
      if ch == "{" { depth = depth + 1 }
      if ch == "}" { depth = depth - 1  if depth == 0 { return i } }
      i = i + 1
    }
    return -1
  }
}
