220 Commits

Author SHA1 Message Date
4082abb30c feat(normalization): Phase 142 P0 - Loop statement-level normalization
Phase 142-loopstmt P0: Statement-level normalization

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

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-19 05:28:49 +09:00
275fe45ba4 feat(normalization): Phase 142 P0 - Statement-level normalization
## Summary

Changed normalization unit from "block suffix" to "statement (loop only)"
to prevent pattern explosion.

## Changes

1. **PlanBox** (`plan_box.rs`):
   - Always return `loop_only()` for any `loop(true)`, regardless of what follows
   - Subsequent statements (return, assignments) handled by normal MIR lowering
   - ~70 lines reduced, 7 unit tests updated

2. **build_block** (`stmts.rs`):
   - Removed `break` after consumed=1 from suffix_router
   - Continue processing subsequent statements normally
   - Phase 142 P0 comments added

3. **Tests**:
   - Fixture: `phase142_loop_stmt_only_then_return_length_min.hako`
   - VM smoke: exit code 3 (s="abc" → s.length() → 3)

## Results

-  Unit tests: 10/10 passed
-  Phase 142 VM smoke: PASS
-  Phase 131 regression: PASS
-  Build: Success

## Design

- **Pattern Explosion Prevention**: Normalize only the loop (consumed=1)
- **Out-of-Scope Policy**: Always Ok(None) for fallback
- **Fail-Fast**: Only for "in-scope but broken" cases

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-19 04:41:01 +09:00
ff09adebe0 feat(control_tree): Phase 136/137 - return literal and add expression (dev-only)
Phase 136 P0: Return literal (Integer) support
- Extend loop(true) break-once to support `return 7`
- Fixtures: phase136_loop_true_break_once_return_literal_min.hako (exit code 7)
- VM/LLVM EXE parity achieved

Phase 137 P0: Return add expression support
- Extend to support `return x + 2` and `return 5 + 3`
- LHS: Variable or Integer literal
- RHS: Integer literal only
- Fixtures:
  - phase137_loop_true_break_once_return_add_min.hako (exit code 3)
  - phase137_loop_true_break_once_return_add_const_min.hako (exit code 8)
  - phase137_loop_true_break_once_post_return_add_min.hako (exit code 13)
- VM/LLVM EXE parity achieved

Implementation:
- Added lower_return_value_to_vid() method in loop_true_break_once.rs
- Replaced extract_variable_name() with unified return value lowering
- Supported patterns: Variable, Integer literal, BinaryOp Add
- Out-of-scope patterns return Ok(None) for fallback
- SSOT documentation added (lines 29-46)

Tests: 5 fixtures + 10 smoke tests (5 VM + 5 LLVM EXE), all PASS

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-19 00:15:32 +09:00
91c7dfbf0b refactor(normalization): Phase 135 P0 - Extend plan to zero post-loop assigns
Generalize NormalizationPlan suffix detection to accept zero post-loop assignments:

Goal: Improve entry point consistency by allowing `loop + assign* + return` (N >= 0)

Implementation:
- Modified plan_box.rs detection logic (only file changed)
- Removed `post_assign_count >= 1` requirement
- Unified Phase 131 (loop + return) and Phase 132-133 (loop + assign+ + return) paths

Changes:
- src/mir/builder/control_flow/normalization/plan_box.rs:
  - Removed assignment count constraint
  - Unified pattern detection: `loop + assign* + return` (N >= 0)
- apps/tests/phase135_loop_true_break_once_post_empty_return_min.hako (new fixture)
- tools/smokes/v2/profiles/integration/apps/phase135_*.sh (new smoke tests)

Pattern support:
- Phase 131/135: loop + return only (consumed: 2, post_assign_count: 0) 
- Phase 132: loop + 1 assign + return (consumed: 3, post_assign_count: 1) 
- Phase 133: loop + N assigns + return (consumed: 2+N, post_assign_count: N) 

Design principles maintained:
- **Minimal change**: Only plan_box.rs modified (execute_box unchanged)
- **SSOT**: Detection logic centralized in plan_box.rs
- **Box-First**: Responsibility separation preserved (Plan/Execute)

