using selfhost.common.mini_vm_scan as MiniVmScan using selfhost.common.mini_vm_binop as MiniVmBinOp using selfhost.common.mini_vm_compare as MiniVmCompare // Use the JSON adapter facade for cursor ops (next_non_ws, digits) using selfhost.vm.boxes.json_cur as MiniJsonLoader static box MiniVmPrints { // dev trace flag (0=OFF) _trace_enabled() { return 0 } // fallback toggle for legacy heuristics (0=OFF, 1=ON) _fallback_enabled() { return 0 } // literal string within Print try_print_string_value_at(json, end, print_pos) { local scan = new MiniVmScan() local k_val = "\"value\":\"" local s = scan.index_of_from(json, k_val, print_pos) if s < 0 || s >= end { return -1 } local i = s + k_val.length() local j = scan.index_of_from(json, "\"", i) if j <= 0 || j > end { return -1 } print(json.substring(i, j)) return j + 1 } // literal int within Print (typed) try_print_int_value_at(json, end, print_pos) { local scan = new MiniVmScan() local k_expr = "\"expression\":{" local epos = scan.index_of_from(json, k_expr, print_pos) if epos <= 0 || epos >= end { return -1 } local obj_start = scan.index_of_from(json, "{", epos) if obj_start <= 0 || obj_start >= end { return -1 } local obj_end = scan.find_balanced_object_end(json, obj_start) if obj_end <= 0 || obj_end > end { return -1 } // robust: look for explicit int type within expression object local k_tint = "\"type\":\"int\"" local tpos = scan.index_of_from(json, k_tint, obj_start) if tpos <= 0 || tpos >= obj_end { return -1 } local k_val2 = "\"value\":" local v2 = scan.index_of_from(json, k_val2, tpos) if v2 <= 0 || v2 >= obj_end { return -1 } local digits = scan.read_digits(json, v2 + k_val2.length()) if digits == "" { return -1 } print(digits) return obj_end + 1 } // minimal FunctionCall printer for echo/itoa try_print_functioncall_at(json, end, print_pos) { local scan = new MiniVmScan() local k_fc = "\"kind\":\"FunctionCall\"" local fcp = scan.index_of_from(json, k_fc, print_pos) if fcp <= 0 || fcp >= end { return -1 } local k_name = "\"name\":\"" local npos = scan.index_of_from(json, k_name, fcp) if npos <= 0 || npos >= end { return -1 } local ni = npos + k_name.length() local nj = scan.index_of_from(json, "\"", ni) if nj <= 0 || nj > end { return -1 } local fname = json.substring(ni, nj) local k_args = "\"arguments\":[" local apos = scan.index_of_from(json, k_args, nj) if apos <= 0 || apos >= end { return -1 } local arr_start = scan.index_of_from(json, "[", apos) local arr_end = scan.find_balanced_array_end(json, arr_start) if arr_start <= 0 || arr_end <= 0 || arr_end > end { return -1 } // handle empty args [] local nn = new MiniJsonLoader().next_non_ws(json, arr_start+1) if nn > 0 && nn <= arr_end { if json.substring(nn, nn+1) == "]" { if fname == "echo" { print("") return arr_end + 1 } if fname == "itoa" { print("0") return arr_end + 1 } return -1 } } // first arg type local k_t = "\"type\":\"" local atpos = scan.index_of_from(json, k_t, arr_start) if atpos <= 0 || atpos >= arr_end { if fname == "echo" { print("") return arr_end + 1 } if fname == "itoa" { print("0") return arr_end + 1 } return -1 } atpos = atpos + k_t.length() local at_end = scan.index_of_from(json, "\"", atpos) if at_end <= 0 || at_end > arr_end { return -1 } local aty = json.substring(atpos, at_end) if aty == "string" { local k_sval = "\"value\":\"" local svalp = scan.index_of_from(json, k_sval, at_end) if svalp <= 0 || svalp >= arr_end { return -1 } local si = svalp + k_sval.length() local sj = scan.index_of_from(json, "\"", si) if sj <= 0 || sj > arr_end { return -1 } local sval = json.substring(si, sj) if fname == "echo" { print(sval) return sj + 1 } return -1 } if aty == "int" || aty == "i64" || aty == "integer" { local k_ival = "\"value\":" local ivalp = scan.index_of_from(json, k_ival, at_end) if ivalp <= 0 || ivalp >= arr_end { return -1 } local digits = scan.read_digits(json, ivalp + k_ival.length()) if fname == "itoa" || fname == "echo" { print(digits) return ivalp + k_ival.length() } return -1 } return -1 } // Print all Print-Literal values within [start,end] print_prints_in_slice(json, start, end) { // Preferred route: JSON Box (plugin) – robust and structure-aware // If plugin is available, parse and traverse Program.statements and print. // Fall back to text scanner when plugin is unavailable or parse fails. { // Attempt plugin route in a guarded block @printed = 0 @ok = 0 @dbg = _trace_enabled() // new JsonDocBox()/JsonNodeBox are provided by the JSON plugin @doc = new JsonDocBox() doc.parse(json) if dbg == 1 { @perr = doc.error() if perr == "" { print("[json] parse ok") } else { print("[json] parse err=" + perr) } } @root = doc.root() if dbg == 1 { @rkind = root.kind() print("[json] root.kind=" + rkind) } if root { @stmts = root.get("statements") if dbg == 1 { @skind = stmts.kind() @ssize = stmts.size() print("[json] stmts.kind=" + skind + " size=" + new MiniVmScan()._int_to_str(ssize)) } if stmts { @n = stmts.size() @i = 0 loop (i < n) { if dbg == 1 { print("[json] loop i=" + new MiniVmScan()._int_to_str(i) + "/" + new MiniVmScan()._int_to_str(n)) if i > 1000 { print("[json] debug guard: break loop at i>1000") break } } @node = stmts.at(i) if !node { i = i + 1 continue } @expr = node.get("expression") if !expr { i = i + 1 continue } @k = expr.get("kind").str() if dbg == 1 { print("[json] expr.kind=" + k) } if k == "Literal" { @val = expr.get("value") if val { @ty = val.get("type").str() if ty == "string" { print(val.get("value").str()) } else { print(val.get("value").int()) } } printed = printed + 1 i = i + 1 continue } if k == "FunctionCall" { @name = expr.get("name").str() if dbg == 1 { print("[json] func name=" + name) } @args = expr.get("arguments") if !args { i = i + 1 continue } @asz = args.size() if asz <= 0 { if name == "echo" { print("") } if name == "itoa" { print("0") } printed = printed + 1 i = i + 1 continue } @arg0v = args.at(0).get("value") if name == "echo" { if arg0v { @t = arg0v.get("type").str() if t == "string" { print(arg0v.get("value").str()) } else { print(arg0v.get("value").int()) } } printed = printed + 1 if dbg == 1 { print("[json] before inc i=" + new MiniVmScan()._int_to_str(i)) } i = i + 1 if dbg == 1 { print("[json] after inc i=" + new MiniVmScan()._int_to_str(i)) } continue } if name == "itoa" { if arg0v { print(arg0v.get("value").int()) } printed = printed + 1 if dbg == 1 { print("[json] before inc i=" + new MiniVmScan()._int_to_str(i)) } i = i + 1 if dbg == 1 { print("[json] after inc i=" + new MiniVmScan()._int_to_str(i)) } continue } printed = printed + 1 if dbg == 1 { print("[json] before inc i=" + new MiniVmScan()._int_to_str(i)) } i = i + 1 if dbg == 1 { print("[json] after inc i=" + new MiniVmScan()._int_to_str(i)) } continue } if k == "Compare" { @op = expr.get("operation").str() @lhs = expr.get("lhs").get("value").get("value").int() @rhs = expr.get("rhs").get("value").get("value").int() if op == "<" { if lhs < rhs { print(1) } else { print(0) } } if op == "==" { if lhs == rhs { print(1) } else { print(0) } } if op == "<=" { if lhs <= rhs { print(1) } else { print(0) } } if op == ">" { if lhs > rhs { print(1) } else { print(0) } } if op == ">=" { if lhs >= rhs { print(1) } else { print(0) } } if op == "!=" { if lhs != rhs { print(1) } else { print(0) } } printed = printed + 1 i = i + 1 continue } if k == "BinaryOp" { @op = expr.get("operator").str() if op == "+" { @left = expr.get("left").get("value").get("value").int() @right = expr.get("right").get("value").get("value").int() print(left + right) printed = printed + 1 i = i + 1 continue } } // Unknown expression kind: treat as a no-op; do not count i = i + 1 } ok = 1 } } // Prefer plugin result whenever JSON route ran (ok==1). Even if printed==0, // return early to avoid falling back to the heuristic scanner which can loop // on malformed inputs or seam-edge cases. if dbg == 1 { print("[json] plugin_ok=" + new MiniVmScan()._int_to_str(ok) + " printed=" + new MiniVmScan()._int_to_str(printed)) } if ok == 1 { return printed } } // Fallback: text scanner(開発用) if _trace_enabled() == 1 { print("[json] fallback engaged") } local scan = new MiniVmScan() local bin = new MiniVmBinOp() local cmp = new MiniVmCompare() local pos = start local printed = 0 local guard = 0 loop (true) { guard = guard + 1 if guard > 200 { break } local k_print = "\"kind\":\"Print\"" local p = scan.index_of_from(json, k_print, pos) if p < 0 || p > end { break } // bound current Print object (coarse): use next Print marker as slice end to avoid deep brace scan local p_obj_start = scan.index_of_from(json, "{", p) // coarse slice end by next Print marker local next_p = scan.index_of_from(json, k_print, p + k_print.length()) local p_slice_end = end if next_p > 0 { p_slice_end = next_p } // avoid heavy find_balanced_object_end; use coarse p_slice_end-1 as object end local p_obj_end = p_slice_end - 1 if p_obj_start <= 0 { p_obj_end = p + k_print.length() } // Fast path: handle within [p, p_slice_end) without deep brace scans { local did = 0 // FunctionCall echo/itoa local k_fc = "\"kind\":\"FunctionCall\"" local fcp = scan.index_of_from(json, k_fc, p) if fcp > 0 { if fcp < p_slice_end { local k_name = "\"name\":\"" local npos = scan.index_of_from(json, k_name, fcp) if npos > 0 { if npos < p_slice_end { local ni = npos + k_name.length() local nj = scan.index_of_from(json, "\"", ni) if nj > 0 { if nj <= p_slice_end { local fname = json.substring(ni, nj) local k_args = "\"arguments\":[" local apos = scan.index_of_from(json, k_args, nj) if apos > 0 { if apos < p_slice_end { // quick value-based parse first (avoid type walk) { local k_sval = "\"value\":\"" local vs = scan.index_of_from(json, k_sval, apos) if vs > 0 { if vs < p_slice_end { local si = vs + k_sval.length() local sj = scan.index_of_from(json, "\"", si) if sj > 0 { if sj <= p_slice_end { local sval = json.substring(si, sj) if fname == "echo" { print(sval) printed = printed + 1 did = 1 pos = p_slice_end continue } }} }} local k_ival = "\"value\":" local vi = scan.index_of_from(json, k_ival, apos) if vi > 0 { if vi < p_slice_end { local digits = scan.read_digits(json, vi + k_ival.length()) if digits != "" { if fname == "itoa" || fname == "echo" { print(digits) printed = printed + 1 did = 1 pos = p_slice_end continue } } }} } // empty args local nwn = new MiniJsonLoader().next_non_ws(json, apos + k_args.length()) if nwn == apos + k_args.length() { if fname == "echo" { print("") printed = printed + 1 did = 1 pos = p_slice_end continue } if fname == "itoa" { print("0") printed = printed + 1 did = 1 pos = p_slice_end continue } } local k_t = "\"type\":\"" local atpos = scan.index_of_from(json, k_t, apos) if atpos > 0 { if atpos < p_slice_end { local ati = atpos + k_t.length() local atj = scan.index_of_from(json, "\"", ati) if atj > 0 { if atj <= p_slice_end { local aty = json.substring(ati, atj) if aty == "string" { local k_sval = "\"value\":\"" local svalp = scan.index_of_from(json, k_sval, atj) if svalp > 0 { if svalp < p_slice_end { local si = svalp + k_sval.length() local sj = scan.index_of_from(json, "\"", si) if sj > 0 { if sj <= p_slice_end { local sval = json.substring(si, sj) if fname == "echo" { print(sval) printed = printed + 1 did = 1 pos = p_slice_end continue } }} }} } if aty == "int" || aty == "i64" || aty == "integer" { local k_ival = "\"value\":" local ivalp = scan.index_of_from(json, k_ival, atj) if ivalp > 0 { if ivalp < p_slice_end { local digits = scan.read_digits(json, ivalp + k_ival.length()) if fname == "itoa" || fname == "echo" { print(digits) printed = printed + 1 did = 1 pos = p_slice_end continue } }} } }} } } }} }} }} }} // Compare within slice local k_cp = "\"kind\":\"Compare\"" local cpos = scan.index_of_from(json, k_cp, p) if cpos > 0 { if cpos < p_slice_end { local k_op = "\"operation\":\"" local opos = scan.index_of_from(json, k_op, cpos) if opos > 0 { if opos < p_slice_end { local oi = opos + k_op.length() local oj = scan.index_of_from(json, "\"", oi) if oj > 0 { if oj <= p_slice_end { local op = json.substring(oi, oj) local k_lhs = "\"lhs\":{\"kind\":\"Literal\"" local hl = scan.index_of_from(json, k_lhs, oj) if hl > 0 { if hl < p_slice_end { local k_v = "\"value\":" local hv = scan.index_of_from(json, k_v, hl) if hv > 0 { if hv < p_slice_end { local a = scan.read_digits(json, hv + k_v.length()) local k_rhs = "\"rhs\":{\"kind\":\"Literal\"" local hr = scan.index_of_from(json, k_rhs, hl) if hr > 0 { if hr < p_slice_end { local rv = scan.index_of_from(json, k_v, hr) if rv > 0 { if rv < p_slice_end { local b = scan.read_digits(json, rv + k_v.length()) if a && b { local ai = scan._str_to_int(a) local bi = scan._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) printed = printed + 1 did = 1 pos = p_slice_end continue } }} }} }} }} }} }} }} // BinaryOp '+' (typed ints) within slice if scan.index_of_from(json, "\"kind\":\"BinaryOp\"", p) > 0 { if scan.index_of_from(json, "\"operator\":\"+\"", p) > 0 { local k_lint = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" local k_rint = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" local lp = scan.index_of_from(json, k_lint, p) if lp > 0 { if lp < p_slice_end { local ld = scan.read_digits(json, lp + k_lint.length()) if ld != "" { local rp = scan.index_of_from(json, k_rint, lp + k_lint.length()) if rp > 0 { if rp < p_slice_end { local rd = scan.read_digits(json, rp + k_rint.length()) if rd != "" { print(new MiniVmScan()._int_to_str(new MiniVmScan()._str_to_int(ld) + new MiniVmScan()._str_to_int(rd))) printed = printed + 1 did = 1 pos = p_slice_end continue } }} } }} }} // Literal string within slice { local k_val = "\"value\":\"" local s = scan.index_of_from(json, k_val, p) if s > 0 { if s < p_slice_end { local i = s + k_val.length() local j = scan.index_of_from(json, "\"", i) if j > 0 { if j <= p_slice_end { print(json.substring(i, j)) printed = printed + 1 did = 1 pos = p_slice_end continue }} }} } // Literal int within slice { local k_tint = "\"type\":\"int\"" local tpos = scan.index_of_from(json, k_tint, p) if tpos > 0 { if tpos < p_slice_end { local k_val2 = "\"value\":" local v2 = scan.index_of_from(json, k_val2, tpos) if v2 > 0 { if v2 < p_slice_end { local digits = scan.read_digits(json, v2 + k_val2.length()) if digits != "" { print(digits) printed = printed + 1 did = 1 pos = p_slice_end continue } }} }} } if did == 1 { pos = p_slice_end + 1 continue } } // 0) BinaryOp typed/expr(重スキャン回避のため無効化。必要なら下の軽量パスを使用) // 1) BinaryOp fallbacks(開発用トグル。既定OFF) if (new MiniVmPrints()._fallback_enabled() == 1) { local nextp = bin.try_print_binop_sum_any(json, end, p) if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue } nextp = bin.try_print_binop_at(json, end, p) if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue } nextp = bin.try_print_binop_int_greedy(json, end, p) if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue } nextp = bin.try_print_binop_sum_any(json, end, p) if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue } // Inline typed sum within this Print BinaryOp('+') { local k_expr = "\"expression\":{" local epos = scan.index_of_from(json, k_expr, p) if epos > 0 { if epos < p_obj_end { if scan.index_of_from(json, "\"kind\":\"BinaryOp\"", epos) > 0 { if scan.index_of_from(json, "\"operator\":\"+\"", epos) > 0 { local k_l = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" local k_r = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" local lp = scan.index_of_from(json, k_l, epos) if lp > 0 { if lp < p_obj_end { local ld = scan.read_digits(json, lp + k_l.length()) if ld != "" { local rp = scan.index_of_from(json, k_r, lp + k_l.length()) if rp > 0 { if rp < p_obj_end { local rd = scan.read_digits(json, rp + k_r.length()) if rd != "" { print(new MiniVmScan()._int_to_str(new MiniVmScan()._str_to_int(ld) + new MiniVmScan()._str_to_int(rd))) printed = printed + 1 pos = p_obj_end + 1 continue } }} } }} } } }} } } // 2) Compare nextp = cmp.try_print_compare_at(json, end, p) if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue } // 3) FunctionCall(既定: 軽量スライス限定パスで処理済み。重い版は呼ばない) // nextp = new MiniVmPrints().try_print_functioncall_at(json, end, p) // if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue } // 4) literal string nextp = new MiniVmPrints().try_print_string_value_at(json, end, p) if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue } // 5) literal int via type(重走査を避けるため無効化。スライス限定の軽量パスで処理済み) // nextp = new MiniVmPrints().try_print_int_value_at(json, end, p) // if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue } // 5b) literal int(簡易フォールバック;既定OFF) if (new MiniVmPrints()._fallback_enabled() == 1) { local ki = "\"type\":\"int\",\"value\":" local pi = scan.index_of_from(json, ki, p) if pi > 0 { if pi < p_slice_end { local digits = scan.read_digits(json, pi + ki.length()) if digits != "" { print(digits) printed = printed + 1 pos = p_slice_end continue } }} // Unknown shape: skip this Print object entirely to avoid stalls pos = p_obj_end + 1 if pos <= p { pos = p + k_print.length() } } else { // 既定は最小前進(次の探索へ) pos = p + k_print.length() } } return printed } // Process top-level If with literal condition; print branch prints. Returns printed count. process_if_once(json) { local scan = new MiniVmScan() local k_if = "\"kind\":\"If\"" local p = scan.index_of_from(json, k_if, 0) if p < 0 { return 0 } local k_cond = "\"condition\"" local cpos = scan.index_of_from(json, k_cond, p) if cpos < 0 { return 0 } local k_val = "\"value\":" local vpos = scan.index_of_from(json, k_val, cpos) if vpos < 0 { return 0 } local val_digits = scan.read_digits(json, vpos + k_val.length()) local truthy = 0 if val_digits { if val_digits != "0" { truthy = 1 } } local k_then = "\"then_body\"" local k_else = "\"else_body\"" local bkey = k_then if truthy == 0 { bkey = k_else } local bpos = scan.index_of_from(json, bkey, cpos) if bpos < 0 { return 0 } local arr_start = scan.index_of_from(json, "[", bpos) if arr_start < 0 { return 0 } local arr_end = new MiniVmScan().find_balanced_array_end(json, arr_start) if arr_end < 0 { return 0 } return new MiniVmPrints().print_prints_in_slice(json, arr_start, arr_end) } // Print all Print-Literal values in Program.statements (string/int only; MVP) print_all_print_literals(json) { return new MiniVmPrints().print_prints_in_slice(json, 0, json.length()) } }