Files
hakorune/tools/hako_check/render/graphviz.hako
nyash-codex 301b1d212a Phase 21.2 Complete: VM Adapter正規実装 + devブリッジ完全撤去
## 🎉 Phase 21.2完全達成

###  実装完了
- VM static box 永続化(singleton infrastructure)
- devブリッジ完全撤去(adapter_dev.rs削除、by-name dispatch削除)
- .hako正規実装(MirCallV1Handler, AbiAdapterRegistry等)
- text-merge経路完全動作
- 全phase2120 adapter reps PASS(7テスト)

### 🐛 バグ修正
1. strip_local_decl修正
   - トップレベルのみlocal削除、メソッド内は保持
   - src/runner/modes/common_util/hako.rs:29

2. static box フィールド永続化
   - MirInterpreter singleton storage実装
   - me parameter binding修正(1:1マッピング)
   - getField/setField string→singleton解決
   - src/backend/mir_interpreter/{mod,exec,handlers/boxes_object_fields}.rs

3. Map.len alias rc=0修正
   - [map/missing]パターン検出でnull扱い(4箇所)
   - lang/src/vm/boxes/mir_call_v1_handler.hako:91-93,131-133,151-153,199-201

### 📁 主要変更ファイル

#### Rust(VM Runtime)
- src/backend/mir_interpreter/mod.rs - static box singleton storage
- src/backend/mir_interpreter/exec.rs - parameter binding fix
- src/backend/mir_interpreter/handlers/boxes_object_fields.rs - singleton resolution
- src/backend/mir_interpreter/handlers/calls.rs - dev bridge removal
- src/backend/mir_interpreter/utils/mod.rs - adapter_dev module removal
- src/backend/mir_interpreter/utils/adapter_dev.rs - DELETED (7555 bytes)
- src/runner/modes/vm.rs - static box declaration collection
- src/runner/modes/common_util/hako.rs - strip_local_decl fix
- src/instance_v2.rs - Clone implementation

#### Hako (.hako実装)
- lang/src/vm/boxes/mir_call_v1_handler.hako - [map/missing] detection
- lang/src/vm/boxes/abi_adapter_registry.hako - NEW (adapter registry)
- lang/src/vm/helpers/method_alias_policy.hako - method alias support

#### テスト
- tools/smokes/v2/profiles/quick/core/phase2120/s3_vm_adapter_*.sh - 7 new tests

### 🎯 テスト結果
```
 s3_vm_adapter_array_len_canary_vm.sh
 s3_vm_adapter_array_len_per_recv_canary_vm.sh
 s3_vm_adapter_array_length_alias_canary_vm.sh
 s3_vm_adapter_array_size_alias_canary_vm.sh
 s3_vm_adapter_map_len_alias_state_canary_vm.sh
 s3_vm_adapter_map_length_alias_state_canary_vm.sh
 s3_vm_adapter_map_size_struct_canary_vm.sh
```

環境フラグ: HAKO_ABI_ADAPTER=1 HAKO_ABI_ADAPTER_DEV=0

### 🏆 設計品質
-  ハードコード禁止(AGENTS.md 5.1)完全準拠
-  構造的・一般化設計(特定Box名のif分岐なし)
-  後方互換性保持(既存コード破壊ゼロ)
-  text-merge経路(.hako依存関係正しくマージ)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 19:32:44 +09:00

114 lines
3.6 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

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

// tools/hako_check/render/graphviz.hako — GraphvizRenderBox (MVP)
// Render minimal DOT graph from one or more Analysis IRs.
using selfhost.shared.common.string_helpers as Str
static box GraphvizRenderBox {
render_multi(irs) {
// irs: ArrayBox of IR Map
print("digraph Hako {")
// optional graph attributes (kept minimal)
// print(" rankdir=LR;")
// Node and edge sets to avoid duplicates
local nodes = new MapBox()
local edges = new MapBox()
if irs != null {
local gi = 0
while gi < irs.size() {
local ir = irs.get(gi)
me._render_ir(ir, nodes, edges)
gi = gi + 1
}
}
// Emit nodes
local itn = nodes
// Map iteration: keys() not available → store labels as keys in map
// Use a synthetic loop by scanning a known list captured during _render_ir
// For MVP, nodes map has key=name, value=1
// We cannot iterate map keys deterministically; accept arbitrary order.
// Re-emitting by re-collecting from edges as well (ensures endpoints appear).
// Emit edges
if edges != null {
// edges map key = from + "\t" + to
// naive iteration by trying to get keys from a stored list
// We kept an ArrayBox under edges.get("__keys__") for listing
local ks = edges.get("__keys__")
if ks != null {
local ei = 0
while ei < ks.size() {
local key = ks.get(ei)
local tab = key.indexOf("\t")
if tab > 0 {
local src = key.substring(0, tab)
local dst = key.substring(tab+1)
print(" \"" + src + "\" -> \"" + dst + "\";")
// also register nodes (in case they werent explicitly collected)
nodes.set(src, 1)
nodes.set(dst, 1)
}
ei = ei + 1
}
}
}
// Now emit nodes at the end for any isolated methods
// Rebuild a list of node keys from a synthetic array stored under nodes.get("__keys__")
local nk = nodes.get("__keys__")
if nk != null {
local ni = 0
while ni < nk.size() {
local name = nk.get(ni)
print(" \"" + name + "\";")
ni = ni + 1
}
}
print("}")
return 0
}
_render_ir(ir, nodes, edges) {
if ir == null { return }
// methods
local ms = ir.get("methods")
if ms != null {
local mi = 0
while mi < ms.size() {
me._add_node(nodes, ms.get(mi))
mi = mi + 1
}
}
// calls
local cs = ir.get("calls")
if cs != null {
local ci = 0
while ci < cs.size() {
local c = cs.get(ci)
local f = c.get("from")
local t = c.get("to")
me._add_edge(edges, f, t)
ci = ci + 1
}
}
}
_add_node(nodes, name) {
if name == null { return }
nodes.set(name, 1)
// also store a list of keys for emitting (since Map has no key iterator)
local arr = nodes.get("__keys__"); if arr == null { arr = new ArrayBox(); nodes.set("__keys__", arr) }
// avoid duplicates
local seen = 0
local i = 0; while i < arr.size() { if arr.get(i) == name { seen = 1; break } i = i + 1 }
if seen == 0 { arr.push(name) }
}
_add_edge(edges, src, dst) {
if src == null || dst == null { return }
local key = src + "\t" + dst
if edges.get(key) == null { edges.set(key, 1) }
local arr = edges.get("__keys__"); if arr == null { arr = new ArrayBox(); edges.set("__keys__", arr) }
// avoid duplicates
local seen = 0
local i = 0; while i < arr.size() { if arr.get(i) == key { seen = 1; break } i = i + 1 }
if seen == 0 { arr.push(key) }
}
}
static box GraphvizRenderMain { method main(args) { return 0 } }