Test results:
- Unit tests (plan_box): 9/9 PASS (2 new tests added)
- Phase 135 VM/LLVM EXE: PASS (exit code 1)
- Phase 131 regression: 2/2 PASS (path now unified)
- Phase 133 regression: 2/2 PASS
- cargo test --lib: PASS

Benefits:
- Unified entry point for all loop + post patterns
- Easier maintenance (single detection logic)
- Future extensibility (easy to add new patterns)
- Clear separation of Phase 131 and Phase 132-135 paths

Default behavior unchanged: Dev-only guard maintained

Related: Phase 135 normalization pattern consistency improvement

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-18 22:46:32 +09:00
ef71ea955c feat(control_tree): Phase 133 P0 - Multiple post-loop assigns support
Extend Phase 132's loop(true) + post-loop to accept multiple assignments:

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

Implementation:
- Extended loop_true_break_once.rs pattern detection (len() == 2 → len() >= 2)
- Added iterative assignment lowering (for loop over post_nodes)
- Reused Phase 130's lower_assign_stmt for each assignment
- Maintained ExitMeta DirectValue mode (PHI-free)

Changes:
- apps/tests/phase133_loop_true_break_once_post_multi_add_min.hako (new fixture)
- tools/smokes/v2/profiles/integration/apps/phase133_*_multi_add_*.sh (new smokes)
- src/mir/control_tree/normalized_shadow/loop_true_break_once.rs (+30 lines)
- docs/development/current/main/phases/phase-133/README.md (new documentation)
- docs/development/current/main/10-Now.md (Phase 133 entry added)

Scope (Phase 130 baseline):
-  x = <int literal>
-  x = y (variable copy)
-  x = x + <int literal> (increment)
-  Function calls / general expressions (future phases)

Design principles:
- Minimal change: ~30 lines added
- SSOT preservation: env_post_k remains single source of truth
- Reuse: Leveraged existing lower_assign_stmt
- Fail-Fast: Contract violations trigger freeze_with_hint

Test results:
- cargo test --lib: 1176 PASS
- Phase 133 VM: PASS (exit code 6)
- Phase 133 LLVM EXE: PASS (exit code 6)
- Phase 132 regression: PASS (exit code 3)
- Phase 131 regression: PASS (exit code 1)
- Phase 97 regression: PASS

Architecture maintained:
- 5-function structure unchanged (main/loop_step/loop_body/k_exit/post_k)
- PHI-free DirectValue mode
- Zero changes to ExitMeta, merge logic, or JoinIR contracts

Related: Phase 133 loop(true) + multiple post-loop assignments

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-18 22:11:08 +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
38d3c98822 test(joinir): Phase 131 loop(true) break-once fixture + VM/LLVM smokes
Add minimal fixture and smoke tests for loop(true) break-once pattern:

**Fixture**:
- apps/tests/phase131_loop_true_break_once_min.hako
  - Pattern: x=0; loop(true) { x=1; break }; return x
  - Expected: return value 1 (exit code 1)

**Smokes**:
- tools/smokes/v2/profiles/integration/apps/phase131_loop_true_break_once_vm.sh
  - VM backend test with dev-only flags
- tools/smokes/v2/profiles/integration/apps/phase131_loop_true_break_once_llvm_exe.sh
  - LLVM EXE backend test with plugin gating

**Note**: Smokes currently fail (execution path not yet wired).
Structure implementation only - follow-up phase will wire execution.

Related: Phase 131 P0 (Normalized shadow structure)
2025-12-18 09:36:25 +09:00
1afbb17529 test(joinir): Phase 130 post-if add fixture + smokes 2025-12-18 09:13:13 +09:00
f0a03d20d0 test(joinir): Phase 129 join_k as-last fixture + VM smoke 2025-12-18 07:53:27 +09:00
083be99214 test(joinir): Phase 129 P2 - add post-if return var fixture + VM smoke
- Add phase129_if_only_post_if_return_var_min.hako
  - Pattern: x=1; if flag==1 { x=2 }; print(x)
  - Tests join_k continuation env merge

