Commit Graph

221 Commits

Author SHA1 Message Date
f4ab5ca5f4 refactor(control_flow): Phase 134 P0 - Normalization entry point SSOT
Consolidate dual entry points into unified NormalizationPlan system:

Problem:
- Dual entry points: try_normalized_shadow() + suffix_router_box
- ~220 lines of duplicated pattern detection logic
- Maintenance burden: changes required in two places

Solution:
- New normalization module with Box-First architecture
- NormalizationPlanBox: Single source of truth for pattern detection
- NormalizationExecuteBox: Single source of truth for execution

Implementation:
- src/mir/builder/control_flow/normalization/ (new module)
  - README.md: Design contract (SSOT)
  - plan.rs: NormalizationPlan data structure
  - plan_box.rs: Pattern detection (7 unit tests)
  - execute_box.rs: Execution logic
  - mod.rs: Module integration

Refactored files:
- routing.rs::try_normalized_shadow(): 165 → 87 lines (-78 lines)
- suffix_router_box::try_lower_loop_suffix(): 258 → 116 lines (-142 lines)

Pattern support maintained:
- Phase 131: loop(true) only (consumed: 1)
- Phase 132: loop + single post (consumed: 3)
- Phase 133: loop + multiple post (consumed: 2+N)

Box-First principles:
- Plan Box: Detection responsibility only
- Execute Box: Execution responsibility only
- README.md: Contract documentation (SSOT)
- Clear separation enables independent testing

Test results:
- cargo test --lib: 1186 PASS (10 new tests added)
- Phase 133 VM/LLVM EXE: PASS (exit code 6)
- Phase 132 LLVM EXE: PASS (exit code 3)
- Phase 131 LLVM EXE: PASS (exit code 1)

Benefits:
- Code duplication eliminated (~220 lines)
- Single source of truth for normalization decisions
- Improved maintainability and testability
- Future-proof extensibility (easy to add new patterns)

Default behavior unchanged: Dev-only guard maintained

Related: Phase 134 normalization infrastructure improvement

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-18 22:29:29 +09:00
d5a36cf818 refactor(joinir): Phase 132-R0 - Continuation SSOT + legacy isolation
**Task 1: Continuation SSOT 一本化** 
- Add JoinInlineBoundary::default_continuations()
- Replace all BTreeSet::from([JoinFuncId::new(2)]) hardcoding (7 locations)
- Single source of truth for continuation function IDs

**Task 2: merge 契約 docs SSOT 化** 
- New: src/mir/builder/control_flow/joinir/merge/README.md
- Document continuation contracts, skip conditions, forbidden behaviors
- Prohibit by-name/by-id classification

**Task 3: テスト配置正規化** 
- New: src/mir/builder/control_flow/joinir/merge/tests/continuation_contract.rs
- Move tests from instruction_rewriter.rs to dedicated test file
- Add 4 test cases (Case A-D)

**Task 4: legacy 導線隔離** 
- New: src/mir/builder/control_flow/joinir/legacy/
- Move routing_legacy_binding.rs → legacy/routing_legacy_binding.rs
- Add legacy/README.md with removal conditions
- No cfg(feature="legacy") (docs-only isolation for now)

**Task 5: ノイズ除去** 
- Remove unused imports (ConstValue, MirInstruction)
- Clean warnings in touched files

Changes:
- src/mir/join_ir/lowering/inline_boundary.rs: +default_continuations()
- src/mir/builder/control_flow/joinir/merge/README.md: +140 lines
- src/mir/builder/control_flow/joinir/merge/tests/: +180 lines
- src/mir/builder/control_flow/joinir/legacy/: +3 files

Test results:
- cargo test --lib: 1176 PASS
- All Phase 131/132/97 smokes: PASS

Benefits:
- Continuation definition centralized (SSOT)
- Merge contracts documented and tested
- Legacy code path clearly isolated
- Code quality improved (warnings reduced)

Related: Phase 132 infrastructure improvements

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-18 21:52:21 +09:00
149e30cae5 fix(joinir): Phase 132 P1 - k_exit continuation classification fix
Problem: k_exit with TailCall(post_k) was classified as skippable continuation,
causing post_k block to become unreachable.

Root cause:
- Continuation classification was name-based ("join_func_2")
- Skippable continuation check didn't examine function body
- k_exit with tail call to post_k had its block skipped during merge

Solution:
- Check function body structure before classifying as skippable
- Non-skippable pattern: continuation with TailCall to another function
- Properly emit tail call as Jump instruction

Changes:
- src/mir/builder/control_flow/joinir/merge/mod.rs:
  - Add structural check in is_skippable_continuation()
  - Detect TailCall(other_func) pattern
  - Skip only if function is truly empty (1 block, Return only)

- src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs:
  - Improve k_exit continuation handling
  - Properly rewrite TailCall → Jump for post_k

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

