diff --git a/lang/src/mir/builder/internal/lower_loop_sum_bc_box.hako b/lang/src/mir/builder/internal/lower_loop_sum_bc_box.hako index 8ad2a9bc..16da1b62 100644 --- a/lang/src/mir/builder/internal/lower_loop_sum_bc_box.hako +++ b/lang/src/mir/builder/internal/lower_loop_sum_bc_box.hako @@ -72,7 +72,7 @@ static box LowerLoopSumBcBox { local kb = JsonFragBox.index_of_from(s, "\"type\":\"Break\"", k_loop) if kb >= 0 { // Find nearest previous Compare and grab rhs Int - local kbc = s.lastIndexOf("\"type\":\"Compare\"", kb) + local kbc = JsonFragBox.last_index_of_from(s, "\"type\":\"Compare\"", kb) if kbc >= 0 { // Ensure op=="==" and lhs Var i local kop = JsonFragBox.index_of_from(s, "\"op\":", kbc); local bop = null; if kop >= 0 { bop = JsonFragBox.read_string_after(s, kop + 5) } @@ -110,7 +110,7 @@ static box LowerLoopSumBcBox { { local kc = JsonFragBox.index_of_from(s, "\"type\":\"Continue\"", k_loop) if kc >= 0 { - local kcc = s.lastIndexOf("\"type\":\"Compare\"", kc) + local kcc = JsonFragBox.last_index_of_from(s, "\"type\":\"Compare\"", kc) if kcc >= 0 { local kop2 = JsonFragBox.index_of_from(s, "\"op\":", kcc); local cop = null; if kop2 >= 0 { cop = JsonFragBox.read_string_after(s, kop2 + 5) } if cop != null && cop == "==" { diff --git a/lang/src/shared/json/utils/json_frag.hako b/lang/src/shared/json/utils/json_frag.hako index 395357dc..f8640810 100644 --- a/lang/src/shared/json/utils/json_frag.hako +++ b/lang/src/shared/json/utils/json_frag.hako @@ -124,6 +124,20 @@ static box JsonFragBox { if idx < 0 { return -1 } return p2 + idx } + last_index_of_from(hay, needle, pos) { + // VM fallback: reverse search from pos backwards to start + if hay == null || needle == null { return -1 } + local s = "" + hay + local n = s.length() + local p2 = pos + if p2 < 0 { return -1 } + if p2 >= n { p2 = n - 1 } + // Extract substring from 0 to pos (inclusive) + local substr = s.substring(0, p2 + 1) + // Find last occurrence of needle in substring + local idx = substr.lastIndexOf(needle) + return idx + } read_digits(text, pos) { return StringHelpers.read_digits(text, pos) } _str_to_int(s) { return StringHelpers.to_i64(s) } _to_bool10(ch) { if ch == "t" { return 1 } if ch == "f" { return 0 } return null } diff --git a/tools/smokes/v2/profiles/quick/core/phase2211/json_frag_last_index_of_from_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2211/json_frag_last_index_of_from_canary_vm.sh new file mode 100644 index 00000000..b477fa29 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2211/json_frag_last_index_of_from_canary_vm.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# JsonFrag.last_index_of_from() canary — Loop with break/continue → expect 0+1+4 = 5 +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_json="/tmp/program_json_frag_last_index_$$.json" +cat > "$tmp_json" <<'JSON' +{ + "version": 0, + "kind": "Program", + "body": [ + { "type":"Local", "name":"i", "expr": {"type":"Int","value":0} }, + { "type":"Local", "name":"s", "expr": {"type":"Int","value":0} }, + { "type":"Loop", + "cond": {"type":"Compare","op":"<","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":5}}, + "body": [ + { "type":"If", "cond": {"type":"Compare","op":"==","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":2}}, + "then": [ { "type":"Local", "name":"i", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":1}} }, { "type":"Continue" } ], + "else": [ ] + }, + { "type":"If", "cond": {"type":"Compare","op":"==","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":3}}, + "then": [ { "type":"Break" } ], + "else": [ ] + }, + { "type":"Local", "name":"s", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"s"},"rhs":{"type":"Var","name":"i"}} }, + { "type":"Local", "name":"i", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":1}} } + ] + }, + { "type":"Return", "expr": {"type":"Var","name":"s"} } + ] +} +JSON + +set +e +HAKO_VERIFY_PRIMARY=core verify_mir_rc "$tmp_json" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_json" || true + +if [ "$rc" -eq 5 ]; then + echo "[PASS] json_frag_last_index_of_from_canary_vm" + exit 0 +fi +echo "[FAIL] json_frag_last_index_of_from_canary_vm (rc=$rc, expect 5)" >&2; exit 1