feat: Enhance VM execution capabilities and fix comparison/string operations

- Add Void/Bool comparison support (Eq/Ne only) to prevent VM crashes
- Implement BoolBox→bool coercion in as_bool() for branch conditions
- Add VoidBox→false coercion for nullish false behavior
- Support String+BoxRef concatenation with automatic toString()
- Add PluginBoxV2 toString() support for debugging
- Add legacy ResultBox method support for compatibility

This fixes VM execution errors with plugin methods returning Result types
and enables proper string concatenation with plugin boxes.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Moe Charm
2025-08-23 18:12:33 +09:00
parent 70af0fe566
commit 7c018104a0

View File

@ -122,6 +122,18 @@ impl VMValue {
match self {
VMValue::Bool(b) => Ok(*b),
VMValue::Integer(i) => Ok(*i != 0),
// Pragmatic coercions for dynamic boxes
VMValue::BoxRef(b) => {
// BoolBox → bool
if let Some(bb) = b.as_any().downcast_ref::<BoolBox>() {
return Ok(bb.value);
}
// VoidBox → false (nullish false)
if b.as_any().downcast_ref::<VoidBox>().is_some() {
return Ok(false);
}
Err(VMError::TypeError(format!("Expected bool, got BoxRef({})", b.type_name())))
}
_ => Err(VMError::TypeError(format!("Expected bool, got {:?}", self))),
}
}
@ -959,6 +971,22 @@ impl VM {
}
},
// String + BoxRef concatenation
(VMValue::String(l), VMValue::BoxRef(r)) => {
match op {
BinaryOp::Add => Ok(VMValue::String(format!("{}{}", l, r.to_string_box().value))),
_ => Err(VMError::TypeError("String-BoxRef operations only support addition".to_string())),
}
},
// BoxRef + String concatenation
(VMValue::BoxRef(l), VMValue::String(r)) => {
match op {
BinaryOp::Add => Ok(VMValue::String(format!("{}{}", l.to_string_box().value, r))),
_ => Err(VMError::TypeError("BoxRef-String operations only support addition".to_string())),
}
},
_ => Err(VMError::TypeError(format!("Unsupported binary operation: {:?} on {:?} and {:?}", op, left, right))),
}
}
@ -975,6 +1003,34 @@ impl VM {
/// Execute comparison operation
fn execute_compare_op(&self, op: &CompareOp, left: &VMValue, right: &VMValue) -> Result<bool, VMError> {
match (left, right) {
// Bool comparisons: support Eq/Ne only for now
(VMValue::Bool(l), VMValue::Bool(r)) => {
let result = match op {
CompareOp::Eq => l == r,
CompareOp::Ne => l != r,
_ => return Err(VMError::TypeError(format!("Unsupported boolean comparison: {:?}", op))),
};
Ok(result)
},
// Void comparisons: only Eq/Ne are defined
(VMValue::Void, VMValue::Void) => {
let result = match op {
CompareOp::Eq => true,
CompareOp::Ne => false,
_ => return Err(VMError::TypeError("Cannot order Void".to_string())),
};
Ok(result)
},
(VMValue::Void, _) | (_, VMValue::Void) => {
let result = match op {
CompareOp::Eq => false, // void == X (X != void) is false
CompareOp::Ne => true, // void != X is true
_ => return Err(VMError::TypeError("Cannot order Void".to_string())),
};
Ok(result)
},
(VMValue::Integer(l), VMValue::Integer(r)) => {
let result = match op {
CompareOp::Eq => l == r,
@ -1099,7 +1155,7 @@ impl VM {
// For now, implement basic methods for common box types
// This is a simplified version - real implementation would need full method dispatch
// ResultBox (NyashResultBox) methods
// ResultBox (NyashResultBox - new)
if let Some(result_box) = box_value.as_any().downcast_ref::<crate::boxes::result::NyashResultBox>() {
match method {
// Rust側の公開APIメソッド名に合わせたバリアントを許容
@ -1116,6 +1172,22 @@ impl VM {
}
}
// ResultBox (box_trait::ResultBox - legacy)
if let Some(result_box_legacy) = box_value.as_any().downcast_ref::<crate::box_trait::ResultBox>() {
match method {
"is_ok" | "isOk" => {
return Ok(result_box_legacy.is_ok());
}
"get_value" | "getValue" => {
return Ok(result_box_legacy.get_value());
}
"get_error" | "getError" => {
return Ok(result_box_legacy.get_error());
}
_ => return Ok(Box::new(VoidBox::new())),
}
}
// Generic fallback: toString for any Box type
if method == "toString" {
return Ok(Box::new(StringBox::new(box_value.to_string_box().value)));
@ -1230,6 +1302,19 @@ impl VM {
}
}
// PluginBoxV2 support
if let Some(plugin_box) = box_value.as_any().downcast_ref::<crate::runtime::plugin_loader_v2::PluginBoxV2>() {
// For toString on plugins, return a descriptive string
if method == "toString" {
return Ok(Box::new(StringBox::new(format!("{}(id={})", plugin_box.box_type, plugin_box.inner.instance_id))));
}
// Other plugin methods should be called via BoxCall instruction
// This path shouldn't normally be reached for plugin methods
eprintln!("Warning: Plugin method '{}' called via call_box_method - should use BoxCall", method);
return Ok(Box::new(VoidBox::new()));
}
// Default: return void for any unrecognized box type or method
Ok(Box::new(VoidBox::new()))
}