- Add phase129_if_only_post_if_return_var_vm.sh
  - Expected output: 2 (x updated in then branch)
  - Dev-only: NYASH_JOINIR_DEV=1 HAKO_JOINIR_STRICT=1

Note: Currently passes via fallback path (non-Normalized)
P1 implementation (join_k materialization) is next step
2025-12-18 07:18:00 +09:00
daf1827c03 test(joinir): Phase 128 - add fixture + smoke test (VM)
- Fixture: phase128_if_only_partial_assign_normalized_min.hako
  - Tests basic assign lowering with if/return pattern
  - Expected output: 2 (from then branch with print)
- Smoke: phase128_if_only_partial_assign_normalized_vm.sh
  - Validates output: 2 with exit code 0
  - Dev-only: NYASH_JOINIR_DEV=1 HAKO_JOINIR_STRICT=1
- Result: PASS
2025-12-18 07:07:04 +09:00
505ce03dfc test(joinir): Phase 128 P3 - add minimal fixture for partial assign pattern
Note: Full join_k continuation implementation deferred to future phase.
Current fixture tests basic assign lowering with simplified if/return pattern.
2025-12-18 07:05:32 +09:00
7ae424df3c test(joinir): Phase 126 assert readonly inputs actually wired
- phase125_if_only_return_readonly_input_min.hako enhanced
- Actual if-only pattern: outer_x is read-only (not in writes)
- return outer_x resolves from inputs (reads ∩ available_inputs)
- Smoke test PASS: exit code 7 (NYASH_JOINIR_DEV=1 HAKO_JOINIR_STRICT=1)
2025-12-18 06:45:56 +09:00
92b3c2afb5 test(joinir): Phase 125 P5 fixture + smoke (VM, structure-only)
Phase 125 P5: Integration smoke test
- fixture: apps/tests/phase125_if_only_return_readonly_input_min.hako
  - Expected: 7 (return x from reads-only input)
  - Note: Demonstrates structure, full functionality needs P3 wiring
- smoke: tools/smokes/v2/profiles/integration/apps/phase125_if_only_return_input_vm.sh
  - NYASH_JOINIR_DEV=1 HAKO_JOINIR_STRICT=1
  - VM backend only

Test results:
- Phase 125 smoke: PASS (exit code 7)
- Regression (Phase 121-124, 118): PASS
  - phase124_if_only_return_var_vm: PASS
  - phase123_if_only_normalized_semantics_vm: PASS
  - phase121_shadow_if_only_vm: PASS (3/3 tests)
  - phase118_loop_nested_if_merge_vm: PASS

Note:
- P3 (available_inputs wiring) not implemented yet
- Fixture uses simple return (no if-only pattern yet)
- Serves as design document for future P3 implementation
- EnvLayout.inputs will be populated when P3 is complete

Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:32:10 +09:00
8e6791a623 test(joinir): Phase 124 return-var normalized smoke (VM)
Phase 124-P4:
- Add fixture: apps/tests/phase124_if_only_return_var_min.hako
  - local x; x = 7; print(x); return x
  - Expected output: 7 (print), RC: 7 (return x)
- Add smoke: tools/smokes/v2/profiles/integration/apps/phase124_if_only_return_var_vm.sh
  - NYASH_JOINIR_DEV=1 HAKO_JOINIR_STRICT=1 for dev-only features
  - Accept exit code 7 (return x where x=7) as valid
- Verify all Phase 121/123/118 smokes still PASS
2025-12-18 06:09:36 +09:00
b3cd7c0884 test(joinir): Phase 123 normalized semantics smoke (VM)
Adds integration smoke test for Phase 123 normalized semantics lowering.

**New Files**:
- `apps/tests/phase123_if_only_return_literal_min.hako`: Minimal test fixture (output: 7)
- `tools/smokes/v2/profiles/integration/apps/phase123_if_only_normalized_semantics_vm.sh`: Smoke test script

**What's Tested**:
- Return(Integer literal) generates correct output
- Dev+strict mode does not fail (graceful degradation works)

