// phi_decode_box.hako — PhiDecodeBox // Responsibility: decode a minimal PHI instruction segment from JSON v0 text. // Input: seg (string for one instruction object), prev_bb (i64 of predecessor bb) // Output: [dst:int, vin:int] when resolvable; otherwise [null,null] // Non-goals: MIR execution, register I/O (caller applies values), full JSON parser. using "lang/src/shared/json/utils/json_frag.hako" as JsonFragBox using "lang/src/shared/json/json_cursor.hako" as JsonCursorBox using "lang/src/vm/boxes/result_box.hako" as Result static box PhiDecodeBox { // tiny helpers to avoid raw quote/backslash sequences in source (prelude‑safe) _dq() { return "\"" } _lb() { return "{" } _rb() { return "}" } _lsq() { return "[" } _rsq() { return "]" } // Decode single incoming (legacy/simple form): {"op":"phi","dst":D,"pred":P,"value":V} _decode_single(seg) { local dst = JsonFragBox.get_int(seg, "dst") local pred = JsonFragBox.get_int(seg, "pred") local vin = JsonFragBox.get_int(seg, "value") // single-form requires dst and value if dst == null { return { type: "err", code: "phi:invalid-object:dst-missing" } } if vin == null { return { type: "err", code: "phi:invalid-object:value-missing" } } local out = new ArrayBox() out.push(dst) out.push(vin) // pred may be null in simple form return { type: "ok", pair: out, pred: pred } } // Decode array incoming form: {"op":"phi","dst":D, "values":[ {"pred":P,"value":V}, ... ]} _decode_array(seg, prev_bb) { // Find start of values array local key = me._dq()+"values"+me._dq()+":"+me._lsq() local p = seg.indexOf(key) if p < 0 { return null } local arr_br = p + key.length() - 1 // points at '[' local i = arr_br + 1 local endp = JsonCursorBox.seek_array_end(seg, arr_br) local n = seg.length() if endp >= 0 { n = endp } local best_dst = JsonFragBox.get_int(seg, "dst") if best_dst == null { return { type: "err", code: "phi:invalid-object:dst-missing" } } // Iterate objects inside values array; pick first matching pred==prev_bb, else remember the first local chosen_v = null local fallback_v = null local valid_cnt = 0 local invalid_cnt = 0 local guard = 0 local elem_cnt = 0 loop(i < n) { guard = guard + 1 if guard > 512 { break } // seek next object head '{' local ob = JsonFragBox.index_of_from(seg, me._lb(), i) if ob < 0 || ob >= n { break } local ob_end = JsonCursorBox.seek_obj_end(seg, ob) if ob_end < 0 || ob_end > n { invalid_cnt = invalid_cnt + 1 break } elem_cnt = elem_cnt + 1 local obj = seg.substring(ob, ob_end+1) // read pred/value from object segment local pred = JsonFragBox.get_int(obj, "pred") local vin = JsonFragBox.get_int(obj, "value") if vin != null { valid_cnt = valid_cnt + 1 if fallback_v == null { fallback_v = vin } if pred != null && prev_bb != null && pred == prev_bb { chosen_v = vin i = ob_end + 1 break } } else { invalid_cnt = invalid_cnt + 1 } i = ob_end + 1 } local vin2 = chosen_v if vin2 == null { vin2 = fallback_v } if vin2 == null { // values[] present but no valid entries if elem_cnt == 0 { return { type: "err", code: "phi:no-values:empty" } } if valid_cnt == 0 { return { type: "err", code: "phi:no-values:all-malformed" } } return { type: "err", code: "phi:no-values" } } local pair = new ArrayBox() pair.push(best_dst) pair.push(vin2) return { type: "ok", pair: pair, pred: prev_bb } } // Public: decode seg into [dst, vin] using prev_bb when provided decode(seg, prev_bb) { // Prefer array form; fallback to single form local arr = me._decode_array(seg, prev_bb) if arr != null { if arr.get != null { return arr.get("pair") } // If arr is an error map, propagate by returning as-is return arr } local one = me._decode_single(seg) if one != null { if one.get != null { return one.get("pair") } return one } local out = new ArrayBox() out.push(null) out.push(null) return out } // Public: decode seg and wrap into Result.Ok([dst,vin]) or Result.Err(msg) decode_result(seg, prev_bb) { // Prefer array-form; if not present, fall back to single-form local arr = me._decode_array(seg, prev_bb) if arr != null { local typ = arr.get("type") if typ == "ok" { return Result.Ok(arr.get("pair")) } return Result.Err(arr.get("code")) } local one = me._decode_single(seg) local typ2 = one.get("type") if typ2 == "ok" { return Result.Ok(one.get("pair")) } return Result.Err(one.get("code")) } }