Related: Phase 132 loop(true) + post-loop VM/LLVM parity

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-18 21:51:52 +09:00
b5d8ace6ab 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>
2025-12-18 21:51:33 +09:00
d6225a88d0 refactor(joinir): Task 6 & 7 - MergeConfig unification + contract_checks tests
Task 6: MergeConfig 一構造体化
- Consolidate dispersed parameters (dev_log, strict_mode, exit_reconnect_mode)
- Reduce function argument clutter in merge/mod.rs
- Single source of truth for merge configuration
- Added MergeConfig struct with factory methods (default, strict, with_debug)

Task 7: contract_checks 単体テスト追加
- Add 4 test cases for verify_all_terminator_targets_exist
- Test coverage: all_present, missing_allowed, missing_disallowed, MergeContracts creation
- Validate fail-fast behavior with freeze_with_hint
- Enable regression detection during future refactoring

Changes:
- src/mir/builder/control_flow/joinir/merge/mod.rs (+54 -6 lines)
- src/mir/builder/control_flow/joinir/merge/contract_checks.rs (+116 lines)

Test Results:
- New tests: 4 PASS
- Regression tests: 1162 PASS
- No breaking changes

Related: Phase 131 refactoring to improve code organization and maintainability

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

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-18 18:28:24 +09:00
02c4c313e5 feat(control_tree): Phase 131 P1.5-P2 DirectValue exit reconnection
Implement DirectValue mode for Normalized shadow exit handling:

**P1.5 Changes**:
- Add ExitReconnectMode::DirectValue (skip exit PHI generation)
- Carry remapped_exit_values through merge result
- Update host variable_map directly with exit values
- Fix loop(true) { x = 1; break }; return x to return 1 correctly

**P2 Changes**:
- Normalize k_exit continuation entry/exit edges
- Rewrite TailCall(k_exit) → Jump(exit_block) for proper merge
- Add verify_all_terminator_targets_exist contract check
- Extend ExitLineReconnector to handle DirectValue mode

**Infrastructure**:
- tools/build_llvm.sh: Force TMPDIR under target/ (EXDEV mitigation)
- llvm_exe_runner.sh: Add exit_code verification support
- Phase 131 smokes: Update for dev-only + exit code validation

**Contracts**:
- PHI-free: Normalized path uses continuations only
- Exit values reconnect via remapped ValueIds
- Existing patterns unaffected (既定挙動不変)

Related: Phase 131 loop(true) break-once Normalized support

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-18 17:48:05 +09:00
052040e59c refactor(joinir): extract ExitArgsCollectorBox for jump_args SSOT
Phase 118 refactoring: Box modularization for exit value collection.

# Changes
- Created `exit_args_collector.rs` with ExitArgsCollectorBox
- Extracted jump_args processing logic from instruction_rewriter.rs
- Implemented SSOT for offset calculation (0 vs 1 legacy layout)
- Added comprehensive unit tests (6 tests, all passing)

# Design
- **Responsibility**: Collects exit PHI inputs + carrier inputs from jump_args
- **SSOT**: Centralized offset calculation logic
- **Fail-Fast**: Validates jump_args length against exit_bindings
- **Phase 118 P2 Contract**: Uses boundary.exit_bindings as SSOT

# Key Features
- Filters ConditionOnly carriers (no exit PHI needed)
- Handles both direct mapping (offset=0) and legacy layout (offset=1)
- Strict mode: Fail-Fast on validation errors
- Non-strict mode: Warns and continues with best effort

# Test Results
- Unit tests: 6/6 PASS
- Phase 118 smoke tests: PASS (VM + LLVM)
- Phase 117 regression: PASS

# Reduced Code Complexity
- instruction_rewriter.rs: ~90 lines → ~25 lines (box call)
- Offset logic: Centralized in ExitArgsCollectorBox

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 03:56:21 +09:00
1080dee58f fix(joinir): Phase 118 Pattern3 exit carrier PHI SSOT 2025-12-18 03:43:00 +09:00
ce7e2c1b91 refactor(env): centralize NYASH_JOINIR_STRUCTURE_ONLY flag
Moved NYASH_JOINIR_STRUCTURE_ONLY environment variable handling
from inline std::env::var() in routing.rs to a centralized helper
function in src/config/env/joinir_flags.rs.

Changes:
- Added joinir_structure_only_enabled() helper function
- Replaced direct env::var() call in routing.rs with helper
- Maintains existing behavior: default ON, NYASH_JOINIR_STRUCTURE_ONLY=0/off to disable
- Follows env module centralization pattern (Box Theory: separation of concerns)

