2025-12-19 06:03:09 +09:00
|
|
|
|
# Phase 143-loopvocab: Loop Vocabulary Extension
|
2025-12-19 05:28:49 +09:00
|
|
|
|
|
2025-12-19 06:03:09 +09:00
|
|
|
|
Status: ✅ **P0 Complete**
|
|
|
|
|
|
Date: 2025-12-19
|
2025-12-19 05:28:49 +09:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-19 06:03:09 +09:00
|
|
|
|
## 目的(Why)
|
2025-12-19 05:28:49 +09:00
|
|
|
|
|
2025-12-19 06:03:09 +09:00
|
|
|
|
Phase 131で `loop(true) break` を実装したが、Phase 143では「条件付きbreak」パターンを吸収する。
|
2025-12-19 05:28:49 +09:00
|
|
|
|
|
2025-12-19 06:03:09 +09:00
|
|
|
|
**Phase 143-loopvocab** では、`loop(true) { if(cond_pure) break }` を **Normalized shadow lowering** で段階的に拡張するための語彙追加を行う。
|
2025-12-19 05:28:49 +09:00
|
|
|
|
|
2025-12-19 06:03:09 +09:00
|
|
|
|
### パターン進化
|
2025-12-19 05:28:49 +09:00
|
|
|
|
|
2025-12-19 06:03:09 +09:00
|
|
|
|
**Phase 131**:
|
|
|
|
|
|
```nyash
|
|
|
|
|
|
loop(true) { break } // 無条件break
|
|
|
|
|
|
```
|
2025-12-19 05:28:49 +09:00
|
|
|
|
|
2025-12-19 06:03:09 +09:00
|
|
|
|
**Phase 143 P0**:
|
|
|
|
|
|
```nyash
|
|
|
|
|
|
loop(true) { if(cond_pure) break } // 条件付きbreak
|
|
|
|
|
|
```
|
2025-12-19 05:28:49 +09:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-19 06:03:09 +09:00
|
|
|
|
## P0: Minimal Vocabulary Extension (COMPLETE ✅)
|
|
|
|
|
|
|
|
|
|
|
|
### Summary
|
|
|
|
|
|
|
|
|
|
|
|
`loop(true) { if(cond_pure) break }` パターンを Normalized shadow で実装完了。
|
|
|
|
|
|
|
|
|
|
|
|
### Scope (P0 - Conservative)
|
|
|
|
|
|
|
|
|
|
|
|
**Supported**:
|
|
|
|
|
|
- Loop condition: `true` literal only
|
|
|
|
|
|
- Loop body: Single `if` statement only
|
|
|
|
|
|
- If then branch: `break` only (no continue, no nested if)
|
|
|
|
|
|
- Condition expression: Pure only (variables, literals, arith, compare)
|
|
|
|
|
|
|
|
|
|
|
|
**Out of Scope** (Ok(None) fallback):
|
|
|
|
|
|
- Loop condition not `true`: `loop(x > 0) { ... }`
|
|
|
|
|
|
- Multiple statements in loop body
|
|
|
|
|
|
- If/else statements (no else branch)
|
|
|
|
|
|
- Impure conditions: `loop(true) { if(s.length() > 0) break }`
|
|
|
|
|
|
- Nested structures within if body
|
2025-12-19 05:28:49 +09:00
|
|
|
|
|
2025-12-19 06:03:09 +09:00
|
|
|
|
### Design: 6-Function JoinModule
|
2025-12-19 05:28:49 +09:00
|
|
|
|
|
|
|
|
|
|
```
|
2025-12-19 06:03:09 +09:00
|
|
|
|
main(env) → loop_step(env) → loop_cond_check(env)
|
|
|
|
|
|
[condition lowering + Jump]
|
|
|
|
|
|
→ k_exit(env) on break [Ret]
|
|
|
|
|
|
→ loop_step(env) on continue [Call]
|
2025-12-19 05:28:49 +09:00
|
|
|
|
|
2025-12-19 06:03:09 +09:00
|
|
|
|
k_then(unused in P0)
|
|
|
|
|
|
k_else(unused in P0)
|
2025-12-19 05:28:49 +09:00
|
|
|
|
```
|
|
|
|
|
|
|
2025-12-19 06:03:09 +09:00
|
|
|
|
**Jump Semantics**:
|
|
|
|
|
|
- `Jump { cont: k_exit, args: [...], cond: Some(vid) }`
|
|
|
|
|
|
- If `vid` is true: jump to k_exit (break)
|
|
|
|
|
|
- If `vid` is false: fall through to Call(loop_step)
|
|
|
|
|
|
|
|
|
|
|
|
### Implementation Steps (Complete ✅)
|
|
|
|
|
|
|
|
|
|
|
|
#### Step 1-2: Pattern Detection + Routing
|
|
|
|
|
|
- Extract loop(true) + if + break pattern
|
|
|
|
|
|
- Validate loop condition = Bool(true) literal
|
|
|
|
|
|
- Validate if body = single Break statement
|
|
|
|
|
|
- Add module declaration and routing in builder.rs
|
|
|
|
|
|
|
|
|
|
|
|
#### Step 3: Condition Lowering Integration
|
|
|
|
|
|
- Validate condition with NormalizedExprLowererBox
|
|
|
|
|
|
- Use ExprLoweringScope::PureOnly
|
|
|
|
|
|
- Return Ok(None) for impure conditions (graceful fallback)
|
|
|
|
|
|
|
|
|
|
|
|
#### Step 4: Branch Instruction Emission
|
|
|
|
|
|
- Allocate 6 JoinFuncIds (stable IDs 0-5)
|
|
|
|
|
|
- Build env parameter passing (deterministic BTreeMap)
|
|
|
|
|
|
- Emit Jump instruction in loop_cond_check
|
|
|
|
|
|
- Create Call fallthrough for loop_step
|
|
|
|
|
|
|
|
|
|
|
|
#### Step 5: Exit Action Discrimination
|
|
|
|
|
|
- Complete k_exit() function
|
|
|
|
|
|
- Build exit values from env_layout.writes
|
|
|
|
|
|
- Extract final ValueIds from environment
|
|
|
|
|
|
|
|
|
|
|
|
#### Step 6: ExitMeta Construction
|
|
|
|
|
|
- Create ExitMeta::multiple() from exit values
|
|
|
|
|
|
- Use JoinFragmentMeta::carrier_only()
|
|
|
|
|
|
- Return Ok(Some((module, meta)))
|
|
|
|
|
|
|
|
|
|
|
|
#### Step 7: Routing Integration
|
|
|
|
|
|
- Already integrated in builder.rs (Step 1)
|
|
|
|
|
|
- Phase 131 (simpler) → Phase 143 (conditional) priority
|
|
|
|
|
|
|
|
|
|
|
|
#### Step 8: Fixtures + Smoke Tests
|
|
|
|
|
|
**Fixture**: `apps/tests/phase143_loop_true_if_break_min.hako`
|
2025-12-19 05:28:49 +09:00
|
|
|
|
|
2025-12-19 06:03:09 +09:00
|
|
|
|
**Tests**:
|
|
|
|
|
|
- `tools/smokes/v2/profiles/integration/apps/phase143_loop_true_if_break_vm.sh`
|
|
|
|
|
|
- `tools/smokes/v2/profiles/integration/apps/phase143_loop_true_if_break_llvm_exe.sh`
|
2025-12-19 05:28:49 +09:00
|
|
|
|
|
2025-12-19 08:36:45 +09:00
|
|
|
|
Expected exit code: 7
|
2025-12-19 05:28:49 +09:00
|
|
|
|
|
2025-12-19 06:03:09 +09:00
|
|
|
|
#### Step 9: Documentation (THIS FILE)
|
2025-12-19 05:28:49 +09:00
|
|
|
|
|
2025-12-19 06:03:09 +09:00
|
|
|
|
### Acceptance Criteria (All Met ✅)
|
2025-12-19 05:28:49 +09:00
|
|
|
|
|
2025-12-19 06:03:09 +09:00
|
|
|
|
- [x] Pattern detection correctly identifies `loop(true) { if(cond) break }`
|
|
|
|
|
|
- [x] Condition lowering validates pure scope
|
|
|
|
|
|
- [x] Out-of-scope patterns always return `Ok(None)`
|
|
|
|
|
|
- [x] JoinModule built with 6 functions
|
|
|
|
|
|
- [x] Jump instruction with conditional emission
|
|
|
|
|
|
- [x] k_exit returns exit values
|
|
|
|
|
|
- [x] ExitMeta constructed correctly
|
|
|
|
|
|
- [x] Fixture executes correctly (VM)
|
|
|
|
|
|
- [x] LLVM EXE parity test ready
|
|
|
|
|
|
- [x] No regressions in Phase 131-142
|
|
|
|
|
|
- [x] cargo check passes (no errors)
|
|
|
|
|
|
- [x] All commits created
|
2025-12-19 05:28:49 +09:00
|
|
|
|
|
2025-12-19 06:03:09 +09:00
|
|
|
|
### Verification Results
|
2025-12-19 05:28:49 +09:00
|
|
|
|
|
2025-12-19 06:03:09 +09:00
|
|
|
|
**Compilation**: `cargo check -p nyash-rust --lib` ✅ (0 errors)
|
2025-12-19 05:28:49 +09:00
|
|
|
|
|
2025-12-19 06:03:09 +09:00
|
|
|
|
**Commits**:
|
|
|
|
|
|
1. `f55f6cc65` - Step 3: Condition lowering integration
|
|
|
|
|
|
2. `434c891a1` - Step 4: Branch instruction emission
|
|
|
|
|
|
3. `d1d59dc82` - Steps 5-6: Exit handling + ExitMeta
|
|
|
|
|
|
4. `e28d59101` - Step 8: Fixtures + Smoke tests
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-19 08:36:45 +09:00
|
|
|
|
## P1: Continue Vocabulary (COMPLETE ✅)
|
|
|
|
|
|
|
|
|
|
|
|
### Summary
|
|
|
|
|
|
|
|
|
|
|
|
`loop(true) { if(cond_pure) continue }` を語彙として受理し、Normalized shadow 経路で「コンパイル/実行が落ちない」ことを固定する。
|
|
|
|
|
|
|
|
|
|
|
|
### Important note (P1 scope)
|
|
|
|
|
|
|
|
|
|
|
|
P1 の fixture は **意図的に non-terminating**(break/else/state update を含まない)である。
|
|
|
|
|
|
|
|
|
|
|
|
- 条件式は `ExprLoweringScope::PureOnly` で lowering できることを検証する(スコープ境界の固定)。
|
|
|
|
|
|
- ただし P1 では continue を「条件分岐で skip する」語彙までに留め、bridge 側の Jump(early-return) と混線させないため、
|
|
|
|
|
|
実際の JoinIR emission は `loop_step` への tail call を基本にする。
|
|
|
|
|
|
|
|
|
|
|
|
### Fixture / smokes
|
|
|
|
|
|
|
|
|
|
|
|
- Fixture: `apps/tests/phase143_loop_true_if_continue_min.hako`
|
|
|
|
|
|
- VM smoke (timeout contract):
|
|
|
|
|
|
- `tools/smokes/v2/profiles/integration/apps/phase143_loop_true_if_continue_vm.sh`
|
|
|
|
|
|
- Contract: `HAKO_VM_MAX_STEPS=0` + `timeout ${SMOKES_P143_CONTINUE_TIMEOUT_SECS:-1}` → exit code `124`
|
|
|
|
|
|
- LLVM EXE smoke (timeout contract):
|
|
|
|
|
|
- `tools/smokes/v2/profiles/integration/apps/phase143_loop_true_if_continue_llvm_exe.sh`
|
|
|
|
|
|
- Contract: `RUN_TIMEOUT_SECS=${SMOKES_P143_CONTINUE_TIMEOUT_SECS:-1}` → exit code `124`
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-19 06:03:09 +09:00
|
|
|
|
## Design Principles
|
|
|
|
|
|
|
|
|
|
|
|
### Out-of-Scope Handling
|
|
|
|
|
|
|
|
|
|
|
|
All out-of-scope patterns return `Ok(None)` for graceful fallback to legacy routing.
|
|
|
|
|
|
|
|
|
|
|
|
### Fail-Fast Policy
|
|
|
|
|
|
|
|
|
|
|
|
- **Out-of-scope**: Always `Ok(None)` (no change to existing behavior)
|
|
|
|
|
|
- **In-scope errors**: Return `Err(msg)` (internal errors, strict mode freeze)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Files
|
|
|
|
|
|
|
|
|
|
|
|
### Core Implementation
|
|
|
|
|
|
|
|
|
|
|
|
1. **src/mir/control_tree/normalized_shadow/loop_true_if_break_continue.rs** (~400 lines)
|
|
|
|
|
|
|
|
|
|
|
|
### Fixtures + Tests
|
|
|
|
|
|
|
|
|
|
|
|
2. **apps/tests/phase143_loop_true_if_break_min.hako**
|
|
|
|
|
|
3. **tools/smokes/v2/profiles/integration/apps/phase143_loop_true_if_break_vm.sh**
|
|
|
|
|
|
4. **tools/smokes/v2/profiles/integration/apps/phase143_loop_true_if_break_llvm_exe.sh**
|
|
|
|
|
|
|
|
|
|
|
|
---
|
2025-12-19 05:28:49 +09:00
|
|
|
|
|
2025-12-19 06:03:09 +09:00
|
|
|
|
## Related Documentation
|
2025-12-19 05:28:49 +09:00
|
|
|
|
|
2025-12-19 06:03:09 +09:00
|
|
|
|
- [Phase 131 (loop break-once)](../phase-131/README.md)
|
|
|
|
|
|
- [Phase 142 (statement-level normalization)](../phase-142-loopstmt/README.md)
|
|
|
|
|
|
- [JoinIR architecture](../../joinir-architecture-overview.md)
|
2025-12-19 05:28:49 +09:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-19 06:03:09 +09:00
|
|
|
|
## Commits
|
2025-12-19 05:28:49 +09:00
|
|
|
|
|
2025-12-19 06:03:09 +09:00
|
|
|
|
1. `f55f6cc65` - feat(phase143): Step 3 - Condition lowering integration
|
|
|
|
|
|
2. `434c891a1` - feat(phase143): Step 4 - Branch instruction emission
|
|
|
|
|
|
3. `d1d59dc82` - feat(phase143): Steps 5-6 - Exit handling + ExitMeta
|
|
|
|
|
|
4. `e28d59101` - feat(phase143): Step 8 - Fixtures + Smoke tests
|