//! Phase 41-4: NestedIfMerge A/B Test //! //! Route A: 既存経路(AST→MIR→if_phi/conservative→VM) //! Route B: 新経路(AST→JoinIR(NestedIfMerge)→MIR→VM) //! //! このテストは HAKO_JOINIR_NESTED_IF=1 フラグでのみ Route B を有効化する。 use crate::mir::join_ir::frontend::AstToJoinIrLowerer; use crate::mir::join_ir::JoinInst; use crate::mir::join_ir_ops::JoinValue; use crate::mir::join_ir_vm_bridge::run_joinir_via_vm; /// Phase 41-4.5: NestedIfMerge パスが有効化されることを確認 /// /// dev flag HAKO_JOINIR_NESTED_IF=1 がある場合のみ、 /// parse_loop 関数が NestedIfMerge 命令を生成することを確認する。 #[test] fn phase41_nested_if_merge_path_activation() { // Dev flag がない場合はスキップ if std::env::var("HAKO_JOINIR_NESTED_IF").ok().as_deref() != Some("1") { eprintln!( "[Phase 41-4] Skipping phase41_nested_if_merge_path_activation: \ Set HAKO_JOINIR_NESTED_IF=1 to enable" ); return; } // 2レベルのネスト if: if a > 0 { if b > 0 { result = 42 } }; return result let program_json = serde_json::json!({ "defs": [{ "name": "parse_loop", "params": ["a", "b"], "body": { "body": [ { "type": "Local", "name": "result", "expr": {"type": "Int", "value": 0} }, { "type": "If", "cond": {"type": "Compare", "op": ">", "lhs": {"type": "Var", "name": "a"}, "rhs": {"type": "Int", "value": 0}}, "then": [ { "type": "If", "cond": {"type": "Compare", "op": ">", "lhs": {"type": "Var", "name": "b"}, "rhs": {"type": "Int", "value": 0}}, "then": [ { "type": "Local", "name": "result", "expr": {"type": "Int", "value": 42} } ], "else": [] } ], "else": [] }, { "type": "Return", "expr": {"type": "Var", "name": "result"} } ] } }] }); let mut lowerer = AstToJoinIrLowerer::new(); let join_module = lowerer.lower_program_json(&program_json); // NestedIfMerge 命令が含まれていることを確認 let entry_id = join_module.entry.expect("Entry should be set"); let entry_func = join_module.functions.get(&entry_id).expect("Entry function"); let nested_if_merge_count = entry_func.body.iter() .filter(|inst| matches!(inst, JoinInst::NestedIfMerge { .. })) .count(); assert!( nested_if_merge_count > 0, "[Phase 41-4.5] NestedIfMerge instruction not found in parse_loop. \ Expected at least 1, found {}", nested_if_merge_count ); eprintln!( "[Phase 41-4.5] NestedIfMerge path activated: {} NestedIfMerge instructions generated", nested_if_merge_count ); } /// Phase 41-4.6: Route B (JoinIR NestedIfMerge) の実行テスト /// /// 2レベルのネスト if パターンを JoinIR で lowering し、 /// VM Bridge 経由で実行して正しい結果を得ることを確認する。 #[test] fn phase41_nested_if_merge_route_b_execution() { // Dev flag がない場合はスキップ if std::env::var("HAKO_JOINIR_NESTED_IF").ok().as_deref() != Some("1") { eprintln!( "[Phase 41-4] Skipping phase41_nested_if_merge_route_b_execution: \ Set HAKO_JOINIR_NESTED_IF=1 to enable" ); return; } // 2レベルのネスト if let program_json = serde_json::json!({ "defs": [{ "name": "parse_loop", "params": ["a", "b"], "body": { "body": [ { "type": "Local", "name": "result", "expr": {"type": "Int", "value": 0} }, { "type": "If", "cond": {"type": "Compare", "op": ">", "lhs": {"type": "Var", "name": "a"}, "rhs": {"type": "Int", "value": 0}}, "then": [ { "type": "If", "cond": {"type": "Compare", "op": ">", "lhs": {"type": "Var", "name": "b"}, "rhs": {"type": "Int", "value": 0}}, "then": [ { "type": "Local", "name": "result", "expr": {"type": "Int", "value": 42} } ], "else": [] } ], "else": [] }, { "type": "Return", "expr": {"type": "Var", "name": "result"} } ] } }] }); let mut lowerer = AstToJoinIrLowerer::new(); let join_module = lowerer.lower_program_json(&program_json); let entry_id = join_module.entry.expect("Entry should be set"); // テストケース: (a, b) -> expected result let test_cases = [ // 両方 true -> 42 ((5, 5), 42), // a > 0 だが b <= 0 -> 0 (else path) ((5, 0), 0), ((5, -1), 0), // a <= 0 -> 0 (outer else path) ((0, 5), 0), ((-1, 5), 0), // 両方 false -> 0 ((0, 0), 0), ((-1, -1), 0), ]; for ((a, b), expected) in test_cases { let inputs = vec![JoinValue::Int(a), JoinValue::Int(b)]; let result = run_joinir_via_vm(&join_module, entry_id, &inputs) .expect(&format!("Failed to execute with inputs ({}, {})", a, b)); assert_eq!( result, JoinValue::Int(expected), "[Phase 41-4.6] Route B execution failed for ({}, {}): expected {}, got {:?}", a, b, expected, result ); } eprintln!("[Phase 41-4.6] Route B execution test PASSED: {} test cases", test_cases.len()); } /// Phase 41-4.6: Route A/B 結果比較テスト /// /// Route A(既存 if_phi/conservative)と Route B(JoinIR NestedIfMerge)の /// 実行結果が一致することを確認する。 /// /// 注意: このテストは現時点では Route B の実行結果のみを確認する。 /// Route A との完全な比較は、parse_loop が本番パイプラインに統合された後に行う。 #[test] fn phase41_nested_if_merge_route_ab_comparison() { // Dev flag がない場合はスキップ if std::env::var("HAKO_JOINIR_NESTED_IF").ok().as_deref() != Some("1") { eprintln!( "[Phase 41-4] Skipping phase41_nested_if_merge_route_ab_comparison: \ Set HAKO_JOINIR_NESTED_IF=1 to enable" ); return; } // Route B の実行結果を確認(Route A は parse_loop 統合後に比較予定) let program_json = serde_json::json!({ "defs": [{ "name": "parse_loop", "params": ["a", "b"], "body": { "body": [ { "type": "Local", "name": "result", "expr": {"type": "Int", "value": 0} }, { "type": "If", "cond": {"type": "Compare", "op": ">", "lhs": {"type": "Var", "name": "a"}, "rhs": {"type": "Int", "value": 0}}, "then": [ { "type": "If", "cond": {"type": "Compare", "op": ">", "lhs": {"type": "Var", "name": "b"}, "rhs": {"type": "Int", "value": 0}}, "then": [ { "type": "Local", "name": "result", "expr": {"type": "Int", "value": 42} } ], "else": [] } ], "else": [] }, { "type": "Return", "expr": {"type": "Var", "name": "result"} } ] } }] }); let mut lowerer = AstToJoinIrLowerer::new(); let join_module = lowerer.lower_program_json(&program_json); let entry_id = join_module.entry.expect("Entry should be set"); // Route B: JoinIR経由で実行 let route_b_result = run_joinir_via_vm( &join_module, entry_id, &[JoinValue::Int(5), JoinValue::Int(5)] ).expect("Route B execution failed"); // 期待結果: a=5, b=5 -> 両方 > 0 -> result = 42 let expected = JoinValue::Int(42); assert_eq!( route_b_result, expected, "[Phase 41-4.6] Route B result mismatch: expected {:?}, got {:?}", expected, route_b_result ); eprintln!( "[Phase 41-4.6] Route A/B comparison: Route B = {:?} (Route A comparison deferred to pipeline integration)", route_b_result ); }