Testing:
- cargo test --lib: 1126 passed 
- Regression: Phase 107 VM smoke 
- Phase 113/114 maintained 

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 02:19:14 +09:00
09ce24e132 feat(joinir): Phase 112 strict guard for StepTree required_caps
- Add control_tree_capability_guard.rs with check(tree, func_name, strict, dev)
- Allowlist: If, NestedIf, Loop, Return, Break, Continue
- Deny (strict): NestedLoop, TryCatch, Throw, Lambda, While, ForRange, Match, Arrow
- Wire into lower_function_body() (strict-only check)
- Error format: [joinir/control_tree/cap_missing/<Cap>] with 1-line Hint
- Unit tests: nested_loop_rejects, if_only_passes, strict_false_passes
- Default behavior unchanged (strict=false always Ok)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 01:38:25 +09:00
14730c227f feat(control_tree): add StepTreeContract and signature (dev-only) 2025-12-18 00:57:58 +09:00
9bcda215f8 refactor(joinir): split Pattern2 orchestrator into smaller steps 2025-12-18 00:44:31 +09:00
3987aa5b06 refactor(joinir): drop unused break helper wrappers 2025-12-18 00:30:01 +09:00
2b5c141e22 feat(control_tree): add StepTree builder (dev-only) 2025-12-18 00:22:21 +09:00
a9f92f8f1a refactor(joinir): add hints for Phase107/104/100 policy rejects
- balanced_depth_scan: missing_tail_inc, missing_return_i hints
- read_digits: missing_eos_guard, digit_set_mismatch hints
- pinned: missing_host_id hint
- Gradual migration (representative cases only)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 23:45:49 +09:00
27e8e0f16a refactor(joinir): Phase 108 unify Pattern2 policy routing 2025-12-17 23:30:08 +09:00
3c1d8a824d feat(joinir): extend balanced depth-scan policy to object family 2025-12-17 23:09:19 +09:00
09dd10349f refactor(joinir): make Pattern2 body-local handling policy-driven 2025-12-17 23:00:26 +09:00
10a2f3b48b refactor(joinir): centralize balanced depth-scan policy decision 2025-12-17 22:59:27 +09:00
6036627920 fix(joinir): avoid false rejects in balanced depth-scan policy 2025-12-17 22:52:29 +09:00
d8ce9fdb99 fix(joinir): wire balanced depth-scan policy through Pattern2 2025-12-17 22:47:36 +09:00
9ec2e28b6a feat(joinir): add Pattern2 post-loop early return step 2025-12-17 22:32:55 +09:00
aa29dc8085 feat(joinir): emit balanced depth-scan derived vars 2025-12-17 22:32:50 +09:00
bf80789757 feat(joinir): route balanced depth-scan via Pattern2 policy 2025-12-17 22:32:43 +09:00
f1a570fd45 feat(joinir): Phase 107 balanced depth-scan policy (analysis-only) 2025-12-17 22:25:34 +09:00
5f4d8ba112 refactor(joinir): Phase 106 Pattern2 step boxes 2025-12-17 22:01:19 +09:00
368b363694 refactor(joinir): split Pattern2 facts from lowering orchestration 2025-12-17 21:34:11 +09:00
ae2a1d4339 refactor(joinir): boxify Pattern2 routing and schedule facts 2025-12-17 21:24:46 +09:00
950560a3d9 test(joinir): Phase 104 read_digits loop(true) parity 2025-12-17 18:29:27 +09:00
27fd9720d0 feat(joinir): string accumulator emitter (JoinIR)
- Add StringAccumulatorEmitter in join_ir/lowering/common/
- Emit string concat as BinOp(Add) for polymorphic VM/LLVM handling
- Ensure VM/LLVM same semantics
- Fail-Fast: RHS must be Variable (not Literal/MethodCall)
- Pattern2 wiring: string carrier昇格 + type refinement + validation

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-17 16:33:18 +09:00
468977e9b3 feat(joinir): allow accumulator as LoopState carrier (Pattern2 + ScopeManager delegation)
- Integrate MutableAccumulatorAnalyzer into pattern2_with_break.rs
- Delegate read-only check to ScopeManager (SSOT search order)
- Promote valid accumulators to mutable LoopState carriers
- Accumulator updates handled by existing carrier mechanism
- Fail-Fast: mutable RHS (not supported yet)
- Allow LoopBodyLocal RHS (validated later in lowering)
- loop_body_local_init.rs: Align receiver search order with SSOT (ConditionEnv first)
- Error prefix: [joinir/mutable-acc]

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-17 06:10:50 +09:00
0661e92225 feat(joinir): phase 100 P1 - pinned local analyzer and wiring into CapturedEnv
- Implement PinnedLocalAnalyzer box to identify pinned loop-outer locals
  * Pure AST analysis (no MIR dependencies)
  * Detects locals: defined before loop, referenced in loop, NOT assigned in loop
  * 5 unit tests covering all edge cases (no assignment, assigned, empty body, etc.)
- Integrate PinnedLocalAnalyzer into pattern2_with_break.rs
  * Call analyzer with loop body AST and candidate locals from variable_map
  * Wire pinned locals into CapturedEnv with CapturedKind::Pinned
  * Fail-Fast on host_id lookup failure or analyzer errors
