Phase 45: read_quoted_from JoinIR Frontend/Bridge
- Implement lower_read_quoted_pattern() for Guard if + Loop with break + accumulator pattern
- Add T1-T4 Route B E2E tests (all PASS)
- Create phase45_read_quoted_fixture.hako for Route A testing
Phase 46: IfMerge extension for loop-internal if-body reassignment
- Add escape handling: if ch == "\\" { i = i+1; ch = s.substring(...) }
- Use IfMerge to merge i and ch after if-body (speculative execution)
- T5 PASS: "a\"b" → 'a"b' (escape handling works!)
Dev flags:
- HAKO_JOINIR_READ_QUOTED=1: Enable Phase 45 JoinIR route
- HAKO_JOINIR_READ_QUOTED_IFMERGE=1: Enable Phase 46 IfMerge escape handling
Test results (Route B):
- T1: "abc" → 'abc' ✅
- T2: "" → '' ✅
- T3: abc → '' ✅
- T4: xx"def" → 'def' ✅
- T5: "a\"b" → 'a"b' ✅
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
266 lines
9.8 KiB
Rust
266 lines
9.8 KiB
Rust
//! 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
|
||
);
|
||
}
|