**Test Status**: PASS

**Verification**:
```bash
bash tools/smokes/v2/profiles/integration/apps/phase123_if_only_normalized_semantics_vm.sh
# Result: PASS (output: 7)
```

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:16 +09:00
4abd434366 test: Phase 122 if-only Normalized emit smoke
Phase 122 P4: Fixtures and smoke tests
- New fixture: phase122_if_only_normalized_emit_min.hako
- Smoke test: phase122_if_only_normalized_emit_vm.sh
- Verifies: module emission + structure verification in dev+strict mode
- Regression check: phase103 fixture still passes
- All tests PASS
2025-12-18 04:53:04 +09:00
8fb393b5e8 test(joinir): Phase 118 loop+if merge parity smokes 2025-12-18 03:43:10 +09:00
bc561682f6 test: Phase 117 if-only nested-if call merge parity (VM + LLVM EXE)
Fixture & Smoke tests for nested if-only with call merge verification.

**Fixture**:
- apps/tests/phase117_if_only_nested_if_call_merge_min.hako
- Pattern: nested if (inner: b == 1) inside outer if (a == 1), outer else
- Call merge: f(1), f(2), f(3) results merged to single variable v
- Expected output: 2, 3, 4 (f(x) = x + 1)

**VM Smoke**:
- tools/smokes/v2/profiles/integration/apps/phase117_if_only_nested_if_call_merge_vm.sh
- Execution: NYASH_DISABLE_PLUGINS=1 HAKO_JOINIR_STRICT=1
- Validation: numeric output 3 lines "2\n3\n4"

**LLVM EXE Smoke**:
- tools/smokes/v2/profiles/integration/apps/phase117_if_only_nested_if_call_merge_llvm_exe.sh
- Required plugins: FileBox, MapBox, StringBox, ConsoleBox, IntegerBox
- Validation: numeric output "2\n3\n4" (3 lines)

**Verification**:
 VM smoke: PASS
 LLVM EXE smoke: PASS
 Regression (Phase 116): PASS

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 02:55:02 +09:00
ed38aa820a test: Phase 116 if-only keep+call merge parity (VM + LLVM EXE)
Phase 116 固定: if-only で片側が元値保持、片側が call 結果の merge パターン

## 実装内容

### Fixture
- `apps/tests/phase116_if_only_keep_plus_call_min.hako`
- Expected output: `10\n2`
- Pattern:
  - then側: call結果でvを更新 (`v = f(1)`)
  - else側: 元の値を保持 (`v = 10`)
  - merge地点: 異なるソース(元値 vs call結果)からのPHI

### Smoke Tests
- `phase116_if_only_keep_plus_call_vm.sh` - VM parity
  - output_validator.sh で数値2行 `10\n2` を検証
  - `NYASH_DISABLE_PLUGINS=1 HAKO_JOINIR_STRICT=1`
- `phase116_if_only_keep_plus_call_llvm_exe.sh` - LLVM EXE parity
  - llvm_exe_runner.sh を利用(plugin dlopen/cache/build-all SSOT)
  - llvm_exe_build_and_run_numeric_smoke で検証

## 検証結果

 VM smoke: PASS (10\n2)
 LLVM EXE smoke: PASS (10\n2)
 回帰 (Phase 115): PASS (2\n3)

## 技術的詳細

### JoinIR Pattern 1 (Simple If)

```
entry_block:
  v = 10
  if flag == 1 goto then_block else exit_block

then_block:
  v = f(1)
  goto exit_block

exit_block:
  v_merged = PHI [v=10 from entry, v=f(1) from then]
  print(v_merged)
```

### PHI接続の重要性
- entry → exit: 元値 (`10`) を直接伝播
- then → exit: call結果 (`f(1)`) を伝播
- PHI: 異なる型のソース(変数 vs call結果)を正しくmerge

LLVM IRでは、これらが適切な型で統一される必要がある。

## Box-First原則の適用

 既存の箱化されたコンポーネントを活用
  - output_validator.sh による出力検証の統一
  - llvm_exe_runner.sh によるLLVM実行の標準化
  - テストインフラの再利用(no reinvention)