- Update loop_body_local_init.rs resolver to search CapturedEnv
  * New search order: LoopBodyLocalEnv → ConditionEnv → CapturedEnv
  * Access via cond_env.captured (already integrated in ConditionEnv)
  * Updated error message to show full search order
- All existing tests pass (1101 passed, 1 unrelated failure)
- Smoke tests verified: phase96_json_loader_next_non_ws_vm, phase94_p5b_escape_e2e

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

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-17 05:32:35 +09:00
bc1a09f2c3 fix(joinir): Phase 96 next_non_ws break condition SSOT 2025-12-17 01:59:21 +09:00
ad67d50798 refactor(joinir): unify policy decisions and trim routing 2025-12-17 01:20:35 +09:00
8e17534829 refactor(joinir): move P5b escape policy under patterns/policies 2025-12-17 01:14:07 +09:00
7ab459503b feat(joinir): Phase 94 - P5b escape full E2E (derived ch + +1/+2) 2025-12-17 00:59:33 +09:00
c213ecc3c0 refactor(mir): Phase 93 リファクタリング - 箱化モジュール化
## 概要
Phase 93 P0実装後のコード整理。スケジュール決定ロジックとbreak semanticsを
明確化し、デバッグログを統一。

## 変更内容

### 1. スケジュール決定ロジックの関数化 (step_schedule.rs)
- `ScheduleDecision`構造体追加(判定結果+理由+デバッグコンテキスト)
- `decide_pattern2_schedule()` - スケジュール決定のSSOT
- `build_pattern2_schedule_from_decision()` - 新しい決定ベースAPI
- 判定理由が4種類で明確化(ConditionOnly → body-local → loop-local → default)
- 後方互換性維持(`Pattern2ScheduleContext`はwrapperに)

### 2. ConditionOnlyRecipe強化 (condition_only_emitter.rs)
- `BreakSemantics` enum追加(WhenMatch vs WhenNotMatch)
- `generate_break_condition()` - semanticsに基づくAST生成
- `from_trim_helper_condition_only()` - factory method追加
- break semanticsがrecipeに明示的に含まれる

### 3. trim_loop_lowering.rs簡素化
- `generate_condition_only_break_condition()`削除(DRY原則)
- `recipe.generate_break_condition()`で統一
- break条件生成ロジックが1箇所に集約

### 4. デバッグログ統一
- `[phase93/schedule]` - スケジュール決定
- `[phase93/condition-only]` - ConditionOnlyレシピ作成
- `[phase93/break-cond]` - break条件生成
- 既存の`joinir_dev_enabled()`使用(新規env var不要)

## テスト結果
- step_schedule: 10 tests PASS
- condition_only_emitter: 4 tests PASS
- 後方互換性維持

## 統計
- 3ファイル変更
- +249行 / -57行 = +192 net

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 23:43:03 +09:00
04fdac42f2 feat(mir): Phase 93 P0 - ConditionOnly Derived Slot実装
## 概要
body-local変数を参照するbreak条件が毎イテレーション正しく再計算される
ConditionOnlyパターンを実装。

## 問題
- `is_ch_match`がConditionBindingで運ばれると初回計算値が固定
- loop header PHIで更新されず、毎周回同じ値がコピーされる
- 結果: `if ch == "b" { break }` が正しく動作しない

## 解決策 (B: ConditionOnly)
1. ConditionOnlyRecipe作成 - Derived slot再計算レシピ
2. setup_condition_env_bindings()でConditionBinding登録停止
3. Pattern2スケジュールでbody-init → break順序保証
4. break条件: ConditionOnlyでは非反転版を使用

## 変更ファイル
- condition_only_emitter.rs (NEW): Derived slot再計算ロジック
- step_schedule.rs: from_env()にhas_condition_only_recipe追加
- loop_with_break_minimal.rs: スケジュール決定でrecipe考慮
- trim_loop_lowering.rs: ConditionOnly用break条件生成追加

## テスト
- step_schedule: 6 tests PASS (新規1: condition_only_recipe_triggers_body_first)
- condition_only_emitter: 3 tests PASS
- Phase 92 baseline: 2 cases PASS
- E2E: /tmp/test_body_local_simple.hako → 出力 "1" ✓

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 23:24:11 +09:00
d2972c1437 feat(joinir): Phase 92完了 - ConditionalStep + body-local変数サポート
## Phase 92全体の成果

**Phase 92 P0-P2**: ConditionalStep JoinIR生成とbody-local変数サポート
- ConditionalStep(条件付きキャリア更新)のJoinIR生成実装
- Body-local変数(ch等)の条件式での参照サポート
- 変数解決優先度: ConditionEnv → LoopBodyLocalEnv

**Phase 92 P3**: BodyLocalPolicyBox + 安全ガード
- BodyLocalPolicyDecision実装(Accept/Reject判定)
- BodyLocalSlot + DualValueRewriter(JoinIR/MIR二重書き込み)
- Fail-Fast契約(Cannot promote LoopBodyLocal検出)

