trace: add execution route visibility + debug passthrough; phase2170 canaries; docs
- Add HAKO_TRACE_EXECUTION to trace executor route - Rust hv1_inline: stderr [trace] executor: hv1_inline (rust) - Hakovm dispatcher: stdout [trace] executor: hakovm (hako) - test_runner: trace lines for hv1_inline/core/hakovm routes - Add HAKO_VERIFY_SHOW_LOGS and HAKO_DEBUG=1 (enables both) - verify_v1_inline_file() log passthrough with numeric rc extraction - test_runner exports via HAKO_DEBUG - Canary expansion under phase2170 (state spec) - Array: push×5/10 → size, len/length alias, per‑recv/global, flow across blocks - Map: set dup-key non-increment, value_state get/has - run_all.sh: unify, remove SKIPs; all PASS - Docs - ENV_VARS.md: add Debug/Tracing toggles and examples - PLAN.md/CURRENT_TASK.md: mark 21.7 green, add Quickstart lines All changes gated by env vars; default behavior unchanged.
This commit is contained in:
@ -39,28 +39,46 @@ static box MirBuilderBox {
|
||||
if internal != null && ("" + internal) == "1" {
|
||||
// Optional: registry-driven lowering (scaffold). When HAKO_MIR_BUILDER_REGISTRY=1,
|
||||
// iterate PatternRegistryBox.candidates() and dispatch by name.
|
||||
// NOTE: include not supported in VM, registry disabled for VM execution
|
||||
// NOTE: using/alias は prelude で解決される(位置に依存しない)。
|
||||
local use_reg = env.get("HAKO_MIR_BUILDER_REGISTRY")
|
||||
if use_reg != null && ("" + use_reg) == "1" && 0 == 1 {
|
||||
if use_reg != null && ("" + use_reg) == "1" {
|
||||
// Registry list
|
||||
using "hako.mir.builder.pattern_registry" as PatternRegistryBox
|
||||
// Lowers needed by registry dispatch(using は prelude で集約される)
|
||||
using "hako.mir.builder.internal.lower_if_compare" as LowerIfCompareBox
|
||||
using "hako.mir.builder.internal.lower_if_compare_fold_binints" as LowerIfCompareFoldBinIntsBox
|
||||
using "hako.mir.builder.internal.lower_if_compare_fold_varint" as LowerIfCompareFoldVarIntBox
|
||||
using "hako.mir.builder.internal.lower_if_compare_varint" as LowerIfCompareVarIntBox
|
||||
using "hako.mir.builder.internal.lower_if_compare_varvar" as LowerIfCompareVarVarBox
|
||||
using "hako.mir.builder.internal.lower_return_method_array_map" as LowerReturnMethodArrayMapBox
|
||||
using "hako.mir.builder.internal.lower_return_var_local" as LowerReturnVarLocalBox
|
||||
using "hako.mir.builder.internal.lower_return_string" as LowerReturnStringBox
|
||||
using "hako.mir.builder.internal.lower_return_float" as LowerReturnFloatBox
|
||||
using "hako.mir.builder.internal.lower_return_bool" as LowerReturnBoolBox
|
||||
using "hako.mir.builder.internal.lower_return_logical" as LowerReturnLogicalBox
|
||||
using "hako.mir.builder.internal.lower_return_binop_varint" as LowerReturnBinOpVarIntBox
|
||||
using "hako.mir.builder.internal.lower_return_binop_varvar" as LowerReturnBinOpVarVarBox
|
||||
using "hako.mir.builder.internal.lower_return_binop" as LowerReturnBinOpBox
|
||||
using "hako.mir.builder.internal.lower_return_int" as LowerReturnIntBox
|
||||
local names = PatternRegistryBox.candidates()
|
||||
local i = 0; local n = names.length()
|
||||
loop(i < n) {
|
||||
local nm = "" + names.get(i)
|
||||
if nm == "if.compare.intint" { local out = LowerIfCompareBox.try_lower(s); if out != null { return out } }
|
||||
if nm == "if.compare.fold.binints" { local out = LowerIfCompareFoldBinIntsBox.try_lower(s); if out != null { return out } }
|
||||
if nm == "if.compare.fold.varint" { local out = LowerIfCompareFoldVarIntBox.try_lower(s); if out != null { return out } }
|
||||
if nm == "if.compare.varint" { local out = LowerIfCompareVarIntBox.try_lower(s); if out != null { return out } }
|
||||
if nm == "if.compare.varvar" { local out = LowerIfCompareVarVarBox.try_lower(s); if out != null { return out } }
|
||||
if nm == "return.method.arraymap" { local out = LowerReturnMethodArrayMapBox.try_lower(s); if out != null { return out } }
|
||||
if nm == "return.var.local" { local out = LowerReturnVarLocalBox.try_lower(s); if out != null { return out } }
|
||||
if nm == "return.string" { local out = LowerReturnStringBox.try_lower(s); if out != null { return out } }
|
||||
if nm == "return.float" { local out = LowerReturnFloatBox.try_lower(s); if out != null { return out } }
|
||||
if nm == "return.bool" { local out = LowerReturnBoolBox.try_lower(s); if out != null { return out } }
|
||||
if nm == "return.logical" { local out = LowerReturnLogicalBox.try_lower(s); if out != null { return out } }
|
||||
if nm == "return.binop.varint" { local out = LowerReturnBinOpVarIntBox.try_lower(s); if out != null { return out } }
|
||||
if nm == "return.binop.varvar" { local out = LowerReturnBinOpVarVarBox.try_lower(s); if out != null { return out } }
|
||||
if nm == "return.binop.intint" { local out = LowerReturnBinOpBox.try_lower(s); if out != null { return out } }
|
||||
if nm == "return.int" { local out = LowerReturnIntBox.try_lower(s); if out != null { return out } }
|
||||
if nm == "if.compare.intint" { local out = LowerIfCompareBox.try_lower(s); if out != null { if env.get("HAKO_MIR_BUILDER_DEBUG")=="1" || env.get("NYASH_CLI_VERBOSE")=="1" { print("[mirbuilder/registry:" + nm + "]") } return out } }
|
||||
if nm == "if.compare.fold.binints" { local out = LowerIfCompareFoldBinIntsBox.try_lower(s); if out != null { if env.get("HAKO_MIR_BUILDER_DEBUG")=="1" || env.get("NYASH_CLI_VERBOSE")=="1" { print("[mirbuilder/registry:" + nm + "]") } return out } }
|
||||
if nm == "if.compare.fold.varint" { local out = LowerIfCompareFoldVarIntBox.try_lower(s); if out != null { if env.get("HAKO_MIR_BUILDER_DEBUG")=="1" || env.get("NYASH_CLI_VERBOSE")=="1" { print("[mirbuilder/registry:" + nm + "]") } return out } }
|
||||
if nm == "if.compare.varint" { local out = LowerIfCompareVarIntBox.try_lower(s); if out != null { if env.get("HAKO_MIR_BUILDER_DEBUG")=="1" || env.get("NYASH_CLI_VERBOSE")=="1" { print("[mirbuilder/registry:" + nm + "]") } return out } }
|
||||
if nm == "if.compare.varvar" { local out = LowerIfCompareVarVarBox.try_lower(s); if out != null { if env.get("HAKO_MIR_BUILDER_DEBUG")=="1" || env.get("NYASH_CLI_VERBOSE")=="1" { print("[mirbuilder/registry:" + nm + "]") } return out } }
|
||||
if nm == "return.method.arraymap" { local out = LowerReturnMethodArrayMapBox.try_lower(s); if out != null { if env.get("HAKO_MIR_BUILDER_DEBUG")=="1" || env.get("NYASH_CLI_VERBOSE")=="1" { print("[mirbuilder/registry:" + nm + "]") } return out } }
|
||||
if nm == "return.var.local" { local out = LowerReturnVarLocalBox.try_lower(s); if out != null { if env.get("HAKO_MIR_BUILDER_DEBUG")=="1" || env.get("NYASH_CLI_VERBOSE")=="1" { print("[mirbuilder/registry:" + nm + "]") } return out } }
|
||||
if nm == "return.string" { local out = LowerReturnStringBox.try_lower(s); if out != null { if env.get("HAKO_MIR_BUILDER_DEBUG")=="1" || env.get("NYASH_CLI_VERBOSE")=="1" { print("[mirbuilder/registry:" + nm + "]") } return out } }
|
||||
if nm == "return.float" { local out = LowerReturnFloatBox.try_lower(s); if out != null { if env.get("HAKO_MIR_BUILDER_DEBUG")=="1" || env.get("NYASH_CLI_VERBOSE")=="1" { print("[mirbuilder/registry:" + nm + "]") } return out } }
|
||||
if nm == "return.bool" { local out = LowerReturnBoolBox.try_lower(s); if out != null { if env.get("HAKO_MIR_BUILDER_DEBUG")=="1" || env.get("NYASH_CLI_VERBOSE")=="1" { print("[mirbuilder/registry:" + nm + "]") } return out } }
|
||||
if nm == "return.logical" { local out = LowerReturnLogicalBox.try_lower(s); if out != null { if env.get("HAKO_MIR_BUILDER_DEBUG")=="1" || env.get("NYASH_CLI_VERBOSE")=="1" { print("[mirbuilder/registry:" + nm + "]") } return out } }
|
||||
if nm == "return.binop.varint" { local out = LowerReturnBinOpVarIntBox.try_lower(s); if out != null { if env.get("HAKO_MIR_BUILDER_DEBUG")=="1" || env.get("NYASH_CLI_VERBOSE")=="1" { print("[mirbuilder/registry:" + nm + "]") } return out } }
|
||||
if nm == "return.binop.varvar" { local out = LowerReturnBinOpVarVarBox.try_lower(s); if out != null { if env.get("HAKO_MIR_BUILDER_DEBUG")=="1" || env.get("NYASH_CLI_VERBOSE")=="1" { print("[mirbuilder/registry:" + nm + "]") } return out } }
|
||||
if nm == "return.binop.intint" { local out = LowerReturnBinOpBox.try_lower(s); if out != null { if env.get("HAKO_MIR_BUILDER_DEBUG")=="1" || env.get("NYASH_CLI_VERBOSE")=="1" { print("[mirbuilder/registry:" + nm + "]") } return out } }
|
||||
if nm == "return.int" { local out = LowerReturnIntBox.try_lower(s); if out != null { if env.get("HAKO_MIR_BUILDER_DEBUG")=="1" || env.get("NYASH_CLI_VERBOSE")=="1" { print("[mirbuilder/registry:" + nm + "]") } return out } }
|
||||
i = i + 1
|
||||
}
|
||||
// Fall-through to chain if none matched
|
||||
@ -88,7 +106,7 @@ static box MirBuilderBox {
|
||||
using "hako.mir.builder.internal.lower_return_var_local" as LowerReturnVarLocalBox
|
||||
using "hako.mir.builder.internal.lower_return_string" as LowerReturnStringBox
|
||||
using "hako.mir.builder.internal.lower_return_float" as LowerReturnFloatBox
|
||||
using "hako.mir.builder.internal.lower.logical" as LowerReturnLogicalBox
|
||||
using "hako.mir.builder.internal.lower_return_logical" as LowerReturnLogicalBox
|
||||
using "hako.mir.builder.internal.lower_return_method_array_map" as LowerReturnMethodArrayMapBox
|
||||
using "hako.mir.builder.internal.lower_return_bool" as LowerReturnBoolBox
|
||||
using "hako.mir.builder.internal.lower_return_binop_varint" as LowerReturnBinOpVarIntBox
|
||||
@ -314,22 +332,51 @@ static box MirBuilderBox {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Case (Int): Return(Int N)
|
||||
local k_int = s.indexOf("\"type\":\"Int\"", k_ret)
|
||||
if k_int >= 0 {
|
||||
local k_val = s.indexOf("\"value\":", k_int)
|
||||
if k_val >= 0 {
|
||||
local i = k_val + 8
|
||||
// Case (Int): Return(Int N) — ensure expr.type is Int (not Binary/Logical/etc)
|
||||
local k_expr = s.indexOf("\"expr\":{", k_ret)
|
||||
if k_expr >= 0 {
|
||||
// Check direct type after "expr":{
|
||||
local k_type_start = k_expr + 8
|
||||
local k_type = s.indexOf("\"type\":", k_type_start)
|
||||
if k_type >= 0 && k_type < k_type_start + 20 {
|
||||
// Extract the type value
|
||||
local k_type_val = k_type + 7
|
||||
local n = s.length()
|
||||
loop(i < n) { if s.substring(i,i+1) != " " { break } i = i + 1 }
|
||||
local j = i
|
||||
if j < n && s.substring(j,j+1) == "-" { j = j + 1 }
|
||||
local had = 0
|
||||
loop(j < n) { local ch = s.substring(j,j+1); if ch >= "0" && ch <= "9" { had = 1 j = j + 1 } else { break } }
|
||||
if had == 1 {
|
||||
local num = s.substring(i, j)
|
||||
local mir = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[{\"id\":0,\"instructions\":[{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + num + "}},{\"op\":\"ret\",\"value\":1}]}]}]}"
|
||||
return mir
|
||||
loop(k_type_val < n) { if s.substring(k_type_val, k_type_val+1) != " " && s.substring(k_type_val, k_type_val+1) != "\"" { break } k_type_val = k_type_val + 1 }
|
||||
// Check if it's "Int" (not "Binary", "Logical", "Var", etc)
|
||||
local is_int_type = 0
|
||||
if k_type_val + 3 <= n {
|
||||
if s.substring(k_type_val, k_type_val+3) == "Int" {
|
||||
// Verify it's followed by quote (not "Integer" or other extension)
|
||||
if k_type_val + 3 < n && s.substring(k_type_val+3, k_type_val+4) == "\"" {
|
||||
is_int_type = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
if is_int_type == 1 {
|
||||
local debug_on = 0
|
||||
if env.get("HAKO_MIR_BUILDER_DEBUG") == "1" || env.get("NYASH_CLI_VERBOSE") == "1" { debug_on = 1 }
|
||||
local k_expr_int = s.indexOf("\"type\":\"Int\"", k_expr)
|
||||
local k_val = s.indexOf("\"value\":", k_expr_int)
|
||||
if k_val >= 0 {
|
||||
local i = k_val + 8
|
||||
loop(i < n) { if s.substring(i,i+1) != " " { break } i = i + 1 }
|
||||
local j = i
|
||||
if j < n && s.substring(j,j+1) == "-" { j = j + 1 }
|
||||
local had = 0
|
||||
loop(j < n) { local ch = s.substring(j,j+1); if ch >= "0" && ch <= "9" { had = 1 j = j + 1 } else { break } }
|
||||
if had == 1 {
|
||||
local num = s.substring(i, j)
|
||||
if debug_on == 1 { print("[mirbuilder/fallback:Return(Int) val=" + num + "]") }
|
||||
local mir = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[{\"id\":0,\"instructions\":[{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + num + "}},{\"op\":\"ret\",\"value\":1}]}]}]}"
|
||||
return mir
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// expr.type is not Int (e.g. Binary) - don't match this fallback
|
||||
if env.get("HAKO_MIR_BUILDER_DEBUG") == "1" || env.get("NYASH_CLI_VERBOSE") == "1" {
|
||||
print("[mirbuilder/fallback:Return(Int) skip - expr.type not Int]")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,17 +15,20 @@ static box LowerReturnBinOpBox {
|
||||
local op = JsonFragBox.read_string_after(s, k_op + 5)
|
||||
if op == null { return null }
|
||||
if !(op == "+" || op == "-" || op == "*" || op == "/") { return null }
|
||||
// lhs int
|
||||
// lhs/rhs object starts
|
||||
local klhs = s.indexOf("\"lhs\":{", k_bin)
|
||||
local krhs = s.indexOf("\"rhs\":{", k_bin)
|
||||
if klhs < 0 { return null }
|
||||
// strictly ensure lhs node is Int by bounding search before rhs start
|
||||
local ti = s.indexOf("\"type\":\"Int\"", klhs)
|
||||
if ti < 0 { return null }
|
||||
if krhs >= 0 && ti >= krhs { return null }
|
||||
local kv_lhs = s.indexOf("\"value\":", ti)
|
||||
if kv_lhs < 0 { return null }
|
||||
if krhs >= 0 && kv_lhs >= krhs { return null }
|
||||
local lhs_val = JsonFragBox.read_int_after(s, kv_lhs + 8)
|
||||
if lhs_val == null { return null }
|
||||
// rhs int
|
||||
local krhs = s.indexOf("\"rhs\":{", k_bin)
|
||||
if krhs < 0 { return null }
|
||||
local ti2 = s.indexOf("\"type\":\"Int\"", krhs)
|
||||
if ti2 < 0 { return null }
|
||||
|
||||
@ -7,13 +7,37 @@ static box LowerReturnIntBox {
|
||||
local s = "" + program_json
|
||||
local k_ret = s.indexOf("\"type\":\"Return\"")
|
||||
if k_ret < 0 { return null }
|
||||
// Expect Int after Return
|
||||
local k_int = s.indexOf("\"type\":\"Int\"", k_ret)
|
||||
// Find expr object
|
||||
local k_expr = s.indexOf("\"expr\":{", k_ret)
|
||||
if k_expr < 0 { return null }
|
||||
// Check that expr.type is directly Int (not Binary, Logical, Var, etc)
|
||||
local k_type_start = k_expr + 8
|
||||
local k_type = s.indexOf("\"type\":", k_type_start)
|
||||
if k_type < 0 || k_type > k_type_start + 20 { return null }
|
||||
// Extract type value to verify it's "Int"
|
||||
local k_type_val = k_type + 7
|
||||
local n = s.length()
|
||||
loop(k_type_val < n) {
|
||||
local ch = s.substring(k_type_val, k_type_val+1)
|
||||
if ch != " " && ch != "\"" { break }
|
||||
k_type_val = k_type_val + 1
|
||||
}
|
||||
// Verify it's exactly "Int" followed by quote
|
||||
if k_type_val + 3 > n { return null }
|
||||
if s.substring(k_type_val, k_type_val+3) != "Int" { return null }
|
||||
if k_type_val + 3 >= n { return null }
|
||||
if s.substring(k_type_val+3, k_type_val+4) != "\"" { return null }
|
||||
// Now extract the value
|
||||
local k_int = s.indexOf("\"type\":\"Int\"", k_expr)
|
||||
if k_int < 0 { return null }
|
||||
// Read value after Int
|
||||
local kv = s.indexOf("\"value\":", k_int); if kv < 0 { return null }
|
||||
local val = JsonFragBox.read_int_after(s, kv + 8)
|
||||
if val == null { return null }
|
||||
local debug_on = 0
|
||||
if env.get("HAKO_MIR_BUILDER_DEBUG") == "1" || env.get("NYASH_CLI_VERBOSE") == "1" {
|
||||
debug_on = 1
|
||||
print("[mirbuilder/registry:return.int val=" + val + "]")
|
||||
}
|
||||
// Emit minimal MIR JSON v0 (functions as array; blocks use id field)
|
||||
// Shape expected by src/runner/mir_json_v0.rs::parse_mir_v0_to_module
|
||||
local mir = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[{\"id\":0,\"instructions\":[{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + val + "}},{\"op\":\"ret\",\"value\":1}]}]}]}"
|
||||
|
||||
@ -21,8 +21,11 @@ static box LowerReturnLogicalBox {
|
||||
local op = JsonFragBox.read_string_after(s, k_op + 5)
|
||||
if op == null { return null }
|
||||
if !(op == "&&" || op == "||") { return null }
|
||||
local debug_on = 0
|
||||
if env.get("HAKO_MIR_BUILDER_DEBUG") == "1" || env.get("NYASH_CLI_VERBOSE") == "1" { debug_on = 1 }
|
||||
// Resolve lhs to 0/1 (Bool or Var with Local Bool) - robust version
|
||||
local lhs_true = null
|
||||
local lhs_name = null
|
||||
{
|
||||
local klhs_b = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Bool\"", k_log)
|
||||
if klhs_b >= 0 {
|
||||
@ -34,15 +37,21 @@ static box LowerReturnLogicalBox {
|
||||
local klhs_v = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\"", k_log)
|
||||
if klhs_v >= 0 {
|
||||
local kn = JsonFragBox.index_of_from(s, "\"name\":", klhs_v)
|
||||
if kn < 0 { return null }
|
||||
local name = JsonFragBox.read_string_after(s, kn + 7)
|
||||
if name != null { lhs_true = PatternUtilBox.find_local_bool_before(s, name, k_log) }
|
||||
if kn < 0 { if debug_on == 1 { print("[logical/miss:lhs_name extraction]") } return null }
|
||||
lhs_name = JsonFragBox.read_string_after(s, kn + 7)
|
||||
if lhs_name != null {
|
||||
lhs_true = PatternUtilBox.find_local_bool_before(s, lhs_name, k_log)
|
||||
if debug_on == 1 && lhs_true == null { print("[logical/miss:lhs_true for name=" + lhs_name + "]") }
|
||||
} else {
|
||||
if debug_on == 1 { print("[logical/miss:lhs_name null]") }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if lhs_true == null { return null }
|
||||
if lhs_true == null { if debug_on == 1 { print("[logical/miss:lhs_true final]") } return null }
|
||||
// Resolve rhs to 0/1 (Bool or Var) - robust version
|
||||
local rhs_true = null
|
||||
local rhs_name = null
|
||||
{
|
||||
local krhs_b = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Bool\"", k_log)
|
||||
if krhs_b >= 0 {
|
||||
@ -54,15 +63,23 @@ static box LowerReturnLogicalBox {
|
||||
local krhs_v = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\"", k_log)
|
||||
if krhs_v >= 0 {
|
||||
local kn2 = JsonFragBox.index_of_from(s, "\"name\":", krhs_v)
|
||||
if kn2 < 0 { return null }
|
||||
local name2 = JsonFragBox.read_string_after(s, kn2 + 7)
|
||||
if name2 != null { rhs_true = PatternUtilBox.find_local_bool_before(s, name2, k_log) }
|
||||
if kn2 < 0 { if debug_on == 1 { print("[logical/miss:rhs_name extraction]") } return null }
|
||||
rhs_name = JsonFragBox.read_string_after(s, kn2 + 7)
|
||||
if rhs_name != null {
|
||||
rhs_true = PatternUtilBox.find_local_bool_before(s, rhs_name, k_log)
|
||||
if debug_on == 1 && rhs_true == null { print("[logical/miss:rhs_true for name=" + rhs_name + "]") }
|
||||
} else {
|
||||
if debug_on == 1 { print("[logical/miss:rhs_name null]") }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if rhs_true == null { return null }
|
||||
if rhs_true == null { if debug_on == 1 { print("[logical/miss:rhs_true final]") } return null }
|
||||
|
||||
// Build MIR(JSON v0) string directly (functions[]/name="main"/blocks.id)
|
||||
if debug_on == 1 {
|
||||
print("[mirbuilder/registry:return.logical op=" + op + " lhs_true=" + lhs_true + " rhs_true=" + rhs_true + "]")
|
||||
}
|
||||
local json_head = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":["
|
||||
local bb0 = "{\"id\":0,\"instructions\":[{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + lhs_true + "}},{\"op\":\"branch\",\"cond\":1,\"then\":1,\"else\":2}]}"
|
||||
if op == "&&" {
|
||||
|
||||
@ -47,17 +47,27 @@ static box PatternUtilBox {
|
||||
local pos=0; local last=-1
|
||||
loop(true){ local k=JsonFragBox.index_of_from(s, "\"type\":\"Local\"",pos); if k<0||k>=before_pos{break}; local kn=JsonFragBox.index_of_from(s, "\"name\":\"",k); if kn>=0{ local ii=kn+8; local nn=s.length(); local jj=ii; loop(jj<nn){ if s.substring(jj,jj+1)=="\"" {break} jj=jj+1 } if s.substring(ii,jj)==name { last=k } } pos=k+1 }
|
||||
if last<0 { return null }
|
||||
local ki=s.indexOf("\"type\":\"Int\"",last); if ki<0||ki>=before_pos { return null }
|
||||
local kv=s.indexOf("\"value\":",ki); if kv<0 { return null }
|
||||
// Bound the search between this Local and the next Local/before_pos
|
||||
local next = JsonFragBox.index_of_from(s, "\"type\":\"Local\"", last + 1)
|
||||
if next < 0 || next > before_pos { next = before_pos }
|
||||
local ki = s.indexOf("\"type\":\"Int\"", last)
|
||||
if ki < 0 || ki >= next { return null }
|
||||
local kv = s.indexOf("\"value\":", ki)
|
||||
if kv < 0 || kv >= next { return null }
|
||||
return JsonFragBox.read_int_after(s, kv+8)
|
||||
}
|
||||
find_local_bool_before(s, name, before_pos) {
|
||||
local pos=0; local last=-1
|
||||
loop(true){ local k=JsonFragBox.index_of_from(s, "\"type\":\"Local\"",pos); if k<0||k>=before_pos{break}; local kn=JsonFragBox.index_of_from(s, "\"name\":\"",k); if kn>=0{ local ii=kn+8; local nn=s.length(); local jj=ii; loop(jj<nn){ if s.substring(jj,jj+1)=="\"" {break} jj=jj+1 } if s.substring(ii,jj)==name { last=k } } pos=k+1 }
|
||||
if last<0 { return null }
|
||||
local kb=s.indexOf("\"type\":\"Bool\"",last); if kb<0||kb>=before_pos { return null }
|
||||
local kv=s.indexOf("\"value\":",kb); if kv<0 { return null }
|
||||
return JsonFragBox.read_bool_after(s, kv+8)
|
||||
local next = JsonFragBox.index_of_from(s, "\"type\":\"Local\"", last + 1)
|
||||
if next < 0 || next > before_pos { next = before_pos }
|
||||
local kb = s.indexOf("\"type\":\"Bool\"", last)
|
||||
if kb < 0 || kb >= next { return null }
|
||||
local kv = s.indexOf("\"value\":", kb)
|
||||
if kv < 0 || kv >= next { return null }
|
||||
// JSON v0 uses 0/1 for bool values, not true/false literals
|
||||
return JsonFragBox.read_int_after(s, kv+8)
|
||||
}
|
||||
|
||||
// Find the last Local(Int) before a given position (name-agnostic).
|
||||
|
||||
@ -10,7 +10,43 @@ using selfhost.vm.helpers.method_alias_policy as MethodAliasPolicy
|
||||
using selfhost.vm.boxes.abi_adapter_registry as AbiAdapterRegistryBox
|
||||
|
||||
static box MirCallV1HandlerBox {
|
||||
// キー正規化ヘルパー(SSOT)
|
||||
_norm_key_str(s) {
|
||||
if s == null { return null }
|
||||
local orig = s
|
||||
|
||||
// 先頭・末尾の引用符を除去("k1" → k1)
|
||||
local len = s.length()
|
||||
if len >= 2 {
|
||||
local first = s.substring(0, 1)
|
||||
local last = s.substring(len - 1, len)
|
||||
if first == "\"" && last == "\"" {
|
||||
s = s.substring(1, len - 1)
|
||||
}
|
||||
}
|
||||
|
||||
// [map/missing] はnullを返す
|
||||
if s.indexOf("[map/missing]") >= 0 {
|
||||
return null
|
||||
}
|
||||
|
||||
if env.get("HAKO_VM_MIRCALL_TRACE_KEYS") == "1" {
|
||||
print("[vm/_norm_key_str] IN=" + orig + " OUT=" + s)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// デバッグトレース(任意)
|
||||
_norm_key_dbg(raw, norm) {
|
||||
local trace_keys = env.get("HAKO_VM_MIRCALL_TRACE_KEYS")
|
||||
if trace_keys == "1" {
|
||||
print("[vm/trace/keys] raw=" + raw + " norm=" + norm)
|
||||
}
|
||||
}
|
||||
|
||||
handle(seg, regs) {
|
||||
print("[DEBUG_HANDLER_ENTRY] seg=" + seg.substring(0, 80))
|
||||
// Constructor: write dst=0 (SSA continuity)
|
||||
if seg.indexOf("\"type\":\"Constructor\"") >= 0 {
|
||||
local d0 = JsonFragBox.get_int(seg, "dst"); if d0 != null { regs.setField(StringHelpers.int_to_str(d0), "0") }
|
||||
@ -83,19 +119,22 @@ static box MirCallV1HandlerBox {
|
||||
}
|
||||
// Map.set: 重複キー検知つきでサイズ更新 + 値保存(値状態ON時)
|
||||
if btype == "MapBox" && mname == "set" {
|
||||
print("[DEBUG_ADAPTER_MAP_SET] ENTER")
|
||||
// 受信者・キー抽出
|
||||
local arg0 = MiniMirV1Scan.first_arg_register(seg)
|
||||
local key_str = null
|
||||
if arg0 >= 0 {
|
||||
key_str = regs.getField(StringHelpers.int_to_str(arg0))
|
||||
// MapBox.get returns "[map/missing] ..." for missing keys; treat as null
|
||||
if key_str != null && key_str.indexOf("[map/missing]") >= 0 { key_str = null }
|
||||
local key_str_raw = regs.getField(StringHelpers.int_to_str(arg0))
|
||||
key_str = me._norm_key_str(key_str_raw)
|
||||
me._norm_key_dbg(key_str_raw, key_str)
|
||||
print("[DEBUG_ADAPTER_MAP_SET] raw=" + key_str_raw + " norm=" + key_str)
|
||||
}
|
||||
// 重複キー検知(presence フラグを別ネーム空間に保持)
|
||||
if key_str != null {
|
||||
local rid_s = rid == null ? "null" : (""+rid)
|
||||
local pres_key = "hvm.map.k:" + (per_recv == "1" ? rid_s : "*") + ":" + key_str
|
||||
local had = regs.getField(pres_key)
|
||||
if env.get("HAKO_VM_MIRCALL_TRACE") == "1" { print("[vm/trace/adapter] pres_key=" + pres_key + " had=" + had + " cur_len=" + cur_len) }
|
||||
if had == null {
|
||||
regs.setField(pres_key, "1")
|
||||
cur_len = cur_len + 1
|
||||
@ -126,9 +165,9 @@ static box MirCallV1HandlerBox {
|
||||
if btype == "MapBox" && mname == "get" && value_state == "1" {
|
||||
local arg0 = MiniMirV1Scan.first_arg_register(seg)
|
||||
if arg0 >= 0 {
|
||||
local key_str = regs.getField(StringHelpers.int_to_str(arg0))
|
||||
// MapBox.get returns "[map/missing] ..." for missing keys; treat as null
|
||||
if key_str != null && key_str.indexOf("[map/missing]") >= 0 { key_str = null }
|
||||
local key_str_raw = regs.getField(StringHelpers.int_to_str(arg0))
|
||||
local key_str = me._norm_key_str(key_str_raw)
|
||||
me._norm_key_dbg(key_str_raw, key_str)
|
||||
if key_str != null {
|
||||
local val_key = MethodAliasPolicy.recv_map_key(per_recv, rid, key_str)
|
||||
local val_str = regs.getField(val_key)
|
||||
@ -146,9 +185,9 @@ static box MirCallV1HandlerBox {
|
||||
local arg0 = MiniMirV1Scan.first_arg_register(seg)
|
||||
local has_result = 0
|
||||
if arg0 >= 0 {
|
||||
local key_str = regs.getField(StringHelpers.int_to_str(arg0))
|
||||
// MapBox.get returns "[map/missing] ..." for missing keys; treat as null
|
||||
if key_str != null && key_str.indexOf("[map/missing]") >= 0 { key_str = null }
|
||||
local key_str_raw = regs.getField(StringHelpers.int_to_str(arg0))
|
||||
local key_str = me._norm_key_str(key_str_raw)
|
||||
me._norm_key_dbg(key_str_raw, key_str)
|
||||
if key_str != null {
|
||||
local val_key = MethodAliasPolicy.recv_map_key(per_recv, rid, key_str)
|
||||
local val_str = regs.getField(val_key)
|
||||
@ -193,23 +232,41 @@ static box MirCallV1HandlerBox {
|
||||
local d1 = JsonFragBox.get_int(seg, "dst"); if d1 != null { regs.setField(StringHelpers.int_to_str(d1), "0") }
|
||||
return
|
||||
}
|
||||
// Map.set: 重複キー検知つきサイズ更新(値状態に依存しない最小実装)
|
||||
// Map.set: 重複キー検知つきサイズ更新(値状態ONなら値も保存)
|
||||
if btype == "MapBox" && mname == "set" {
|
||||
// キー抽出
|
||||
local arg0 = MiniMirV1Scan.first_arg_register(seg)
|
||||
if arg0 >= 0 {
|
||||
local key_str = regs.getField(StringHelpers.int_to_str(arg0))
|
||||
// MapBox.get returns "[map/missing] ..." for missing keys; treat as null
|
||||
if key_str != null && key_str.indexOf("[map/missing]") >= 0 { key_str = null }
|
||||
local key_str_raw = regs.getField(StringHelpers.int_to_str(arg0))
|
||||
local key_str = me._norm_key_str(key_str_raw)
|
||||
me._norm_key_dbg(key_str_raw, key_str)
|
||||
print("[DEBUG_MAP_SET] raw=" + key_str_raw + " norm=" + key_str)
|
||||
if key_str != null {
|
||||
local rid_s = rid == null ? "null" : (""+rid)
|
||||
local pres_key = "hvm.map.k:" + (per_recv == "1" ? rid_s : "*") + ":" + key_str
|
||||
local had = regs.getField(pres_key)
|
||||
print("[DEBUG_MAP_SET] pres_key=" + pres_key + " had=" + had + " cur_len=" + cur_len)
|
||||
if env.get("HAKO_VM_MIRCALL_TRACE") == "1" { print("[vm/trace/fallback] pres_key=" + pres_key + " had=" + had + " cur_len=" + cur_len) }
|
||||
if had == null {
|
||||
regs.setField(pres_key, "1")
|
||||
cur_len = cur_len + 1
|
||||
regs.setField(key, StringHelpers.int_to_str(cur_len))
|
||||
print("[DEBUG_MAP_SET] NEW KEY, cur_len now=" + cur_len)
|
||||
if env.get("HAKO_VM_MIRCALL_TRACE") == "1" { print("[vm/trace] map.set(fallback,new) cur_len=" + cur_len) }
|
||||
} else {
|
||||
print("[DEBUG_MAP_SET] DUP KEY, cur_len unchanged=" + cur_len)
|
||||
}
|
||||
// 値状態ON時は値も保持(get/hasで参照可能に)
|
||||
local value_state2 = env.get("HAKO_VM_MIRCALL_VALUESTATE"); if value_state2 == null { value_state2 = "0" }
|
||||
if value_state2 == "1" {
|
||||
local arg1_id2 = MiniMirV1Scan.nth_arg_register(seg, 1)
|
||||
if arg1_id2 >= 0 {
|
||||
local val_str2 = regs.getField(StringHelpers.int_to_str(arg1_id2))
|
||||
if val_str2 != null {
|
||||
local vkey2 = MethodAliasPolicy.recv_map_key(per_recv, rid, key_str)
|
||||
regs.setField(vkey2, ""+val_str2)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cur_len = cur_len + 1
|
||||
|
||||
@ -164,6 +164,7 @@ static box NyVmDispatcherV1Box {
|
||||
}
|
||||
// Main entry: Choose internal scanner when enabled; otherwise delegate to Mini‑VM
|
||||
run(json) {
|
||||
if env.get("HAKO_TRACE_EXECUTION") == "1" { print("[trace] executor: hakovm (hako)") }
|
||||
// Typed IR primary (限定): 構造IR生成を有効化しつつ既存フローを使用(挙動不変)
|
||||
if env.get("HAKO_V1_TYPED_IR_PRIMARY") == "1" {
|
||||
// ShadowをONにして構造IR生成のオーバーヘッドを観測(必要時)
|
||||
|
||||
Reference in New Issue
Block a user