## Fail-Fast原則

 VM/LLVM両方でエラーを即座に検出
  - `HAKO_JOINIR_STRICT=1` で厳密な検証
  - フォールバック処理なし(エラーは明示的に失敗)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 02:39:33 +09:00
0a29f1443e test: Phase 115 if-only call result merge parity (VM + LLVM EXE)
Phase 115実装 - if分岐内での関数呼び出し結果をマージするパターンを固定

**実装内容**:
- Fixture: phase115_if_only_call_merge_min.hako (expected: 2, 3)
  - if/else両分岐で関数呼び出し f() の結果を変数 v に代入
  - if後にマージされた v を使用(LLVM EXE でのPHI node生成を検証)
- VM smoke: phase115_if_only_call_merge_vm.sh
  - NYASH_DISABLE_PLUGINS=1 HAKO_JOINIR_STRICT=1 で実行
- LLVM EXE smoke: phase115_if_only_call_merge_llvm_exe.sh
  - llvm_exe_runner.sh を利用した標準パリティ検証

**検証結果**:
- VM test: PASS 
- LLVM EXE test: PASS 
- Phase 114 regression: PASS 

**箱化モジュール化の観点**:
- 単一責任: 各smokeは1パターンのみ検証(call result merge)
- 分離: VM/LLVM EXEで独立したテスト(llvm_exe_runner.sh経由)
- Fail-Fast: HAKO_JOINIR_STRICT=1 で不正な制御フローを即座に検出

**関連**:
- Phase 103: If-Only基本パリティ(制御フロー基礎)
- Phase 113: If-Only部分代入パリティ(変数マージ)
- Phase 114: If-Only return+post パリティ(early returnとpost-if文)
- Phase 115: If-Only call result merge パリティ(関数呼び出し結果マージ) ← 今回

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 02:32:08 +09:00
80be814fa4 test: Phase 114 if-only return+post parity (VM + LLVM EXE)
Phase 114 validates that if-only lowering correctly handles cases with:
- Early return in the if-only branch
- Post-if statements that execute on the else path
- Different return values from each path

Fixture: apps/tests/phase114_if_only_return_then_post_min.hako
- Expected output: 7\n2
- f(1): condition true → early return 7
- f(0): condition false → x=1+1=2, return 2

Testing:
- VM backend: phase114_if_only_return_then_post_vm.sh 
- LLVM EXE backend: phase114_if_only_return_then_post_llvm_exe.sh 
- Regression: Phase 103/113 maintained 

Implementation: No new code required - validates existing if-only
exit line routing and post-if statement processing.

Documentation:
- docs/development/current/main/phases/phase-114/README.md
- Updated: 10-Now.md, 01-JoinIR-Selfhost-INDEX.md

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 02:18:57 +09:00
ba25fe6d01 test: Phase 113 if-only partial assign fixture + smokes (VM + LLVM)
- Add apps/tests/phase113_if_only_partial_assign_min.hako
  * Pattern: x=1; if flag==1 { x=2 } print(x)
  * Tests "preserve merge" on else side
- Add VM smoke: phase113_if_only_partial_assign_vm.sh
- Add LLVM EXE smoke: phase113_if_only_partial_assign_llvm_exe.sh
- Expected output: 1\n2 (flag=0 preserves, flag=1 updates)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 01:58:38 +09:00
9fa2f5a8ad test: align Phase 107 object fixture expected output 2025-12-17 23:16:53 +09:00
3c934dc69d test: Phase 107 add find_balanced_object_end fixture + smokes 2025-12-17 23:12:49 +09:00
d42117ac5f test: Phase 107 find_balanced_array_end fixture + smokes 2025-12-17 22:47:42 +09:00
a05ce39a1f test: add Phase104 json_cur read_digits fixture and smokes 2025-12-17 21:25:12 +09:00
950560a3d9 test(joinir): Phase 104 read_digits loop(true) parity 2025-12-17 18:29:27 +09:00
3fe92312a1 test: Phase 103 P1 if-only early return parity 2025-12-17 17:45:12 +09:00
99e1d24eaf test: Phase 103 if-only merge fixture + VM/LLVM smokes 2025-12-17 17:41:07 +09:00
5b4f9c25e4 test: Phase 102 real-app read_quoted fixture + VM/LLVM smokes 2025-12-17 16:57:11 +09:00
dfc01f4dc5 test: Phase 100 string accumulator fixture+smokes (VM+LLVM)
- Add phase100_string_accumulator_min.hako fixture
  * out = out + ch string accumulation
  * print(out.length()) for stable numeric output
