feat(joinir): S-5.2完了 - BoxCall → VM method_router 経由実装
実装内容:
- box_to_join_value() ヘルパー関数追加(VM Box → JoinValue 変換)
- StringBox.length/substring を VM 実装経由で呼び出し(hardcoded削除)
- safe_substring() 削除(不要になった)
技術的成果:
- ガードレール設計実現: 制御フローは JoinIR Runner、Box実装は VM に委譲
- VM 2号機 回避: Box実装の重複なし
- テスト全 PASS: joinir_runner_standalone_skip_ws/trim 両方成功
Phase 27-shortterm S-5.2 完了 ✅
This commit is contained in:
@ -138,6 +138,9 @@ fn eval_compute(inst: &MirLikeInst, locals: &mut HashMap<VarId, JoinValue>) -> 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<VarId, JoinValue>) -> 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<VarId, JoinValue>) -> 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<VarId, JoinValue>) -> R
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn safe_substring(s: &str, start: i64, end: i64) -> Result<String, JoinRuntimeError> {
|
||||
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<VarId, JoinValue>, var: VarId) -> Result<JoinValue, JoinRuntimeError> {
|
||||
locals
|
||||
.get(&var)
|
||||
@ -243,3 +240,25 @@ fn expect_str(value: &JoinValue) -> Result<String, JoinRuntimeError> {
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
/// S-5.2: Convert Box<dyn NyashBox> 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<dyn crate::box_trait::NyashBox>) -> Result<JoinValue, JoinRuntimeError> {
|
||||
use std::sync::Arc;
|
||||
|
||||
// Try to downcast to known primitive types first
|
||||
if let Some(int_box) = nyash_box.as_any().downcast_ref::<crate::boxes::basic::IntegerBox>() {
|
||||
return Ok(JoinValue::Int(int_box.value));
|
||||
}
|
||||
if let Some(bool_box) = nyash_box.as_any().downcast_ref::<crate::boxes::basic::BoolBox>() {
|
||||
return Ok(JoinValue::Bool(bool_box.value));
|
||||
}
|
||||
if let Some(str_box) = nyash_box.as_any().downcast_ref::<crate::boxes::basic::StringBox>() {
|
||||
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)))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user