**Phase 92 P4**: E2E固定+回帰最小化 (本コミット)
- Unit test 3本追加(body-local変数解決検証)
- Integration smoke追加(phase92_pattern2_baseline.sh、2ケースPASS)
- P4-E2E-PLAN.md、P4-COMPLETION.md作成

## 主要な実装

### ConditionalStep(条件付きキャリア更新)
- `conditional_step_emitter.rs`: JoinIR Select命令生成
- `loop_with_break_minimal.rs`: ConditionalStep検出と統合
- `loop_with_continue_minimal.rs`: Pattern4対応

### Body-local変数サポート
- `condition_lowerer.rs`: body-local変数解決機能
  - `lower_condition_to_joinir`: body_local_env パラメータ追加
  - 変数解決優先度実装(ConditionEnv優先)
  - Unit test 3本追加: 変数解決/優先度/エラー
- `header_break_lowering.rs`: break条件でbody-local変数参照
- 7ファイルで後方互換ラッパー(lower_condition_to_joinir_no_body_locals)

### Body-local Policy & Safety
- `body_local_policy.rs`: BodyLocalPolicyDecision(Accept/Reject)
- `body_local_slot.rs`: JoinIR/MIR二重書き込み
- `dual_value_rewriter.rs`: ValueId書き換えヘルパー

## テスト体制

### Unit Tests (+3)
- `test_body_local_variable_resolution`: body-local変数解決
- `test_variable_resolution_priority`: 変数解決優先度(ConditionEnv優先)
- `test_undefined_variable_error`: 未定義変数エラー
- 全7テストPASS(cargo test --release condition_lowerer::tests)

### Integration Smoke (+1)
- `phase92_pattern2_baseline.sh`:
  - Case A: loop_min_while.hako (Pattern2 baseline)
  - Case B: phase92_conditional_step_minimal.hako (条件付きインクリメント)
  - 両ケースPASS、integration profileで発見可能

### 退行確認
-  既存Pattern2Breakテスト正常(退行なし)
-  Phase 135 smoke正常(MIR検証PASS)

## アーキテクチャ設計

### 変数解決メカニズム
```rust
// Priority 1: ConditionEnv (loop params, captured)
if let Some(value_id) = env.get(name) { return Ok(value_id); }
// Priority 2: LoopBodyLocalEnv (body-local like `ch`)
if let Some(body_env) = body_local_env {
    if let Some(value_id) = body_env.get(name) { return Ok(value_id); }
}
```

### Fail-Fast契約
- Delta equality check (conditional_step_emitter.rs)
- Variable resolution error messages (ConditionEnv)
- Body-local promotion rejection (BodyLocalPolicyDecision::Reject)

## ドキュメント

- `P4-E2E-PLAN.md`: 3レベルテスト戦略(Level 1-2完了、Level 3延期)
- `P4-COMPLETION.md`: Phase 92完了報告
- `README.md`: Phase 92全体のまとめ

## 将来の拡張(Phase 92スコープ外)

- Body-local promotionシステム拡張
- P5bパターン認識の汎化(flagベース条件サポート)
- 完全なP5b E2Eテスト(body-local promotion実装後)

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 21:37:07 +09:00
3093ac2ca4 refactor(joinir): Phase 92 P1 - 箱化モジュール化・レガシー削除
P1-1: ConditionalStep lowering を1箱に隔離
- 新規作成: src/mir/join_ir/lowering/common/conditional_step_emitter.rs
  - emit_conditional_step_update() を carrier_update_emitter.rs から移動
  - Fail-Fast 不変条件チェック追加(then_delta != else_delta)
  - 副作用を減らしたクリーンなインターフェース
  - 包括的なテストスイート(3テスト)

P1-0: 境界SSOTの固定
- routing.rs: skeleton 設定をrouting層から削除
- pattern2_with_break.rs: skeleton 取得をlower()内部に閉じ込め
  - parity_checker から skeleton を直接取得
  - skeleton の使用を Pattern2 のみに限定

P1-2: escape recognizer をSSOTに戻す
- escape_pattern_recognizer.rs: 未使用フィールド削除
  - quote_char, escape_char 削除(使われていない)
  - 責務を cond/delta 抽出のみに限定
- pattern_recognizer.rs: デフォルト値を使用

P1-3: E2Eテスト作成(実行は後回し)
- apps/tests/test_pattern5b_escape_minimal.hako 作成
  - body-local 変数対応後に検証予定

テスト結果:
- conditional_step_emitter tests: 3 passed
- Pattern2 tests: 18 passed
- Regression: 0 failures

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 15:53:40 +09:00
a718af3213 feat(joinir): Phase 92 P0-3 - ConditionalStep → JoinIR Select generation
Complete implementation of P5b escape sequence handling pattern lowering:

