using selfhost.vm.boxes.json_cur as MiniJson
using selfhost.common.mini_vm_scan as MiniVmScan
using selfhost.common.mini_vm_binop as MiniVmBinOp
using selfhost.common.mini_vm_compare as MiniVmCompare
using selfhost.vm.boxes.mini_vm_prints as MiniVmPrints

static box MiniVm {
  _is_digit(ch) {
    if ch == "0" { return 1 }
    if ch == "1" { return 1 }
    if ch == "2" { return 1 }
    if ch == "3" { return 1 }
    if ch == "4" { return 1 }
    if ch == "5" { return 1 }
    if ch == "6" { return 1 }
    if ch == "7" { return 1 }
    if ch == "8" { return 1 }
    if ch == "9" { return 1 }
    return 0
  }
  _str_to_int(s) { return new MiniVmScan()._str_to_int(s) }
  _int_to_str(n) { return new MiniVmScan()._int_to_str(n) }
  read_digits(json, pos) { return new MiniJson().read_digits_from(json, pos) }
  // Read a JSON string starting at position pos (at opening quote); returns the decoded string
  read_json_string(json, pos) { return new MiniJson().read_quoted_from(json, pos) }
  // helper: find needle from position pos
  index_of_from(hay, needle, pos) { return new MiniVmScan().index_of_from(hay, needle, pos) }
  // helper: next non-whitespace character index from pos
  next_non_ws(json, pos) { return new MiniJson().next_non_ws(json, pos) }
  // ——— Helpers (as box methods) ———

  // Minimal: Print(BinaryOp) with operator "+"; supports string+string and int+int
  // try_print_binop_at moved to MiniVmBinOp

  // Greedy fallback: detect BinaryOp int+int by pattern regardless of field order nuances
  // try_print_binop_int_greedy moved to MiniVmBinOp

  // Fallback: within the current Print's expression BinaryOp object, scan for two numeric values and sum
  // try_print_binop_sum_any moved to MiniVmBinOp

  // Deterministic: within the first Print.expression BinaryOp('+'),
  // find exactly two numeric values from successive '"value":' fields and sum.
  // Stops after collecting two ints; bounded strictly by the expression object.
  // try_print_binop_sum_expr_values moved to MiniVmBinOp

  // Simpler deterministic fallback: after the first BinaryOp '+',
  // scan forward for two successive 'value' fields and sum their integer digits.
  // This avoids brace matching and remains bounded by two finds.
  // try_print_binop_sum_after_bop moved to MiniVmBinOp

  // Direct typed BinaryOp(int+int) matcher using explicit left/right literal paths
  try_print_binop_typed_direct(json) {
    local k_left = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
    local k_right = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
    local lp = json.indexOf(k_left)
    if lp < 0 { return -1 }
    local ld = read_digits(json, lp + k_left.length())
    if ld == "" { return -1 }
    local rp = index_of_from(json, k_right, lp + k_left.length())
    if rp < 0 { return -1 }
    local rd = read_digits(json, rp + k_right.length())
    if rd == "" { return -1 }
    print(_int_to_str(_str_to_int(ld) + _str_to_int(rd)))
    return rp + k_right.length()
  }

  // Tokenized typed extractor: search left/right blocks then type/value pairs
  try_print_binop_typed_tokens(json) {
    local k_bo = "\"kind\":\"BinaryOp\""
    local bpos = json.indexOf(k_bo)
    if bpos < 0 { return -1 }
    local lp = index_of_from(json, "\"left\":", bpos)
    if lp < 0 { return -1 }
    local kt = "\"type\":\"int\""
    local kv = "\"value\":"
    local tp1 = index_of_from(json, kt, lp)
    if tp1 < 0 { return -1 }
    local vp1 = index_of_from(json, kv, tp1)
    if vp1 < 0 { return -1 }
    local ld = read_digits(json, vp1 + kv.length())
    if ld == "" { return -1 }
    local rp = index_of_from(json, "\"right\":", lp)
    if rp < 0 { return -1 }
    local tp2 = index_of_from(json, kt, rp)
    if tp2 < 0 { return -1 }
    local vp2 = index_of_from(json, kv, tp2)
    if vp2 < 0 { return -1 }
    local rd = read_digits(json, vp2 + kv.length())
    if rd == "" { return -1 }
    print(_int_to_str(_str_to_int(ld) + _str_to_int(rd)))
    return rp
  }

  // Fast value-pair extractor: find left/right then first value digits after each
  try_print_binop_value_pairs(json) {
    local k_bo = "\"kind\":\"BinaryOp\""
    local bpos = json.indexOf(k_bo)
    if bpos < 0 { return -1 }
    local kl = "\"left\":"
    local kv = "\"value\":"
    local lp = index_of_from(json, kl, bpos)
    if lp < 0 { return -1 }
    local v1 = index_of_from(json, kv, lp)
    if v1 < 0 { return -1 }
    local ld = read_digits(json, v1 + kv.length())
    if ld == "" { return -1 }
    local rp = index_of_from(json, "\"right\":", lp)
    if rp < 0 { return -1 }
    local v2 = index_of_from(json, kv, rp)
    if v2 < 0 { return -1 }
    local rd = read_digits(json, v2 + kv.length())
    if rd == "" { return -1 }
    print(_int_to_str(_str_to_int(ld) + _str_to_int(rd)))
    return v2 + kv.length()
  }

  // Minimal: Print(Compare) for integers. Prints 1/0 for true/false.
  // try_print_compare_at moved to MiniVmCompare
  // Extract first Print literal from JSON v0 Program and return its string representation
  parse_first_print_literal(json) {
    // Find a Print statement
    local k_print = "\"kind\":\"Print\""
    local p = json.indexOf(k_print)
    if p < 0 { return null }
    // Find value type in the expression following Print
    local k_type = "\"type\":\""
    local tpos = json.indexOf(k_type)
    if tpos < 0 { return null }
    tpos = tpos + k_type.length()
    // Read type name until next quote
    local t_end = index_of_from(json, "\"", tpos)
    if t_end < 0 { return null }
    local ty = json.substring(tpos, t_end)
    // Find value field
    local k_val = "\"value\":"
    local vpos = index_of_from(json, k_val, t_end)
    if vpos < 0 { return null }
    vpos = vpos + k_val.length()
    if ty == "int" || ty == "i64" || ty == "integer" {
      // read digits via MiniJson
      local digits = new MiniJson().read_digits_from(json, vpos)
      return digits
    }
    if ty == "string" {
      // read quoted via MiniJson
      local i = index_of_from(json, "\"", vpos)
      if i < 0 { return null }
      return new MiniJson().read_quoted_from(json, i)
    }
    // Other types not supported yet
    return null
  }
  // helper: find balanced bracket range [ ... ] starting at idx (points to '[')
  find_balanced_array_end(json, idx) { return new MiniVmScan().find_balanced_array_end(json, idx) }
  // helper: find balanced object range { ... } starting at idx (points to '{')
  find_balanced_object_end(json, idx) { return new MiniVmScan().find_balanced_object_end(json, idx) }
  // Print all Print-Literal values within [start,end] (inclusive slice indices)
  print_prints_in_slice(json, start, end) { return new MiniVmPrints().print_prints_in_slice(json, start, end) }
  // Process top-level If with literal condition; print branch prints. Returns printed count.
  process_if_once(json) { return new MiniVmPrints().process_if_once(json) }
  print_all_print_literals(json) { return new MiniVmPrints().print_all_print_literals(json) }
  parse_first_int(json) {
    local key = "\"value\":{\"type\":\"int\",\"value\":"
    local idx = json.lastIndexOf(key)
    if idx < 0 { return "0" }
    local start = idx + key.length()
    return read_digits(json, start)
  }
  // Fallback: find first BinaryOp and return sum of two numeric values as string; empty if not found
  parse_first_binop_sum(json) {
    local k_bo = "\"kind\":\"BinaryOp\""
    local bpos = json.indexOf(k_bo)
    if bpos < 0 { return "" }
    // typed pattern inside left/right.literal.value: {"type":"int","value":<digits>}
    local k_typed = "\"type\":\"int\",\"value\":"
    // first number
    local p1 = index_of_from(json, k_typed, bpos)
    if p1 < 0 { return "" }
    local d1 = read_digits(json, p1 + k_typed.length())
    if d1 == "" { return "" }
    // second number
    local p2 = index_of_from(json, k_typed, p1 + k_typed.length())
    if p2 < 0 { return "" }
    local d2 = read_digits(json, p2 + k_typed.length())
    if d2 == "" { return "" }
    return _int_to_str(_str_to_int(d1) + _str_to_int(d2))
  }
  // Linear pass: sum all numbers outside of quotes (fast, finite)
  sum_numbers_no_quotes(json) { return new MiniVmScan().sum_numbers_no_quotes(json) }
  // Naive: sum all digit runs anywhere (for simple BinaryOp JSON)
  sum_all_digits_naive(json) { return new MiniVmScan().sum_all_digits_naive(json) }
  // Sum first two integers outside quotes; returns string or empty if not found
  sum_first_two_numbers(json) { return new MiniVmScan().sum_first_two_numbers(json) }

  // Sum two integers near a BinaryOp '+' token; bounded window to keep steps low
  sum_two_numbers_near_plus(json) {
    local k_plus = "\"operator\":\"+\""
    local op = json.indexOf(k_plus)
    if op < 0 { return "" }
    local n = json.length()
    local start = op - 120
    if start < 0 { start = 0 }
    local limit = op + 240
    if limit > n { limit = n }
    local i = start
    local found = 0
    local a = 0
    loop (i < limit) {
      local ch = json.substring(i, i+1)
      if ch == "\"" {
        // skip to next quote within window
        local j = index_of_from(json, "\"", i+1)
        if j < 0 || j > limit { break }
        i = j + 1
        continue
      }
      local d = read_digits(json, i)
      if d {
        if found == 0 {
          a = _str_to_int(d)
          found = 1
        } else {
          local b = _str_to_int(d)
          return _int_to_str(a + b)
        }
        i = i + d.length()
        continue
      }
      i = i + 1
    }
    return ""
  }
  // Fallback: sum all bare numbers (not inside quotes) in the JSON; return string or empty if none
  sum_all_numbers(json) {
    local cur = new MiniJson()
    local i = 0
    local n = json.length()
    local sum = 0
    loop (i < n) {
      local ch = json.substring(i, i+1)
      if ch == "\"" {
        // skip quoted string
        local s = cur.read_quoted_from(json, i)
        i = i + s.length() + 2
        continue
      }
      // try digits
      local d = cur.read_digits_from(json, i)
      if d != "" { sum = sum + _str_to_int(d)  i = i + d.length()  continue }
      i = i + 1
    }
    if sum == 0 { return "" }
    return _int_to_str(sum)
  }
  // (reserved) helper for future robust binop scan
  run(json) {
    // entry: attempt minimal quick shapes first, then broader routes
    // Quick path: Program-level Print of a single Literal string/int
    if json.indexOf("\"kind\":\"Program\"") >= 0 && json.indexOf("\"kind\":\"Print\"") >= 0 {
      // Literal string
      if json.indexOf("\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"string\"") >= 0 {
        local ks = "\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"string\",\"value\":\""
        local ps = json.indexOf(ks)
        if ps >= 0 {
          local si = ps + ks.length()
          local sj = json.indexOf("\"", si)
          if sj >= 0 { print(json.substring(si, sj))  return 0 }
        }
      }
      // Literal int
      if json.indexOf("\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\"") >= 0 {
        local ki = "\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
        local pi = json.indexOf(ki)
        if pi >= 0 {
          local ii = pi + ki.length()
          // digits until closing brace
          local ie = json.indexOf("}", ii)
          if ie < 0 { ie = ii }
          local d = json.substring(ii, ie)
          if d { print(d)  return 0 }
        }
      }
    }
    // Single-purpose fast path for smoke: if BinaryOp '+' exists, try expression-bounded extractor first.
    if json.indexOf("\"BinaryOp\"") >= 0 && json.indexOf("\"operator\":\"+\"") >= 0 {
      // Bind to first Print and extract value×2 within expression bounds
      local k_print = "\"kind\":\"Print\""
      local p = index_of_from(json, k_print, 0)
      if p >= 0 {
        local np0 = new MiniVmBinOp().try_print_binop_sum_expr_values(json, json.length(), p)
        if np0 > 0 { return 0 }
      }
      // Typed direct inside BinaryOp object (fast and finite)
      local k_bo = "\"kind\":\"BinaryOp\""
      local bpos = json.indexOf(k_bo)
      if bpos >= 0 {
        local k_lint = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
        local li = index_of_from(json, k_lint, bpos)
        if li >= 0 {
          local ld = read_digits(json, li + k_lint.length())
          if ld != "" {
            local k_rint = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
            local ri = index_of_from(json, k_rint, li + k_lint.length())
            if ri >= 0 {
              local rd = read_digits(json, ri + k_rint.length())
              if rd != "" { print(_int_to_str(_str_to_int(ld) + _str_to_int(rd)))  return 0 }
            }
          }
        }
      }
      // As a final bounded fallback under BinaryOp '+', sum first two numbers outside quotes
      {
        local s2 = sum_first_two_numbers(json)
        if s2 { print(s2)  return 0 }
      }
      // (skip near-operator windowed scan to avoid high step counts under PyVM)
    }
    // Prefer If(literal) branch handling first
    local ifc = process_if_once(json)
    if ifc > 0 { return 0 }
    // Quick conservative path: if BinaryOp exists, sum bare numbers outside quotes
    // (limited to simple BinaryOp(int,int) JSON)
    if json.indexOf("\"BinaryOp\"") >= 0 {
      // Prefer expression-bounded scan first
      local k_print = "\"kind\":\"Print\""
      local p = index_of_from(json, k_print, 0)
      if p >= 0 {
        // Deterministic: sum the first two numbers from successive 'value' fields
        local np0 = new MiniVmBinOp().try_print_binop_sum_expr_values(json, json.length(), p)
        if np0 > 0 { return 0 }
      }
      // Brace-free deterministic fallback tied to the first BinaryOp
      {
        local np1 = new MiniVmBinOp().try_print_binop_sum_after_bop(json)
        if np1 > 0 { return 0 }
      }
      // avoid global number-sum fallback to keep steps bounded
    }
    // 0) direct typed BinaryOp '+' fast-path (explicit left/right literal ints)
    local k_bo = "\"kind\":\"BinaryOp\""
    local k_plus = "\"operator\":\"+\""
    if json.indexOf(k_bo) >= 0 && json.indexOf(k_plus) >= 0 {
      local np = try_print_binop_typed_direct(json)
      if np > 0 { return 0 }
      np = try_print_binop_typed_tokens(json)
      if np > 0 { return 0 }
      np = try_print_binop_value_pairs(json)
      if np > 0 { return 0 }
      // (skip bounded-window fallback around '+')
    }
    // 0) quick path: BinaryOp(int+int) typed fast-path
    local k_bo = "\"kind\":\"BinaryOp\""
    local bpos = json.indexOf(k_bo)
    if bpos >= 0 {
      // typed left/right ints inside BinaryOp
      local k_lint = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
      local li = index_of_from(json, k_lint, bpos)
      if li >= 0 {
        local ld = read_digits(json, li + k_lint.length())
        if ld != "" {
          local k_rint = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
          local ri = index_of_from(json, k_rint, li + k_lint.length())
          if ri >= 0 {
            local rd = read_digits(json, ri + k_rint.length())
            if rd != "" {
              print(_int_to_str(_str_to_int(ld) + _str_to_int(rd)))
              return 0
            }
          }
        }
      }
      // fallback: sum two numeric values within the first Print.expression BinaryOp object
      local k_print = "\"kind\":\"Print\""
      local p = index_of_from(json, k_print, 0)
      if p >= 0 {
        local k_expr = "\"expression\":{"
        local epos = index_of_from(json, k_expr, p)
        if epos > 0 {
          local obj_start = index_of_from(json, "{", epos)
          local obj_end = find_balanced_object_end(json, obj_start)
          if obj_start > 0 && obj_end > 0 {
            local k_bo2 = "\"kind\":\"BinaryOp\""
            local b2 = index_of_from(json, k_bo2, obj_start)
            if b2 > 0 && b2 < obj_end {
              local k_v = "\"value\":"
              local p1 = index_of_from(json, k_v, obj_start)
              local d1 = ""
              loop (p1 > 0 && p1 < obj_end) {
                d1 = new MiniJson().read_digits_from(json, p1 + k_v.length())
                if d1 != "" { break }
                p1 = index_of_from(json, k_v, p1 + k_v.length())
              }
              if d1 != "" {
                local p2 = index_of_from(json, k_v, p1 + k_v.length())
                local d2 = ""
                loop (p2 > 0 && p2 < obj_end) {
                  d2 = new MiniJson().read_digits_from(json, p2 + k_v.length())
                  if d2 != "" { break }
                  p2 = index_of_from(json, k_v, p2 + k_v.length())
                }
                if d2 != "" {
                  local ai = _str_to_int(d1)
                  local bi = _str_to_int(d2)
                  print(_int_to_str(ai + bi))
                  return 0
                }
              }
            }
          }
        }
      }
      // fallback: parse-first within BinaryOp scope by scanning two numeric values
      local ssum = new MiniVmBinOp().parse_first_binop_sum(json)
      if ssum { print(ssum)  return 0 }
    }
    // Attempt expression-local BinaryOp sum via existing helper on first Print
    {
      local k_print = "\"kind\":\"Print\""
      local p = index_of_from(json, k_print, 0)
      if p >= 0 {
        local np = new MiniVmBinOp().try_print_binop_sum_any(json, json.length(), p)
        if np > 0 { return 0 }
      }
    }
    // 0-c) quick path: Compare(lhs int, rhs int)
    local k_cp = "\"kind\":\"Compare\""
    local cpos = json.indexOf(k_cp)
    if cpos >= 0 {
      // operation
      local k_op = "\"operation\":\""
      local opos = index_of_from(json, k_op, cpos)
      if opos > 0 {
        local oi = opos + k_op.length()
        local oj = index_of_from(json, "\"", oi)
        if oj > 0 {
          local op = json.substring(oi, oj)
          // lhs value
          local k_lhs = "\"lhs\":{\"kind\":\"Literal\""
          local hl = index_of_from(json, k_lhs, oj)
          if hl > 0 {
            local k_v = "\"value\":"
            local hv = index_of_from(json, k_v, hl)
            if hv > 0 {
      local a = read_digits(json, hv + k_v.length())
              // rhs value
              local k_rhs = "\"rhs\":{\"kind\":\"Literal\""
              local hr = index_of_from(json, k_rhs, hl)
              if hr > 0 {
                local rv = index_of_from(json, k_v, hr)
                if rv > 0 {
                  local b = read_digits(json, rv + k_v.length())
                  if a && b {
                    local ai = _str_to_int(a)
                    local bi = _str_to_int(b)
                    local res = 0
                    if op == "<"  { if ai <  bi { res = 1 } }
                    if op == "==" { if ai == bi { res = 1 } }
                    if op == "<=" { if ai <= bi { res = 1 } }
                    if op == ">"  { if ai >  bi { res = 1 } }
                    if op == ">=" { if ai >= bi { res = 1 } }
                    if op == "!=" { if ai != bi { res = 1 } }
                    print(res)
                    return 0
                  }
                }
              }
            }
          }
        }
      }
    }
    // Scan global prints (flat programs)
    local pc = print_all_print_literals(json)
    // 2) as a robustness fallback, handle first BinaryOp sum within first Print.expression
    if pc == 0 {
      local k_print = "\"kind\":\"Print\""
      local p = index_of_from(json, k_print, 0)
      if p >= 0 {
        local k_expr = "\"expression\":{"
        local epos = index_of_from(json, k_expr, p)
        if epos > 0 {
          local obj_start = index_of_from(json, "{", epos)
          local obj_end = find_balanced_object_end(json, obj_start)
          if obj_start > 0 && obj_end > 0 {
            local k_bo = "\"kind\":\"BinaryOp\""
            local bpos = index_of_from(json, k_bo, obj_start)
            if bpos > 0 && bpos < obj_end {
              // sum two numeric values inside this expression object
              local cur = new MiniJson()
              local k_v = "\"value\":"
              local p1 = index_of_from(json, k_v, obj_start)
              local d1 = ""
              loop (p1 > 0 && p1 < obj_end) {
                d1 = cur.read_digits_from(json, p1 + k_v.length())
                if d1 != "" { break }
                p1 = index_of_from(json, k_v, p1 + k_v.length())
              }
              if d1 != "" {
                local p2 = index_of_from(json, k_v, p1 + k_v.length())
                local d2 = ""
                loop (p2 > 0 && p2 < obj_end) {
                  d2 = cur.read_digits_from(json, p2 + k_v.length())
                  if d2 != "" { break }
                  p2 = index_of_from(json, k_v, p2 + k_v.length())
                }
                if d2 != "" {
                  local ai = _str_to_int(d1)
                  local bi = _str_to_int(d2)
                  print(_int_to_str(ai + bi))
                  pc = 1
                }
              }
            }
          }
        }
      }
    }
    if pc == 0 {
      // last resort: typed pattern-wide sum, then safe number sum outside quotes, else single int literal
      local s = new MiniVmBinOp().parse_first_binop_sum(json)
      if s { print(s) } else {
        local ts = sum_numbers_no_quotes(json)
        if ts { print(ts) } else {
          local n = parse_first_int(json)
          print(n)
        }
      }
    }
    return 0
  }

  // Pure helper: collect minimal print outputs (literals only) into an array
  collect_prints(json) {
    // Ported from self-contained smoke (Hardened minimal scanner)
    local out = new ArrayBox()
    local pos = 0
    local guard = 0
    // DEV trace: flip to 1 for one-run diagnosis; keep 0 for normal
    local trace = 0
    if trace == 1 { print("[collect][start] method entry") }
    local k_print = "\"kind\":\"Print\""
    loop (true) {
      guard = guard + 1
      if guard > 200 {
        if trace == 1 { print("[collect][guard_break] guard="+guard) }
        if trace == 1 { print("[collect][loop_exit] guard="+guard+" out.size="+out.size()) }
        if trace == 1 { print("[collect][return] out.size="+out.size()) }
        return out
      }
      local p = index_of_from(json, k_print, pos)
      if trace == 1 { print("[collect][loop] pos="+pos+" p="+p+" guard="+guard) }
      if p < 0 {
        if trace == 1 { print("[collect][p_break] p="+p) }
        if trace == 1 { print("[collect][loop_exit] guard="+guard+" out.size="+out.size()) }
        if trace == 1 { print("[collect][return] out.size="+out.size()) }
        return out
      }
      // bound current Print slice to [this, next)
      local obj_start = p
      local next_p = index_of_from(json, k_print, p + k_print.length())
      local obj_end = json.length()
      if next_p > 0 { obj_end = next_p }
      if trace == 1 { print("[collect][p] "+p)  print("[collect][next_p] "+next_p)  print("[collect][slice_end] "+obj_end) }
      if trace == 1 {
        local k_expr = "\"expression\":{"
        local epos_dbg = index_of_from(json, k_expr, obj_start)
        print("[scan][expr] "+epos_dbg)
        local fc_dbg = index_of_from(json, "\"kind\":\"FunctionCall\"", obj_start)
        print("[scan][fc] "+fc_dbg)
        local bo_dbg = index_of_from(json, "\"kind\":\"BinaryOp\"", obj_start)
        print("[scan][bo] "+bo_dbg)
        local cp_dbg = index_of_from(json, "\"kind\":\"Compare\"", obj_start)
        print("[scan][cp] "+cp_dbg)
        local ts_dbg = index_of_from(json, "\"type\":\"string\"", obj_start)
        print("[scan][ts] "+ts_dbg)
        local ti_dbg = index_of_from(json, "\"type\":\"int\"", obj_start)
        print("[scan][ti] "+ti_dbg)
        // positions for tight patterns used by branches
        local ks_pat = "\"type\":\"string\",\"value\":\""
        print("[scan][ks] "+index_of_from(json, ks_pat, obj_start))
        local ki_pat = "\"type\":\"int\",\"value\":"
        print("[scan][ki] "+index_of_from(json, ki_pat, obj_start))
      }

      // 1) FunctionCall echo/itoa (single literal or empty args)
      {
        // Limit search within Print.expression object for stability
        local k_expr = "\"expression\":{"
        local epos = index_of_from(json, k_expr, obj_start)
        if epos > 0 { if epos < obj_end {
          local expr_start = index_of_from(json, "{", epos)
          if expr_start > 0 { if expr_start < obj_end {
            local expr_end = new MiniVmScan().find_balanced_object_end(json, expr_start)
            if expr_end > 0 { if expr_end <= obj_end {
              if trace == 1 { print("[collect][expr] "+expr_start+","+expr_end) }
              local k_fc = "\"kind\":\"FunctionCall\""
              local fcp = index_of_from(json, k_fc, expr_start)
              if trace == 1 { print("[collect][fc_in_expr] "+fcp+" (bounds "+expr_start+","+expr_end+")") }
              if fcp > 0 { if fcp < expr_end {
                if trace == 1 { print("[collect][fc_found] entering function call handler") }
                local kn = "\"name\":\""
                local np = index_of_from(json, kn, fcp)
                if trace == 1 { print("[collect][name_search] "+np+" (obj_end "+obj_end+")") }
              if np > 0 { if np < obj_end {
                local ni = np + kn.length()
                local nj = index_of_from(json, "\"", ni)
                if trace == 1 { print("[collect][name_bounds] "+ni+","+nj+" (expr_end "+expr_end+")") }
                if nj > 0 { if nj <= expr_end {
                  local fname = json.substring(ni, nj)
                  if trace == 1 { print("[collect][fname] '"+fname+"'") }
                  local ka = "\"arguments\":["
                  local ap = index_of_from(json, ka, nj)
                  if ap <= 0 {
                    local ka0 = "\"arguments\":"
                    local ap0 = index_of_from(json, ka0, nj)
                    if ap0 >= 0 { if ap0 < expr_end { ap = ap0 } }
                  }
                  if ap >= 0 { if ap < expr_end {
                    // detect empty args [] quickly: no type token inside balanced array
                    local arr_start = index_of_from(json, "[", ap)
                    if arr_start >= 0 { if arr_start < expr_end {
                      local arr_end = new MiniVmScan().find_balanced_array_end(json, arr_start)
                      if arr_end >= 0 { if arr_end <= expr_end {
                      local kt = "\"type\":\""
                      local atpos = index_of_from(json, kt, arr_start)
                      if trace == 1 { print("[collect][empty_check] atpos="+atpos+" arr_bounds=["+arr_start+","+arr_end+"]") }
                      if atpos < 0 || atpos >= arr_end {
                        if trace == 1 { print("[collect][empty_args] fname='"+fname+"'") }
                        if fname == "echo" { out.push("")  pos = obj_end  continue }
                        if fname == "itoa" { out.push("0")  pos = obj_end  continue }
                      }
                    }}}}
                    // string arg
                    local ks = "\"type\":\"string\",\"value\":\""
                    local ps = index_of_from(json, ks, ap)
                    if ps > 0 { if ps < expr_end {
                      local si = ps + ks.length()
                      local sj = index_of_from(json, "\"", si)
                      if sj > 0 { if sj <= expr_end {
                        local sval = json.substring(si, sj)
                        if fname == "echo" { out.push(sval)  pos = obj_end + 1  continue }
                      }}
                    }}
                    // int arg
                    local ki = "\"type\":\"int\",\"value\":"
                    local pi = index_of_from(json, ki, ap)
                    if pi > 0 { if pi < expr_end {
                      local ival = read_digits(json, pi + ki.length())
                      if ival != "" { if fname == "itoa" { out.push(ival)  pos = obj_end + 1  continue } else { if fname == "echo" { out.push(ival)  pos = obj_end + 1  continue } } }
                    }}
                  }}
                }}
              }}
            }}}
          }}
        }}
      }

      // 2) BinaryOp(int '+' int)
      {
        local k_expr = "\"expression\":{"
        local epos = index_of_from(json, k_expr, obj_start)
        if epos > 0 { if epos < obj_end {
          local k_bo = "\"kind\":\"BinaryOp\""
          local bpos = index_of_from(json, k_bo, epos)
          if bpos > 0 { if bpos < obj_end {
            if index_of_from(json, "\"operator\":\"+\"", bpos) > 0 {
              local k_l = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
              local k_r = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
              local lp = index_of_from(json, k_l, bpos)
              if lp > 0 { if lp < obj_end {
                local ld = read_digits(json, lp + k_l.length())
                if ld != "" {
                  local rp = index_of_from(json, k_r, lp + k_l.length())
                  if rp > 0 { if rp < obj_end {
                    local rd = read_digits(json, rp + k_r.length())
                    if rd != "" { if trace == 1 { print("[hit][bo-typed] "+ld+"+"+rd) } out.push(_int_to_str(_str_to_int(ld) + _str_to_int(rd)))  pos = p + k_print.length()  continue }
                  }}
                }
              }}
              // fallback: two successive 'value' digits within expression bounds
              local k_v = "\"value\":"
              local v1 = index_of_from(json, k_v, epos)
              if v1 > 0 { if v1 < obj_end {
                local d1 = new MiniJson().read_digits_from(json, v1 + k_v.length())
                if d1 != "" {
                  local v2 = index_of_from(json, k_v, v1 + k_v.length())
                  if v2 > 0 { if v2 < obj_end {
                    local d2 = new MiniJson().read_digits_from(json, v2 + k_v.length())
                    if d2 != "" { if trace == 1 { print("[hit][bo-fallback] "+d1+"+"+d2) } out.push(_int_to_str(_str_to_int(d1) + _str_to_int(d2)))  pos = p + k_print.length()  continue }
                  }}
                }
              }}
            }
          }}
        }}
      }

      // 3) Compare(lhs/rhs ints)
      {
        local k_cp = "\"kind\":\"Compare\""
        local cpos = index_of_from(json, k_cp, obj_start)
        if cpos > 0 { if cpos < obj_end {
          local k_op = "\"operation\":\""
          local opos = index_of_from(json, k_op, cpos)
          if opos > 0 { if opos < obj_end {
            local oi = opos + k_op.length()
            local oj = index_of_from(json, "\"", oi)
            if oj > 0 { if oj <= obj_end {
              local op = json.substring(oi, oj)
              local k_v = "\"value\":"
              local lhs_v = index_of_from(json, k_v, oj)
              if lhs_v > 0 { if lhs_v < obj_end {
                local la = read_digits(json, lhs_v + k_v.length())
                if la != "" {
                  local rhs_v = index_of_from(json, k_v, lhs_v + k_v.length())
                  if rhs_v > 0 { if rhs_v < obj_end {
                    local rb = read_digits(json, rhs_v + k_v.length())
                    if rb != "" {
                      local ai = _str_to_int(la)
                      local bi = _str_to_int(rb)
                      local res = 0
                      if op == "<"  { if ai <  bi { res = 1 } }
                      if op == "==" { if ai == bi { res = 1 } }
                      if op == "<=" { if ai <= bi { res = 1 } }
                      if op == ">"  { if ai >  bi { res = 1 } }
                      if op == ">=" { if ai >= bi { res = 1 } }
                      if op == "!=" { if ai != bi { res = 1 } }
                      out.push(_int_to_str(res))
                      pos = p + k_print.length()
                      continue
                    }
                  }}
                }
              }}
            }}
          }}
        }}
      }

      // (FunctionCall branch moved earlier)

      // 4) Literal string
      {
        local ks = "\"type\":\"string\",\"value\":\""
        local ps = index_of_from(json, ks, obj_start)
        if ps > 0 { if ps < obj_end {
          local si = ps + ks.length()
          local sj = index_of_from(json, "\"", si)
          if sj > 0 { if sj <= obj_end {
            if trace == 1 { print("[hit][str]") }
            out.push(json.substring(si, sj))  pos = p + k_print.length()  continue
          }}
        }}
      }
      // 5) Literal int
      {
        local ki = "\"type\":\"int\",\"value\":"
        local pi = index_of_from(json, ki, obj_start)
        if pi > 0 { if pi < obj_end {
          local digits = read_digits(json, pi + ki.length())
          if digits != "" { if trace == 1 { print("[hit][i-lit] "+digits) } out.push(digits)  pos = p + k_print.length()  continue }
        }}
      }
      // Unknown: skip this Print object entirely to avoid stalls and mis-detection
      // Use coarse slice end (next Print position) when available; fallback to k_print-length step
      pos = obj_end + 1
      if pos <= p { pos = p + k_print.length() }
    }
    if trace == 1 { print("[collect][loop_exit] guard="+guard+" out.size="+out.size()) }
    if trace == 1 { print("[collect][return] out.size="+out.size()) }
    return out
  }
}
