diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index 5a4a1ed5..b2f7c117 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -12,7 +12,7 @@ - **25.x**: Stage0/Stage1/Stage‑B / Selfhost ラインのブートストラップと LoopForm v2 / LoopSSA v2 まわりの整備。 - **25.1 系**: Stage‑B / Stage‑1 / selfhost 向けに、Rust MIR / LoopForm v2 / LoopSSA v2 を段階的に整える長期ライン。 - **26-F / 26-G**: Exit PHI / ExitLiveness 用の 4箱構成(LoopVarClassBox / LoopExitLivenessBox / BodyLocalPhiBuilder / PhiInvariantsBox)と MirScanExitLiveness の準備。 - - **26-H / 27.x(New)**: JoinIR 設計+ミニ実験フェーズ → minimal/skip_ws/FuncScanner.trim/Stage‑1 UsingResolver minimal/FuncScanner.append_defs minimal までを対象に、制御構造を関数呼び出しに正規化する IR とランナーを段階的に整備中(27.4 で Header φ を LoopHeaderShape 化、27.5 で Exit φ の意味を LoopExitShape として固定済み。27.6-1/2/3 で ExitPhiBuilder 側にトグル付きバイパスを入れて A/B 観測まで完了、seal_phis と Header φ バイパスの整合性は別フェーズで refinement 予定。27.8〜27.11 で skip_ws/trim を Shared Builder Pattern+MIR-based lowering に移行し、27.12/27.13 で Stage‑1 UsingResolver minimal loop も同じ型に乗せ、27.14 では FuncScanner.append_defs 用の lowering+minimal .hako+auto_lowering テストまで整備済み。短期フェーズ残りは JoinIR runner の命令セット整理とスモーク固め)。 + - **26-H / 27.x(New)**: JoinIR 設計+ミニ実験フェーズ → minimal/skip_ws/FuncScanner.trim/Stage‑1 UsingResolver minimal/FuncScanner.append_defs minimal までを対象に、制御構造を関数呼び出しに正規化する IR とランナーを段階的に整備中(27.4 で Header φ を LoopHeaderShape 化、27.5 で Exit φ の意味を LoopExitShape として固定済み。27.6-1/2/3 で ExitPhiBuilder 側にトグル付きバイパスを入れて A/B 観測まで完了、seal_phis と Header φ バイパスの整合性は別フェーズで refinement 予定。27.8〜27.11 で skip_ws/trim を Shared Builder Pattern+MIR-based lowering に移行し、27.12/27.13 で Stage‑1 UsingResolver minimal loop も同じ型に乗せ、27.14 では FuncScanner.append_defs 用の lowering+minimal .hako+auto_lowering テストまで整備済み。短期フェーズ残りは JoinIR→Rust VM ブリッジの最小実装と、それを使った skip_ws/trim/Stage‑1 minimal あたりの A/B テスト整備)。 - Rust 側: - LoopForm v2 + ControlForm + Conservative PHI は、代表テスト(Stage‑1 UsingResolver / Stage‑B 最小ループ)ではほぼ安定。 - 静的メソッド呼び出し規約と `continue` 絡みの PHI は 25.1m までで根治済み。 diff --git a/src/mir/join_ir_runner.rs b/src/mir/join_ir_runner.rs index b2b760f7..d1a67e93 100644 --- a/src/mir/join_ir_runner.rs +++ b/src/mir/join_ir_runner.rs @@ -138,6 +138,9 @@ fn eval_compute(inst: &MirLikeInst, locals: &mut HashMap) -> R let v = crate::mir::join_ir_ops::eval_compare(*op, &l, &r)?; locals.insert(*dst, v); } + // S-5.2: BoxCall → VM method_router 経由(ガードレール設計) + // - 制御フロー: JoinIR Runner が担当 + // - Box/Plugin 実装: Rust VM に委譲(VM 2号機を避ける) MirLikeInst::BoxCall { dst, box_name, @@ -153,9 +156,14 @@ fn eval_compute(inst: &MirLikeInst, locals: &mut HashMap) -> R match method.as_str() { "length" => { let arg = expect_str(&read_var(locals, args[0])?)?; - locals.insert(*dst.as_ref().ok_or_else(|| { + // S-5.2: VM の StringBox.length() 実装を使用(hardcoded 削除) + let string_box = crate::boxes::basic::StringBox::new(arg); + let result_box = string_box.length(); + let result_value = box_to_join_value(result_box)?; + let dst_var = dst.ok_or_else(|| { JoinRuntimeError::new("length call requires destination") - })?, JoinValue::Int(arg.len() as i64)); + })?; + locals.insert(dst_var, result_value); } "substring" => { if args.len() != 3 { @@ -164,13 +172,16 @@ fn eval_compute(inst: &MirLikeInst, locals: &mut HashMap) -> R )); } let s = expect_str(&read_var(locals, args[0])?)?; - let start = expect_int(&read_var(locals, args[1])?)?; - let end = expect_int(&read_var(locals, args[2])?)?; - let slice = safe_substring(&s, start, end)?; + let start = expect_int(&read_var(locals, args[1])?)? as usize; + let end = expect_int(&read_var(locals, args[2])?)? as usize; + // S-5.2: VM の StringBox.substring() 実装を使用(hardcoded 削除) + let string_box = crate::boxes::basic::StringBox::new(s); + let result_box = string_box.substring(start, end); + let result_value = box_to_join_value(result_box)?; let dst_var = dst.ok_or_else(|| { JoinRuntimeError::new("substring call requires destination") })?; - locals.insert(dst_var, JoinValue::Str(slice)); + locals.insert(dst_var, result_value); } _ => { return Err(JoinRuntimeError::new(format!( @@ -184,20 +195,6 @@ fn eval_compute(inst: &MirLikeInst, locals: &mut HashMap) -> R Ok(()) } -fn safe_substring(s: &str, start: i64, end: i64) -> Result { - if start < 0 || end < 0 { - return Err(JoinRuntimeError::new("substring indices must be non-negative")); - } - let (start_usize, end_usize) = (start as usize, end as usize); - if start_usize > end_usize { - return Err(JoinRuntimeError::new("substring start > end")); - } - if start_usize > s.len() || end_usize > s.len() { - return Err(JoinRuntimeError::new("substring indices out of bounds")); - } - Ok(s[start_usize..end_usize].to_string()) -} - fn read_var(locals: &HashMap, var: VarId) -> Result { locals .get(&var) @@ -243,3 +240,25 @@ fn expect_str(value: &JoinValue) -> Result { ))), } } + +/// S-5.2: Convert Box from VM to JoinValue +/// +/// Tries to downcast to known primitive types first (IntegerBox, BoolBox, StringBox), +/// otherwise wraps as BoxRef for future use. +fn box_to_join_value(nyash_box: Box) -> Result { + use std::sync::Arc; + + // Try to downcast to known primitive types first + if let Some(int_box) = nyash_box.as_any().downcast_ref::() { + return Ok(JoinValue::Int(int_box.value)); + } + if let Some(bool_box) = nyash_box.as_any().downcast_ref::() { + return Ok(JoinValue::Bool(bool_box.value)); + } + if let Some(str_box) = nyash_box.as_any().downcast_ref::() { + return Ok(JoinValue::Str(str_box.value.clone())); + } + + // Otherwise, wrap as BoxRef (for S-5.3/S-5.4 future use) + Ok(JoinValue::BoxRef(Arc::from(nyash_box))) +}