fix(mir/builder): use function-local ValueId throughout MIR builder
Phase 25.1b: Complete SSA fix - eliminate all global ValueId usage in function contexts. Root cause: ~75 locations throughout MIR builder were using global value generator (self.value_gen.next()) instead of function-local allocator (f.next_value_id()), causing SSA verification failures and runtime "use of undefined value" errors. Solution: - Added next_value_id() helper that automatically chooses correct allocator - Fixed 19 files with ~75 occurrences of ValueId allocation - All function-context allocations now use function-local IDs Files modified: - src/mir/builder/utils.rs: Added next_value_id() helper, fixed 8 locations - src/mir/builder/builder_calls.rs: 17 fixes - src/mir/builder/ops.rs: 8 fixes - src/mir/builder/stmts.rs: 7 fixes - src/mir/builder/emission/constant.rs: 6 fixes - src/mir/builder/rewrite/*.rs: 10 fixes - + 13 other files Verification: - cargo build --release: SUCCESS - Simple tests with NYASH_VM_VERIFY_MIR=1: Zero undefined errors - Multi-parameter static methods: All working Known remaining: ValueId(22) in Stage-B (separate issue to investigate) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -3,14 +3,14 @@
|
||||
// 削減: 7ファイル × 2パターン = 14重複 → 1箇所に集約
|
||||
|
||||
using selfhost.shared.common.string_helpers as StringHelpers
|
||||
using selfhost.shared.common.box_type_inspector as BoxTypeInspectorBox
|
||||
|
||||
static box BoxHelpers {
|
||||
// ArrayBox.size/1 の結果unwrap (MapBox-wrapped integer対応)
|
||||
array_len(arr) {
|
||||
if arr == null { return 0 }
|
||||
local size_val = arr.length()
|
||||
local repr = "" + size_val
|
||||
if repr.indexOf("MapBox(") == 0 {
|
||||
if BoxTypeInspectorBox.is_map(size_val) {
|
||||
local inner = size_val.get("value")
|
||||
if inner != null { return inner }
|
||||
}
|
||||
@ -39,8 +39,7 @@ static box BoxHelpers {
|
||||
// MapBox-wrapped integer の unwrap (汎用版)
|
||||
value_i64(val) {
|
||||
if val == null { return 0 }
|
||||
local repr = "" + val
|
||||
if repr.indexOf("MapBox(") == 0 {
|
||||
if BoxTypeInspectorBox.is_map(val) {
|
||||
local inner = val.get("value")
|
||||
if inner != null { return inner }
|
||||
}
|
||||
@ -49,71 +48,56 @@ static box BoxHelpers {
|
||||
|
||||
// MapBox型判定
|
||||
is_map(val) {
|
||||
if val == null { return 0 }
|
||||
local repr = "" + val
|
||||
if repr.indexOf("MapBox(") == 0 { return 1 }
|
||||
return 0
|
||||
return BoxTypeInspectorBox.is_map(val)
|
||||
}
|
||||
|
||||
// ArrayBox型判定
|
||||
is_array(val) {
|
||||
if val == null { return 0 }
|
||||
local repr = "" + val
|
||||
if repr.indexOf("ArrayBox(") == 0 { return 1 }
|
||||
return 0
|
||||
return BoxTypeInspectorBox.is_array(val)
|
||||
}
|
||||
|
||||
// Fail-fast helpers (Phase 31.3+)
|
||||
expect_map(val, context) {
|
||||
if val == null {
|
||||
print("[BoxHelpers] expected MapBox for " + context + " but got null")
|
||||
val.get("__box_helpers_expect_map_null")
|
||||
return val
|
||||
}
|
||||
if me.is_map(val) == 1 { return val }
|
||||
if BoxHelpers.is_map(val) { return val }
|
||||
print("[BoxHelpers] dev assert failed: expected MapBox for " + context)
|
||||
val.get("__box_helpers_expect_map")
|
||||
return val
|
||||
}
|
||||
|
||||
expect_array(val, context) {
|
||||
if val == null {
|
||||
print("[BoxHelpers] expected ArrayBox for " + context + " but got null")
|
||||
val.get(0)
|
||||
return val
|
||||
}
|
||||
if me.is_array(val) == 1 { return val }
|
||||
if BoxHelpers.is_array(val) { return val }
|
||||
print("[BoxHelpers] dev assert failed: expected ArrayBox for " + context)
|
||||
val.get(0)
|
||||
return val
|
||||
}
|
||||
|
||||
expect_i64(val, context) {
|
||||
if val == null {
|
||||
print("[BoxHelpers] dev assert failed: expected i64 (non-null) for " + context)
|
||||
val.get("__box_helpers_expect_i64_null")
|
||||
return 0
|
||||
}
|
||||
local repr = "" + val
|
||||
if repr.indexOf("MapBox(") == 0 {
|
||||
if BoxTypeInspectorBox.is_map(val) {
|
||||
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)
|
||||
val.get("__box_helpers_expect_i64_type")
|
||||
return 0
|
||||
}
|
||||
}
|
||||
local inner = val.get("value")
|
||||
if inner != null { return StringHelpers.to_i64(inner) }
|
||||
print("[BoxHelpers] dev assert failed: missing value in " + context)
|
||||
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)
|
||||
val.get("__box_helpers_expect_i64_direct")
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ common.mini_vm_compare = "common/mini_vm_compare.hako"
|
||||
common.string_helpers = "common/string_helpers.hako"
|
||||
common.string_ops = "common/string_ops.hako"
|
||||
common.box_helpers = "common/box_helpers.hako"
|
||||
common.box_type_inspector = "common/box_type_inspector_box.hako"
|
||||
common.entry_point_base = "common/entry_point_base.hako"
|
||||
common.common_imports = "common/common_imports.hako"
|
||||
|
||||
@ -26,6 +27,7 @@ json.utils.json_number_canonical = "json/utils/json_number_canonical_box.hako"
|
||||
|
||||
# Host bridge & adapters
|
||||
host_bridge.host_bridge = "host_bridge/host_bridge_box.hako"
|
||||
host_bridge.codegen_bridge = "host_bridge/codegen_bridge_box.hako"
|
||||
adapters.map_kv_string_to_array = "adapters/map_kv_string_to_array.hako"
|
||||
|
||||
# MIR helpers (exported as stable module names)
|
||||
|
||||
42
lang/src/shared/host_bridge/codegen_bridge_box.hako
Normal file
42
lang/src/shared/host_bridge/codegen_bridge_box.hako
Normal file
@ -0,0 +1,42 @@
|
||||
// codegen_bridge_box.hako — Thin wrapper for env.codegen extern calls
|
||||
// Responsibility:
|
||||
// - Provide emit_object/link_object helpers instead of duplicating
|
||||
// hostbridge.extern_invoke("env.codegen", ...) everywhere.
|
||||
|
||||
using selfhost.shared.common.box_type_inspector as BoxTypeInspectorBox
|
||||
|
||||
static box CodegenBridgeBox {
|
||||
method emit_object(mir_json) {
|
||||
local args = new ArrayBox()
|
||||
if mir_json != null { args.push("" + mir_json) }
|
||||
return hostbridge.extern_invoke("env.codegen", "emit_object", args)
|
||||
}
|
||||
|
||||
method emit_object_args(args) {
|
||||
local arr = me._ensure_array(args)
|
||||
return hostbridge.extern_invoke("env.codegen", "emit_object", arr)
|
||||
}
|
||||
|
||||
method link_object(obj_path, out_path) {
|
||||
local args = new ArrayBox()
|
||||
if obj_path != null { args.push("" + obj_path) }
|
||||
if out_path != null && ("" + out_path) != "" {
|
||||
args.push("" + out_path)
|
||||
}
|
||||
return hostbridge.extern_invoke("env.codegen", "link_object", args)
|
||||
}
|
||||
|
||||
method link_object_args(args) {
|
||||
local arr = me._ensure_array(args)
|
||||
return hostbridge.extern_invoke("env.codegen", "link_object", arr)
|
||||
}
|
||||
|
||||
method _ensure_array(value) {
|
||||
if value != null && BoxTypeInspectorBox.is_array(value) {
|
||||
return value
|
||||
}
|
||||
local arr = new ArrayBox()
|
||||
if value != null { arr.push(value) }
|
||||
return arr
|
||||
}
|
||||
}
|
||||
@ -6,33 +6,26 @@ using selfhost.shared.common.box_helpers as BoxHelpers
|
||||
|
||||
static box JsonEmitBox {
|
||||
_expect_map(val, context) {
|
||||
if BoxHelpers.is_map(val) == 1 { return val }
|
||||
if BoxHelpers.is_map(val) { return val }
|
||||
print("[JsonEmitBox] dev assert failed: expected MapBox for " + context)
|
||||
val.get("__json_emit_expect_map")
|
||||
return val
|
||||
}
|
||||
_expect_array(val, context) {
|
||||
if BoxHelpers.is_array(val) == 1 { return val }
|
||||
if BoxHelpers.is_array(val) { return val }
|
||||
print("[JsonEmitBox] dev assert failed: expected ArrayBox for " + context)
|
||||
val.get(0)
|
||||
return val
|
||||
}
|
||||
_expect_i64(val, context) {
|
||||
if val == null {
|
||||
print("[JsonEmitBox] dev assert failed: expected i64 (non-null) for " + context)
|
||||
val.get("__json_emit_expect_i64_null")
|
||||
return 0
|
||||
}
|
||||
local repr = "" + val
|
||||
if repr.indexOf("MapBox(") == 0 {
|
||||
local inner = val.get("value")
|
||||
if inner != null { return inner }
|
||||
print("[JsonEmitBox] dev assert failed: missing value in " + context)
|
||||
val.get("__json_emit_expect_i64_value")
|
||||
return 0
|
||||
if BoxHelpers.is_map(val) {
|
||||
// MapBox-wrapped integer (possibly nested); delegate unwrapping.
|
||||
return BoxHelpers.value_i64(val)
|
||||
}
|
||||
# Assume numeric immediate; avoid module function coercion for safety
|
||||
return val
|
||||
// Non-MapBox: treat as numeric immediate and normalize via helper.
|
||||
return BoxHelpers.value_i64(val)
|
||||
}
|
||||
|
||||
// ---- helpers ------------------------------------------------------------
|
||||
@ -109,8 +102,7 @@ static box JsonEmitBox {
|
||||
if val == null { return "{\"type\":\"i64\",\"value\":0}" }
|
||||
local ty = "i64"
|
||||
local inner = val
|
||||
local repr = "" + val
|
||||
if repr.indexOf("MapBox(") == 0 {
|
||||
if BoxHelpers.is_map(val) {
|
||||
local ty_box = val.get("type")
|
||||
if ty_box != null { ty = "" + ty_box }
|
||||
local inner_box = val.get("value")
|
||||
@ -235,8 +227,8 @@ static box JsonEmitBox {
|
||||
if blocks == null {
|
||||
if params != null || flags != null {
|
||||
local head = "{\"name\":" + me._quote(name)
|
||||
if params != null { head = head + ",\"params\":" + JSON.stringify(params) }
|
||||
if flags != null { head = head + ",\"flags\":" + JSON.stringify(flags) }
|
||||
if params != null { head = head + ",\"params\":" + me._emit_params(params) }
|
||||
if flags != null { head = head + ",\"flags\":" + me._emit_flags(flags) }
|
||||
return head + ",\"blocks\":[]}"
|
||||
}
|
||||
return "{\"name\":" + me._quote(name) + ",\"blocks\":[]}"
|
||||
@ -244,8 +236,8 @@ static box JsonEmitBox {
|
||||
local n = BoxHelpers.array_len(blocks)
|
||||
local body = me._emit_function_rec(blocks, 0, n)
|
||||
local head2 = "{\"name\":" + me._quote(name)
|
||||
if params != null { head2 = head2 + ",\"params\":" + JSON.stringify(params) }
|
||||
if flags != null { head2 = head2 + ",\"flags\":" + JSON.stringify(flags) }
|
||||
if params != null { head2 = head2 + ",\"params\":" + me._emit_params(params) }
|
||||
if flags != null { head2 = head2 + ",\"flags\":" + me._emit_flags(flags) }
|
||||
return head2 + ",\"blocks\":[" + body + "]}"
|
||||
}
|
||||
_emit_function_rec(blocks, idx, len) {
|
||||
@ -256,16 +248,48 @@ static box JsonEmitBox {
|
||||
return head + "," + tail
|
||||
}
|
||||
|
||||
_emit_params(params) {
|
||||
if params == null { return "[]" }
|
||||
if !BoxHelpers.is_array(params) { return "[]" }
|
||||
local n = BoxHelpers.array_len(params)
|
||||
if n == 0 { return "[]" }
|
||||
return "[" + me._emit_params_rec(params, 0, n) + "]"
|
||||
}
|
||||
_emit_params_rec(params, idx, len) {
|
||||
if idx >= len { return "" }
|
||||
local head = me._int_str(params.get(idx))
|
||||
local tail = me._emit_params_rec(params, idx + 1, len)
|
||||
if tail == "" { return head }
|
||||
return head + "," + tail
|
||||
}
|
||||
|
||||
_emit_flags(flags) {
|
||||
if flags == null { return "null" }
|
||||
if !BoxHelpers.is_map(flags) { return "null" }
|
||||
local keys = flags.keys()
|
||||
if keys == null { return "{}" }
|
||||
local n = BoxHelpers.array_len(keys)
|
||||
if n == 0 { return "{}" }
|
||||
local body = me._emit_flags_rec(flags, keys, 0, n)
|
||||
return "{" + body + "}"
|
||||
}
|
||||
_emit_flags_rec(flags, keys, idx, len) {
|
||||
if idx >= len { return "" }
|
||||
local k = keys.get(idx)
|
||||
local v = flags.get(k)
|
||||
local head = me._quote(k) + ":" + me._quote(v)
|
||||
local tail = me._emit_flags_rec(flags, keys, idx + 1, len)
|
||||
if tail == "" { return head }
|
||||
return head + "," + tail
|
||||
}
|
||||
|
||||
to_json(module) {
|
||||
if module == null { return "" }
|
||||
// Prefer single-function fallbackを強化: has() 未実装環境でも repr チェックで検出
|
||||
local f0 = module.get("functions_0")
|
||||
if f0 != null {
|
||||
local repr = "" + f0
|
||||
if repr.indexOf("MapBox(") == 0 || repr.indexOf("HostHandleBox(") == 0 {
|
||||
local one = me._emit_function(f0)
|
||||
return "{\"kind\":\"MIR\",\"schema_version\":\"1.0\",\"functions\":[" + one + "]}"
|
||||
}
|
||||
local one = me._emit_function(f0)
|
||||
return "{\"kind\":\"MIR\",\"schema_version\":\"1.0\",\"functions\":[" + one + "]}"
|
||||
}
|
||||
// Legacy path: try functions array if available
|
||||
local funcs = module.get("functions")
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
// LoopFormBox — minimal loop structure builder (P2: continue/break snapshots + Exit PHI)
|
||||
|
||||
using selfhost.shared.mir.schema as MirSchemaBox
|
||||
using selfhost.shared.common.string_helpers as StringHelpers
|
||||
|
||||
static box LoopFormBox {
|
||||
|
||||
@ -277,63 +278,132 @@ static box LoopFormBox {
|
||||
// Shape: i from 0 to limit, with 2 additional carried variables (a, b)
|
||||
// carriers param: [init_a, init_b] (e.g. [0, 1] for fibonacci)
|
||||
method build_loop_multi_carrier(opts) {
|
||||
local limit = opts.get("limit")
|
||||
if limit == null { limit = 10 }
|
||||
local carriers = opts.get("carriers")
|
||||
local init_a = 0
|
||||
local init_b = 1
|
||||
if carriers != null && carriers.length() >= 2 {
|
||||
init_a = carriers.get(0)
|
||||
init_b = carriers.get(1)
|
||||
local limit_kind = "const"
|
||||
{
|
||||
local lim_any = opts.get("limit_kind")
|
||||
if lim_any != null { limit_kind = "" + lim_any }
|
||||
}
|
||||
local limit_val = opts.get("limit")
|
||||
local limit_param_reg = opts.get("limit_param_reg")
|
||||
if limit_kind == "param" {
|
||||
if limit_param_reg == null { return null }
|
||||
limit_param_reg = StringHelpers.to_i64(limit_param_reg)
|
||||
if limit_param_reg <= 0 { return null }
|
||||
} else {
|
||||
if limit_val == null { limit_val = 10 }
|
||||
limit_val = StringHelpers.to_i64(limit_val)
|
||||
limit_kind = "const"
|
||||
}
|
||||
|
||||
// Preheader (block 0): init i=0, limit, a=init_a, b=init_b
|
||||
local carriers_any = opts.get("carriers")
|
||||
local carrier_vals = new ArrayBox()
|
||||
if carriers_any != null {
|
||||
local ci = 0
|
||||
local cn = carriers_any.length()
|
||||
loop(ci < cn) {
|
||||
carrier_vals.push(StringHelpers.to_i64(carriers_any.get(ci)))
|
||||
ci = ci + 1
|
||||
}
|
||||
}
|
||||
if carrier_vals.length() < 2 {
|
||||
return null
|
||||
}
|
||||
local carrier_count = carrier_vals.length()
|
||||
|
||||
// Register layout
|
||||
local reg_i_init = 1
|
||||
local reg_limit = 2
|
||||
local reg_carrier_init = new ArrayBox()
|
||||
local idx = 0
|
||||
loop(idx < carrier_count) {
|
||||
reg_carrier_init.push(3 + idx)
|
||||
idx = idx + 1
|
||||
}
|
||||
local reg_step = 3 + carrier_count
|
||||
local reg_i_curr = reg_step + 1
|
||||
local reg_carrier_curr = new ArrayBox()
|
||||
idx = 0
|
||||
loop(idx < carrier_count) {
|
||||
reg_carrier_curr.push(reg_i_curr + idx + 1)
|
||||
idx = idx + 1
|
||||
}
|
||||
local reg_cmp = reg_i_curr + carrier_count + 1
|
||||
local reg_i_next = reg_cmp + 1
|
||||
local reg_carrier_next = new ArrayBox()
|
||||
idx = 0
|
||||
loop(idx < carrier_count) {
|
||||
reg_carrier_next.push(reg_i_next + idx + 1)
|
||||
idx = idx + 1
|
||||
}
|
||||
local next_reg = reg_carrier_next.get(carrier_count - 1) + 1
|
||||
|
||||
// Preheader
|
||||
local pre = new ArrayBox()
|
||||
pre.push(MirSchemaBox.inst_const(1, 0)) // r1 = 0 (i)
|
||||
pre.push(MirSchemaBox.inst_const(2, limit)) // r2 = limit
|
||||
pre.push(MirSchemaBox.inst_const(3, init_a)) // r3 = init_a
|
||||
pre.push(MirSchemaBox.inst_const(4, init_b)) // r4 = init_b
|
||||
pre.push(MirSchemaBox.inst_const(reg_i_init, 0))
|
||||
if limit_kind == "const" {
|
||||
pre.push(MirSchemaBox.inst_const(reg_limit, limit_val))
|
||||
} else {
|
||||
pre.push(MirSchemaBox.inst_copy(limit_param_reg, reg_limit))
|
||||
}
|
||||
idx = 0
|
||||
loop(idx < carrier_count) {
|
||||
pre.push(MirSchemaBox.inst_const(reg_carrier_init.get(idx), carrier_vals.get(idx)))
|
||||
idx = idx + 1
|
||||
}
|
||||
pre.push(MirSchemaBox.inst_const(reg_step, 1))
|
||||
pre.push(MirSchemaBox.inst_jump(1))
|
||||
|
||||
// Header (block 1): PHI(i), PHI(a), PHI(b), compare, branch
|
||||
// Header with PHIs
|
||||
local header = new ArrayBox()
|
||||
local phi_i_inc = new ArrayBox()
|
||||
phi_i_inc.push(MirSchemaBox.phi_incoming(0, 1)) // from preheader
|
||||
phi_i_inc.push(MirSchemaBox.phi_incoming(3, 17)) // from latch
|
||||
header.push(MirSchemaBox.inst_phi(10, phi_i_inc)) // r10 = i
|
||||
local phi_i = new ArrayBox()
|
||||
phi_i.push(MirSchemaBox.phi_incoming(0, reg_i_init))
|
||||
phi_i.push(MirSchemaBox.phi_incoming(3, reg_i_next))
|
||||
header.push(MirSchemaBox.inst_phi(reg_i_curr, phi_i))
|
||||
|
||||
local phi_a_inc = new ArrayBox()
|
||||
phi_a_inc.push(MirSchemaBox.phi_incoming(0, 3)) // from preheader
|
||||
phi_a_inc.push(MirSchemaBox.phi_incoming(3, 18)) // from latch
|
||||
header.push(MirSchemaBox.inst_phi(11, phi_a_inc)) // r11 = a
|
||||
idx = 0
|
||||
loop(idx < carrier_count) {
|
||||
local phi_car = new ArrayBox()
|
||||
phi_car.push(MirSchemaBox.phi_incoming(0, reg_carrier_init.get(idx)))
|
||||
phi_car.push(MirSchemaBox.phi_incoming(3, reg_carrier_next.get(idx)))
|
||||
header.push(MirSchemaBox.inst_phi(reg_carrier_curr.get(idx), phi_car))
|
||||
idx = idx + 1
|
||||
}
|
||||
|
||||
local phi_b_inc = new ArrayBox()
|
||||
phi_b_inc.push(MirSchemaBox.phi_incoming(0, 4)) // from preheader
|
||||
phi_b_inc.push(MirSchemaBox.phi_incoming(3, 19)) // from latch
|
||||
header.push(MirSchemaBox.inst_phi(12, phi_b_inc)) // r12 = b
|
||||
header.push(MirSchemaBox.inst_compare("Lt", reg_i_curr, reg_limit, reg_cmp))
|
||||
header.push(MirSchemaBox.inst_branch(reg_cmp, 2, 4))
|
||||
|
||||
header.push(MirSchemaBox.inst_compare("Lt", 10, 2, 13)) // r13 = (i < limit)
|
||||
header.push(MirSchemaBox.inst_branch(13, 2, 4)) // body or exit
|
||||
|
||||
// Body (block 2): t = a + b; a' = b; b' = t; i' = i + 1
|
||||
// Body: compute new value = sum of carriers
|
||||
local body = new ArrayBox()
|
||||
body.push(MirSchemaBox.inst_binop("Add", 11, 12, 14)) // r14 = a + b (t)
|
||||
body.push(MirSchemaBox.inst_const(20, 1)) // r20 = step (1)
|
||||
body.push(MirSchemaBox.inst_binop("Add", 10, 20, 15)) // r15 = i + 1
|
||||
local reg_sum = next_reg
|
||||
next_reg = next_reg + 1
|
||||
body.push(MirSchemaBox.inst_copy(reg_carrier_curr.get(0), reg_sum))
|
||||
local current_sum = reg_sum
|
||||
idx = 1
|
||||
loop(idx < carrier_count) {
|
||||
local reg_tmp = next_reg
|
||||
next_reg = next_reg + 1
|
||||
body.push(MirSchemaBox.inst_binop("Add", current_sum, reg_carrier_curr.get(idx), reg_tmp))
|
||||
current_sum = reg_tmp
|
||||
idx = idx + 1
|
||||
}
|
||||
local reg_new_value = current_sum
|
||||
body.push(MirSchemaBox.inst_jump(3))
|
||||
|
||||
// Latch (block 3): pass updated values (i', a'=b, b'=t) back to header
|
||||
// Latch: i' and carrier shifts
|
||||
local latch = new ArrayBox()
|
||||
latch.push(MirSchemaBox.inst_copy(15, 17)) // r17 = i'
|
||||
latch.push(MirSchemaBox.inst_copy(12, 18)) // r18 = a' (=b)
|
||||
latch.push(MirSchemaBox.inst_copy(14, 19)) // r19 = b' (=t)
|
||||
latch.push(MirSchemaBox.inst_binop("Add", reg_i_curr, reg_step, reg_i_next))
|
||||
idx = 0
|
||||
loop(idx < carrier_count - 1) {
|
||||
latch.push(MirSchemaBox.inst_copy(reg_carrier_curr.get(idx + 1), reg_carrier_next.get(idx)))
|
||||
idx = idx + 1
|
||||
}
|
||||
latch.push(MirSchemaBox.inst_copy(reg_new_value, reg_carrier_next.get(carrier_count - 1)))
|
||||
latch.push(MirSchemaBox.inst_jump(1))
|
||||
|
||||
// Exit (block 4): return final b value
|
||||
// Exit: return last carrier
|
||||
local exit = new ArrayBox()
|
||||
exit.push(MirSchemaBox.inst_ret(12))
|
||||
exit.push(MirSchemaBox.inst_ret(reg_carrier_curr.get(carrier_count - 1)))
|
||||
|
||||
// Assemble blocks
|
||||
local blocks = new ArrayBox()
|
||||
blocks.push(MirSchemaBox.block(0, pre))
|
||||
blocks.push(MirSchemaBox.block(1, header))
|
||||
|
||||
@ -2,66 +2,55 @@
|
||||
// MirSchemaBox — minimal MIR(JSON v0) constructors (P1 scope)
|
||||
|
||||
using selfhost.shared.common.string_helpers as StringHelpers
|
||||
using selfhost.shared.common.box_type_inspector as BoxTypeInspectorBox
|
||||
|
||||
static box MirSchemaBox {
|
||||
_expect_map(val, context) {
|
||||
if val == null {
|
||||
print("[MirSchemaBox] dev assert failed: expected MapBox (non-null) for " + context)
|
||||
val.get("__mir_schema_expect_map_null")
|
||||
return val
|
||||
}
|
||||
local repr = "" + val
|
||||
if repr.indexOf("MapBox(") == 0 { return val }
|
||||
if BoxTypeInspectorBox.is_map(val) { return val }
|
||||
print("[MirSchemaBox] dev assert failed: expected MapBox for " + context)
|
||||
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)
|
||||
val.get(0)
|
||||
return val
|
||||
}
|
||||
local repr = "" + val
|
||||
if repr.indexOf("ArrayBox(") == 0 { return val }
|
||||
if BoxTypeInspectorBox.is_array(val) { return val }
|
||||
print("[MirSchemaBox] dev assert failed: expected ArrayBox for " + context)
|
||||
val.get(0)
|
||||
return val
|
||||
}
|
||||
_expect_i64(val, context) {
|
||||
if val == null {
|
||||
print("[MirSchemaBox] dev assert failed: expected i64 (non-null) for " + context)
|
||||
val.get("__mir_schema_expect_i64_null")
|
||||
return 0
|
||||
}
|
||||
local repr = "" + val
|
||||
if repr.indexOf("MapBox(") == 0 {
|
||||
if BoxTypeInspectorBox.is_map(val) {
|
||||
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)
|
||||
val.get("__mir_schema_expect_i64_type")
|
||||
return 0
|
||||
}
|
||||
}
|
||||
local inner = val.get("value")
|
||||
if inner != null { return StringHelpers.to_i64(inner) }
|
||||
print("[MirSchemaBox] dev assert failed: missing value in " + context)
|
||||
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)
|
||||
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 = arr.length()
|
||||
local repr = "" + size_val
|
||||
if repr.indexOf("MapBox(") == 0 {
|
||||
if BoxTypeInspectorBox.is_map(size_val) {
|
||||
local inner = size_val.get("value")
|
||||
if inner != null { return inner }
|
||||
}
|
||||
@ -124,6 +113,13 @@ static box MirSchemaBox {
|
||||
m.set("dst", this.i(dst))
|
||||
return m
|
||||
}
|
||||
inst_copy(src, dst) {
|
||||
local m = new MapBox()
|
||||
m.set("op", "copy")
|
||||
m.set("src", this.i(src))
|
||||
m.set("dst", this.i(dst))
|
||||
return m
|
||||
}
|
||||
inst_branch(cond, then_id, else_id) {
|
||||
local m = new MapBox()
|
||||
m.set("op", "branch")
|
||||
|
||||
Reference in New Issue
Block a user