- Add VM smoke: phase100_string_accumulator_vm.sh
- Add LLVM EXE smoke: phase100_string_accumulator_llvm_exe.sh (Phase 97 gating)
- Regression: all phase100/97/94 tests pass

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-17 16:33:26 +09:00
536e6280c5 test: Phase 100 mutable accumulator fixture + smoke (numeric validation)
- Add apps/tests/phase100_mutable_accumulator_min.hako
  * Pattern2 with break (if i >= 3 { break })
  * Two accumulators: out = out + ch (string), count = count + 1 (integer)
  * print(count) for stable numeric output
- Add phase100_mutable_accumulator_vm.sh smoke test
  * HAKO_JOINIR_STRICT=1 validation
  * Numeric-only output extraction (expected: 3)
- Regression: all phase100/96/94 tests pass

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-17 06:10:59 +09:00
82806f8f90 test: Phase 100 pinned local receiver fixture + smoke
- Add apps/tests/phase100_pinned_local_receiver_min.hako
  * Dynamic string construction with pinned receiver usage
  * Demonstrates loop-outer local as method receiver
- Add tools/smokes/v2/profiles/integration/apps/phase100_pinned_local_receiver_vm.sh
  * HAKO_JOINIR_STRICT=1 validation
  * Numeric output extraction for log-resistant testing
- Regression: phase96 and phase94 smoke tests pass

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

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-17 05:43:44 +09:00
708d01d1f8 test: Phase 99 add trailing backslash escape best-effort (VM+LLVM)
末尾バックスラッシュ処理:
- 現行仕様: best-effort(そのまま出力)として固定
- fixture: "hello\\" → "hello\" を出力
- VM+LLVM EXE parity完全対応

Integration smokeで検証済み

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-17 04:26:05 +09:00
b23d23f11f test: Phase 99 extend next_non_ws to 3 cases (VM+LLVM)
3ケース固定:
- 既存: "  hi" → 2, " \t" → -1
- 新規: "\n\r\tX" → 3 (mixed newline/CR/tab)

VM+LLVM EXE parity完全対応

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-17 04:25:57 +09:00
db4453eb3c test: strengthen phase96 next_non_ws fixture 2025-12-17 01:35:43 +09:00
ba87afd35c test: add phase96 trim loop fixture and smoke 2025-12-17 01:25:06 +09:00
1a3e6474c3 test: add phase95 json_loader escape fixture 2025-12-17 01:01:07 +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
568619df89 feat(mir): Phase 92 P2-2 - Body-local variable support for ConditionalStep
Phase 92 P2-2完了:ConditionalStepのcondition(ch == '\\'など)でbody-local変数をサポート

## 主要変更

### 1. condition_lowerer.rs拡張
- `lower_condition_to_joinir`に`body_local_env`パラメータ追加
- 変数解決優先度:ConditionEnv → LoopBodyLocalEnv
- すべての再帰ヘルパー(comparison, logical_and, logical_or, not, value_expression)対応

### 2. conditional_step_emitter.rs修正
- `emit_conditional_step_update`に`body_local_env`パラメータ追加
- condition loweringにbody-local環境を渡す

### 3. loop_with_break_minimal.rs修正
- break condition loweringをbody-local init の**後**に移動(line 411)
- header_break_lowering::lower_break_conditionにbody_local_env渡す
- emit_conditional_step_updateにbody_local_env渡す(line 620)