Core changes:
- skeleton_types.rs: Add `cond` field to ConditionalStep for escape condition
- escape_pattern_recognizer.rs: Extract and return escape_cond AST
- pattern_recognizer.rs: Pass escape_cond to ConditionalStep
- canonicalizer.rs: Store escape_cond in ConditionalStep variant

JoinIR lowering:
- carrier_update_emitter.rs: Add emit_conditional_step_update() function
  - Lower condition AST via lower_condition_to_joinir
  - Compute both then/else branches (carrier + delta)
  - Emit JoinInst::Select for conditional carrier update
- loop_with_break_minimal.rs: Add skeleton parameter, detect ConditionalStep
- pattern2_with_break.rs: Pass skeleton to lowering function

Backward compatibility:
- skeleton=None preserves existing Pattern1-4 behavior
- fixtures.rs, tests.rs updated for new signature

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 15:36:36 +09:00
51017a0f9a feat(joinir): Phase 92 P0-2 - Skeleton to LoopPatternContext (Option A)
SSOT principle: Pass canonicalizer-derived ConditionalStep info to Pattern2 lowerer
without re-detecting from AST.

Changes:
- router.rs: Add skeleton: Option<&'a LoopSkeleton> to LoopPatternContext
- parity_checker.rs: Return (Result, Option<LoopSkeleton>) to reuse skeleton
- routing.rs: Pass skeleton to context when joinir_dev_enabled()
- pattern2_with_break.rs: Detect ConditionalStep in can_lower()

Next: P0-3 implements actual JoinIR generation for ConditionalStep.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 15:22:29 +09:00
d5de808afa refactor(phase-91): Modularize P5b escape pattern recognizer
### Changes

#### 1. New Module: escape_pattern_recognizer.rs (255 lines)
- Dedicated module for P5b (Escape Sequence Handling) pattern
- Single Responsibility Principle: handles only escape pattern detection
- Clean interface: exports only `detect_escape_skip_pattern()` and `EscapeSkipPatternInfo`
- Private helpers for pattern-specific analysis

**Moved functions**:
- `detect_escape_skip_pattern()` - main recognizer
- `find_break_in_if()` - break detection
- `find_escape_in_if()` - escape check detection
- `extract_delta_pair_from_if()` - delta extraction
- `try_extract_increment_assignment()` - increment parsing

#### 2. ast_feature_extractor.rs (1046 lines, was 1345)
- Removed deprecated `extract_escape_delta_from_if()` function
- Removed P5b-specific implementation (moved to escape_pattern_recognizer)
- Added re-export for backward compatibility
- **Result**: 299 lines removed (77% of original), cleaner focus on general pattern analysis

#### 3. mod.rs (patterns/)
- Registered new `escape_pattern_recognizer` module
- Updated documentation to reflect modularization

### Results

 **File Size Reduction**: 1345 → 1046 lines in ast_feature_extractor
 **Code Organization**: Single-responsibility modules
 **Reusability**: P5b helpers isolated for Phase 92+ reuse
 **Test Status**: 1062/1062 tests PASS (no regressions)
 **Dead Code**: Removed deprecated function

### Architecture Improvement

**Before**:
```
ast_feature_extractor.rs (1345 lines)
  ├─ Generic pattern detection (detect_continue, detect_parse_*, etc.)
  └─ P5b-specific helpers (deeply nested, hard to navigate)
```

**After**:
```
ast_feature_extractor.rs (1046 lines) - Generic patterns only
escape_pattern_recognizer.rs (255 lines) - P5b-specific, organized
  ├─ Main recognizer
  └─ Focused private helpers
```

### Next Steps

- Phase 92: Implement JoinIR lowering for P5b using this recognizer
- Phase 93: Pattern P5 (guard-bounded) detection

Boxification/modularity complete! 🎉

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

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-16 15:01:46 +09:00
570c1f6b73 feat(phase-91): Phase 91 Step 2-B/2-D - P5b escape sequence pattern recognition
### Changes

#### 1. UpdateKind Extension (skeleton_types.rs)
- Added `ConditionalStep { then_delta: i64, else_delta: i64 }` variant
- Enables P5b patterns with conditional numeric deltas
- Used for escape sequence handling (i.e., +2 vs +1 based on escape char)

#### 2. Canonicalizer Integration (canonicalizer.rs)
- Added P5b pattern detection after existing patterns
- Routes to Pattern2Break (same as skip_whitespace, reflects has_break=true)
- Builds LoopSkeleton with ConditionalStep update
- Position: AFTER skip_whitespace (Pattern2Break refinement, not separate choice)

#### 3. AST Recognizer Enhancement (ast_feature_extractor.rs)
- Updated `find_escape_in_if` to handle both:
  - `if ch == '\\' { i += 2 }` (no else)
  - `if ch == '\\' { i += 2 } else { i += 1 }` (with else)
