Files
hakorune/src/tests/mir_joinir_min.rs

140 lines
4.8 KiB
Rust
Raw Normal View History

feat(mir): Phase 26-H JoinIR型定義実装完了 - ChatGPT設計 ## 実装内容(Step 1-3 完全達成) ### Step 1: src/mir/join_ir.rs 型定義追加 - **JoinFuncId / JoinContId**: 関数・継続ID型 - **JoinFunction**: 関数(引数 = φノード) - **JoinInst**: Call/Jump/Ret/Compute 最小命令セット - **MirLikeInst**: 算術・比較命令ラッパー - **JoinModule**: 複数関数保持コンテナ - **単体テスト**: 型サニティチェック追加 ### Step 2: テストケース追加 - **apps/tests/joinir_min_loop.hako**: 最小ループ+breakカナリア - **src/tests/mir_joinir_min.rs**: 手書きJoinIR構築テスト - MIR → JoinIR手動構築で型妥当性確認 - #[ignore] で手動実行専用化 - NYASH_JOINIR_EXPERIMENT=1 トグル制御 ### Step 3: 環境変数トグル実装 - **NYASH_JOINIR_EXPERIMENT=1**: 実験モード有効化 - **デフォルト挙動**: 既存MIR/LoopForm経路のみ(破壊的変更なし) - **トグルON時**: JoinIR手書き構築テスト実行 ## Phase 26-H スコープ遵守 ✅ 型定義のみ(変換ロジックは未実装) ✅ 最小限の命令セット ✅ Debug 出力で妥当性確認 ✅ 既存パイプライン無影響 ## テスト結果 ``` $ NYASH_JOINIR_EXPERIMENT=1 cargo test --release mir_joinir_min_manual_construction -- --ignored --nocapture [joinir/min] MIR module compiled, 3 functions [joinir/min] JoinIR module constructed: [joinir/min] ✅ JoinIR型定義は妥当(Phase 26-H) test result: ok. 1 passed; 0 failed ``` ## JoinIR理論の実証 - **φノード = 関数引数**: `fn loop_step(i, k_exit)` - **merge = join関数**: 分岐後の合流点 - **ループ = 再帰関数**: `loop_step` 自己呼び出し - **break = 継続呼び出し**: `k_exit(i)` ## 次フェーズ (Phase 27.x) - LoopForm v2 → JoinIR 自動変換実装 - break/continue ハンドリング - Exit PHI の JoinIR 引数化 🌟 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: ChatGPT <noreply@openai.com>
2025-11-23 04:10:12 +09:00
// mir_joinir_min.rs
// Phase 26-H: JoinIR型定義妥当性確認テスト最小ループ
//
// 目的:
// - JoinFunction/JoinInst の型が破綻していないか確認
// - 手書きで JoinIR を組み立ててみて、設計の妥当性をチェック
// - まだ LoopForm → JoinIR 自動変換は書かないPhase 27以降
//
// 実行条件:
// - デフォルトでは #[ignore] にしておいて手動実行用にする
// - 環境変数 NYASH_JOINIR_EXPERIMENT=1 で実験モード有効化
use crate::ast::ASTNode;
use crate::mir::join_ir::*;
use crate::mir::{MirCompiler, ValueId};
use crate::parser::NyashParser;
#[test]
#[ignore] // 手動実行用Phase 26-H 実験段階)
fn mir_joinir_min_manual_construction() {
// Phase 26-H スコープ: 型定義の妥当性確認のみ
// LoopForm からの自動変換は Phase 27 以降で実装
// 環境変数トグルチェック
if std::env::var("NYASH_JOINIR_EXPERIMENT").ok().as_deref() != Some("1") {
eprintln!("[joinir/min] NYASH_JOINIR_EXPERIMENT=1 not set, skipping manual construction test");
return;
}
// Step 1: MIR までコンパイル(既存パイプラインで)
// Stage-3 環境変数を設定local キーワード対応)
std::env::set_var("NYASH_PARSER_STAGE3", "1");
std::env::set_var("HAKO_PARSER_STAGE3", "1");
let test_file = "apps/tests/joinir_min_loop.hako";
let src = std::fs::read_to_string(test_file)
.unwrap_or_else(|_| panic!("Failed to read {}", test_file));
let ast: ASTNode = NyashParser::parse_from_string(&src)
.expect("joinir_min: parse failed");
let mut mc = MirCompiler::with_options(false);
let compiled = mc.compile(ast).expect("joinir_min: MIR compile failed");
eprintln!(
"[joinir/min] MIR module compiled, {} functions",
compiled.module.functions.len()
);
// Step 2: 手書きで JoinIR を構築(設計の妥当性チェック)
let mut join_module = JoinModule::new();
// fn main(k_exit) { loop_step(0, k_exit) }
let main_id = JoinFuncId::new(0);
let mut main_func = JoinFunction::new(main_id, "main".to_string(), vec![]);
// 引数: i_init = 0 (ValueId(100) とする)
let i_init = ValueId(100);
main_func.body.push(JoinInst::Compute(MirLikeInst::Const {
dst: i_init,
value: ConstValue::Integer(0),
}));
// loop_step(i_init, k_exit)
let loop_step_id = JoinFuncId::new(1);
let k_exit_id = JoinContId::new(0);
main_func.body.push(JoinInst::Call {
func: loop_step_id,
args: vec![i_init],
k_next: Some(k_exit_id),
});
join_module.add_function(main_func);
// fn loop_step(i, k_exit) { if i >= 2 { k_exit(i) } else { loop_step(i+1, k_exit) } }
let mut loop_step_func = JoinFunction::new(
loop_step_id,
"loop_step".to_string(),
vec![ValueId(200)], // i の引数
);
let i_param = ValueId(200);
let cmp_result = ValueId(201);
let i_plus_1 = ValueId(202);
// cmp_result = (i >= 2)
loop_step_func.body.push(JoinInst::Compute(MirLikeInst::Compare {
dst: cmp_result,
op: CompareOp::Ge,
lhs: i_param,
rhs: ValueId(203), // const 2
}));
// const 2
loop_step_func.body.push(JoinInst::Compute(MirLikeInst::Const {
dst: ValueId(203),
value: ConstValue::Integer(2),
}));
// if cmp_result { k_exit(i) } else { loop_step(i+1, k_exit) }
// ここでは簡略化して Jump 命令だけ書く(実際は分岐制御が必要だが Phase 26-H では型チェックのみ)
loop_step_func.body.push(JoinInst::Jump {
cont: k_exit_id,
args: vec![i_param],
});
// i_plus_1 = i + 1
loop_step_func.body.push(JoinInst::Compute(MirLikeInst::BinOp {
dst: i_plus_1,
op: BinOpKind::Add,
lhs: i_param,
rhs: ValueId(204), // const 1
}));
join_module.add_function(loop_step_func);
// Step 3: Debug 出力で妥当性確認
eprintln!("[joinir/min] JoinIR module constructed:");
eprintln!("{:#?}", join_module);
// アサーション(型定義が使えることを確認)
assert_eq!(join_module.functions.len(), 2);
assert!(join_module.functions.contains_key(&main_id));
assert!(join_module.functions.contains_key(&loop_step_id));
eprintln!("[joinir/min] ✅ JoinIR型定義は妥当Phase 26-H");
}
#[test]
fn mir_joinir_min_type_sanity() {
// Phase 26-H: 型定義の基本的なサニティチェック(常時実行)
let func_id = JoinFuncId::new(0);
let func = JoinFunction::new(func_id, "test".to_string(), vec![ValueId(1)]);
assert_eq!(func.id, func_id);
assert_eq!(func.name, "test");
assert_eq!(func.params.len(), 1);
assert_eq!(func.body.len(), 0);
}