### 4. header_break_lowering.rs修正
- `lower_break_condition`に`body_local_env`パラメータ追加
- scope_managerにbody-local環境を渡す

### 5. 全呼び出し箇所修正
- expr_lowerer.rs (2箇所)
- method_call_lowerer.rs (2箇所)
- loop_with_if_phi_if_sum.rs (3箇所)
- loop_with_continue_minimal.rs (1箇所)
- carrier_update_emitter.rs (1箇所・legacy)

## アーキテクチャ改善

### Break Condition Lowering順序修正
旧: Header → **Break Cond** → Body-local Init
新: Header → **Body-local Init** → Break Cond

理由:break conditionが`ch == '\"'`のようにbody-local変数を参照する場合、body-local initが先に必要

### 変数解決優先度(Phase 92 P2-2)
1. ConditionEnv(ループパラメータ、captured変数)
2. LoopBodyLocalEnv(body-local変数like `ch`)

## テスト

### ビルド
 cargo build --release成功(30 warnings、0 errors)

### E2E
⚠️ body-local promotion問題でブロック(Phase 92範囲外)
- Pattern2はbody-local変数をcarrier promotionする必要あり
- 既存パターン(A-3 Trim, A-4 DigitPos)に`ch = get_char(i)`が該当しない
- **Phase 92 P2-2目標(condition loweringでbody-local変数サポート)は達成**

## 次タスク(Phase 92 P3以降)
- body-local variable promotion拡張(Pattern2で`ch`のような変数を扱う)
- P5b E2Eテスト完全動作確認

## Phase 92 P2-2完了
 Body-local変数のcondition lowering対応完了
 ConditionalStepでbody-local変数参照可能
 Break condition lowering順序修正
2025-12-16 17:08:15 +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
439633020b test: Phase 133 P1 - Update fixture with P1 fix notes 2025-12-15 13:02:26 +09:00
ae59409282 test: Phase 133 P0 - Promoted carrier join_id test fixture (JsonParser pattern) 2025-12-15 12:35:59 +09:00
aad01a1079 feat(llvm): Phase 132-P2 - Dict ctx removal (FunctionLowerContext SSOT completion)
Completed SSOT unification for FunctionLowerContext by removing the manual
dict ctx creation and assignment in function_lower.py.

Changes:
- Removed builder.ctx = dict(...) creation (18 lines, lines 313-330)
- Removed builder.resolver.ctx assignment (no longer needed)
- Confirmed instruction_lower.py uses context=owner.context throughout
- Added phase132_multifunc_isolation_min.hako test for multi-function isolation
- Extended phase132_exit_phi_parity.sh with Case C (Rust VM context test)

Testing:
- Phase 132 smoke test: All 3 cases PASS
- Phase 87 LLVM exe test: PASS (Result: 42)
- STRICT mode: PASS
- No regressions: Behavior identical before/after (RC:6 maintained)

Impact:
- Reduced manual context management complexity
- FunctionLowerContext now sole source of truth (SSOT)
- Per-function state properly isolated, no cross-function collisions
- Cleaner architecture: context parameter passed explicitly vs manual dict

🤖 Generated with Claude Code
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-15 12:12:54 +09:00
9d57d2cb9c test: Phase 132 LLVM EXE regression smoke (minimal) 2025-12-15 06:24:18 +09:00
cd12a2569e feat(llvm): Phase 87 - LLVM exe line SSOT + integration smoke
Established single pipeline for .hako → executable generation.

SSOT: tools/build_llvm.sh
- Standard procedure: build_llvm.sh input.hako -o output_exe
- Prerequisites: llvm-config-18, llvmlite, LLVM features enabled
- Pipeline: .hako → MIR → LLVM IR → .o → executable

New files:
- docs: phase87-selfhost-llvm-exe-line.md (SSOT procedure doc)
  * Full troubleshooting guide (llvm-config, llvmlite, linking)
  * Advanced usage (custom output, debugging, performance notes)
  * Anti-patterns documentation (no duplication/fragmentation)