- Added `extract_delta_pair_from_if` for clean delta extraction
- Extracts counter_name, escape_delta, normal_delta from single if-else statement

#### 4. Comprehensive Unit Test (canonicalizer.rs)
- Test: `test_escape_skip_pattern_recognition`
- Verifies full P5b pattern recognition
- Confirms ConditionalStep with escape_delta=2, normal_delta=1
- Validates skeleton structure and exit contract (has_break=true)

### Results

 Build: 1062/1062 tests PASS (+1 new P5b test)
 No regressions
 P5b pattern now recognized and routed correctly

### Next Steps

- Step 2-E: Parity verification with strict mode
- Step 2-F: Documentation updates

Phase 91 P5b implementation on track!

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

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-16 14:54:41 +09:00
7db554a763 feat(phase-91): Step 2-A完了 - AST recognizer & re-export chain
## Step 2-A: AST Recognizer (detect_escape_skip_pattern)
- 追加ファイル: src/mir/builder/control_flow/joinir/patterns/ast_feature_extractor.rs
  - EscapeSkipPatternInfo 構造体定義
  - detect_escape_skip_pattern() メイン関数 (MVP実装)
  - Helper関数: find_break_in_if, find_escape_in_if, find_normal_increment等

## Step 2-B: Re-export Chain (SSOT準備)
- 5ファイルで re-export を追加:
  1. src/mir/builder/control_flow/joinir/patterns/mod.rs
  2. src/mir/builder/control_flow/joinir/mod.rs
  3. src/mir/builder/control_flow/mod.rs
  4. src/mir/builder.rs
  5. src/mir/mod.rs
  6. src/mir/loop_canonicalizer/pattern_recognizer.rs

## Pattern Recognizer Wrapper
- try_extract_escape_skip_pattern() を pattern_recognizer.rs に追加
- 既存パターン(skip_whitespace等)に倣う設計

