fix(mir): PHI検証panic修正 - update_cfg()を検証前に呼び出し
A案実装: debug_verify_phi_inputs呼び出し前にCFG predecessorを更新
修正箇所(7箇所):
- src/mir/builder/phi.rs:50, 73, 132, 143
- src/mir/builder/ops.rs:273, 328, 351
根本原因:
- Branch/Jump命令でsuccessorは即座に更新
- predecessorはupdate_cfg()で遅延再構築
- PHI検証が先に実行されてpredecessor未更新でpanic
解決策:
- 各debug_verify_phi_inputs呼び出し前に
if let Some(func) = self.current_function.as_mut() {
func.update_cfg();
}
を挿入してCFGを同期
影響: if/else文、論理演算子(&&/||)のPHI生成が正常動作
This commit is contained in:
@ -10,7 +10,7 @@ static box MapKvStringToArrayAdapter {
|
||||
// Simple scan: split by "\n"
|
||||
local i = 0
|
||||
local start = 0
|
||||
local n = s.size()
|
||||
local n = s.length()
|
||||
loop(i < n) {
|
||||
if s.substring(i, i+1) == "\n" {
|
||||
out.push(s.substring(start, i))
|
||||
|
||||
@ -8,10 +8,10 @@ static box BoxHelpers {
|
||||
// ArrayBox.size/1 の結果unwrap (MapBox-wrapped integer対応)
|
||||
array_len(arr) {
|
||||
if arr == null { return 0 }
|
||||
local size_val = call("ArrayBox.size/1", arr)
|
||||
local size_val = arr.length()
|
||||
local repr = "" + size_val
|
||||
if repr.indexOf("MapBox(") == 0 {
|
||||
local inner = call("MapBox.get/2", size_val, "value")
|
||||
local inner = size_val.get("value")
|
||||
if inner != null { return inner }
|
||||
}
|
||||
return size_val
|
||||
@ -20,19 +20,19 @@ static box BoxHelpers {
|
||||
// ArrayBox.get/2 の安全呼び出し
|
||||
array_get(arr, idx) {
|
||||
if arr == null { return null }
|
||||
return call("ArrayBox.get/2", arr, idx)
|
||||
return arr.get(idx)
|
||||
}
|
||||
|
||||
// MapBox.get/2 の安全呼び出し
|
||||
map_get(obj, key) {
|
||||
if obj == null { return null }
|
||||
return call("MapBox.get/2", obj, key)
|
||||
return obj.get(key)
|
||||
}
|
||||
|
||||
// MapBox.set/3 の安全呼び出し(形だけ統一)
|
||||
map_set(obj, key, val) {
|
||||
if obj == null { obj = new MapBox() }
|
||||
call("MapBox.set/3", obj, key, val)
|
||||
obj.set(key, val)
|
||||
return obj
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ static box BoxHelpers {
|
||||
if val == null { return 0 }
|
||||
local repr = "" + val
|
||||
if repr.indexOf("MapBox(") == 0 {
|
||||
local inner = call("MapBox.get/2", val, "value")
|
||||
local inner = val.get("value")
|
||||
if inner != null { return inner }
|
||||
}
|
||||
return val
|
||||
@ -67,53 +67,53 @@ static box BoxHelpers {
|
||||
expect_map(val, context) {
|
||||
if val == null {
|
||||
print("[BoxHelpers] expected MapBox for " + context + " but got null")
|
||||
call("MapBox.get/2", val, "__box_helpers_expect_map_null")
|
||||
val.get("__box_helpers_expect_map_null")
|
||||
return val
|
||||
}
|
||||
if me.is_map(val) == 1 { return val }
|
||||
print("[BoxHelpers] dev assert failed: expected MapBox for " + context)
|
||||
call("MapBox.get/2", val, "__box_helpers_expect_map")
|
||||
val.get("__box_helpers_expect_map")
|
||||
return val
|
||||
}
|
||||
|
||||
expect_array(val, context) {
|
||||
if val == null {
|
||||
print("[BoxHelpers] expected ArrayBox for " + context + " but got null")
|
||||
call("ArrayBox.get/2", val, 0)
|
||||
val.get(0)
|
||||
return val
|
||||
}
|
||||
if me.is_array(val) == 1 { return val }
|
||||
print("[BoxHelpers] dev assert failed: expected ArrayBox for " + context)
|
||||
call("ArrayBox.get/2", val, 0)
|
||||
val.get(0)
|
||||
return val
|
||||
}
|
||||
|
||||
expect_i64(val, context) {
|
||||
if val == null {
|
||||
print("[BoxHelpers] dev assert failed: expected i64 (non-null) for " + context)
|
||||
call("MapBox.get/2", val, "__box_helpers_expect_i64_null")
|
||||
val.get("__box_helpers_expect_i64_null")
|
||||
return 0
|
||||
}
|
||||
local repr = "" + val
|
||||
if repr.indexOf("MapBox(") == 0 {
|
||||
local ty = call("MapBox.get/2", val, "type")
|
||||
local ty = val.get("type")
|
||||
if ty != null {
|
||||
local ty_str = "" + ty
|
||||
if ty_str != "i64" && ty_str != "int" && ty_str != "integer" {
|
||||
print("[BoxHelpers] dev assert failed: unexpected type " + ty_str + " in " + context)
|
||||
call("MapBox.get/2", val, "__box_helpers_expect_i64_type")
|
||||
val.get("__box_helpers_expect_i64_type")
|
||||
return 0
|
||||
}
|
||||
}
|
||||
local inner = call("MapBox.get/2", val, "value")
|
||||
local inner = val.get("value")
|
||||
if inner != null { return StringHelpers.to_i64(inner) }
|
||||
print("[BoxHelpers] dev assert failed: missing value in " + context)
|
||||
call("MapBox.get/2", val, "__box_helpers_expect_i64_value")
|
||||
val.get("__box_helpers_expect_i64_value")
|
||||
return 0
|
||||
}
|
||||
if StringHelpers.is_numeric_str("" + val) == 1 { return StringHelpers.to_i64(val) }
|
||||
print("[BoxHelpers] dev assert failed: expected numeric value for " + context)
|
||||
call("MapBox.get/2", val, "__box_helpers_expect_i64_direct")
|
||||
val.get("__box_helpers_expect_i64_direct")
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,17 +32,17 @@ static box MiniVmBinOp {
|
||||
local k_sval = "\"value\":\""
|
||||
local lvp = scan.index_of_from(json, k_sval, lhdr)
|
||||
if lvp > 0 && lvp < obj_end {
|
||||
local li = lvp + k_sval.size()
|
||||
local li = lvp + k_sval.length()
|
||||
local lval = cur.read_quoted_from(json, li)
|
||||
if lval {
|
||||
local k_right_lit = "\"right\":{\"kind\":\"Literal\""
|
||||
local rhdr = scan.index_of_from(json, k_right_lit, li + lval.size())
|
||||
local rhdr = scan.index_of_from(json, k_right_lit, li + lval.length())
|
||||
if rhdr > 0 && rhdr < obj_end {
|
||||
local rvp = scan.index_of_from(json, k_sval, rhdr)
|
||||
if rvp > 0 && rvp < obj_end {
|
||||
local ri = rvp + k_sval.size()
|
||||
local ri = rvp + k_sval.length()
|
||||
local rval = cur.read_quoted_from(json, ri)
|
||||
if rval { print(lval + rval) return ri + rval.size() + 1 }
|
||||
if rval { print(lval + rval) return ri + rval.length() + 1 }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -55,7 +55,7 @@ static box MiniVmBinOp {
|
||||
local k_lint = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
|
||||
local li2 = scan.index_of_from(json, k_lint, opos)
|
||||
if li2 <= 0 || li2 >= obj_end { return -1 }
|
||||
local ldigits = scan.read_digits(json, li2 + k_lint.size())
|
||||
local ldigits = scan.read_digits(json, li2 + k_lint.length())
|
||||
if ldigits == "" { return -1 }
|
||||
local k_r = "\"right\":{\"kind\":\"Literal\""
|
||||
local rpos = scan.index_of_from(json, k_r, lpos)
|
||||
@ -63,7 +63,7 @@ static box MiniVmBinOp {
|
||||
local k_rint = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
|
||||
local ri2 = scan.index_of_from(json, k_rint, lpos)
|
||||
if ri2 <= 0 || ri2 >= obj_end { return -1 }
|
||||
local rdigits = scan.read_digits(json, ri2 + k_rint.size())
|
||||
local rdigits = scan.read_digits(json, ri2 + k_rint.length())
|
||||
if rdigits == "" { return -1 }
|
||||
local ai = scan._str_to_int(ldigits)
|
||||
local bi = scan._str_to_int(rdigits)
|
||||
@ -92,11 +92,11 @@ static box MiniVmBinOp {
|
||||
if scan.index_of_from(json, "\"kind\":\"BinaryOp\"", print_pos) > 0 {
|
||||
local lp = scan.index_of_from(json, k_lint, print_pos)
|
||||
if lp > 0 { if lp < slice_end {
|
||||
local ld = scan.read_digits(json, lp + k_lint.size())
|
||||
local ld = scan.read_digits(json, lp + k_lint.length())
|
||||
if ld != "" {
|
||||
local rp = scan.index_of_from(json, k_rint, lp + k_lint.size())
|
||||
local rp = scan.index_of_from(json, k_rint, lp + k_lint.length())
|
||||
if rp > 0 { if rp < slice_end {
|
||||
local rd = scan.read_digits(json, rp + k_rint.size())
|
||||
local rd = scan.read_digits(json, rp + k_rint.length())
|
||||
if rd != "" { print(scan._int_to_str(scan._str_to_int(ld) + scan._str_to_int(rd))) return 1 }
|
||||
}}
|
||||
}
|
||||
@ -117,11 +117,11 @@ static box MiniVmBinOp {
|
||||
local k_rint = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
|
||||
local lp = scan.index_of_from(json, k_lint, obj_start)
|
||||
if lp > 0 { if lp < obj_end2 {
|
||||
local ld = scan.read_digits(json, lp + k_lint.size())
|
||||
local ld = scan.read_digits(json, lp + k_lint.length())
|
||||
if ld != "" {
|
||||
local rp = scan.index_of_from(json, k_rint, lp + k_lint.size())
|
||||
local rp = scan.index_of_from(json, k_rint, lp + k_lint.length())
|
||||
if rp > 0 { if rp < obj_end2 {
|
||||
local rd = scan.read_digits(json, rp + k_rint.size())
|
||||
local rd = scan.read_digits(json, rp + k_rint.length())
|
||||
if rd != "" { print(scan._int_to_str(scan._str_to_int(ld) + scan._str_to_int(rd))) return 1 }
|
||||
}}
|
||||
}
|
||||
@ -136,11 +136,11 @@ static box MiniVmBinOp {
|
||||
local k_rint = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
|
||||
local lp = scan.index_of_from(json, k_lint, obj_start)
|
||||
if lp > 0 { if lp < obj_end {
|
||||
local ld = scan.read_digits(json, lp + k_lint.size())
|
||||
local ld = scan.read_digits(json, lp + k_lint.length())
|
||||
if ld != "" {
|
||||
local rp = scan.index_of_from(json, k_rint, lp + k_lint.size())
|
||||
local rp = scan.index_of_from(json, k_rint, lp + k_lint.length())
|
||||
if rp > 0 { if rp < obj_end {
|
||||
local rd = scan.read_digits(json, rp + k_rint.size())
|
||||
local rd = scan.read_digits(json, rp + k_rint.length())
|
||||
if rd != "" { print(scan._int_to_str(scan._str_to_int(ld) + scan._str_to_int(rd))) return 1 }
|
||||
}}
|
||||
}
|
||||
@ -155,11 +155,11 @@ static box MiniVmBinOp {
|
||||
local k_rint = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
|
||||
local lp = scan.index_of_from(json, k_lint, obj_start)
|
||||
if lp > 0 { if lp < obj_end {
|
||||
local ld = scan.read_digits(json, lp + k_lint.size())
|
||||
local ld = scan.read_digits(json, lp + k_lint.length())
|
||||
if ld != "" {
|
||||
local rp = scan.index_of_from(json, k_rint, lp + k_lint.size())
|
||||
local rp = scan.index_of_from(json, k_rint, lp + k_lint.length())
|
||||
if rp > 0 { if rp < obj_end {
|
||||
local rd = scan.read_digits(json, rp + k_rint.size())
|
||||
local rd = scan.read_digits(json, rp + k_rint.length())
|
||||
if rd != "" { print(scan._int_to_str(scan._str_to_int(ld) + scan._str_to_int(rd))) return 1 }
|
||||
}}
|
||||
}
|
||||
@ -169,17 +169,17 @@ static box MiniVmBinOp {
|
||||
local nums = []
|
||||
local i = obj_start
|
||||
loop (i < obj_end) {
|
||||
if call("String.substring/2", json, i, i+1) == "\"" {
|
||||
if json.substring(i, i+1) == "\"" {
|
||||
local j = scan.index_of_from(json, "\"", i+1)
|
||||
if j < 0 || j >= obj_end { break }
|
||||
i = j + 1
|
||||
continue
|
||||
}
|
||||
local d = scan.read_digits(json, i)
|
||||
if d { nums.push(d) i = i + d.size() continue }
|
||||
if d { nums.push(d) i = i + d.length() continue }
|
||||
i = i + 1
|
||||
}
|
||||
local nsz = nums.size()
|
||||
local nsz = nums.length()
|
||||
if nsz < 2 { return -1 }
|
||||
local a = scan._str_to_int(nums.get(nsz-2))
|
||||
local b = scan._str_to_int(nums.get(nsz-1))
|
||||
@ -209,7 +209,7 @@ static box MiniVmBinOp {
|
||||
local a = 0
|
||||
local pos = scan.index_of_from(json, k_v, obj_start)
|
||||
loop (pos > 0 && pos < obj_end) {
|
||||
local di = cur.read_digits_from(json, pos + k_v.size())
|
||||
local di = cur.read_digits_from(json, pos + k_v.length())
|
||||
if di != "" {
|
||||
if found == 0 { a = scan._str_to_int(di) found = 1 } else {
|
||||
local b = scan._str_to_int(di)
|
||||
@ -217,7 +217,7 @@ static box MiniVmBinOp {
|
||||
return obj_end + 1
|
||||
}
|
||||
}
|
||||
pos = scan.index_of_from(json, k_v, pos + k_v.size())
|
||||
pos = scan.index_of_from(json, k_v, pos + k_v.length())
|
||||
if pos <= 0 || pos >= obj_end { break }
|
||||
}
|
||||
return -1
|
||||
@ -236,19 +236,19 @@ static box MiniVmBinOp {
|
||||
local p = opos
|
||||
p = scan.index_of_from(json, k_v, p)
|
||||
if p < 0 { return -1 }
|
||||
p = scan.index_of_from(json, k_v, p + k_v.size())
|
||||
p = scan.index_of_from(json, k_v, p + k_v.length())
|
||||
if p < 0 { return -1 }
|
||||
local end1 = scan.index_of_from(json, "}", p)
|
||||
if end1 < 0 { return -1 }
|
||||
local d1 = scan.read_digits(json, p + k_v.size())
|
||||
local d1 = scan.read_digits(json, p + k_v.length())
|
||||
if d1 == "" { return -1 }
|
||||
p = scan.index_of_from(json, k_v, end1)
|
||||
if p < 0 { return -1 }
|
||||
p = scan.index_of_from(json, k_v, p + k_v.size())
|
||||
p = scan.index_of_from(json, k_v, p + k_v.length())
|
||||
if p < 0 { return -1 }
|
||||
local end2 = scan.index_of_from(json, "}", p)
|
||||
if end2 < 0 { return -1 }
|
||||
local d2 = scan.read_digits(json, p + k_v.size())
|
||||
local d2 = scan.read_digits(json, p + k_v.length())
|
||||
if d2 == "" { return -1 }
|
||||
local ai = scan._str_to_int(d1)
|
||||
local bi = scan._str_to_int(d2)
|
||||
@ -265,11 +265,11 @@ static box MiniVmBinOp {
|
||||
local k_typed = "\"type\":\"int\",\"value\":"
|
||||
local p1 = scan.index_of_from(json, k_typed, bpos)
|
||||
if p1 < 0 { return "" }
|
||||
local d1 = scan.read_digits(json, p1 + k_typed.size())
|
||||
local d1 = scan.read_digits(json, p1 + k_typed.length())
|
||||
if d1 == "" { return "" }
|
||||
local p2 = scan.index_of_from(json, k_typed, p1 + k_typed.size())
|
||||
local p2 = scan.index_of_from(json, k_typed, p1 + k_typed.length())
|
||||
if p2 < 0 { return "" }
|
||||
local d2 = scan.read_digits(json, p2 + k_typed.size())
|
||||
local d2 = scan.read_digits(json, p2 + k_typed.length())
|
||||
if d2 == "" { return "" }
|
||||
return scan._int_to_str(scan._str_to_int(d1) + scan._str_to_int(d2))
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ static box MiniVmCompare {
|
||||
local k_op = "\"operation\":\""
|
||||
local opos = scan.index_of_from(json, k_op, cpos)
|
||||
if opos <= 0 || opos >= end { return -1 }
|
||||
local oi = opos + k_op.size()
|
||||
local oi = opos + k_op.length()
|
||||
local oj = scan.index_of_from(json, "\"", oi)
|
||||
if oj <= 0 || oj > end { return -1 }
|
||||
local op = json.substring(oi, oj)
|
||||
@ -22,14 +22,14 @@ static box MiniVmCompare {
|
||||
local k_v = "\"value\":"
|
||||
local hv = scan.index_of_from(json, k_v, hl)
|
||||
if hv <= 0 || hv >= end { return -1 }
|
||||
local a = scan.read_digits(json, hv + k_v.size())
|
||||
local a = scan.read_digits(json, hv + k_v.length())
|
||||
// rhs value
|
||||
local k_rhs = "\"rhs\":{\"kind\":\"Literal\""
|
||||
local hr = scan.index_of_from(json, k_rhs, hl)
|
||||
if hr <= 0 || hr >= end { return -1 }
|
||||
local rv = scan.index_of_from(json, k_v, hr)
|
||||
if rv <= 0 || rv >= end { return -1 }
|
||||
local b = scan.read_digits(json, rv + k_v.size())
|
||||
local b = scan.read_digits(json, rv + k_v.length())
|
||||
if !a || !b { return -1 }
|
||||
local ai = scan._str_to_int(a)
|
||||
local bi = scan._str_to_int(b)
|
||||
|
||||
@ -20,10 +20,10 @@ static box MiniVmScan {
|
||||
// Linear pass: sum all numbers outside of quotes
|
||||
sum_numbers_no_quotes(json) {
|
||||
@i = 0
|
||||
@n = json.size()
|
||||
@n = json.length()
|
||||
@total = 0
|
||||
loop (i < n) {
|
||||
@ch = call("String.substring/2", json, i, i+1)
|
||||
@ch = json.substring(i, i+1)
|
||||
if ch == "\"" {
|
||||
@j = me.index_of_from(json, "\"", i+1)
|
||||
if j < 0 { break }
|
||||
@ -31,7 +31,7 @@ static box MiniVmScan {
|
||||
continue
|
||||
}
|
||||
@d = me.read_digits(json, i)
|
||||
if d { total = total + me._str_to_int(d) i = i + d.size() continue }
|
||||
if d { total = total + me._str_to_int(d) i = i + d.length() continue }
|
||||
i = i + 1
|
||||
}
|
||||
return me._int_to_str(total)
|
||||
@ -40,11 +40,11 @@ static box MiniVmScan {
|
||||
// Naive: sum all digit runs anywhere
|
||||
sum_all_digits_naive(json) {
|
||||
@i = 0
|
||||
@n = json.size()
|
||||
@n = json.length()
|
||||
@total = 0
|
||||
loop (i < n) {
|
||||
@d = me.read_digits(json, i)
|
||||
if d { total = total + me._str_to_int(d) i = i + d.size() continue }
|
||||
if d { total = total + me._str_to_int(d) i = i + d.length() continue }
|
||||
i = i + 1
|
||||
}
|
||||
return me._int_to_str(total)
|
||||
@ -53,11 +53,11 @@ static box MiniVmScan {
|
||||
// Sum first two integers outside quotes; returns string or empty
|
||||
sum_first_two_numbers(json) {
|
||||
@i = 0
|
||||
@n = json.size()
|
||||
@n = json.length()
|
||||
@total = 0
|
||||
local found = 0
|
||||
loop (i < n) {
|
||||
@ch = call("String.substring/2", json, i, i+1)
|
||||
@ch = json.substring(i, i+1)
|
||||
if ch == "\"" {
|
||||
@j = me.index_of_from(json, "\"", i+1)
|
||||
if j < 0 { break }
|
||||
@ -68,7 +68,7 @@ static box MiniVmScan {
|
||||
if d {
|
||||
total = total + me._str_to_int(d)
|
||||
found = found + 1
|
||||
i = i + d.size()
|
||||
i = i + d.length()
|
||||
if found >= 2 { return me._int_to_str(total) }
|
||||
continue
|
||||
}
|
||||
|
||||
@ -8,14 +8,14 @@ static box ModulesInspectBox {
|
||||
if path == null { return "" }
|
||||
local s = "" + path
|
||||
// Strip leading ./
|
||||
if s.size() >= 2 && s.substring(0,2) == "./" { s = s.substring(2, s.size()) }
|
||||
if s.length() >= 2 && s.substring(0,2) == "./" { s = s.substring(2, s.length()) }
|
||||
// Remove leading apps/
|
||||
local pref = "apps/"
|
||||
if s.size() >= pref.size() && s.substring(0, pref.size()) == pref { s = s.substring(pref.size(), s.size()) }
|
||||
if s.length() >= pref.length() && s.substring(0, pref.length()) == pref { s = s.substring(pref.length(), s.length()) }
|
||||
// Replace '-' with '.' in directory parts only
|
||||
local out = ""
|
||||
local i = 0
|
||||
loop(i < s.size()) {
|
||||
loop(i < s.length()) {
|
||||
local ch = s.substring(i, i+1)
|
||||
if ch == "/" { out = out + "." i = i + 1 continue }
|
||||
if ch == "-" { out = out + "." i = i + 1 continue }
|
||||
@ -23,11 +23,11 @@ static box ModulesInspectBox {
|
||||
i = i + 1
|
||||
}
|
||||
// Drop .hako and optional _box suffix
|
||||
if out.size() >= 5 && out.substring(out.size()-5, out.size()) == ".hako" {
|
||||
out = out.substring(0, out.size()-5)
|
||||
if out.length() >= 5 && out.substring(out.length()-5, out.length()) == ".hako" {
|
||||
out = out.substring(0, out.length()-5)
|
||||
}
|
||||
if out.size() >= 4 && out.substring(out.size()-4, out.size()) == "_box" {
|
||||
out = out.substring(0, out.size()-4)
|
||||
if out.length() >= 4 && out.substring(out.length()-4, out.length()) == "_box" {
|
||||
out = out.substring(0, out.length()-4)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ static box StringHelpers {
|
||||
local i = 0
|
||||
local neg = 0
|
||||
if s.substring(0,1) == "-" { neg = 1 i = 1 }
|
||||
local n = s.size()
|
||||
local n = s.length()
|
||||
if i >= n { return 0 }
|
||||
local acc = 0
|
||||
loop (i < n) {
|
||||
@ -46,7 +46,7 @@ static box StringHelpers {
|
||||
if s == null { return "\"\"" }
|
||||
local out = ""
|
||||
local i = 0
|
||||
local n = s.size()
|
||||
local n = s.length()
|
||||
loop (i < n) {
|
||||
local ch = s.substring(i, i+1)
|
||||
if ch == "\\" { out = out + "\\\\" }
|
||||
@ -65,7 +65,7 @@ static box StringHelpers {
|
||||
// Check if string is numeric-like (optional leading '-', then digits).
|
||||
is_numeric_str(s) {
|
||||
if s == null { return 0 }
|
||||
local n = s.size()
|
||||
local n = s.length()
|
||||
if n == 0 { return 0 }
|
||||
local i = 0
|
||||
if s.substring(0,1) == "-" { if n == 1 { return 0 } i = 1 }
|
||||
@ -95,8 +95,8 @@ static box StringHelpers {
|
||||
|
||||
// Pattern matching
|
||||
starts_with(src, i, pat) {
|
||||
local n = src.size()
|
||||
local m = pat.size()
|
||||
local n = src.length()
|
||||
local m = pat.length()
|
||||
if i + m > n { return 0 }
|
||||
local k = 0
|
||||
loop(k < m) {
|
||||
@ -109,8 +109,8 @@ static box StringHelpers {
|
||||
// Keyword match with word boundary (next char not [A-Za-z0-9_])
|
||||
starts_with_kw(src, i, kw) {
|
||||
if me.starts_with(src, i, kw) == 0 { return 0 }
|
||||
local n = src.size()
|
||||
local j = i + kw.size()
|
||||
local n = src.length()
|
||||
local j = i + kw.length()
|
||||
if j >= n { return 1 }
|
||||
local ch = src.substring(j, j+1)
|
||||
if me.is_alpha(ch) || me.is_digit(ch) { return 0 }
|
||||
@ -119,8 +119,8 @@ static box StringHelpers {
|
||||
|
||||
// String search
|
||||
index_of(src, i, pat) {
|
||||
local n = src.size()
|
||||
local m = pat.size()
|
||||
local n = src.length()
|
||||
local m = pat.length()
|
||||
if m == 0 { return i }
|
||||
local j = i
|
||||
loop(j + m <= n) {
|
||||
@ -133,7 +133,7 @@ static box StringHelpers {
|
||||
// Trim spaces and tabs (with optional semicolon at end)
|
||||
trim(s) {
|
||||
local i = 0
|
||||
local n = s.size()
|
||||
local n = s.length()
|
||||
loop(i < n && (s.substring(i,i+1) == " " || s.substring(i,i+1) == "\t")) { i = i + 1 }
|
||||
local j = n
|
||||
loop(j > i && (s.substring(j-1,j) == " " || s.substring(j-1,j) == "\t" || s.substring(j-1,j) == ";")) { j = j - 1 }
|
||||
@ -143,7 +143,7 @@ static box StringHelpers {
|
||||
// Skip whitespace from position i
|
||||
skip_ws(src, i) {
|
||||
if src == null { return i }
|
||||
local n = src.size()
|
||||
local n = src.length()
|
||||
local cont = 1
|
||||
local guard = 0
|
||||
local max = 100000
|
||||
@ -160,8 +160,8 @@ static box StringHelpers {
|
||||
last_index_of(src, pat) {
|
||||
if src == null { return -1 }
|
||||
if pat == null { return -1 }
|
||||
local n = src.size()
|
||||
local m = pat.size()
|
||||
local n = src.length()
|
||||
local m = pat.length()
|
||||
if m == 0 { return n }
|
||||
if m > n { return -1 }
|
||||
local i = n - m
|
||||
|
||||
@ -8,9 +8,9 @@ static box StringOps {
|
||||
index_of_from(text, needle, pos) {
|
||||
if text == null { return -1 }
|
||||
if pos < 0 { pos = 0 }
|
||||
local n = text.size()
|
||||
local n = text.length()
|
||||
if pos >= n { return -1 }
|
||||
local m = needle.size()
|
||||
local m = needle.length()
|
||||
if m <= 0 { return pos }
|
||||
local i = pos
|
||||
local limit = n - m
|
||||
|
||||
@ -10,9 +10,9 @@ static box JsonScanBox {
|
||||
// Seek the end index (inclusive) of an object starting at `start` (must be '{').
|
||||
seek_obj_end(text, start) {
|
||||
if text == null { return -1 }
|
||||
if start < 0 || start >= text.size() { return -1 }
|
||||
if call("String.substring/2", text, start, start+1) != "{" { return -1 }
|
||||
local n = text.size()
|
||||
if start < 0 || start >= text.length() { return -1 }
|
||||
if text.substring(start, start+1) != "{" { return -1 }
|
||||
local n = text.length()
|
||||
local depth = 0
|
||||
local i = start
|
||||
local in_str = 0
|
||||
@ -54,7 +54,7 @@ static box JsonScanBox {
|
||||
// Normalize start to integer (defensive against stringified input)
|
||||
local start_s = "" + start
|
||||
local start_i = me._str_to_int(start_s)
|
||||
local n = text.size()
|
||||
local n = text.length()
|
||||
if start_i < 0 || start_i >= n { return -1 }
|
||||
local first_ch = text.substring(start_i, start_i+1)
|
||||
if first_ch != "[" { return -1 }
|
||||
|
||||
@ -8,7 +8,7 @@ static box StringScanBox {
|
||||
read_char(text, i) {
|
||||
if text == null { return "" }
|
||||
if i < 0 { return "" }
|
||||
local n = text.size()
|
||||
local n = text.length()
|
||||
if i >= n { return "" }
|
||||
return text.substring(i, i+1)
|
||||
}
|
||||
@ -25,7 +25,7 @@ static box StringScanBox {
|
||||
find_unescaped(text, ch, pos) {
|
||||
if text == null { return -1 }
|
||||
if pos < 0 { pos = 0 }
|
||||
local n = text.size()
|
||||
local n = text.length()
|
||||
local i = pos
|
||||
loop (i < n) {
|
||||
local c = me.read_char(text, i)
|
||||
@ -44,10 +44,10 @@ static box StringScanBox {
|
||||
// respecting escape sequences; returns -1 if unterminated.
|
||||
scan_string_end(text, start) {
|
||||
if text == null { return -1 }
|
||||
if start < 0 || start >= text.size() { return -1 }
|
||||
if start < 0 || start >= text.length() { return -1 }
|
||||
if text.substring(start, start+1) != "\"" { return -1 }
|
||||
local i = start + 1
|
||||
local n = text.size()
|
||||
local n = text.length()
|
||||
loop (i < n) {
|
||||
local c = me.read_char(text, i)
|
||||
if c == "\\" { i = i + 2 continue }
|
||||
|
||||
@ -20,7 +20,7 @@ static box JsonCursorBox {
|
||||
digits_from(text, start_pos) {
|
||||
if text == null { return "" }
|
||||
local i = start_pos
|
||||
local n = text.size()
|
||||
local n = text.length()
|
||||
local out = ""
|
||||
if i < n {
|
||||
local ch = text.substring(i, i+1)
|
||||
|
||||
@ -10,7 +10,7 @@ static box JsonUtilsBox {
|
||||
local pattern = "\"" + key + "\""
|
||||
local idx = StringHelpers.index_of(json, 0, pattern)
|
||||
if idx < 0 { return null }
|
||||
idx = idx + pattern.size()
|
||||
idx = idx + pattern.length()
|
||||
idx = StringHelpers.skip_ws(json, idx)
|
||||
if json.substring(idx, idx + 1) != ":" { return null }
|
||||
idx = StringHelpers.skip_ws(json, idx + 1)
|
||||
@ -25,15 +25,15 @@ static box JsonUtilsBox {
|
||||
local raw = me.extract_value(json, key)
|
||||
if raw == null { return default_value }
|
||||
local trimmed = StringHelpers.trim(raw)
|
||||
if trimmed.size() >= 2 && trimmed.substring(0,1) == "\"" && trimmed.substring(trimmed.size()-1, trimmed.size()) == "\"" {
|
||||
return me.unescape_string(trimmed.substring(1, trimmed.size()-1))
|
||||
if trimmed.length() >= 2 && trimmed.substring(0,1) == "\"" && trimmed.substring(trimmed.length()-1, trimmed.length()) == "\"" {
|
||||
return me.unescape_string(trimmed.substring(1, trimmed.length()-1))
|
||||
}
|
||||
return default_value
|
||||
}
|
||||
|
||||
// Read JSON value (dispatch to appropriate reader)
|
||||
read_value(json, idx) {
|
||||
local n = json.size()
|
||||
local n = json.length()
|
||||
if idx >= n { return "@" + StringHelpers.int_to_str(idx) }
|
||||
local ch = json.substring(idx, idx + 1)
|
||||
if ch == "\"" { return me.read_string(json, idx) }
|
||||
@ -45,7 +45,7 @@ static box JsonUtilsBox {
|
||||
// Read JSON string (escape-aware) with position marker
|
||||
read_string(json, idx) {
|
||||
local i = idx + 1
|
||||
local n = json.size()
|
||||
local n = json.length()
|
||||
local done = 0
|
||||
loop(done == 0 && i < n) {
|
||||
local ch = json.substring(i, i + 1)
|
||||
@ -61,7 +61,7 @@ static box JsonUtilsBox {
|
||||
// Skip JSON string (returns end position)
|
||||
skip_string(json, idx) {
|
||||
local i = idx + 1
|
||||
local n = json.size()
|
||||
local n = json.length()
|
||||
local done = 0
|
||||
loop(done == 0 && i < n) {
|
||||
local ch = json.substring(i, i + 1)
|
||||
@ -75,7 +75,7 @@ static box JsonUtilsBox {
|
||||
read_object(json, idx) {
|
||||
local depth = 0
|
||||
local i = idx
|
||||
local n = json.size()
|
||||
local n = json.length()
|
||||
loop(i < n) {
|
||||
local ch = json.substring(i, i + 1)
|
||||
if ch == "\"" {
|
||||
@ -96,7 +96,7 @@ static box JsonUtilsBox {
|
||||
read_array(json, idx) {
|
||||
local depth = 0
|
||||
local i = idx
|
||||
local n = json.size()
|
||||
local n = json.length()
|
||||
loop(i < n) {
|
||||
local ch = json.substring(i, i + 1)
|
||||
if ch == "\"" {
|
||||
@ -115,7 +115,7 @@ static box JsonUtilsBox {
|
||||
|
||||
// Read JSON literal (number/true/false/null) with position marker
|
||||
read_literal(json, idx) {
|
||||
local n = json.size()
|
||||
local n = json.length()
|
||||
local i = idx
|
||||
loop(i < n) {
|
||||
local ch = json.substring(i, i + 1)
|
||||
@ -128,7 +128,7 @@ static box JsonUtilsBox {
|
||||
// Split JSON array at top-level commas (depth-aware, escape-aware)
|
||||
split_top_level(array_json) {
|
||||
local out = new ArrayBox()
|
||||
local n = array_json.size()
|
||||
local n = array_json.length()
|
||||
local i = 1
|
||||
local start = 1
|
||||
local depth = 0
|
||||
@ -169,7 +169,7 @@ static box JsonUtilsBox {
|
||||
if s == null { return "" }
|
||||
local out = ""
|
||||
local i = 0
|
||||
local n = s.size()
|
||||
local n = s.length()
|
||||
loop(i < n) {
|
||||
local ch = s.substring(i, i + 1)
|
||||
if ch == "\\" && i + 1 < n {
|
||||
|
||||
@ -9,7 +9,7 @@ box MirJsonBuilder2 {
|
||||
|
||||
// ---- lifecycle ----
|
||||
setup() {
|
||||
me.st = map({
|
||||
me.st = {
|
||||
buf: "",
|
||||
phase: 0,
|
||||
first_inst: 1,
|
||||
@ -19,7 +19,7 @@ box MirJsonBuilder2 {
|
||||
prefer_rebuild: 0,
|
||||
append_headers: 0,
|
||||
append_insts: 0
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ---- internal helpers ----
|
||||
@ -39,7 +39,7 @@ box MirJsonBuilder2 {
|
||||
_cur_insts() {
|
||||
local blks = me.st.get("blocks")
|
||||
if blks == null || blks.size == null { return null }
|
||||
local n = blks.size()
|
||||
local n = blks.length()
|
||||
if n <= 0 { return null }
|
||||
local idx = me.st.get("cur_block_index")
|
||||
if idx == null || idx < 0 || idx >= n { idx = n - 1 }
|
||||
@ -68,10 +68,10 @@ box MirJsonBuilder2 {
|
||||
me.st.set("phase", 3)
|
||||
me.st.set("first_inst", 1)
|
||||
// 配列側
|
||||
local blk = map({ id: id, instructions: new ArrayBox() })
|
||||
local blk = { id: id, instructions: new ArrayBox() }
|
||||
local blks = me.st.get("blocks")
|
||||
blks.push(blk)
|
||||
me.st.set("cur_block_index", blks.size() - 1)
|
||||
me.st.set("cur_block_index", blks.length() - 1)
|
||||
// 文字列側
|
||||
me._append_header("{\"id\":" + me._int_to_str(id) + ",\"instructions\":[")
|
||||
}
|
||||
@ -140,7 +140,7 @@ box MirJsonBuilder2 {
|
||||
local blks = me.st.get("blocks")
|
||||
local blocks = new ArrayBox()
|
||||
if blks != null && blks.size != null {
|
||||
local n = blks.size()
|
||||
local n = blks.length()
|
||||
local i = 0
|
||||
loop (i < n) {
|
||||
local blk = blks.get(i)
|
||||
|
||||
@ -59,11 +59,11 @@ box MirJsonBuilderMin {
|
||||
if arr_text == null { return out }
|
||||
local s = "" + arr_text
|
||||
local i = 0
|
||||
loop (i < s.size()) {
|
||||
loop (i < s.length()) {
|
||||
local ch = s.substring(i, i+1)
|
||||
if ch >= "0" && ch <= "9" {
|
||||
local j = i
|
||||
loop (j < s.size()) {
|
||||
loop (j < s.length()) {
|
||||
local cj = s.substring(j, j+1)
|
||||
if !(cj >= "0" && cj <= "9") { break }
|
||||
j = j + 1
|
||||
@ -104,9 +104,9 @@ box MirJsonBuilderMin {
|
||||
start_block(id) {
|
||||
me.phase = 3
|
||||
me.first_inst = 1
|
||||
local blk = map({ id: id, instructions: new ArrayBox() })
|
||||
local blk = { id: id, instructions: new ArrayBox() }
|
||||
me.blocks.push(blk)
|
||||
me.cur_block_index = me.blocks.size() - 1
|
||||
me.cur_block_index = me.blocks.length() - 1
|
||||
local b = "{\"id\":" + me._int_to_str(id) + ",\"instructions\":["
|
||||
return me._append(b)
|
||||
}
|
||||
@ -399,7 +399,7 @@ box MirJsonBuilderMin {
|
||||
|
||||
get_function_structure() {
|
||||
local blks = me.get_blocks_array()
|
||||
return map({ name: me.fn_name, params: new ArrayBox(), blocks: blks })
|
||||
return { name: me.fn_name, params: new ArrayBox(), blocks: blks }
|
||||
}
|
||||
|
||||
emit_to_string() { return me.to_string() }
|
||||
@ -412,7 +412,7 @@ box MirJsonBuilderMin {
|
||||
local blks_size_str = "null"
|
||||
local blks_len = BoxHelpers.array_len(blks)
|
||||
if blks_len >= 0 { blks_size_str = me._int_to_str(blks_len) }
|
||||
print("[DEBUG rebuild] fn_name=" + name + " blks.size()=" + blks_size_str)
|
||||
print("[DEBUG rebuild] fn_name=" + name + " blks.length()=" + blks_size_str)
|
||||
local out = "{\"functions\":[{\"name\":" + me._quote(name) + ",\"params\":[],\"blocks\":["
|
||||
local n = blks_len
|
||||
print("[DEBUG rebuild] n=" + me._int_to_str(n))
|
||||
|
||||
@ -34,12 +34,12 @@ static box MirJsonV1Adapter {
|
||||
local dst = 0
|
||||
if dpos >= 0 {
|
||||
local dd = me._read_digits(seg, dpos + 6)
|
||||
if dd != "" { dst = 0 + ("" + dd).size() // placeholder to avoid lints
|
||||
if dd != "" { dst = 0 + ("" + dd).length() // placeholder to avoid lints
|
||||
dst = 0 // reassign after parse
|
||||
// parse int
|
||||
local acc = 0
|
||||
local i = 0
|
||||
loop(i < dd.size()) { acc = acc * 10 + ("0123456789".indexOf(dd.substring(i,i+1))) i = i + 1 }
|
||||
loop(i < dd.length()) { acc = acc * 10 + ("0123456789".indexOf(dd.substring(i,i+1))) i = i + 1 }
|
||||
dst = acc
|
||||
}
|
||||
}
|
||||
@ -74,7 +74,7 @@ static box MirJsonV1Adapter {
|
||||
if rd != "" {
|
||||
local acc2 = 0
|
||||
local i2 = 0
|
||||
loop(i2 < rd.size()) { acc2 = acc2 * 10 + ("0123456789".indexOf(rd.substring(i2,i2+1))) i2 = i2 + 1 }
|
||||
loop(i2 < rd.length()) { acc2 = acc2 * 10 + ("0123456789".indexOf(rd.substring(i2,i2+1))) i2 = i2 + 1 }
|
||||
recv = acc2
|
||||
}
|
||||
}
|
||||
@ -109,8 +109,8 @@ static box MirJsonV1Adapter {
|
||||
if end <= start { break }
|
||||
local seg = out.substring(start, end)
|
||||
local rep = me._convert_mir_call(seg)
|
||||
out = out.substring(0, start) + rep + out.substring(end, out.size())
|
||||
cur = start + rep.size()
|
||||
out = out.substring(0, start) + rep + out.substring(end, out.length())
|
||||
cur = start + rep.length()
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
@ -9,14 +9,14 @@ static box MirV1MetaInjectBox {
|
||||
inject_meta_externs(mir_json, externs_json) {
|
||||
if mir_json == null { return null }
|
||||
local s = "" + mir_json
|
||||
if s.size() < 2 { return s }
|
||||
if s.length() < 2 { return s }
|
||||
if s.substring(0,1) != "{" { return s }
|
||||
local ext = externs_json
|
||||
if ext == null { ext = "[]" }
|
||||
if ext.size() == 0 { ext = "[]" }
|
||||
if ext.length() == 0 { ext = "[]" }
|
||||
// Construct v1 root by inserting header + metadata at the beginning
|
||||
// { <insert here> existing_without_leading_brace
|
||||
local tail = s.substring(1, s.size())
|
||||
local tail = s.substring(1, s.length())
|
||||
local head = "{\"kind\":\"MIR\",\"schema_version\":\"1.0\",\"metadata\":{\"extern_c\":" + ext + "},"
|
||||
return head + tail
|
||||
}
|
||||
|
||||
104
lang/src/shared/json/stringify.hako
Normal file
104
lang/src/shared/json/stringify.hako
Normal file
@ -0,0 +1,104 @@
|
||||
// JSON.stringify minimal stub for Stage-B compiler
|
||||
// Provides: stringify_map, stringify_array
|
||||
|
||||
static box JSON {
|
||||
// Convert Map to JSON string
|
||||
stringify_map(obj) {
|
||||
if obj == null { return "null" }
|
||||
local keys = obj.keys()
|
||||
if keys == null { return "{}" }
|
||||
local n = keys.length()
|
||||
if n == 0 { return "{}" }
|
||||
|
||||
local parts = new ArrayBox()
|
||||
local i = 0
|
||||
loop(i < n) {
|
||||
local k = keys.get(i)
|
||||
local v = obj.get(k)
|
||||
local key_json = me._escape_string(k)
|
||||
local val_json = me._value_to_json(v)
|
||||
parts.push("\"" + key_json + "\":" + val_json)
|
||||
i = i + 1
|
||||
}
|
||||
return "{" + me._join_array(parts, ",") + "}"
|
||||
}
|
||||
|
||||
// Convert Array to JSON string
|
||||
stringify_array(arr) {
|
||||
if arr == null { return "null" }
|
||||
local n = arr.length()
|
||||
if n == 0 { return "[]" }
|
||||
|
||||
local parts = new ArrayBox()
|
||||
local i = 0
|
||||
loop(i < n) {
|
||||
local v = arr.get(i)
|
||||
local val_json = me._value_to_json(v)
|
||||
parts.push(val_json)
|
||||
i = i + 1
|
||||
}
|
||||
return "[" + me._join_array(parts, ",") + "]"
|
||||
}
|
||||
|
||||
// Convert value to JSON representation
|
||||
_value_to_json(v) {
|
||||
if v == null { return "null" }
|
||||
local t = "" + v
|
||||
// Check if it's a number (starts with digit or -)
|
||||
if t.length() > 0 {
|
||||
local first = t.substring(0, 1)
|
||||
if first == "-" || (first >= "0" && first <= "9") {
|
||||
return t
|
||||
}
|
||||
}
|
||||
// Check if it's a boolean
|
||||
if t == "true" || t == "false" { return t }
|
||||
// Check if it's already a JSON object/array
|
||||
if t.length() > 0 {
|
||||
local f = t.substring(0, 1)
|
||||
if f == "{" || f == "[" { return t }
|
||||
}
|
||||
// Otherwise treat as string
|
||||
return "\"" + me._escape_string(t) + "\""
|
||||
}
|
||||
|
||||
// Escape special characters in string
|
||||
_escape_string(s) {
|
||||
if s == null { return "" }
|
||||
local out = ""
|
||||
local i = 0
|
||||
local n = s.length()
|
||||
loop(i < n) {
|
||||
local ch = s.substring(i, i + 1)
|
||||
if ch == "\"" {
|
||||
out = out + "\\\""
|
||||
} else if ch == "\\" {
|
||||
out = out + "\\\\"
|
||||
} else if ch == "\n" {
|
||||
out = out + "\\n"
|
||||
} else if ch == "\r" {
|
||||
out = out + "\\r"
|
||||
} else if ch == "\t" {
|
||||
out = out + "\\t"
|
||||
} else {
|
||||
out = out + ch
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Join array elements with separator
|
||||
_join_array(arr, sep) {
|
||||
if arr == null { return "" }
|
||||
local n = arr.length()
|
||||
if n == 0 { return "" }
|
||||
local out = arr.get(0)
|
||||
local i = 1
|
||||
loop(i < n) {
|
||||
out = out + sep + arr.get(i)
|
||||
i = i + 1
|
||||
}
|
||||
return out
|
||||
}
|
||||
}
|
||||
@ -16,7 +16,7 @@ static box JsonFragBox {
|
||||
local pat1 = "\"" + key + "\":"
|
||||
local p = me.index_of_from(seg, pat1, 0)
|
||||
if p >= 0 {
|
||||
local v = me.read_digits(seg, p + pat1.size())
|
||||
local v = me.read_digits(seg, p + pat1.length())
|
||||
if v != "" { return me._str_to_int(v) }
|
||||
}
|
||||
return null
|
||||
@ -27,7 +27,7 @@ static box JsonFragBox {
|
||||
local pat = "\"" + key + "\":\""
|
||||
local p = me.index_of_from(seg, pat, 0)
|
||||
if p >= 0 {
|
||||
local vstart = p + pat.size() // start of value (right after opening quote)
|
||||
local vstart = p + pat.length() // start of value (right after opening quote)
|
||||
local vend = JsonCursorBox.scan_string_end(seg, vstart - 1)
|
||||
if vend > vstart { return seg.substring(vstart, vend) }
|
||||
}
|
||||
@ -57,10 +57,10 @@ static box JsonFragBox {
|
||||
if mjson == null { return "" }
|
||||
// Find the instructions array start reliably
|
||||
local key = "\"instructions\":["
|
||||
local pk = call("String.indexOf/2", mjson, key)
|
||||
local pk = mjson.indexOf(key)
|
||||
if pk < 0 { return "" }
|
||||
// '[' position
|
||||
local arr_bracket = pk + key.size() - 1
|
||||
local arr_bracket = pk + key.length() - 1
|
||||
// Use escape-aware scanner to find matching ']'
|
||||
local endp = JsonCursorBox.seek_array_end(mjson, arr_bracket)
|
||||
if endp < 0 { return "" }
|
||||
|
||||
@ -9,14 +9,14 @@ static box BlockBuilderBox {
|
||||
|
||||
_array_len(arr) {
|
||||
if arr == null { return 0 }
|
||||
return StringHelpers.to_i64(call("ArrayBox.size/1", arr))
|
||||
return StringHelpers.to_i64(arr.length())
|
||||
}
|
||||
|
||||
_unwrap_vid(val) {
|
||||
if val == null { return null }
|
||||
local repr = "" + val
|
||||
if repr.indexOf("MapBox(") == 0 {
|
||||
local inner = call("MapBox.get/2", val, "value")
|
||||
local inner = val.get("value")
|
||||
if inner != null { return StringHelpers.to_i64(inner) }
|
||||
}
|
||||
return StringHelpers.to_i64(val)
|
||||
@ -25,28 +25,28 @@ static box BlockBuilderBox {
|
||||
// Ensure every block ends with a terminator (ret/jump/branch/throw)
|
||||
_ensure_terminators(mod_full) {
|
||||
if mod_full == null { return mod_full }
|
||||
local fns = call("MapBox.get/2", mod_full, "functions")
|
||||
local fns = mod_full.get("functions")
|
||||
if fns == null { return mod_full }
|
||||
local fn_count = me._array_len(fns)
|
||||
local fi = 0
|
||||
loop(fi < fn_count) {
|
||||
local func = call("ArrayBox.get/2", fns, fi)
|
||||
local func = fns.get(fi)
|
||||
if func != null {
|
||||
local blocks = call("MapBox.get/2", func, "blocks")
|
||||
local blocks = func.get("blocks")
|
||||
if blocks != null {
|
||||
local bn = me._array_len(blocks)
|
||||
local bi = 0
|
||||
loop(bi < bn) {
|
||||
local block = call("ArrayBox.get/2", blocks, bi)
|
||||
local block = blocks.get(bi)
|
||||
local insts = null
|
||||
if block != null { insts = call("MapBox.get/2", block, "instructions") }
|
||||
if block != null { insts = block.get("instructions") }
|
||||
if insts != null {
|
||||
local n = me._array_len(insts)
|
||||
if n > 0 {
|
||||
local last = call("ArrayBox.get/2", insts, n - 1)
|
||||
local last = insts.get(n - 1)
|
||||
local op = ""
|
||||
if last != null {
|
||||
local maybe_op = call("MapBox.get/2", last, "op")
|
||||
local maybe_op = last.get("op")
|
||||
if maybe_op != null { op = "" + maybe_op }
|
||||
}
|
||||
if !(op == "ret" || op == "return" || op == "jump" || op == "branch" || op == "throw") {
|
||||
@ -54,9 +54,9 @@ static box BlockBuilderBox {
|
||||
local max_vid = -1
|
||||
local last_dst = -1
|
||||
loop(idx < n) {
|
||||
local inst = call("ArrayBox.get/2", insts, idx)
|
||||
local inst = insts.get(idx)
|
||||
local dst_map = null
|
||||
if inst != null { dst_map = call("MapBox.get/2", inst, "dst") }
|
||||
if inst != null { dst_map = inst.get("dst") }
|
||||
local vid = me._unwrap_vid(dst_map)
|
||||
if vid != null {
|
||||
if vid > max_vid { max_vid = vid }
|
||||
@ -66,13 +66,13 @@ static box BlockBuilderBox {
|
||||
}
|
||||
if last_dst < 0 {
|
||||
last_dst = max_vid + 1
|
||||
call("ArrayBox.push/2", insts, MirSchemaBox.inst_const(last_dst, 0))
|
||||
insts.push(MirSchemaBox.inst_const(last_dst, 0))
|
||||
}
|
||||
call("ArrayBox.push/2", insts, MirSchemaBox.inst_ret(last_dst))
|
||||
insts.push(MirSchemaBox.inst_ret(last_dst))
|
||||
}
|
||||
} else {
|
||||
call("ArrayBox.push/2", insts, MirSchemaBox.inst_const(0, 0))
|
||||
call("ArrayBox.push/2", insts, MirSchemaBox.inst_ret(0))
|
||||
insts.push(MirSchemaBox.inst_const(0, 0))
|
||||
insts.push(MirSchemaBox.inst_ret(0))
|
||||
}
|
||||
}
|
||||
bi = bi + 1
|
||||
@ -87,10 +87,10 @@ static box BlockBuilderBox {
|
||||
const_ret(val) {
|
||||
local insts = new ArrayBox()
|
||||
// Public name route: MirSchemaBox.* helpers
|
||||
call("ArrayBox.push/2", insts, MirSchemaBox.inst_const(1, val))
|
||||
call("ArrayBox.push/2", insts, MirSchemaBox.inst_ret(1))
|
||||
insts.push(MirSchemaBox.inst_const(1, val))
|
||||
insts.push(MirSchemaBox.inst_ret(1))
|
||||
local blocks = new ArrayBox()
|
||||
call("ArrayBox.push/2", blocks, MirSchemaBox.block(0, insts))
|
||||
blocks.push(MirSchemaBox.block(0, insts))
|
||||
local module = MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
return me._ensure_terminators(module)
|
||||
}
|
||||
@ -101,9 +101,9 @@ static box BlockBuilderBox {
|
||||
local count = me._array_len(insts)
|
||||
loop(i < count) {
|
||||
if i > 0 { out = out + "," }
|
||||
local it = call("ArrayBox.get/2", insts, i)
|
||||
local it = insts.get(i)
|
||||
if it != null {
|
||||
local op = call("MapBox.get/2", it, "op")
|
||||
local op = it.get("op")
|
||||
if op != null { out = out + op } else { out = out + "?" }
|
||||
} else { out = out + "?" }
|
||||
i = i + 1
|
||||
@ -117,9 +117,9 @@ static box BlockBuilderBox {
|
||||
local count = me._array_len(blocks)
|
||||
loop(i < count) {
|
||||
if i > 0 { all = all + "|" }
|
||||
local b = call("ArrayBox.get/2", blocks, i)
|
||||
local b = blocks.get(i)
|
||||
local insts = null
|
||||
if b != null { insts = call("MapBox.get/2", b, "instructions") }
|
||||
if b != null { insts = b.get("instructions") }
|
||||
all = all + me._ops_str_from_insts(insts)
|
||||
i = i + 1
|
||||
}
|
||||
@ -136,20 +136,20 @@ static box BlockBuilderBox {
|
||||
compare_branch(lhs, rhs, cmp) {
|
||||
// entry
|
||||
local b0 = new ArrayBox()
|
||||
call("ArrayBox.push/2", b0, MirSchemaBox.inst_const(1, lhs))
|
||||
call("ArrayBox.push/2", b0, MirSchemaBox.inst_const(2, rhs))
|
||||
call("ArrayBox.push/2", b0, MirSchemaBox.inst_compare(cmp, 1, 2, 3))
|
||||
call("ArrayBox.push/2", b0, MirSchemaBox.inst_branch(3, 1, 2))
|
||||
b0.push(MirSchemaBox.inst_const(1, lhs))
|
||||
b0.push(MirSchemaBox.inst_const(2, rhs))
|
||||
b0.push(MirSchemaBox.inst_compare(cmp, 1, 2, 3))
|
||||
b0.push(MirSchemaBox.inst_branch(3, 1, 2))
|
||||
// then/else
|
||||
local b1 = new ArrayBox(); call("ArrayBox.push/2", b1, MirSchemaBox.inst_const(6, 1)); call("ArrayBox.push/2", b1, MirSchemaBox.inst_jump(3))
|
||||
local b2 = new ArrayBox(); call("ArrayBox.push/2", b2, MirSchemaBox.inst_const(6, 0)); call("ArrayBox.push/2", b2, MirSchemaBox.inst_jump(3))
|
||||
local b1 = new ArrayBox(); b1.push(MirSchemaBox.inst_const(6, 1)); b1.push(MirSchemaBox.inst_jump(3))
|
||||
local b2 = new ArrayBox(); b2.push(MirSchemaBox.inst_const(6, 0)); b2.push(MirSchemaBox.inst_jump(3))
|
||||
// merge
|
||||
local b3 = new ArrayBox(); call("ArrayBox.push/2", b3, MirSchemaBox.inst_ret(6))
|
||||
local b3 = new ArrayBox(); b3.push(MirSchemaBox.inst_ret(6))
|
||||
local blocks = new ArrayBox()
|
||||
call("ArrayBox.push/2", blocks, MirSchemaBox.block(0, b0))
|
||||
call("ArrayBox.push/2", blocks, MirSchemaBox.block(1, b1))
|
||||
call("ArrayBox.push/2", blocks, MirSchemaBox.block(2, b2))
|
||||
call("ArrayBox.push/2", blocks, MirSchemaBox.block(3, b3))
|
||||
blocks.push(MirSchemaBox.block(0, b0))
|
||||
blocks.push(MirSchemaBox.block(1, b1))
|
||||
blocks.push(MirSchemaBox.block(2, b2))
|
||||
blocks.push(MirSchemaBox.block(3, b3))
|
||||
local module = MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
return me._ensure_terminators(module)
|
||||
}
|
||||
@ -157,11 +157,11 @@ static box BlockBuilderBox {
|
||||
// binop: const lhs/rhs; binop -> dst=3; ret 3
|
||||
binop(lhs, rhs, opk) {
|
||||
local b0 = new ArrayBox()
|
||||
call("ArrayBox.push/2", b0, MirSchemaBox.inst_const(1, lhs))
|
||||
call("ArrayBox.push/2", b0, MirSchemaBox.inst_const(2, rhs))
|
||||
call("ArrayBox.push/2", b0, MirSchemaBox.inst_binop(opk, 1, 2, 3))
|
||||
call("ArrayBox.push/2", b0, MirSchemaBox.inst_ret(3))
|
||||
local blocks = new ArrayBox(); call("ArrayBox.push/2", blocks, MirSchemaBox.block(0, b0))
|
||||
b0.push(MirSchemaBox.inst_const(1, lhs))
|
||||
b0.push(MirSchemaBox.inst_const(2, rhs))
|
||||
b0.push(MirSchemaBox.inst_binop(opk, 1, 2, 3))
|
||||
b0.push(MirSchemaBox.inst_ret(3))
|
||||
local blocks = new ArrayBox(); blocks.push(MirSchemaBox.block(0, b0))
|
||||
local module = MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
return me._ensure_terminators(module)
|
||||
}
|
||||
@ -181,12 +181,12 @@ static box BlockBuilderBox {
|
||||
|
||||
// loop_counter: while (i < limit) { i = i + 1 } ; return i
|
||||
loop_counter(limit) {
|
||||
local b0 = new ArrayBox(); call("ArrayBox.push/2", b0, MirSchemaBox.inst_const(1, 0)); call("ArrayBox.push/2", b0, MirSchemaBox.inst_const(2, limit)); call("ArrayBox.push/2", b0, MirSchemaBox.inst_const(4, 1)); call("ArrayBox.push/2", b0, MirSchemaBox.inst_jump(1))
|
||||
local b1 = new ArrayBox(); call("ArrayBox.push/2", b1, MirSchemaBox.inst_compare("Lt", 1, 2, 3)); call("ArrayBox.push/2", b1, MirSchemaBox.inst_branch(3, 2, 3))
|
||||
local b2 = new ArrayBox(); call("ArrayBox.push/2", b2, MirSchemaBox.inst_binop("Add", 1, 4, 1)); call("ArrayBox.push/2", b2, MirSchemaBox.inst_jump(1))
|
||||
local b3 = new ArrayBox(); call("ArrayBox.push/2", b3, MirSchemaBox.inst_ret(1))
|
||||
local b0 = new ArrayBox(); b0.push(MirSchemaBox.inst_const(1, 0)); b0.push(MirSchemaBox.inst_const(2, limit)); b0.push(MirSchemaBox.inst_const(4, 1)); b0.push(MirSchemaBox.inst_jump(1))
|
||||
local b1 = new ArrayBox(); b1.push(MirSchemaBox.inst_compare("Lt", 1, 2, 3)); b1.push(MirSchemaBox.inst_branch(3, 2, 3))
|
||||
local b2 = new ArrayBox(); b2.push(MirSchemaBox.inst_binop("Add", 1, 4, 1)); b2.push(MirSchemaBox.inst_jump(1))
|
||||
local b3 = new ArrayBox(); b3.push(MirSchemaBox.inst_ret(1))
|
||||
local blocks = new ArrayBox();
|
||||
call("ArrayBox.push/2", blocks, MirSchemaBox.block(0, b0)); call("ArrayBox.push/2", blocks, MirSchemaBox.block(1, b1)); call("ArrayBox.push/2", blocks, MirSchemaBox.block(2, b2)); call("ArrayBox.push/2", blocks, MirSchemaBox.block(3, b3))
|
||||
blocks.push(MirSchemaBox.block(0, b0)); blocks.push(MirSchemaBox.block(1, b1)); blocks.push(MirSchemaBox.block(2, b2)); blocks.push(MirSchemaBox.block(3, b3))
|
||||
local module = MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
return me._ensure_terminators(module)
|
||||
}
|
||||
@ -281,21 +281,21 @@ static box BlockBuilderBox {
|
||||
local m = 0
|
||||
if arg_vals != null { m = me._array_len(arg_vals) }
|
||||
loop(i < m) {
|
||||
call("ArrayBox.push/2", insts, MirSchemaBox.inst_const(i, call("ArrayBox.get/2", arg_vals, i)))
|
||||
insts.push(MirSchemaBox.inst_const(i, arg_vals.get(i)))
|
||||
i = i + 1
|
||||
}
|
||||
n = m
|
||||
local args_ids = new ArrayBox()
|
||||
i = 0
|
||||
loop(i < n) {
|
||||
call("ArrayBox.push/2", args_ids, i)
|
||||
args_ids.push(i)
|
||||
i = i + 1
|
||||
}
|
||||
local dst = n
|
||||
call("ArrayBox.push/2", insts, MirSchemaBox.inst_mir_call_extern(actual_name, args_ids, dst))
|
||||
call("ArrayBox.push/2", insts, MirSchemaBox.inst_ret(dst))
|
||||
insts.push(MirSchemaBox.inst_mir_call_extern(actual_name, args_ids, dst))
|
||||
insts.push(MirSchemaBox.inst_ret(dst))
|
||||
local blocks = new ArrayBox()
|
||||
call("ArrayBox.push/2", blocks, MirSchemaBox.block(0, insts))
|
||||
blocks.push(MirSchemaBox.block(0, insts))
|
||||
local _m = MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
return me._ensure_terminators(_m)
|
||||
}
|
||||
@ -313,38 +313,38 @@ static box BlockBuilderBox {
|
||||
if arg_vals != null { m = me._array_len(arg_vals) }
|
||||
local i = 0
|
||||
loop(i < m) {
|
||||
call("ArrayBox.push/2", insts, MirSchemaBox.inst_const(i, call("ArrayBox.get/2", arg_vals, i)))
|
||||
insts.push(MirSchemaBox.inst_const(i, arg_vals.get(i)))
|
||||
i = i + 1
|
||||
}
|
||||
local args_ids = new ArrayBox()
|
||||
i = 0
|
||||
loop(i < m) {
|
||||
call("ArrayBox.push/2", args_ids, i)
|
||||
args_ids.push(i)
|
||||
i = i + 1
|
||||
}
|
||||
local dst = m
|
||||
call("ArrayBox.push/2", insts, MirSchemaBox.inst_mir_call_global(actual_name, args_ids, dst))
|
||||
call("ArrayBox.push/2", insts, MirSchemaBox.inst_ret(dst))
|
||||
insts.push(MirSchemaBox.inst_mir_call_global(actual_name, args_ids, dst))
|
||||
insts.push(MirSchemaBox.inst_ret(dst))
|
||||
local blocks = new ArrayBox()
|
||||
call("ArrayBox.push/2", blocks, MirSchemaBox.block(0, insts))
|
||||
blocks.push(MirSchemaBox.block(0, insts))
|
||||
local _m = MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
return me._ensure_terminators(_m)
|
||||
}
|
||||
|
||||
method_call_ival_ret(method, recv_val, arg_vals, method_literal) {
|
||||
local insts = new ArrayBox()
|
||||
call("ArrayBox.push/2", insts, MirSchemaBox.inst_const(0, recv_val))
|
||||
insts.push(MirSchemaBox.inst_const(0, recv_val))
|
||||
local m = 0
|
||||
if arg_vals != null { m = me._array_len(arg_vals) }
|
||||
local i = 0
|
||||
loop(i < m) {
|
||||
call("ArrayBox.push/2", insts, MirSchemaBox.inst_const(1 + i, call("ArrayBox.get/2", arg_vals, i)))
|
||||
insts.push(MirSchemaBox.inst_const(1 + i, arg_vals.get(i)))
|
||||
i = i + 1
|
||||
}
|
||||
local args_ids = new ArrayBox()
|
||||
i = 0
|
||||
loop(i < m) {
|
||||
call("ArrayBox.push/2", args_ids, 1 + i)
|
||||
args_ids.push(1 + i)
|
||||
i = i + 1
|
||||
}
|
||||
local dst = 1 + m
|
||||
@ -355,10 +355,10 @@ static box BlockBuilderBox {
|
||||
actual_method = method_literal
|
||||
}
|
||||
}
|
||||
call("ArrayBox.push/2", insts, MirSchemaBox.inst_mir_call_method(actual_method, 0, args_ids, dst))
|
||||
call("ArrayBox.push/2", insts, MirSchemaBox.inst_ret(dst))
|
||||
insts.push(MirSchemaBox.inst_mir_call_method(actual_method, 0, args_ids, dst))
|
||||
insts.push(MirSchemaBox.inst_ret(dst))
|
||||
local blocks = new ArrayBox()
|
||||
call("ArrayBox.push/2", blocks, MirSchemaBox.block(0, insts))
|
||||
blocks.push(MirSchemaBox.block(0, insts))
|
||||
local _m = MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
return me._ensure_terminators(_m)
|
||||
}
|
||||
@ -369,13 +369,13 @@ static box BlockBuilderBox {
|
||||
if arg_vals != null { m = me._array_len(arg_vals) }
|
||||
local i = 0
|
||||
loop(i < m) {
|
||||
call("ArrayBox.push/2", insts, MirSchemaBox.inst_const(i, call("ArrayBox.get/2", arg_vals, i)))
|
||||
insts.push(MirSchemaBox.inst_const(i, arg_vals.get(i)))
|
||||
i = i + 1
|
||||
}
|
||||
local args_ids = new ArrayBox()
|
||||
i = 0
|
||||
loop(i < m) {
|
||||
call("ArrayBox.push/2", args_ids, i)
|
||||
args_ids.push(i)
|
||||
i = i + 1
|
||||
}
|
||||
local dst = m
|
||||
@ -386,10 +386,10 @@ static box BlockBuilderBox {
|
||||
actual_box_type = box_type_literal
|
||||
}
|
||||
}
|
||||
call("ArrayBox.push/2", insts, MirSchemaBox.inst_mir_call_constructor(actual_box_type, args_ids, dst))
|
||||
call("ArrayBox.push/2", insts, MirSchemaBox.inst_ret(dst))
|
||||
insts.push(MirSchemaBox.inst_mir_call_constructor(actual_box_type, args_ids, dst))
|
||||
insts.push(MirSchemaBox.inst_ret(dst))
|
||||
local blocks = new ArrayBox()
|
||||
call("ArrayBox.push/2", blocks, MirSchemaBox.block(0, insts))
|
||||
blocks.push(MirSchemaBox.block(0, insts))
|
||||
local _m = MirSchemaBox.module(MirSchemaBox.fn_main(blocks))
|
||||
return me._ensure_terminators(_m)
|
||||
}
|
||||
|
||||
@ -8,27 +8,27 @@ static box JsonEmitBox {
|
||||
_expect_map(val, context) {
|
||||
if BoxHelpers.is_map(val) == 1 { return val }
|
||||
print("[JsonEmitBox] dev assert failed: expected MapBox for " + context)
|
||||
call("MapBox.get/2", val, "__json_emit_expect_map")
|
||||
val.get("__json_emit_expect_map")
|
||||
return val
|
||||
}
|
||||
_expect_array(val, context) {
|
||||
if BoxHelpers.is_array(val) == 1 { return val }
|
||||
print("[JsonEmitBox] dev assert failed: expected ArrayBox for " + context)
|
||||
call("ArrayBox.get/2", val, 0)
|
||||
val.get(0)
|
||||
return val
|
||||
}
|
||||
_expect_i64(val, context) {
|
||||
if val == null {
|
||||
print("[JsonEmitBox] dev assert failed: expected i64 (non-null) for " + context)
|
||||
call("MapBox.get/2", val, "__json_emit_expect_i64_null")
|
||||
val.get("__json_emit_expect_i64_null")
|
||||
return 0
|
||||
}
|
||||
local repr = "" + val
|
||||
if repr.indexOf("MapBox(") == 0 {
|
||||
local inner = call("MapBox.get/2", val, "value")
|
||||
local inner = val.get("value")
|
||||
if inner != null { return inner }
|
||||
print("[JsonEmitBox] dev assert failed: missing value in " + context)
|
||||
call("MapBox.get/2", val, "__json_emit_expect_i64_value")
|
||||
val.get("__json_emit_expect_i64_value")
|
||||
return 0
|
||||
}
|
||||
# Assume numeric immediate; avoid module function coercion for safety
|
||||
@ -53,7 +53,7 @@ static box JsonEmitBox {
|
||||
}
|
||||
_emit_vid_array_rec(arr, idx, len) {
|
||||
if idx >= len { return "" }
|
||||
local head = me._emit_vid_or_null(call("ArrayBox.get/2", arr, idx))
|
||||
local head = me._emit_vid_or_null(arr.get(idx))
|
||||
local tail = me._emit_vid_array_rec(arr, idx + 1, len)
|
||||
if tail == "" { return head }
|
||||
return head + "," + tail
|
||||
@ -66,7 +66,7 @@ static box JsonEmitBox {
|
||||
}
|
||||
_emit_effects_rec(effects, idx, len) {
|
||||
if idx >= len { return "" }
|
||||
local head = me._quote(call("ArrayBox.get/2", effects, idx))
|
||||
local head = me._quote(effects.get(idx))
|
||||
local tail = me._emit_effects_rec(effects, idx + 1, len)
|
||||
if tail == "" { return head }
|
||||
return head + "," + tail
|
||||
@ -75,30 +75,30 @@ static box JsonEmitBox {
|
||||
_emit_callee(callee) {
|
||||
if callee == null { return "{\"type\":\"Extern\",\"name\":\"\"}" }
|
||||
callee = me._expect_map(callee, "mir_call.callee")
|
||||
local ty_box = call("MapBox.get/2", callee, "type")
|
||||
local ty_box = callee.get("type")
|
||||
local ty = ""
|
||||
if ty_box != null { ty = "" + ty_box }
|
||||
if ty == "Extern" {
|
||||
local name = call("MapBox.get/2", callee, "name")
|
||||
local name = callee.get("name")
|
||||
if name == null { name = "" }
|
||||
return "{\"type\":\"Extern\",\"name\":" + me._quote(name) + "}"
|
||||
}
|
||||
if ty == "ModuleFunction" {
|
||||
local name = call("MapBox.get/2", callee, "name")
|
||||
local name = callee.get("name")
|
||||
if name == null { name = "" }
|
||||
return "{\"type\":\"ModuleFunction\",\"name\":" + me._quote(name) + "}"
|
||||
}
|
||||
if ty == "Method" {
|
||||
local box_name = call("MapBox.get/2", callee, "box_name")
|
||||
local box_name = callee.get("box_name")
|
||||
if box_name == null { box_name = "" }
|
||||
local method = call("MapBox.get/2", callee, "method")
|
||||
local method = callee.get("method")
|
||||
if method == null { method = "" }
|
||||
local receiver = call("MapBox.get/2", callee, "receiver")
|
||||
local receiver = callee.get("receiver")
|
||||
return "{\"type\":\"Method\",\"box_name\":" + me._quote(box_name) +
|
||||
",\"method\":" + me._quote(method) + ",\"receiver\":" + me._emit_vid_or_null(receiver) + "}"
|
||||
}
|
||||
if ty == "Constructor" {
|
||||
local box_type = call("MapBox.get/2", callee, "box_type")
|
||||
local box_type = callee.get("box_type")
|
||||
if box_type == null { box_type = "" }
|
||||
return "{\"type\":\"Constructor\",\"box_type\":" + me._quote(box_type) + "}"
|
||||
}
|
||||
@ -111,9 +111,9 @@ static box JsonEmitBox {
|
||||
local inner = val
|
||||
local repr = "" + val
|
||||
if repr.indexOf("MapBox(") == 0 {
|
||||
local ty_box = call("MapBox.get/2", val, "type")
|
||||
local ty_box = val.get("type")
|
||||
if ty_box != null { ty = "" + ty_box }
|
||||
local inner_box = call("MapBox.get/2", val, "value")
|
||||
local inner_box = val.get("value")
|
||||
if inner_box != null { inner = inner_box }
|
||||
}
|
||||
return "{\"type\":" + me._quote(ty) + ",\"value\":" + me._int_str(inner) + "}"
|
||||
@ -131,12 +131,12 @@ static box JsonEmitBox {
|
||||
}
|
||||
_emit_phi_rec(values, idx, len) {
|
||||
if idx >= len { return "" }
|
||||
local item = call("ArrayBox.get/2", values, idx)
|
||||
local item = values.get(idx)
|
||||
local block_id = null
|
||||
local value_id = null
|
||||
if item != null {
|
||||
block_id = call("MapBox.get/2", item, "block")
|
||||
value_id = call("MapBox.get/2", item, "value")
|
||||
block_id = item.get("block")
|
||||
value_id = item.get("value")
|
||||
}
|
||||
local head = "{\"block\":" + me._int_str(block_id) + ",\"value\":" + me._int_str(value_id) + "}"
|
||||
local tail = me._emit_phi_rec(values, idx + 1, len)
|
||||
@ -147,51 +147,51 @@ static box JsonEmitBox {
|
||||
_emit_inst(inst) {
|
||||
if inst == null { return "{}" }
|
||||
inst = me._expect_map(inst, "instruction")
|
||||
local op = call("MapBox.get/2", inst, "op")
|
||||
local op = inst.get("op")
|
||||
if op == null { op = "" }
|
||||
if op == "const" {
|
||||
return "{\"op\":\"const\",\"dst\":" + me._int_str(call("MapBox.get/2", inst, "dst")) +
|
||||
",\"value\":" + me._emit_box_value(call("MapBox.get/2", inst, "value")) + "}"
|
||||
return "{\"op\":\"const\",\"dst\":" + me._int_str(inst.get("dst")) +
|
||||
",\"value\":" + me._emit_box_value(inst.get("value")) + "}"
|
||||
}
|
||||
if op == "ret" || op == "return" {
|
||||
return "{\"op\":\"ret\",\"value\":" + me._int_str(call("MapBox.get/2", inst, "value")) + "}"
|
||||
return "{\"op\":\"ret\",\"value\":" + me._int_str(inst.get("value")) + "}"
|
||||
}
|
||||
if op == "binop" {
|
||||
local kind = call("MapBox.get/2", inst, "op_kind")
|
||||
local kind = inst.get("op_kind")
|
||||
if kind == null { kind = "" }
|
||||
return "{\"op\":\"binop\",\"op_kind\":" + me._quote(kind) + ",\"lhs\":" +
|
||||
me._int_str(call("MapBox.get/2", inst, "lhs")) + ",\"rhs\":" + me._int_str(call("MapBox.get/2", inst, "rhs")) +
|
||||
",\"dst\":" + me._int_str(call("MapBox.get/2", inst, "dst")) + "}"
|
||||
me._int_str(inst.get("lhs")) + ",\"rhs\":" + me._int_str(inst.get("rhs")) +
|
||||
",\"dst\":" + me._int_str(inst.get("dst")) + "}"
|
||||
}
|
||||
if op == "compare" {
|
||||
local cmp = call("MapBox.get/2", inst, "cmp")
|
||||
local cmp = inst.get("cmp")
|
||||
if cmp == null { cmp = "" }
|
||||
return "{\"op\":\"compare\",\"cmp\":" + me._quote(cmp) + ",\"lhs\":" +
|
||||
me._int_str(call("MapBox.get/2", inst, "lhs")) + ",\"rhs\":" + me._int_str(call("MapBox.get/2", inst, "rhs")) +
|
||||
",\"dst\":" + me._int_str(call("MapBox.get/2", inst, "dst")) + "}"
|
||||
me._int_str(inst.get("lhs")) + ",\"rhs\":" + me._int_str(inst.get("rhs")) +
|
||||
",\"dst\":" + me._int_str(inst.get("dst")) + "}"
|
||||
}
|
||||
if op == "branch" {
|
||||
return "{\"op\":\"branch\",\"cond\":" + me._int_str(call("MapBox.get/2", inst, "cond")) +
|
||||
",\"then\":" + me._int_str(call("MapBox.get/2", inst, "then")) +
|
||||
",\"else\":" + me._int_str(call("MapBox.get/2", inst, "else")) + "}"
|
||||
return "{\"op\":\"branch\",\"cond\":" + me._int_str(inst.get("cond")) +
|
||||
",\"then\":" + me._int_str(inst.get("then")) +
|
||||
",\"else\":" + me._int_str(inst.get("else")) + "}"
|
||||
}
|
||||
if op == "jump" {
|
||||
return "{\"op\":\"jump\",\"target\":" + me._int_str(call("MapBox.get/2", inst, "target")) + "}"
|
||||
return "{\"op\":\"jump\",\"target\":" + me._int_str(inst.get("target")) + "}"
|
||||
}
|
||||
if op == "phi" {
|
||||
return "{\"op\":\"phi\",\"dst\":" + me._int_str(call("MapBox.get/2", inst, "dst")) +
|
||||
",\"values\":" + me._emit_phi_values(call("MapBox.get/2", inst, "values")) + "}"
|
||||
return "{\"op\":\"phi\",\"dst\":" + me._int_str(inst.get("dst")) +
|
||||
",\"values\":" + me._emit_phi_values(inst.get("values")) + "}"
|
||||
}
|
||||
if op == "mir_call" {
|
||||
// SSOT: payload("mir_call") のみを受理。トップレベルの互換フィールドは読まない。
|
||||
local payload = call("MapBox.get/2", inst, "mir_call")
|
||||
local payload = inst.get("mir_call")
|
||||
if payload == null { return "{\"op\":\"mir_call\"}" }
|
||||
payload = me._expect_map(payload, "mir_call payload")
|
||||
local dst_json = me._emit_vid_or_null(call("MapBox.get/2", inst, "dst"))
|
||||
local callee_json = me._emit_callee(call("MapBox.get/2", payload, "callee"))
|
||||
local args_box = call("MapBox.get/2", payload, "args")
|
||||
local dst_json = me._emit_vid_or_null(inst.get("dst"))
|
||||
local callee_json = me._emit_callee(payload.get("callee"))
|
||||
local args_box = payload.get("args")
|
||||
me._expect_array(args_box, "mir_call.args")
|
||||
local effects_box = call("MapBox.get/2", payload, "effects")
|
||||
local effects_box = payload.get("effects")
|
||||
me._expect_array(effects_box, "mir_call.effects")
|
||||
local args_json = me._emit_vid_array(args_box)
|
||||
local effects_json = me._emit_effects(effects_box)
|
||||
@ -206,17 +206,17 @@ static box JsonEmitBox {
|
||||
|
||||
_emit_block(block) {
|
||||
if block == null { return "{\"id\":0,\"instructions\":[]}" }
|
||||
local insts = call("MapBox.get/2", block, "instructions")
|
||||
local insts = block.get("instructions")
|
||||
if insts == null {
|
||||
return "{\"id\":" + me._int_str(call("MapBox.get/2", block, "id")) + ",\"instructions\":[]}"
|
||||
return "{\"id\":" + me._int_str(block.get("id")) + ",\"instructions\":[]}"
|
||||
}
|
||||
local n = BoxHelpers.array_len(insts)
|
||||
local body = me._emit_block_rec(insts, 0, n)
|
||||
return "{\"id\":" + me._int_str(call("MapBox.get/2", block, "id")) + ",\"instructions\":[" + body + "]}"
|
||||
return "{\"id\":" + me._int_str(block.get("id")) + ",\"instructions\":[" + body + "]}"
|
||||
}
|
||||
_emit_block_rec(insts, idx, len) {
|
||||
if idx >= len { return "" }
|
||||
local head = me._emit_inst(call("ArrayBox.get/2", insts, idx))
|
||||
local head = me._emit_inst(insts.get(idx))
|
||||
local tail = me._emit_block_rec(insts, idx + 1, len)
|
||||
if tail == "" { return head }
|
||||
return head + "," + tail
|
||||
@ -226,12 +226,12 @@ static box JsonEmitBox {
|
||||
if func == null {
|
||||
return "{\"name\":\"main\",\"blocks\":[]}"
|
||||
}
|
||||
local name = call("MapBox.get/2", func, "name")
|
||||
local name = func.get("name")
|
||||
if name == null { name = "main" }
|
||||
// Optional fields: params (array) / flags (map)
|
||||
local params = call("MapBox.get/2", func, "params")
|
||||
local flags = call("MapBox.get/2", func, "flags")
|
||||
local blocks = call("MapBox.get/2", func, "blocks")
|
||||
local params = func.get("params")
|
||||
local flags = func.get("flags")
|
||||
local blocks = func.get("blocks")
|
||||
if blocks == null {
|
||||
if params != null || flags != null {
|
||||
local head = "{\"name\":" + me._quote(name)
|
||||
@ -250,7 +250,7 @@ static box JsonEmitBox {
|
||||
}
|
||||
_emit_function_rec(blocks, idx, len) {
|
||||
if idx >= len { return "" }
|
||||
local head = me._emit_block(call("ArrayBox.get/2", blocks, idx))
|
||||
local head = me._emit_block(blocks.get(idx))
|
||||
local tail = me._emit_function_rec(blocks, idx + 1, len)
|
||||
if tail == "" { return head }
|
||||
return head + "," + tail
|
||||
@ -259,7 +259,7 @@ static box JsonEmitBox {
|
||||
to_json(module) {
|
||||
if module == null { return "" }
|
||||
// Prefer single-function fallbackを強化: has() 未実装環境でも repr チェックで検出
|
||||
local f0 = call("MapBox.get/2", module, "functions_0")
|
||||
local f0 = module.get("functions_0")
|
||||
if f0 != null {
|
||||
local repr = "" + f0
|
||||
if repr.indexOf("MapBox(") == 0 || repr.indexOf("HostHandleBox(") == 0 {
|
||||
@ -268,7 +268,7 @@ static box JsonEmitBox {
|
||||
}
|
||||
}
|
||||
// Legacy path: try functions array if available
|
||||
local funcs = call("MapBox.get/2", module, "functions")
|
||||
local funcs = module.get("functions")
|
||||
if funcs == null { return "{\"kind\":\"MIR\",\"schema_version\":\"1.0\",\"functions\":[]}" }
|
||||
local n = BoxHelpers.array_len(funcs)
|
||||
local body = me._emit_module_rec(funcs, 0, n)
|
||||
@ -278,11 +278,11 @@ static box JsonEmitBox {
|
||||
// Defensive fallback: some environments report size=0 for host-managed arrays.
|
||||
// If len==0 at entry, try to probe index 0 once to recover a single element.
|
||||
if idx == 0 && len == 0 {
|
||||
local first = call("ArrayBox.get/2", funcs, 0)
|
||||
local first = funcs.get(0)
|
||||
if first != null { len = 1 }
|
||||
}
|
||||
if idx >= len { return "" }
|
||||
local head = me._emit_function(call("ArrayBox.get/2", funcs, idx))
|
||||
local head = me._emit_function(funcs.get(idx))
|
||||
local tail = me._emit_module_rec(funcs, idx + 1, len)
|
||||
if tail == "" { return head }
|
||||
return head + "," + tail
|
||||
|
||||
@ -24,8 +24,8 @@ static box MirIoBox {
|
||||
_provider_gate_on() {
|
||||
// Accept HAKO_JSON_PROVIDER or NYASH_JSON_PROVIDER (alias). Value: 'yyjson'
|
||||
// Use extern env.local.get to avoid direct field access to `env`.
|
||||
local v = call("env.local.get/1", "HAKO_JSON_PROVIDER")
|
||||
if v == null || v == "" { v = call("env.local.get/1", "NYASH_JSON_PROVIDER") }
|
||||
local v = env.get("HAKO_JSON_PROVIDER")
|
||||
if v == null || v == "" { v = env.get("NYASH_JSON_PROVIDER") }
|
||||
if v == null || v == "" { return 0 }
|
||||
if v == "yyjson" || v == "YYJSON" { return 1 }
|
||||
return 0
|
||||
@ -141,9 +141,9 @@ static box MirIoBox {
|
||||
local key_id = "\"id\":"
|
||||
local p = obj.indexOf(key_id)
|
||||
if p < 0 { return Result.Err("block id missing") }
|
||||
p = p + key_id.size()
|
||||
p = p + key_id.length()
|
||||
// skip ws
|
||||
loop(p < obj.size()) { local ch = obj.substring(p,p+1) if ch == " " || ch == "\n" || ch == "\r" || ch == "\t" { p = p + 1 continue } break }
|
||||
loop(p < obj.length()) { local ch = obj.substring(p,p+1) if ch == " " || ch == "\n" || ch == "\r" || ch == "\t" { p = p + 1 continue } break }
|
||||
local digs = StringHelpers.read_digits(obj, p)
|
||||
if digs == "" { return Result.Err("invalid block id") }
|
||||
ids.set(StringHelpers.int_to_str(StringHelpers.to_i64(digs)), 1)
|
||||
@ -161,7 +161,7 @@ static box MirIoBox {
|
||||
// extract terminator object
|
||||
local ts = obj.indexOf("\"terminator\":{")
|
||||
if ts < 0 { return Result.Err("terminator missing") }
|
||||
local te = ts + "\"terminator\":".size()
|
||||
local te = ts + "\"terminator\":".length()
|
||||
// naive: use general locator to get terminator via instructions fallback if needed
|
||||
local term = me.terminator(obj)
|
||||
if term.is_Err() { return Result.Err("terminator parse failed") }
|
||||
@ -170,9 +170,9 @@ static box MirIoBox {
|
||||
local k = "\"op\""
|
||||
local p2 = tj.indexOf(k)
|
||||
if p2 < 0 { return Result.Err("terminator op not found") }
|
||||
p2 = p2 + k.size()
|
||||
loop(p2 < tj.size()) { local ch2 = tj.substring(p2,p2+1) if ch2 == ":" { p2 = p2 + 1 break } if ch2 == " " || ch2 == "\n" || ch2 == "\r" || ch2 == "\t" { p2 = p2 + 1 continue } return Result.Err("terminator op colon not found") }
|
||||
loop(p2 < tj.size()) { local ch3 = tj.substring(p2,p2+1) if ch3 == " " || ch3 == "\n" || ch3 == "\r" || ch3 == "\t" { p2 = p2 + 1 continue } break }
|
||||
p2 = p2 + k.length()
|
||||
loop(p2 < tj.length()) { local ch2 = tj.substring(p2,p2+1) if ch2 == ":" { p2 = p2 + 1 break } if ch2 == " " || ch2 == "\n" || ch2 == "\r" || ch2 == "\t" { p2 = p2 + 1 continue } return Result.Err("terminator op colon not found") }
|
||||
loop(p2 < tj.length()) { local ch3 = tj.substring(p2,p2+1) if ch3 == " " || ch3 == "\n" || ch3 == "\r" || ch3 == "\t" { p2 = p2 + 1 continue } break }
|
||||
if tj.substring(p2,p2+1) != "\"" { return Result.Err("terminator op quote not found") }
|
||||
local e2 = JsonCursorBox.index_of_from(tj, "\"", p2+1)
|
||||
if e2 < 0 { return Result.Err("terminator op end not found") }
|
||||
@ -181,8 +181,8 @@ static box MirIoBox {
|
||||
local kt = "\"target\":"
|
||||
local pt = tj.indexOf(kt)
|
||||
if pt < 0 { return Result.Err("jump: target missing") }
|
||||
pt = pt + kt.size()
|
||||
loop(pt < tj.size()) {
|
||||
pt = pt + kt.length()
|
||||
loop(pt < tj.length()) {
|
||||
local ch = tj.substring(pt,pt+1)
|
||||
if ch == " " || ch == "\n" || ch == "\r" || ch == "\t" { pt = pt + 1 continue }
|
||||
break
|
||||
@ -190,24 +190,24 @@ static box MirIoBox {
|
||||
local digs2 = StringHelpers.read_digits(tj, pt)
|
||||
if digs2 == "" { return Result.Err("jump: invalid target") }
|
||||
local key = StringHelpers.int_to_str(StringHelpers.to_i64(digs2))
|
||||
if call("MapBox.get/2", ids, key) == null { return Result.Err("jump: unknown target") }
|
||||
if ids.get(key) == null { return Result.Err("jump: unknown target") }
|
||||
} else { if op == "branch" {
|
||||
local k1 = "\"then_bb\":"
|
||||
local p3 = tj.indexOf(k1)
|
||||
if p3 < 0 { return Result.Err("branch: then_bb missing") }
|
||||
p3 = p3 + k1.size()
|
||||
loop(p3 < tj.size()) { local ch = tj.substring(p3,p3+1) if ch == " " || ch == "\n" || ch == "\r" || ch == "\t" { p3 = p3 + 1 continue } break }
|
||||
p3 = p3 + k1.length()
|
||||
loop(p3 < tj.length()) { local ch = tj.substring(p3,p3+1) if ch == " " || ch == "\n" || ch == "\r" || ch == "\t" { p3 = p3 + 1 continue } break }
|
||||
local d1 = StringHelpers.read_digits(tj, p3)
|
||||
if d1 == "" { return Result.Err("branch: invalid then_bb") }
|
||||
local k2 = "\"else_bb\":"
|
||||
local p4 = tj.indexOf(k2)
|
||||
if p4 < 0 { return Result.Err("branch: else_bb missing") }
|
||||
p4 = p4 + k2.size()
|
||||
loop(p4 < tj.size()) { local ch = tj.substring(p4,p4+1) if ch == " " || ch == "\n" || ch == "\r" || ch == "\t" { p4 = p4 + 1 continue } break }
|
||||
p4 = p4 + k2.length()
|
||||
loop(p4 < tj.length()) { local ch = tj.substring(p4,p4+1) if ch == " " || ch == "\n" || ch == "\r" || ch == "\t" { p4 = p4 + 1 continue } break }
|
||||
local d2 = StringHelpers.read_digits(tj, p4)
|
||||
if d2 == "" { return Result.Err("branch: invalid else_bb") }
|
||||
if call("MapBox.get/2", ids, StringHelpers.int_to_str(StringHelpers.to_i64(d1))) == null { return Result.Err("branch: unknown then_bb") }
|
||||
if call("MapBox.get/2", ids, StringHelpers.int_to_str(StringHelpers.to_i64(d2))) == null { return Result.Err("branch: unknown else_bb") }
|
||||
if ids.get(StringHelpers.int_to_str(StringHelpers.to_i64(d1))) == null { return Result.Err("branch: unknown then_bb") }
|
||||
if ids.get(StringHelpers.int_to_str(StringHelpers.to_i64(d2))) == null { return Result.Err("branch: unknown else_bb") }
|
||||
} else { if op == "ret" { /* ok */ } else { return Result.Err("terminator: unsupported op "" + op + """) } }
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,62 +7,62 @@ static box MirSchemaBox {
|
||||
_expect_map(val, context) {
|
||||
if val == null {
|
||||
print("[MirSchemaBox] dev assert failed: expected MapBox (non-null) for " + context)
|
||||
call("MapBox.get/2", val, "__mir_schema_expect_map_null")
|
||||
val.get("__mir_schema_expect_map_null")
|
||||
return val
|
||||
}
|
||||
local repr = "" + val
|
||||
if repr.indexOf("MapBox(") == 0 { return val }
|
||||
print("[MirSchemaBox] dev assert failed: expected MapBox for " + context)
|
||||
call("MapBox.get/2", val, "__mir_schema_expect_map")
|
||||
val.get("__mir_schema_expect_map")
|
||||
return val
|
||||
}
|
||||
_expect_array(val, context) {
|
||||
if val == null {
|
||||
print("[MirSchemaBox] dev assert failed: expected ArrayBox (non-null) for " + context)
|
||||
call("ArrayBox.get/2", val, 0)
|
||||
val.get(0)
|
||||
return val
|
||||
}
|
||||
local repr = "" + val
|
||||
if repr.indexOf("ArrayBox(") == 0 { return val }
|
||||
print("[MirSchemaBox] dev assert failed: expected ArrayBox for " + context)
|
||||
call("ArrayBox.get/2", val, 0)
|
||||
val.get(0)
|
||||
return val
|
||||
}
|
||||
_expect_i64(val, context) {
|
||||
if val == null {
|
||||
print("[MirSchemaBox] dev assert failed: expected i64 (non-null) for " + context)
|
||||
call("MapBox.get/2", val, "__mir_schema_expect_i64_null")
|
||||
val.get("__mir_schema_expect_i64_null")
|
||||
return 0
|
||||
}
|
||||
local repr = "" + val
|
||||
if repr.indexOf("MapBox(") == 0 {
|
||||
local ty = call("MapBox.get/2", val, "type")
|
||||
local ty = val.get("type")
|
||||
if ty != null {
|
||||
local ty_str = "" + ty
|
||||
if ty_str != "i64" && ty_str != "int" && ty_str != "integer" {
|
||||
print("[MirSchemaBox] dev assert failed: unexpected type " + ty_str + " in " + context)
|
||||
call("MapBox.get/2", val, "__mir_schema_expect_i64_type")
|
||||
val.get("__mir_schema_expect_i64_type")
|
||||
return 0
|
||||
}
|
||||
}
|
||||
local inner = call("MapBox.get/2", val, "value")
|
||||
local inner = val.get("value")
|
||||
if inner != null { return StringHelpers.to_i64(inner) }
|
||||
print("[MirSchemaBox] dev assert failed: missing value in " + context)
|
||||
call("MapBox.get/2", val, "__mir_schema_expect_i64_value")
|
||||
val.get("__mir_schema_expect_i64_value")
|
||||
return 0
|
||||
}
|
||||
if StringHelpers.is_numeric_str("" + val) == 1 { return StringHelpers.to_i64(val) }
|
||||
print("[MirSchemaBox] dev assert failed: expected numeric value for " + context)
|
||||
call("MapBox.get/2", val, "__mir_schema_expect_i64_direct")
|
||||
val.get("__mir_schema_expect_i64_direct")
|
||||
return 0
|
||||
}
|
||||
_len(arr) {
|
||||
if arr == null { return 0 }
|
||||
// ArrayBox.size/1 は MapBox-wrapped integer を返すので、unwrap する
|
||||
local size_val = call("ArrayBox.size/1", arr)
|
||||
local size_val = arr.length()
|
||||
local repr = "" + size_val
|
||||
if repr.indexOf("MapBox(") == 0 {
|
||||
local inner = call("MapBox.get/2", size_val, "value")
|
||||
local inner = size_val.get("value")
|
||||
if inner != null { return inner }
|
||||
}
|
||||
return size_val
|
||||
@ -139,7 +139,7 @@ static box MirSchemaBox {
|
||||
local n = me._len(incoming)
|
||||
local i = 0
|
||||
loop(i < n) {
|
||||
arr.push(call("ArrayBox.get/2", incoming, i))
|
||||
arr.push(incoming.get(i))
|
||||
i = i + 1
|
||||
}
|
||||
}
|
||||
@ -155,7 +155,7 @@ static box MirSchemaBox {
|
||||
local i = 0
|
||||
local n = me._len(arr)
|
||||
loop(i < n) {
|
||||
out.push(this.i(call("ArrayBox.get/2", arr, i)))
|
||||
out.push(this.i(arr.get(i)))
|
||||
i = i + 1
|
||||
}
|
||||
return out
|
||||
|
||||
Reference in New Issue
Block a user