- fixture: apps/tests/phase87_llvm_exe_min.hako (5 lines, return 42)
- smoke: integration/apps/phase87_llvm_exe_min.sh
  * Exit code verification (stdout-independent testing)
  * SKIP if LLVM unavailable (graceful degradation)
  * Integration profile only (not in quick)
- index: 10-Now.md, 01-JoinIR-Selfhost-INDEX.md (Phase 87 entries)
- task: CURRENT_TASK.md (Phase 74-87 status update)

Integration smoke: demonstrates full pipeline
- Build: .hako → .o → exe (successful )
- Runtime: Ring0 initialization issue (known limitation, out of scope)
Quick profile: unchanged (integration only, per policy)
Policy: No duplicate build paths, SSOT maintained

987/987 tests PASS (production stable)
2025-12-13 22:51:13 +09:00
463a6240fb chore(test): Improve phase246ex_atoi_mini test format
- Change from string return ("PASS"/"FAIL") to numeric RC (0=success, 1=fail)
- Add print("result = N") for stdout verification
- Update comments to reflect new test format

This makes test results verifiable via both stdout AND return code,
avoiding future confusion about RC interpretation.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-11 17:24:32 +09:00
e356524b0a feat(joinir): Phase 246-EX Part 1 - FromHost carrier infrastructure
Extends Phase 247-EX dual-value architecture for _atoi NumberAccumulation
support. Implements FromHost carrier handling throughout JoinIR pipeline.

## Problem Analysis

_atoi requires `result = result * 10 + digit_pos` where:
- digit_pos is promoted to dual carriers: is_digit_pos (bool) + digit_value (int)
- digit_value is used in NumberAccumulation but NOT updated itself
- Existing infrastructure filtered out carriers without updates

## Implementation

### 1. Carrier Filtering (pattern2_with_break.rs:507-514)
**Added FromHost retention**:
```rust
carrier_updates.contains_key(&carrier.name)
    || carrier.role == CarrierRole::ConditionOnly
    || carrier.init == CarrierInit::FromHost  // Phase 247-EX
```

**Effect**: Keeps digit_value carrier despite no update expression

### 2. Carrier Update Passthrough (loop_with_break_minimal.rs:411-426)
**Added FromHost passthrough**:
- FromHost carriers without updates pass through from env
- Similar to Phase 227 ConditionOnly handling
- Logged as `[loop/carrier_update] Phase 247-EX: FromHost carrier passthrough`

### 3. Exit Bindings Collection (meta_collector.rs:156-172)
**Added FromHost exit_bindings inclusion**:
```rust
Some((CarrierRole::LoopState, CarrierInit::FromHost)) => {
    // Include in exit_bindings for latch incoming
    // Not for exit PHI or variable_map
}
```

**Effect**: digit_value gets latch incoming for header PHI

## Test Results

- **Before**: 931 tests PASS
- **After**: 931 tests PASS (0 regressions)

## Verification

**Phase 247-EX UpdateEnv working**:
```
[update_env/phase247ex] Resolved promoted 'digit_pos' → 'digit_value' (integer carrier): ValueId(111)
```

**NumberAccumulation MIR generated**:
```
%39 = %14 Mul %38    ← result * 10
%40 = %39 Add %9     ← tmp + digit_value
```

## Status

-  Pattern2 classification
-  NumberAccumulation detection
-  dual-value carrier resolution
-  FromHost carrier handling
- ⚠️ RC:0 issue (runtime value problem, Part 2)

## Related

- Phase 247-EX: DigitPos dual-value architecture (commit 8900a3cc)
- Phase 227: ConditionOnly carrier handling
- Phase 228-8: ConditionOnly exit_bindings

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-11 15:28:36 +09:00
250555bfc0 feat(joinir): Phase 224-B - MethodCallLowerer + CoreMethodId extension
- Extend CoreMethodId with is_pure(), allowed_in_condition(), allowed_in_init()
- New MethodCallLowerer box for metadata-driven MethodCall lowering
- Integrate MethodCall handling in condition_lowerer
- P0: Zero-argument methods (length) supported
- Design principle: NO method name hardcoding, CoreMethodId metadata only

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 17:59:24 +09:00