Phase 161 Task 1 completion: Complete documentation of MIR JSON v1 and JoinIR JSON schemas with: - Full schema definitions for all 14 MIR instruction types - PHI/Loop/If identification methods and criteria - Type hint propagation algorithms - 3 representative JSON snippets (if_select_simple, min_loop, skip_ws) - 5-stage implementation checklist for .hako Analyzer Recommendation: Prioritize MIR JSON v1 over JoinIR for initial .hako Analyzer implementation due to unified Call instruction support and CFG integration (Phase 155). docs(phase173b): Add comprehensive StaticBoxRegistry boxification assessment Confirms Phase 173-B reached optimal complexity: - All 3 fields (declarations, detected_boxes, instances) are necessary - All public methods (exists, get_or_create_instance, register_declaration) serve distinct purposes - Design principles properly applied (箱化、境界作成、Fail-Fast、遅延シングルトン) - No further simplification possible without losing correctness - Ready for Phase 34+ work 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
24 KiB
Phase 161: Rust JoinIR/MIR を .hako から読む Analyzer 実装
Task 1 結果: 入力フォーマット仕様完全調査
実施日: 2025-12-04
📋 調査概要
本ドキュメントは、Phase 161 で実装する .hako 側 Analyzer Box が読むべき Rust JoinIR/MIR JSON フォーマットの完全なインベントリです。
調査対象ファイル
src/mir/join_ir/json.rs- JoinIR JSON シリアライザsrc/runner/mir_json_emit.rs- MIR JSON v0/v1 エミットsrc/runner/mir_json_v0.rs- MIR JSON v0 パーサーsrc/tests/joinir_json_min.rs- テスト例tests/fixtures/joinir/v0_*.jsonir- 実際の JoinIR JSON サンプルbuild/doctor/mir/*.mir.json- 実際の MIR JSON サンプル
🎯 推奨アプローチ: MIR JSON v1 を優先
理由
-
統一Call命令対応 (Phase 15.5):
- MIR JSON v1 は統一Call (
mir_call) を完全サポート - Callee型(Global/Method/Constructor/Closure/Value/Extern)を型安全に表現
- Phase 15.5 で確立された設計と完全一致
- MIR JSON v1 は統一Call (
-
スキーマバージョン管理:
- v1 には
schema_version,capabilities,metadataが含まれる - 将来の拡張性を保証
- v1 には
-
CFG情報の統合:
- MIR JSON v1 には
cfg(Control Flow Graph) 情報が含まれる - hako_check で使用する制御フロー解析データが利用可能
- MIR JSON v1 には
-
JoinIR → MIR 変換経路の安定性:
- JoinIR → MIR 変換は Phase 32 で完成済み
- JoinIR は MIR の前段階であり、MIR のほうがより最適化・安定している
📊 1. MIR JSON v1 最小構造(推奨)
1.1 ルートレベル
{
"schema_version": "1.0",
"capabilities": [
"unified_call", // 統一Call命令サポート
"phi", // SSA PHI関数
"effects", // エフェクト追跡
"callee_typing" // 型安全なCallee解決
],
"metadata": {
"generator": "nyash-rust",
"phase": "15.5",
"build_time": "Phase 15.5 Development",
"features": ["mir_call_unification", "json_v1_schema"]
},
"functions": [...], // 関数配列(下記参照)
"cfg": { // 制御フロー情報(Phase 155追加)
"functions": {...} // 関数ごとのCFG情報
}
}
重要キー:
schema_version: "1.0"(固定)capabilities: 機能リスト(.hako側で対応機能を判定可能)functions: 関数定義配列cfg: 制御フロー情報(hako_check用)
1.2 関数レベル
{
"name": "main",
"params": [0, 1, 2], // ValueId配列
"entry": 0, // エントリブロックID
"blocks": [...] // BasicBlock配列(下記参照)
}
重要キー:
name: 関数名("main","Main.main","Main.equals/1"等)params: パラメータのValueId配列entry: エントリBasicBlockのIDblocks: BasicBlock配列
1.3 BasicBlockレベル
{
"id": 0,
"instructions": [...] // Instruction配列(下記参照)
}
重要キー:
id: BasicBlockのID(u32)instructions: 命令配列
1.4 命令レベル(全命令タイプ)
1.4.1 基本命令
Const命令:
{
"op": "const",
"dst": 0,
"value": {
"type": "i64", // "i64" | "f64" | "void" | {"kind":"handle","box_type":"StringBox"}
"value": 42 // 実際の値
}
}
Copy命令:
{
"op": "copy",
"dst": 1,
"src": 0
}
BinOp命令:
{
"op": "binop",
"operation": "+", // "+"|"-"|"*"|"/"|"%"|"&"|"|"|"^"|"<<"|">>"|"&&"|"||"
"lhs": 0,
"rhs": 1,
"dst": 2,
"dst_type": {...} // オプション: StringBox等の型ヒント
}
UnaryOp命令:
{
"op": "unop",
"kind": "neg", // "neg" | "not" | "bitnot"
"src": 0,
"dst": 1
}
Compare命令:
{
"op": "compare",
"operation": "==", // "==" | "!=" | "<" | "<=" | ">" | ">="
"lhs": 0,
"rhs": 1,
"dst": 2,
"cmp_kind": "string" // オプション: 文字列比較ヒント
}
1.4.2 制御フロー命令
Branch命令:
{
"op": "branch",
"cond": 0,
"then": 1,
"else": 2
}
Jump命令:
{
"op": "jump",
"target": 3
}
Return命令:
{
"op": "ret",
"value": 0 // null の場合は void return
}
PHI命令(SSA合流点):
{
"op": "phi",
"dst": 10,
"incoming": [
[5, 1], // [ValueId, BasicBlockId] のペア
[7, 2]
],
"dst_type": {...} // オプション: 型ヒント
}
1.4.3 Box操作命令
NewBox命令:
{
"op": "newbox",
"type": "StringBox",
"args": [0, 1],
"dst": 2
}
BoxCall命令(v0形式):
{
"op": "boxcall",
"box": 0,
"method": "length",
"args": [1],
"dst": 2,
"dst_type": {...} // オプション: 戻り値型ヒント
}
1.4.4 統一Call命令(v1形式、推奨)
MirCall命令(統一Call):
{
"op": "mir_call",
"dst": 10,
"mir_call": {
"callee": {
"type": "Method", // "Global"|"Method"|"Constructor"|"Closure"|"Value"|"Extern"
"box_name": "StringBox",
"method": "substring",
"receiver": 0,
"certainty": "Known" // "Known" | "Union"
},
"args": [1, 2],
"effects": ["IO"], // エフェクトリスト
"flags": {}
}
}
Calleeタイプ別構造:
- Global Call:
{
"type": "Global",
"name": "nyash.builtin.print"
}
- Method Call:
{
"type": "Method",
"box_name": "StringBox",
"method": "substring",
"receiver": 0,
"certainty": "Known"
}
- Constructor Call:
{
"type": "Constructor",
"box_type": "StringBox"
}
- Closure Call:
{
"type": "Closure",
"params": ["x", "y"],
"captures": [["env", 10], ["state", 11]],
"me_capture": 12
}
- Value Call(第一級関数):
{
"type": "Value",
"function_value": 5
}
- Extern Call:
{
"type": "Extern",
"name": "nyash.console.log"
}
1.4.5 その他命令
TypeOp命令:
{
"op": "typeop",
"operation": "check", // "check" | "cast"
"src": 0,
"dst": 1,
"target_type": "StringBox"
}
ExternCall命令(v0形式):
{
"op": "externcall",
"func": "nyash.console.log",
"args": [0],
"dst": null,
"dst_type": "i64"
}
📊 2. JoinIR JSON v0 構造(参考)
JoinIR は MIR の前段階であり、継続渡しスタイル (CPS) で表現されます。
2.1 ルートレベル
{
"version": 0,
"entry": 0, // エントリ関数のID
"functions": [...] // JoinFunction配列
}
2.2 関数レベル
{
"id": 0,
"name": "skip",
"params": [3000],
"exit_cont": null, // 終了継続(オプション)
"body": [...] // JoinInst配列
}
2.3 命令レベル
Compute命令(MIRライクな計算):
{
"type": "compute",
"op": {
"kind": "const",
"dst": 3001,
"value_type": "integer",
"value": 0
}
}
Call命令(継続渡し):
{
"type": "call",
"func": 1,
"args": [3000, 3001, 3002],
"k_next": null, // 継続先(オプション)
"dst": null // 戻り値先(オプション)
}
Jump命令(継続へのジャンプ):
{
"type": "jump",
"cont": 0,
"args": [4001],
"cond": 4003 // 条件(オプション)
}
Select命令(Phase 33追加):
{
"type": "select",
"dst": 10,
"cond": 1,
"then_val": 20,
"else_val": 30,
"type_hint": "..." // オプション
}
IfMerge命令(Phase 33-6追加):
{
"type": "if_merge",
"cond": 1,
"merges": [
{"dst": 10, "then_val": 20, "else_val": 30},
{"dst": 11, "then_val": 21, "else_val": 31}
],
"k_next": null
}
🎯 3. .hako Analyzer Box 実装推奨事項
3.1 優先実装順序
-
Phase 161-1: MIR JSON v1 基本構造読み込み
- ルート構造(schema_version, capabilities, functions)
- 関数構造(name, params, entry, blocks)
- BasicBlock構造(id, instructions)
-
Phase 161-2: 基本命令対応
- Const, Copy, BinOp, Compare
- Branch, Jump, Return
- PHI(SSA合流点)
-
Phase 161-3: 統一Call命令対応
- MirCall(6種のCalleeタイプ)
- エフェクト追跡
- 型ヒント処理
-
Phase 161-4: Box操作命令対応
- NewBox, BoxCall
- TypeOp
-
Phase 161-5: CFG情報活用
- 制御フロー解析
- デッドコード検出
- 到達可能性解析
3.2 必須読み取りキー一覧
最小限の .hako Analyzer が読むべきキー:
ルートレベル
- ✅
schema_version- バージョン確認 - ✅
capabilities- 機能対応チェック - ✅
functions- 関数配列
関数レベル
- ✅
name- 関数名 - ✅
params- パラメータValueId配列 - ✅
entry- エントリブロックID - ✅
blocks- BasicBlock配列
BasicBlockレベル
- ✅
id- ブロックID - ✅
instructions- 命令配列
命令レベル(最小セット)
- ✅
op- 命令タイプ識別子 - ✅
dst- 出力先ValueId - ✅
value- Constの値 - ✅
operation- BinOp/Compareの演算子 - ✅
lhs,rhs- 二項演算のオペランド - ✅
cond,then,else- Branch分岐先 - ✅
target- Jump先 - ✅
incoming- PHIの入力ペア
統一Call命令レベル(Phase 161-3以降)
- ✅
mir_call- 統一Call構造 - ✅
callee.type- Calleeタイプ - ✅
args- 引数ValueId配列 - ✅
effects- エフェクトリスト
🔍 4. 型情報の読み取り方法
4.1 MirType表現
MIR JSON では型情報が以下の形式で表現されます:
プリミティブ型:
"i64"- 整数"f64"- 浮動小数点"void"- void型
Box型:
{
"kind": "handle",
"box_type": "StringBox"
}
4.2 型ヒント活用
以下の命令で型ヒントが提供されます:
- Const命令:
value.typeで定数の型 - BinOp命令:
dst_typeで結果型(文字列連結等) - Compare命令:
cmp_kindで比較種別(文字列比較等) - PHI命令:
dst_typeで合流後の型 - BoxCall命令:
dst_typeで戻り値型
4.3 型伝播アルゴリズム
MIR JSON v0 パーサー (mir_json_emit.rs) では以下の型伝播を実施:
- PHI型伝播: 全incoming値がStringBoxなら結果もStringBox
- BinOp型伝播: 左辺または右辺がStringBoxで演算子が
+なら結果もStringBox - Compare型伝播: 両辺がStringBoxなら
cmp_kind: "string"
🔄 5. PHI, Loop, If の識別方法
5.1 PHI命令の識別
MIR JSON での PHI:
{
"op": "phi",
"dst": 10,
"incoming": [[5, 1], [7, 2]]
}
識別ポイント:
op == "phi"で確実に識別incomingが複数BasicBlockからの入力を持つ- SSA形式の合流点を表す
5.2 Loopの識別
制御フロー解析:
- BasicBlockの
instructionsにbranchまたはjumpがある jump.targetまたはbranch.then/elseが自分より前のBlockを指す(後方エッジ)- 後方エッジがあればループ構造
CFG情報活用 (MIR JSON v1):
{
"cfg": {
"functions": {
"main": {
"loops": [
{
"header": 2,
"body": [2, 3, 4],
"exits": [5]
}
]
}
}
}
}
5.3 Ifの識別
Branch命令:
{
"op": "branch",
"cond": 0,
"then": 1,
"else": 2
}
識別ポイント:
op == "branch"で確実に識別thenとelseが異なるBasicBlockを指す- 条件分岐構造
📊 6. 関数選定基準
.hako Analyzer が解析する関数の選定基準:
6.1 エントリポイント
エントリ関数の検出:
- ルートレベルの
entryフィールド(JoinIR) - 関数名が
"main"または"Main.main"(MIR) - スタティックBox内の
main()メソッド
6.2 解析対象関数
優先順位:
- ✅ エントリ関数: 実行起点
- ✅ 呼び出し元がある関数: Call命令でreachable
- ⚠️ デッドコード関数: 到達不可能(hako_check検出対象)
フィルタリング:
- Phase 161-1: 全関数を読み込み
- Phase 161-4: CFG解析で到達可能性判定
- Phase 161-5: デッドコード検出・警告
🎯 7. 代表的な関数スニペット
7.1 Simple If(MIR JSON v1)
ソース: local_tests/phase123_simple_if.hako
{
"schema_version": "1.0",
"capabilities": ["unified_call", "phi", "effects", "callee_typing"],
"functions": [
{
"name": "main",
"params": [],
"entry": 0,
"blocks": [
{
"id": 0,
"instructions": [
{"op": "const", "dst": 0, "value": {"type": "i64", "value": 1}},
{"op": "const", "dst": 1, "value": {"type": "i64", "value": 0}},
{"op": "compare", "operation": "==", "lhs": 0, "rhs": 1, "dst": 2},
{"op": "branch", "cond": 2, "then": 1, "else": 2}
]
},
{
"id": 1,
"instructions": [
{"op": "const", "dst": 3, "value": {"type": "i64", "value": 10}},
{"op": "jump", "target": 3}
]
},
{
"id": 2,
"instructions": [
{"op": "const", "dst": 4, "value": {"type": "i64", "value": 20}},
{"op": "jump", "target": 3}
]
},
{
"id": 3,
"instructions": [
{"op": "phi", "dst": 5, "incoming": [[3, 1], [4, 2]]},
{"op": "ret", "value": 5}
]
}
]
}
]
}
構造の特徴:
- Block 0: エントリ、条件評価、branch
- Block 1, 2: then/else分岐
- Block 3: PHI合流 + return
- PHI命令が複数ブロックからの値を合流
7.2 Minimum Loop(MIR JSON v1)
ソース: apps/tests/loop_min_while.hako
{
"schema_version": "1.0",
"functions": [
{
"name": "main",
"params": [],
"entry": 0,
"blocks": [
{
"id": 0,
"instructions": [
{"op": "const", "dst": 0, "value": {"type": "i64", "value": 0}},
{"op": "jump", "target": 1}
]
},
{
"id": 1,
"instructions": [
{"op": "phi", "dst": 1, "incoming": [[0, 0], [2, 2]]},
{"op": "const", "dst": 3, "value": {"type": "i64", "value": 3}},
{"op": "compare", "operation": "<", "lhs": 1, "rhs": 3, "dst": 4},
{"op": "branch", "cond": 4, "then": 2, "else": 3}
]
},
{
"id": 2,
"instructions": [
{"op": "const", "dst": 5, "value": {"type": "i64", "value": 1}},
{"op": "binop", "operation": "+", "lhs": 1, "rhs": 5, "dst": 2},
{"op": "jump", "target": 1}
]
},
{
"id": 3,
"instructions": [
{"op": "const", "dst": 6, "value": {"type": "i64", "value": 0}},
{"op": "ret", "value": 6}
]
}
]
}
]
}
構造の特徴:
- Block 0: ループ初期化
- Block 1: ループヘッダ(PHI、条件評価、branch)
- Block 2: ループボディ(インクリメント、後方ジャンプ)
- Block 3: ループ脱出、return
- PHI命令がループ変数を管理
7.3 JoinIR Skip_WS(JoinIR JSON v0)
ソース: tests/fixtures/joinir/v0_skip_ws_min.jsonir
{
"version": 0,
"entry": 0,
"functions": [
{
"id": 0,
"name": "skip",
"params": [3000],
"exit_cont": null,
"body": [
{
"type": "compute",
"op": {
"kind": "const",
"dst": 3001,
"value_type": "integer",
"value": 0
}
},
{
"type": "compute",
"op": {
"kind": "boxcall",
"dst": 3002,
"box": "StringBox",
"method": "length",
"args": [3000]
}
},
{
"type": "call",
"func": 1,
"args": [3000, 3001, 3002],
"k_next": null,
"dst": null
}
]
},
{
"id": 1,
"name": "loop_step",
"params": [4000, 4001, 4002],
"exit_cont": null,
"body": [
{
"type": "compute",
"op": {
"kind": "compare",
"dst": 4003,
"op": "ge",
"lhs": 4001,
"rhs": 4002
}
},
{
"type": "jump",
"cont": 0,
"args": [4001],
"cond": 4003
},
{"type": "compute", "op": {"kind": "const", "dst": 4007, "value_type": "integer", "value": 1}},
{"type": "compute", "op": {"kind": "binop", "dst": 4006, "op": "add", "lhs": 4001, "rhs": 4007}},
{
"type": "call",
"func": 1,
"args": [4000, 4006, 4002],
"k_next": null,
"dst": null
}
]
}
]
}
構造の特徴:
- 継続渡しスタイル (CPS)
- 関数呼び出しが末尾再帰形式
jump命令で継続選択- ループが関数呼び出しで表現
📋 8. Phase 161 実装チェックリスト
Phase 161-1: 基本構造読み込み
AnalyzerBoxまたはMirAnalyzerBox を .hako で実装- JSON読み込み(
JsonBox.parse()またはFileBox.read_all()+ parse) - ルート構造パース(
schema_version,capabilities,functions) - 関数構造パース(
name,params,entry,blocks) - BasicBlock構造パース(
id,instructions)
Phase 161-2: 基本命令対応
- Const命令パース(
op: "const",dst,value) - Copy命令パース(
op: "copy",dst,src) - BinOp命令パース(
op: "binop",operation,lhs,rhs,dst) - Compare命令パース(
op: "compare",operation,lhs,rhs,dst) - Branch命令パース(
op: "branch",cond,then,else) - Jump命令パース(
op: "jump",target) - Return命令パース(
op: "ret",value) - PHI命令パース(
op: "phi",dst,incoming)
Phase 161-3: 統一Call命令対応
- MirCall命令パース(
op: "mir_call",mir_call) - Callee型判定(
callee.type) - Global Call パース
- Method Call パース
- Constructor Call パース
- Closure Call パース
- Value Call パース
- Extern Call パース
Phase 161-4: Box操作命令対応
- NewBox命令パース(
op: "newbox",type,args,dst) - BoxCall命令パース(
op: "boxcall",box,method,args,dst) - TypeOp命令パース(
op: "typeop",operation,src,dst,target_type)
Phase 161-5: 解析機能実装
- CFG解析(
cfgフィールド読み込み) - 到達可能性解析(エントリ関数からのreachability)
- デッドコード検出(unreachable関数・ブロック)
- PHI検証(incoming BlockIdの存在確認)
- Loop検出(後方エッジ検出)
- If検出(Branch命令からの分岐構造)
🎯 9. まとめ: .hako Analyzer が読むべき最小セット
最優先実装(Phase 161-1)
ルートレベル:
schema_version: バージョン確認capabilities: 機能対応チェックfunctions: 関数配列
関数レベル:
name: 関数名params: パラメータValueId配列entry: エントリブロックIDblocks: BasicBlock配列
BasicBlockレベル:
id: ブロックIDinstructions: 命令配列
基本命令:
op: 命令タイプdst,src,value,lhs,rhs: 基本フィールドcond,then,else,target: 制御フロー
次優先実装(Phase 161-2/3)
統一Call命令:
mir_call.callee.type: Calleeタイプmir_call.args: 引数配列mir_call.effects: エフェクトリスト
PHI命令:
incoming: 入力ペア配列
型情報:
dst_type: 型ヒントvalue.type: 定数型
📚 10. 参考資料
実装ファイル(Rust側)
src/mir/join_ir/json.rs- JoinIR JSON シリアライザsrc/runner/mir_json_emit.rs- MIR JSON エミットsrc/runner/mir_json_v0.rs- MIR JSON パーサーsrc/mir/types.rs- MIR型定義src/mir/definitions/call_unified.rs- 統一Call定義
テストケース
src/tests/joinir_json_min.rs- JoinIR JSONテストtests/fixtures/joinir/v0_*.jsonir- JoinIR固定データbuild/doctor/mir/*.mir.json- MIR実例
ドキュメント
docs/development/current/main/phase130_joinir_llvm_baseline.md- Phase 130ベースラインdocs/reference/mir/INSTRUCTION_SET.md- MIR命令セット仕様CLAUDE.md- 開発ガイド(MIRデバッグ手法)
🔍 11. 重要な発見・推奨事項
11.1 JoinIR vs MIR の選択
推奨: MIR JSON v1を優先
理由:
- ✅ 安定性: JoinIR → MIR 変換経路は Phase 32 で確立済み
- ✅ 最適化: MIR はより最適化・正規化されている
- ✅ 統一Call: Phase 15.5 の統一Call命令が完全サポート
- ✅ CFG情報: Phase 155 でCFG情報が統合済み
- ✅ 型情報: 型ヒントが充実(PHI, BinOp, Compare等)
JoinIRの用途:
- JoinIR固有の最適化研究(継続渡しスタイルの解析等)
- MIR変換前の中間表現検証
11.2 PHI処理の重要性
PHI命令は .hako Analyzer の核心:
- SSA形式の合流点を表す
- 複数BasicBlockからの値を統合
- ループ変数、if合流後の変数管理に必須
incomingフィールドで [ValueId, BasicBlockId] ペアを処理
実装のポイント:
incoming配列を順次処理- 各BasicBlockIdの存在を確認(不正なPHIの検出)
- 型ヒント (
dst_type) を活用して型伝播
11.3 統一Call命令の威力
Phase 15.5 統一Call命令の利点:
- 6種のCalleeタイプを統一的に処理
- 型安全な関数解決(コンパイル時)
- シャドウイング問題の根本解決
- エフェクト追跡による最適化
.hako Analyzer での活用:
callee.typeでCall種別判定certaintyフィールドで型確定度判定effectsでIO/副作用解析- デッドコード検出(未使用関数の検出)
11.4 型情報活用のベストプラクティス
型ヒント活用箇所:
- Const命令:
value.typeで定数の型を確定 - BinOp命令:
dst_typeで文字列連結等を判定 - Compare命令:
cmp_kind: "string"で文字列比較判定 - PHI命令:
dst_typeで合流後の型を確定 - BoxCall命令:
dst_typeでメソッド戻り値型を確定
型伝播アルゴリズム:
- Phase 25: MIR JSON エミット時に型伝播を実施
- 4回反復で
copy → phi → copyチェーン完全対応 - .hako Analyzer は型ヒントを信頼してよい
✅ Task 1 完了判定
- JoinIR JSON 最小構造を特定
- MIR JSON v0/v1 最小構造を特定
- 代表的なJSONスニペットを3件抽出(simple if, min loop, skip_ws)
- .hako Analyzer が読むべきキー一覧を作成
- JoinIR vs MIR 優先順位の判定(MIR v1推奨)
- PHI/Loop/If の識別方法を明確化
- 型情報の読み取り方法を文書化
- 関数選定基準を確立
- Phase 161 実装チェックリストを作成
次のステップ: Phase 161-2 (Task 2) - .hako 側 AnalyzerBox の基本実装