Phase 5: Complete destination pattern unification (28 sites, 53 lines)
Unified remaining destination write patterns with new helpers: - write_string() for VMValue::String writes - write_from_box() for VMValue::from_nyash_box() patterns Files updated: - boxes.rs: 8 sites unified (-14 lines) - boxes_plugin.rs: 9 sites unified (-17 lines) - boxes_object_fields.rs: 7 sites unified (-14 lines) - boxes_instance.rs: 2 sites unified (-4 lines) - calls.rs: 2 sites unified (-4 lines) - destination_helpers.rs: +28 lines (new helpers) Impact: 28 sites unified, net -25 lines, improved maintainability Tests: Phase 21.0 PASS (2/2, 100%) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -62,14 +62,10 @@ impl MirInterpreter {
|
|||||||
}
|
}
|
||||||
match host.invoke_instance_method(&p.box_type, method, p.inner.instance_id, &argv) {
|
match host.invoke_instance_method(&p.box_type, method, p.inner.instance_id, &argv) {
|
||||||
Ok(Some(ret)) => {
|
Ok(Some(ret)) => {
|
||||||
if let Some(d) = dst {
|
self.write_from_box(dst, ret);
|
||||||
self.regs.insert(d, VMValue::from_nyash_box(ret));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
if let Some(d) = dst {
|
self.write_void(dst);
|
||||||
self.regs.insert(d, VMValue::Void);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Err(self.err_with_context(
|
return Err(self.err_with_context(
|
||||||
@ -80,10 +76,7 @@ impl MirInterpreter {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
} else if method == "toString" {
|
} else if method == "toString" {
|
||||||
if let Some(d) = dst {
|
self.write_string(dst, recv_box.to_string_box().value);
|
||||||
self.regs
|
|
||||||
.insert(d, VMValue::String(recv_box.to_string_box().value));
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(self.err_method_not_found(&recv_box.type_name(), method))
|
Err(self.err_method_not_found(&recv_box.type_name(), method))
|
||||||
@ -100,12 +93,12 @@ impl MirInterpreter {
|
|||||||
// Dev-safe: stringify(Void) → "null" (最小安全弁)
|
// Dev-safe: stringify(Void) → "null" (最小安全弁)
|
||||||
if method == "stringify" {
|
if method == "stringify" {
|
||||||
if let VMValue::Void = self.reg_load(box_val)? {
|
if let VMValue::Void = self.reg_load(box_val)? {
|
||||||
if let Some(d) = dst { self.regs.insert(d, VMValue::String("null".to_string())); }
|
self.write_string(dst, "null".to_string());
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if let VMValue::BoxRef(b) = self.reg_load(box_val)? {
|
if let VMValue::BoxRef(b) = self.reg_load(box_val)? {
|
||||||
if b.as_any().downcast_ref::<crate::box_trait::VoidBox>().is_some() {
|
if b.as_any().downcast_ref::<crate::box_trait::VoidBox>().is_some() {
|
||||||
if let Some(d) = dst { self.regs.insert(d, VMValue::String("null".to_string())); }
|
self.write_string(dst, "null".to_string());
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,14 +144,14 @@ impl MirInterpreter {
|
|||||||
match self.reg_load(box_val)? {
|
match self.reg_load(box_val)? {
|
||||||
VMValue::Void => {
|
VMValue::Void => {
|
||||||
if let Some(val) = super::boxes_void_guards::handle_void_method(method) {
|
if let Some(val) = super::boxes_void_guards::handle_void_method(method) {
|
||||||
if let Some(d) = dst { self.regs.insert(d, val); }
|
self.write_result(dst, val);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VMValue::BoxRef(ref b) => {
|
VMValue::BoxRef(ref b) => {
|
||||||
if b.as_any().downcast_ref::<crate::box_trait::VoidBox>().is_some() {
|
if b.as_any().downcast_ref::<crate::box_trait::VoidBox>().is_some() {
|
||||||
if let Some(val) = super::boxes_void_guards::handle_void_method(method) {
|
if let Some(val) = super::boxes_void_guards::handle_void_method(method) {
|
||||||
if let Some(d) = dst { self.regs.insert(d, val); }
|
self.write_result(dst, val);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -259,7 +252,7 @@ impl MirInterpreter {
|
|||||||
argv.push(recv_vm);
|
argv.push(recv_vm);
|
||||||
for a in args { argv.push(self.reg_load(*a)?); }
|
for a in args { argv.push(self.reg_load(*a)?); }
|
||||||
let ret = self.exec_function_inner(&func, Some(&argv))?;
|
let ret = self.exec_function_inner(&func, Some(&argv))?;
|
||||||
if let Some(d) = dst { self.regs.insert(d, ret); }
|
self.write_result(dst, ret);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -98,7 +98,7 @@ pub(super) fn try_handle_instance_box(
|
|||||||
argv.push(recv_vm.clone());
|
argv.push(recv_vm.clone());
|
||||||
for a in args { argv.push(this.reg_load(*a)?); }
|
for a in args { argv.push(this.reg_load(*a)?); }
|
||||||
let ret = this.exec_function_inner(&func, Some(&argv))?;
|
let ret = this.exec_function_inner(&func, Some(&argv))?;
|
||||||
if let Some(d) = dst { this.regs.insert(d, ret); }
|
this.write_result(dst, ret);
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
} else {
|
} else {
|
||||||
// Conservative fallback: search unique function by name tail ".method/arity"
|
// Conservative fallback: search unique function by name tail ".method/arity"
|
||||||
|
|||||||
@ -52,7 +52,7 @@ pub(super) fn try_handle_object_fields(
|
|||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let Some(d) = dst { this.regs.insert(d, VMValue::String("[map/bad-key] field name must be string".to_string())); }
|
this.write_string(dst, "[map/bad-key] field name must be string".to_string());
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,19 +113,17 @@ pub(super) fn try_handle_object_fields(
|
|||||||
if std::env::var("NYASH_VM_TRACE").ok().as_deref() == Some("1") {
|
if std::env::var("NYASH_VM_TRACE").ok().as_deref() == Some("1") {
|
||||||
eprintln!("[vm-trace] getField internal {}.{} -> {:?}", inst.class_name, fname, nv);
|
eprintln!("[vm-trace] getField internal {}.{} -> {:?}", inst.class_name, fname, nv);
|
||||||
}
|
}
|
||||||
if let Some(d) = dst {
|
// Special-case: NV::Box should surface as VMValue::BoxRef
|
||||||
// Special-case: NV::Box should surface as VMValue::BoxRef
|
if let crate::value::NyashValue::Box(ref arc_m) = nv {
|
||||||
if let crate::value::NyashValue::Box(ref arc_m) = nv {
|
if let Ok(guard) = arc_m.lock() {
|
||||||
if let Ok(guard) = arc_m.lock() {
|
let cloned: Box<dyn crate::box_trait::NyashBox> = guard.clone_box();
|
||||||
let cloned: Box<dyn crate::box_trait::NyashBox> = guard.clone_box();
|
let arc: std::sync::Arc<dyn crate::box_trait::NyashBox> = std::sync::Arc::from(cloned);
|
||||||
let arc: std::sync::Arc<dyn crate::box_trait::NyashBox> = std::sync::Arc::from(cloned);
|
this.write_result(dst, VMValue::BoxRef(arc));
|
||||||
this.regs.insert(d, VMValue::BoxRef(arc));
|
|
||||||
} else {
|
|
||||||
this.regs.insert(d, VMValue::Void);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
this.regs.insert(d, nv_to_vm(&nv));
|
this.write_void(dst);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
this.write_result(dst, nv_to_vm(&nv));
|
||||||
}
|
}
|
||||||
// Trace get
|
// Trace get
|
||||||
if MirInterpreter::box_trace_enabled() {
|
if MirInterpreter::box_trace_enabled() {
|
||||||
@ -157,7 +155,7 @@ pub(super) fn try_handle_object_fields(
|
|||||||
if std::env::var("NYASH_VM_TRACE").ok().as_deref() == Some("1") {
|
if std::env::var("NYASH_VM_TRACE").ok().as_deref() == Some("1") {
|
||||||
eprintln!("[vm-trace] getField default JsonScanner.{} -> {:?}", fname, v);
|
eprintln!("[vm-trace] getField default JsonScanner.{} -> {:?}", fname, v);
|
||||||
}
|
}
|
||||||
if let Some(d) = dst { this.regs.insert(d, v); }
|
this.write_result(dst, v);
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,7 +173,7 @@ pub(super) fn try_handle_object_fields(
|
|||||||
if std::env::var("NYASH_VM_TRACE").ok().as_deref() == Some("1") {
|
if std::env::var("NYASH_VM_TRACE").ok().as_deref() == Some("1") {
|
||||||
eprintln!("[vm-trace] getField default(JsonScanner missing) {} -> {:?}", fname, v);
|
eprintln!("[vm-trace] getField default(JsonScanner missing) {} -> {:?}", fname, v);
|
||||||
}
|
}
|
||||||
if let Some(d) = dst { this.regs.insert(d, v.clone()); }
|
this.write_result(dst, v.clone());
|
||||||
if MirInterpreter::box_trace_enabled() {
|
if MirInterpreter::box_trace_enabled() {
|
||||||
let kind = match &v {
|
let kind = match &v {
|
||||||
VMValue::Integer(_) => "Integer",
|
VMValue::Integer(_) => "Integer",
|
||||||
@ -194,7 +192,7 @@ pub(super) fn try_handle_object_fields(
|
|||||||
}
|
}
|
||||||
// Finally: legacy fields (SharedNyashBox) for complex values
|
// Finally: legacy fields (SharedNyashBox) for complex values
|
||||||
if let Some(shared) = inst.get_field(&fname) {
|
if let Some(shared) = inst.get_field(&fname) {
|
||||||
if let Some(d) = dst { this.regs.insert(d, VMValue::BoxRef(shared.clone())); }
|
this.write_result(dst, VMValue::BoxRef(shared.clone()));
|
||||||
if MirInterpreter::box_trace_enabled() {
|
if MirInterpreter::box_trace_enabled() {
|
||||||
this.box_trace_emit_get(&inst.class_name, &fname, "BoxRef");
|
this.box_trace_emit_get(&inst.class_name, &fname, "BoxRef");
|
||||||
}
|
}
|
||||||
@ -269,7 +267,7 @@ pub(super) fn try_handle_object_fields(
|
|||||||
eprintln!("[vm-trace] getField legacy {} -> {:?}", fname, v);
|
eprintln!("[vm-trace] getField legacy {} -> {:?}", fname, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(d) = dst { this.regs.insert(d, v.clone()); }
|
this.write_result(dst, v.clone());
|
||||||
if MirInterpreter::box_trace_enabled() {
|
if MirInterpreter::box_trace_enabled() {
|
||||||
let kind = match &v {
|
let kind = match &v {
|
||||||
VMValue::Integer(_) => "Integer",
|
VMValue::Integer(_) => "Integer",
|
||||||
@ -309,7 +307,7 @@ pub(super) fn try_handle_object_fields(
|
|||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let Some(d) = dst { this.regs.insert(d, VMValue::String("[map/bad-key] field name must be string".to_string())); }
|
this.write_string(dst, "[map/bad-key] field name must be string".to_string());
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,9 +36,7 @@ pub(super) fn invoke_plugin_box(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(d) = dst {
|
this.write_string(dst, s);
|
||||||
this.regs.insert(d, VMValue::String(s));
|
|
||||||
}
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let host = crate::runtime::plugin_loader_unified::get_global_plugin_host();
|
let host = crate::runtime::plugin_loader_unified::get_global_plugin_host();
|
||||||
@ -49,15 +47,11 @@ pub(super) fn invoke_plugin_box(
|
|||||||
}
|
}
|
||||||
match host.invoke_instance_method(&p.box_type, method, p.inner.instance_id, &argv) {
|
match host.invoke_instance_method(&p.box_type, method, p.inner.instance_id, &argv) {
|
||||||
Ok(Some(ret)) => {
|
Ok(Some(ret)) => {
|
||||||
if let Some(d) = dst {
|
this.write_from_box(dst, ret);
|
||||||
this.regs.insert(d, VMValue::from_nyash_box(ret));
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
if let Some(d) = dst {
|
this.write_void(dst);
|
||||||
this.regs.insert(d, VMValue::Void);
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(e) => Err(this.err_with_context(
|
Err(e) => Err(this.err_with_context(
|
||||||
@ -75,9 +69,7 @@ pub(super) fn invoke_plugin_box(
|
|||||||
if let Some(arg_id) = args.get(0) {
|
if let Some(arg_id) = args.get(0) {
|
||||||
let needle = this.reg_load(*arg_id)?.to_string();
|
let needle = this.reg_load(*arg_id)?.to_string();
|
||||||
let result_box = string_box.lastIndexOf(&needle);
|
let result_box = string_box.lastIndexOf(&needle);
|
||||||
if let Some(d) = dst {
|
this.write_from_box(dst, result_box);
|
||||||
this.regs.insert(d, VMValue::from_nyash_box(result_box));
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(this.err_invalid("lastIndexOf requires 1 argument"))
|
Err(this.err_invalid("lastIndexOf requires 1 argument"))
|
||||||
@ -87,9 +79,7 @@ pub(super) fn invoke_plugin_box(
|
|||||||
if let Some(arg_id) = args.get(0) {
|
if let Some(arg_id) = args.get(0) {
|
||||||
let needle = this.reg_load(*arg_id)?.to_string();
|
let needle = this.reg_load(*arg_id)?.to_string();
|
||||||
let result_box = string_box.find(&needle);
|
let result_box = string_box.find(&needle);
|
||||||
if let Some(d) = dst {
|
this.write_from_box(dst, result_box);
|
||||||
this.regs.insert(d, VMValue::from_nyash_box(result_box));
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(this.err_invalid("indexOf/find requires 1 argument"))
|
Err(this.err_invalid("indexOf/find requires 1 argument"))
|
||||||
@ -122,15 +112,13 @@ pub(super) fn invoke_plugin_box(
|
|||||||
}
|
}
|
||||||
// Generic toString fallback for any non-plugin box
|
// Generic toString fallback for any non-plugin box
|
||||||
if method == "toString" {
|
if method == "toString" {
|
||||||
if let Some(d) = dst {
|
// Map VoidBox.toString → "null" for JSON-friendly semantics
|
||||||
// Map VoidBox.toString → "null" for JSON-friendly semantics
|
let s = if recv_box.as_any().downcast_ref::<crate::box_trait::VoidBox>().is_some() {
|
||||||
let s = if recv_box.as_any().downcast_ref::<crate::box_trait::VoidBox>().is_some() {
|
"null".to_string()
|
||||||
"null".to_string()
|
} else {
|
||||||
} else {
|
recv_box.to_string_box().value
|
||||||
recv_box.to_string_box().value
|
};
|
||||||
};
|
this.write_string(dst, s);
|
||||||
this.regs.insert(d, VMValue::String(s));
|
|
||||||
}
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
// Minimal runtime fallback for common InstanceBox.is_eof when lowered function is not present.
|
// Minimal runtime fallback for common InstanceBox.is_eof when lowered function is not present.
|
||||||
@ -167,7 +155,7 @@ pub(super) fn invoke_plugin_box(
|
|||||||
argv.push(this.reg_load(*a)?);
|
argv.push(this.reg_load(*a)?);
|
||||||
}
|
}
|
||||||
let ret = this.exec_function_inner(&func, Some(&argv))?;
|
let ret = this.exec_function_inner(&func, Some(&argv))?;
|
||||||
if let Some(d) = dst { this.regs.insert(d, ret); }
|
this.write_result(dst, ret);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,7 +163,7 @@ pub(super) fn invoke_plugin_box(
|
|||||||
// when no class-specific handler is available. This avoids hard stops in JSON lint smokes
|
// when no class-specific handler is available. This avoids hard stops in JSON lint smokes
|
||||||
// while builder rewrite and instance dispatch stabilize.
|
// while builder rewrite and instance dispatch stabilize.
|
||||||
if method == "current" && args.is_empty() {
|
if method == "current" && args.is_empty() {
|
||||||
if let Some(d) = dst { this.regs.insert(d, VMValue::String(String::new())); }
|
this.write_string(dst, String::new());
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
// VoidBox graceful handling for common container-like methods
|
// VoidBox graceful handling for common container-like methods
|
||||||
@ -187,7 +175,7 @@ pub(super) fn invoke_plugin_box(
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
"stringify" => {
|
"stringify" => {
|
||||||
if let Some(d) = dst { this.regs.insert(d, VMValue::String("null".to_string())); }
|
this.write_string(dst, "null".to_string());
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
"array_size" | "length" | "size" => {
|
"array_size" | "length" | "size" => {
|
||||||
|
|||||||
@ -24,7 +24,7 @@ impl MirInterpreter {
|
|||||||
if let Some(Callee::Global(func_name)) = callee {
|
if let Some(Callee::Global(func_name)) = callee {
|
||||||
if func_name == "hostbridge.extern_invoke" || func_name.starts_with("hostbridge.extern_invoke/") {
|
if func_name == "hostbridge.extern_invoke" || func_name.starts_with("hostbridge.extern_invoke/") {
|
||||||
let v = self.execute_extern_function("hostbridge.extern_invoke", args)?;
|
let v = self.execute_extern_function("hostbridge.extern_invoke", args)?;
|
||||||
if let Some(d) = dst { self.regs.insert(d, v); }
|
self.write_result(dst, v);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -33,9 +33,7 @@ impl MirInterpreter {
|
|||||||
} else {
|
} else {
|
||||||
self.execute_legacy_call(func, args)?
|
self.execute_legacy_call(func, args)?
|
||||||
};
|
};
|
||||||
if let Some(d) = dst {
|
self.write_result(dst, call_result);
|
||||||
self.regs.insert(d, call_result);
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -45,4 +45,32 @@ impl MirInterpreter {
|
|||||||
self.regs.insert(d, value);
|
self.regs.insert(d, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// String値をdestinationに書き込む
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `dst` - 書き込み先のValueId (Noneの場合は何もしない)
|
||||||
|
/// * `value` - 書き込むString
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn write_string(&mut self, dst: Option<ValueId>, value: String) {
|
||||||
|
if let Some(d) = dst {
|
||||||
|
self.regs.insert(d, VMValue::String(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Box<dyn NyashBox>をVMValueに変換してdestinationに書き込む
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `dst` - 書き込み先のValueId (Noneの場合は何もしない)
|
||||||
|
/// * `nyash_box` - 書き込むBox (NullBox→Void, IntegerBox→Integer等に自動変換)
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn write_from_box(
|
||||||
|
&mut self,
|
||||||
|
dst: Option<ValueId>,
|
||||||
|
nyash_box: Box<dyn crate::box_trait::NyashBox>,
|
||||||
|
) {
|
||||||
|
if let Some(d) = dst {
|
||||||
|
self.regs.insert(d, VMValue::from_nyash_box(nyash_box));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user