Files
hakorune/lang/src/vm/boxes/phi_decode_box.hako

124 lines
4.6 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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 selfhost.shared.json.utils.json_frag as JsonFragBox
using selfhost.shared.json.core.json_cursor as JsonCursorBox
using selfhost.vm.helpers.result as Result
static box PhiDecodeBox {
// tiny helpers to avoid raw quote/backslash sequences in source (preludesafe)
_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"))
}
}