feat(joinir): Phase 34-7.5 helpers + Phase 34-8 Break/Continue implementation
Phase 34-7.5: Code organization improvements
- Added type conversion helpers (as_cont/as_func) in join_ir/mod.rs
- Enhanced docstrings for JoinCall/JoinJump with usage examples
- Improved error messages in join_ir_vm_bridge.rs
JoinIrFrontendTestRunner box implementation
- Created src/tests/helpers/joinir_frontend.rs (119 lines)
- Reduced test code by 83% (70 lines → 12 lines per test)
- 26% overall reduction in test file (284 → 209 lines)
Phase 34-8: Break/Continue pattern implementation
- Extended ast_lowerer.rs (+630 lines)
- lower_loop_break_pattern(): Break as Jump (early return)
- lower_loop_continue_pattern(): Continue as Select + Call
- Added Bool literal support in extract_value()
- Created 2 fixtures: loop_frontend_{break,continue}.program.json
- Added 2 A/B tests (all 6 Phase 34 tests PASS)
Technical achievements:
- Break = Jump (early return pattern)
- Continue = Select + Call (NOT Jump) - critical discovery
- 3-function structure sufficient (no k_continue needed)
- SSA-style re-assignment with natural var_map updates
Test results:
✅ joinir_frontend_if_select_simple_ab_test
✅ joinir_frontend_if_select_local_ab_test
✅ joinir_frontend_json_shape_read_value_ab_test
✅ joinir_frontend_loop_simple_ab_test
✅ joinir_frontend_loop_break_ab_test
✅ joinir_frontend_loop_continue_ab_test
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -52,6 +52,23 @@ impl JoinFuncId {
|
||||
pub fn new(id: u32) -> Self {
|
||||
JoinFuncId(id)
|
||||
}
|
||||
|
||||
/// JoinFuncId を JoinContId に変換
|
||||
///
|
||||
/// # Use Case
|
||||
/// Jump 命令で関数を continuation として使う場合
|
||||
/// ```rust
|
||||
/// let func_id = JoinFuncId(42);
|
||||
/// let cont_id = func_id.as_cont();
|
||||
/// Jump { cont: cont_id, args: vec![], cond: None }
|
||||
/// ```
|
||||
///
|
||||
/// # Phase 34-7 Note
|
||||
/// JoinFuncId と JoinContId は別の newtype だが、内部的には同じ u32 ID を共有する。
|
||||
/// この変換は型レベルでの役割の明示(関数 vs 継続)を可能にする。
|
||||
pub fn as_cont(self) -> JoinContId {
|
||||
JoinContId(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// 継続(join / ループ step / exit continuation)を識別するID
|
||||
@ -62,6 +79,21 @@ impl JoinContId {
|
||||
pub fn new(id: u32) -> Self {
|
||||
JoinContId(id)
|
||||
}
|
||||
|
||||
/// JoinContId を JoinFuncId に変換
|
||||
///
|
||||
/// # Use Case
|
||||
/// 継続 ID を関数 ID として参照する場合(JoinModule の functions map でルックアップ時など)
|
||||
/// ```rust
|
||||
/// let cont_id = JoinContId(42);
|
||||
/// let func = join_module.functions.get(&cont_id.as_func())?;
|
||||
/// ```
|
||||
///
|
||||
/// # Phase 34-7 Note
|
||||
/// JoinIR では継続も関数として実装されるため、この変換が必要になる。
|
||||
pub fn as_func(self) -> JoinFuncId {
|
||||
JoinFuncId(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// 変数ID(Phase 26-H では MIR の ValueId を再利用)
|
||||
@ -179,7 +211,31 @@ pub struct MergePair {
|
||||
/// JoinIR 命令セット(最小版)
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum JoinInst {
|
||||
/// 通常の関数呼び出し: f(args..., k_next)
|
||||
/// 通常の関数呼び出し(末尾再帰): f(args..., k_next)
|
||||
///
|
||||
/// # Semantics
|
||||
/// - 他の JoinIR 関数を呼び出す(MIR の Call に変換)
|
||||
/// - ループでは末尾再帰として使うのが典型的
|
||||
///
|
||||
/// # MIR 変換
|
||||
/// - `MirInstruction::Call { func, args, ... }` を生成
|
||||
///
|
||||
/// # Constraints (Phase 31/34 時点)
|
||||
/// - **k_next は常に None にすること!**
|
||||
/// JoinIR→MIR bridge が `k_next: Some(...)` 未対応
|
||||
/// → エラー: "Call with k_next is not yet supported"
|
||||
/// - 典型的な使い方: `Call { func, args, k_next: None, dst: Some(...) }`
|
||||
///
|
||||
/// # Loop Pattern での使い方 (Phase 34-7)
|
||||
/// ```rust
|
||||
/// // ✅ 正解: 末尾再帰
|
||||
/// Call {
|
||||
/// func: loop_step_id,
|
||||
/// args: vec![i_next, acc_next, n],
|
||||
/// k_next: None, // ⚠️ 必須: None にすること
|
||||
/// dst: Some(result),
|
||||
/// }
|
||||
/// ```
|
||||
Call {
|
||||
func: JoinFuncId,
|
||||
args: Vec<VarId>,
|
||||
@ -188,7 +244,46 @@ pub enum JoinInst {
|
||||
dst: Option<VarId>,
|
||||
},
|
||||
|
||||
/// 継続呼び出し(join / exit 継続など)
|
||||
/// 継続呼び出し(早期 return / exit 継続)
|
||||
///
|
||||
/// # Semantics
|
||||
/// - **「早期 return」(条件付き関数脱出)として使う!**
|
||||
/// - cond=Some(v): v が true なら cont に Jump、false なら次の命令へ
|
||||
/// - cond=None: 無条件 Jump
|
||||
///
|
||||
/// # MIR 変換
|
||||
/// - cond=Some(v): `Branch(v, exit_block[Return], continue_block)` を生成
|
||||
/// - exit_block: cont 関数を Call して Return
|
||||
/// - continue_block: 次の JoinInst に続く
|
||||
/// - cond=None: 無条件に cont を Call して Return
|
||||
///
|
||||
/// # Loop Pattern での使い方 (Phase 34-7)
|
||||
/// ```rust
|
||||
/// // ✅ 正解: 条件付き早期 return
|
||||
/// Jump {
|
||||
/// cont: k_exit_id.as_cont(),
|
||||
/// args: vec![acc],
|
||||
/// cond: Some(exit_cond), // exit_cond が true なら k_exit へ
|
||||
/// }
|
||||
/// // ↑ exit_cond が false なら次の命令(body 処理)へ進む
|
||||
///
|
||||
/// // ❌ 間違い: Call で条件分岐しようとする
|
||||
/// Call {
|
||||
/// func: k_exit_id,
|
||||
/// cond: Some(exit_cond), // こんなフィールドはない!
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # 典型的なパターン
|
||||
/// ```text
|
||||
/// loop_step(i, acc, n):
|
||||
/// exit_cond = !(i < n)
|
||||
/// Jump(k_exit, [acc], cond=exit_cond) // 🔑 早期 return
|
||||
/// // ↓ Jump で抜けなかった場合のみ実行
|
||||
/// acc_next = acc + 1
|
||||
/// i_next = i + 1
|
||||
/// Call(loop_step, [i_next, acc_next, n]) // 🔑 末尾再帰
|
||||
/// ```
|
||||
Jump {
|
||||
cont: JoinContId,
|
||||
args: Vec<VarId>,
|
||||
|
||||
Reference in New Issue
Block a user