feat(control_tree): Phase 132 P0 + P0.5 - loop(true) + post-loop support

**Phase 132 P0**: Extend loop(true) break-once to support post-loop statements

Goal: Support `loop(true) { x = 1; break }; x = x + 2; return x` → exit code 3

Implementation:
- loop_true_break_once.rs: Add post_k continuation generation
- Reuse Phase 130's lower_assign_stmt for post statements
- ExitMeta uses DirectValue mode (PHI-free)

**Phase 132 P0.5**: Fix StepTree post-loop statement visibility

Root cause: routing.rs created StepTree from Loop node only, losing post statements

Solution:
- New: normalized_shadow_suffix_router_box.rs
- Detects block suffix: Loop + Assign* + Return
- Creates StepTree from entire suffix (Block([Loop, Assign, Return]))
- Modified build_block() to call suffix router (dev-only)

Changes:
- apps/tests/phase132_loop_true_break_once_post_add_min.hako (new fixture)
- tools/smokes/v2/profiles/integration/apps/phase132_loop_true_break_once_post_add_*.sh
- src/mir/control_tree/normalized_shadow/loop_true_break_once.rs (+150 lines)
- src/mir/builder/control_flow/joinir/patterns/policies/normalized_shadow_suffix_router_box.rs (+380 lines)
- src/mir/builder/stmts.rs (build_block modified to support suffix skipping)

Design principles:
- StepTree unchanged: Block is SSOT for statement order
- No data duplication: Loop doesn't hold post_nodes
- Suffix router handles detection + conversion
- build_block() handles wiring only

Test results:
- Phase 132 VM: PASS (exit code 3)
- Phase 131 regression: PASS
- Phase 97 regression: PASS

Related: Phase 132 loop(true) + post-loop minimal support

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-18 21:51:33 +09:00
parent 4169da8c33
commit b5d8ace6ab
7 changed files with 690 additions and 25 deletions

View File

@ -0,0 +1,26 @@
// Phase 132-P4: loop(true) break-once with minimal post-loop computation
//
// Purpose: Test loop(true) { <assign>* ; break }; <post-assign>; return in Normalized shadow
// Expected output: 3
//
// Structure:
// x = 0 // pre-loop init
// loop(true) { // condition is Bool literal true
// x = 1 // body assignment
// break // break at end
// }
// x = x + 2 // post-loop assignment
// return x // return updated value (1 + 2 = 3)
static box Main {
main() {
local x
x = 0
loop(true) {
x = 1
break
}
x = x + 2
return x
}
}