124 lines
4.7 KiB
Plaintext
124 lines
4.7 KiB
Plaintext
|
|
// 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.size() - 1 // points at '['
|
|||
|
|
local i = arr_br + 1
|
|||
|
|
local endp = JsonCursorBox.seek_array_end(seg, arr_br)
|
|||
|
|
local n = seg.size()
|
|||
|
|
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"))
|
|||
|
|
}
|
|||
|
|
}
|