## Phase 91 MVP Design
- Quote/escape char は期待値("と\)にハードコード(Phase 91 MVP)
- Normal delta は常に1を期待
- Escape delta は AST から抽出

## Test Results
 cargo build --release: 成功
 cargo test --release --lib: 1061/1061 PASS
- 退行なし

## 次: Step 2-B本体 (Canonicalizer統合)
- canonicalizer.rs に detect_escape_skip_pattern() 統合
- LoopSkeleton & RoutingDecision を構築
- Pattern2Break に寄せる

🤖 Generated with Claude Code

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-16 14:36:32 +09:00
2674e074b6 feat(joinir): Phase 142 P2 Step 3-A - Pattern4 early return fail-fast 2025-12-16 13:48:30 +09:00
42339ca77f feat(mir): Phase 143 P1 - Add parse_string pattern to canonicalizer
Expand loop canonicalizer to recognize parse_string patterns with both
continue (escape handling) and return (quote found) statements.

## Implementation

### New Pattern Detection (ast_feature_extractor.rs)
- Add `detect_parse_string_pattern()` function
- Support nested continue detection using `has_continue_node()` helper
- Recognize both return and continue in same loop body
- Return ParseStringInfo { carrier_name, delta, body_stmts }
- ~120 lines added

### Canonicalizer Integration (canonicalizer.rs)
- Try parse_string pattern first (most specific)
- Build LoopSkeleton with HeaderCond, Body, Update steps
- Set ExitContract: has_continue=true, has_return=true
- Route to Pattern4Continue (both exits present)
- ~45 lines modified

### Export Chain
- Add re-exports through 7 module levels:
  ast_feature_extractor → patterns → joinir → control_flow → builder → mir
- 10 lines total across 7 files

### Unit Test
- Add `test_parse_string_pattern_recognized()` in canonicalizer.rs
- Verify skeleton structure (3+ steps)
- Verify carrier (name="p", delta=1, role=Counter)
- Verify exit contract (continue=true, return=true, break=false)
- Verify routing decision (Pattern4Continue, no missing_caps)
- ~180 lines added

## Target Pattern
`tools/selfhost/test_pattern4_parse_string.hako`

Pattern structure:
- Check for closing quote → return
- Check for escape sequence → continue (nested inside another if)
- Regular character processing → p++

## Results
-  Strict parity green: Pattern4Continue
-  All 19 unit tests pass
-  Nested continue detection working
-  ExitContract correctly set (first pattern with both continue+return)
-  Default behavior unchanged

## Technical Challenges
1. Nested continue detection required recursive search
2. First pattern with both has_continue=true AND has_return=true
3. Variable step updates (p++ vs p+=2) handled with base delta

## Statistics
- New patterns: 1 (parse_string)
- Total patterns: 4 (skip_whitespace, parse_number, continue, parse_string)
- New capabilities: 0 (uses existing ConstStep)
- Lines added: ~300
- Files modified: 9
- Parity status: Green 

Phase 143 P1: Complete

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 12:37:47 +09:00
d605611a16 feat(canonicalizer): Phase 143-P0 - parse_number pattern support
Add parse_number pattern recognition to canonicalizer, expanding adaptation
range for digit collection loops with break in THEN clause.

## Changes

### New Recognizer (ast_feature_extractor.rs)
- `detect_parse_number_pattern()`: Detects `if invalid { break }` pattern
- `ParseNumberInfo`: Struct for extracted pattern info
- ~150 lines added

### Canonicalizer Integration (canonicalizer.rs)
- Parse_number pattern detection before skip_whitespace
- LoopSkeleton construction with 4 steps (Header + Body x2 + Update)
- Routes to Pattern2Break (has_break=true)
- ~60 lines modified

### Export Chain (6 files)
- patterns/mod.rs → joinir/mod.rs → control_flow/mod.rs
- builder.rs → mir/mod.rs
- 8 lines total

### Tests
- `test_parse_number_pattern_recognized()`: Unit test for recognition
- Strict parity verification: GREEN (canonical and router agree)
- ~130 lines added

## Pattern Comparison

| Aspect | Skip Whitespace | Parse Number |
|--------|----------------|--------------|
| Break location | ELSE clause | THEN clause |
| Pattern | `if cond { update } else { break }` | `if invalid { break } rest... update` |
| Body after if | None | Required (result append) |

## Results

-  Skeleton creation successful
-  RoutingDecision matches router (Pattern2Break)
-  Strict parity OK (canonicalizer ↔ router agreement)
-  Unit test PASS
-  Manual test: test_pattern2_parse_number.hako executes correctly

## Statistics

- New patterns: 1 (parse_number)
- Total patterns: 3 (skip_whitespace, parse_number, continue)
- Lines added: ~280
- Files modified: 8
- Parity status: Green 

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 09:08:37 +09:00
632e495e51 docs(mir): Phase 137-6-S3 - Router委譲の準備コメント追加
## 目的
将来の Router → Canonicalizer 委譲に備えた TODO コメント拡充

## 変更内容

### routing.rs の TODO コメント拡充
- 有効化条件を明記(新フラグ or 既存フラグ)
- 注意事項追加(全 Pattern の parity green 必須)
- コード例を追加(将来実装時の参考)

### Phase 137 README 更新
- Phase 137-6(完了)セクション追加
- S1/S2/S3 の実装内容を記録
- 効果と受け入れ基準達成を記録

## 効果
-  将来の委譲に備えた明確なガイド
-  Phase 137-6 完了記録
-  既定挙動不変(フラグOFF時)

## Phase 137-6 完了サマリー

### 実装完了内容
- **S1**: choose_pattern_kind SSOT 入口(61行追加)
- **S2**: dev-only parity check 統合(52行追加)
- **S3**: Router 委譲準備コメント(ドキュメント拡充)

### 受け入れ基準
-  strict parity green(skip_whitespace)
-  既定挙動不変(フラグOFF時)
-  新 env 追加なし
-  choose_pattern_kind が SSOT 入口として機能
-  全テスト PASS(退行なし)

### テスト結果
-  `cargo build --release`: 成功
-  スモークテスト(simple_*): 5/5 PASS
-  parity check 動作確認:
  ```
  NYASH_JOINIR_DEV=1 HAKO_JOINIR_STRICT=1 ./target/release/hakorune \
    tools/selfhost/test_pattern3_skip_whitespace.hako
  → [choose_pattern_kind/PARITY] OK
  ```

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 07:44:57 +09:00
91d7607682 refactor(mir): Phase 137-6-S2 - dev-only で canonicalizer decision を提案として受け取る
## 目的
Canonicalizer の decision を router に差し込む(既定挙動不変)

## 変更内容

### choose_pattern_kind() に parity check 統合
- dev-only 時に Canonicalizer を呼び出し
- router_choice と canonical_choice を比較
- 不一致時の動作:
  - strict mode (`HAKO_JOINIR_STRICT=1`): panic (Fail-Fast)
  - debug mode (`NYASH_JOINIR_DEV=1`): ログのみ
- 既定挙動: router_choice を維持(Canonicalizer は提案のみ)

### ログ出力
```
[choose_pattern_kind/PARITY] OK: canonical and actual agree on Pattern2Break
```

## 効果
-  Canonicalizer → Router の parity check 統合
-  SSOT 入口での一致性検証
-  既定挙動完全不変(フラグOFF時)
-  新 env 追加なし(既存の `joinir_dev_enabled()` と `strict_enabled()` を使用)

## テスト結果
-  `cargo build --release`: 成功
-  skip_whitespace: parity green
  ```
  NYASH_JOINIR_DEV=1 HAKO_JOINIR_STRICT=1 ./target/release/hakorune \
    tools/selfhost/test_pattern3_skip_whitespace.hako
  → [choose_pattern_kind/PARITY] OK
  ```
-  スモークテスト(simple_*): 5/5 PASS
-  退行なし

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 07:42:35 +09:00