feat(joinir): S-5.2-improved - VM完全意味論統合完了

Phase 27-shortterm S-5.2-improved 実装完了:

## 実装内容
1. **execute_box_call() ラッパー追加**:
   - src/backend/mir_interpreter/mod.rs に公開 API 実装
   - 1_000_000 番台レジスタで一時値管理
   - 適切なクリーンアップ処理実装

2. **handle_box_call 可視性変更**:
   - src/backend/mir_interpreter/handlers/boxes.rs を pub に変更
   - JoinIR Runner からアクセス可能に

3. **JoinIR Runner BoxCall 統合**:
   - src/mir/join_ir_runner.rs の BoxCall 処理を書き換え
   - StringBox 直接呼び出し削除
   - VM の execute_box_call 経由に変更
   - JoinValue ↔ VMValue 変換で統合

4. **不要な関数削除**:
   - expect_str(), expect_int(), box_to_join_value() 削除
   - VMValue 変換に一本化

5. **テスト更新**:
   - joinir_runner_standalone.rs: VM インスタンス追加
   - joinir_runner_min.rs: VM 再利用

## 期待される効果
 Void guards 完全対応 (Void.length() → 0)
 PluginBox/InstanceBox 将来対応可能
 VM の完全な BoxCall 意味論統一
 VM 2号機回避(ガードレール設計成功)

## テスト結果
 joinir_runner_standalone_skip_ws ... ok
 joinir_runner_standalone_trim ... ok
 ビルド成功(0エラー)

## 完了タスク
- [x] MirInterpreter::execute_box_call() 実装
- [x] 1_000_000 レジスタ帯域割り当て
- [x] regs クリーンアップ実装
- [x] JoinIR Runner BoxCall 書き換え
- [x] テスト更新&PASS確認

🎉 VM 完全意味論統合完了!
This commit is contained in:
nyash-codex
2025-11-24 08:37:59 +09:00
parent a8555e67d5
commit 98dadf446f
6 changed files with 129 additions and 91 deletions

View File

@ -79,6 +79,71 @@ impl MirInterpreter {
self.static_box_decls.insert(name, decl);
}
/// Execute a BoxCall with VM's complete semantics (Phase 27-shortterm S-5.2-improved)
///
/// This wrapper allows external modules (e.g., JoinIR Runner) to invoke BoxCall
/// with the VM's complete semantics including:
/// - Void guards (e.g., Void.length() → 0)
/// - PluginBox support (FileBox, NetBox, etc.)
/// - InstanceBox policy checks
/// - object_fields handling
/// - Method re-routing (toString→str)
///
/// # Implementation Notes
/// - Uses 1_000_000 register range for scratch registers (避ける ID 衝突)
/// - Properly cleans up temporary registers after use
/// - Delegates to `handle_box_call` for complete VM semantics
///
/// # Arguments
/// - `receiver`: The box instance (VMValue::BoxRef or primitive)
/// - `method`: Method name to invoke
/// - `args`: Method arguments as VMValue
///
/// # Returns
/// Result value as VMValue (may be Void, Int, String, BoxRef, etc.)
pub fn execute_box_call(
&mut self,
receiver: VMValue,
method: &str,
args: Vec<VMValue>,
) -> Result<VMValue, VMError> {
// Allocate temporary register IDs in the 1_000_000 range (not 1000!)
// This avoids conflicts with user code and future extensions
let base = ValueId(1_000_000);
let recv_id = base;
// Place receiver in register
self.regs.insert(recv_id, receiver);
// Place arguments in consecutive registers
let arg_ids: Vec<ValueId> = args
.into_iter()
.enumerate()
.map(|(i, v)| {
let id = ValueId(base.0 + 1 + i as u32);
self.regs.insert(id, v);
id
})
.collect();
// Allocate destination register
let dst_id = ValueId(base.0 + 1000);
// Invoke handle_box_call for complete VM semantics
self.handle_box_call(Some(dst_id), recv_id, method, &arg_ids)?;
// Read result (may be Void if method returns nothing)
let result = self.regs.remove(&dst_id).unwrap_or(VMValue::Void);
// Cleanup temporary registers (important to avoid stale values!)
self.regs.remove(&recv_id);
for id in arg_ids {
self.regs.remove(&id);
}
Ok(result)
}
/// Ensure static box singleton instance exists, create if not
/// Returns mutable reference to the singleton instance
fn ensure_static_box_instance(