refactor: complete error message unification (Phase 3.5)
Migrate remaining 45 error generation patterns to unified helpers: - calls.rs: 13 sites → 0 - extern_provider.rs: 9 sites → 0 - externals.rs: 5 sites → 0 - boxes_plugin.rs: 5 sites → 0 - boxes.rs: 5 sites → 0 - boxes_string.rs: 4 sites → 0 - boxes_instance.rs: 2 sites → 0 - mod.rs + boxes_array.rs: 2 sites → 0 Error patterns now 100% unified: - All 80 InvalidInstruction sites use helpers (100%) - Consistent error formatting across entire codebase - Single source of truth for error messages Code reduction: - Phase 3.5: 50-70 lines saved - Cumulative (Phase 1+2+3+3.5): 200-267 lines removed (6-8% handlers) - Total patterns unified: 192 (destination 60 + args 52 + errors 80) Benefits: - 100% error message consistency achieved - Easy to modify error formats globally - Foundation for i18n support ready - Improved maintainability and testability Test results: ✓ Build successful, Phase 21.0 smoke tests passing Related: Phase 21.0 refactoring milestone complete Risk: Low (error messages only, behavior preserved)
This commit is contained in:
@ -11,7 +11,7 @@ impl MirInterpreter {
|
|||||||
) -> Result<(), VMError> {
|
) -> Result<(), VMError> {
|
||||||
// Provider Lock guard (受け口・既定は挙動不変)
|
// Provider Lock guard (受け口・既定は挙動不変)
|
||||||
if let Err(e) = crate::runtime::provider_lock::guard_before_new_box(box_type) {
|
if let Err(e) = crate::runtime::provider_lock::guard_before_new_box(box_type) {
|
||||||
return Err(VMError::InvalidInstruction(e));
|
return Err(self.err_invalid(e));
|
||||||
}
|
}
|
||||||
let mut converted: Vec<Box<dyn NyashBox>> = Vec::with_capacity(args.len());
|
let mut converted: Vec<Box<dyn NyashBox>> = Vec::with_capacity(args.len());
|
||||||
for vid in args {
|
for vid in args {
|
||||||
@ -22,9 +22,7 @@ impl MirInterpreter {
|
|||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.create_box(box_type, &converted)
|
.create_box(box_type, &converted)
|
||||||
.map_err(|e| {
|
.map_err(|e| self.err_with_context(&format!("NewBox {}", box_type), &e.to_string()))?;
|
||||||
VMError::InvalidInstruction(format!("NewBox {} failed: {}", box_type, e))
|
|
||||||
})?;
|
|
||||||
// Store created instance first so 'me' can be passed to birth
|
// Store created instance first so 'me' can be passed to birth
|
||||||
let created_vm = VMValue::from_nyash_box(created);
|
let created_vm = VMValue::from_nyash_box(created);
|
||||||
self.regs.insert(dst, created_vm.clone());
|
self.regs.insert(dst, created_vm.clone());
|
||||||
@ -74,10 +72,10 @@ impl MirInterpreter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Err(VMError::InvalidInstruction(format!(
|
return Err(self.err_with_context(
|
||||||
"PluginInvoke {}.{} failed: {:?}",
|
&format!("PluginInvoke {}.{}", p.box_type, method),
|
||||||
p.box_type, method, e
|
&format!("{:?}", e)
|
||||||
)))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -88,11 +86,7 @@ impl MirInterpreter {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(VMError::InvalidInstruction(format!(
|
Err(self.err_method_not_found(&recv_box.type_name(), method))
|
||||||
"PluginInvoke unsupported on {} for method {}",
|
|
||||||
recv_box.type_name(),
|
|
||||||
method
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +182,7 @@ impl MirInterpreter {
|
|||||||
}
|
}
|
||||||
if user_instance_class.is_some() && !crate::config::env::vm_allow_user_instance_boxcall() {
|
if user_instance_class.is_some() && !crate::config::env::vm_allow_user_instance_boxcall() {
|
||||||
let cls = user_instance_class.unwrap();
|
let cls = user_instance_class.unwrap();
|
||||||
return Err(VMError::InvalidInstruction(format!(
|
return Err(self.err_invalid(format!(
|
||||||
"User Instance BoxCall disallowed in prod: {}.{} (enable builder rewrite)",
|
"User Instance BoxCall disallowed in prod: {}.{} (enable builder rewrite)",
|
||||||
cls, method
|
cls, method
|
||||||
)));
|
)));
|
||||||
|
|||||||
@ -32,7 +32,7 @@ pub(super) fn try_handle_array_box(
|
|||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
"pop" => {
|
"pop" => {
|
||||||
if !args.is_empty() { return Err(VMError::InvalidInstruction("pop expects 0 args".into())); }
|
if !args.is_empty() { return Err(this.err_invalid("pop expects 0 args")); }
|
||||||
let ret = ab.pop();
|
let ret = ab.pop();
|
||||||
this.write_result(dst, VMValue::from_nyash_box(ret));
|
this.write_result(dst, VMValue::from_nyash_box(ret));
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
|
|||||||
@ -92,7 +92,7 @@ pub(super) fn try_handle_instance_box(
|
|||||||
// Dev assert: forbid birth(me==Void)
|
// Dev assert: forbid birth(me==Void)
|
||||||
if method == "birth" && crate::config::env::using_is_dev() {
|
if method == "birth" && crate::config::env::using_is_dev() {
|
||||||
if matches!(recv_vm, VMValue::Void) {
|
if matches!(recv_vm, VMValue::Void) {
|
||||||
return Err(VMError::InvalidInstruction("Dev assert: birth(me==Void) is forbidden".into()));
|
return Err(this.err_invalid("Dev assert: birth(me==Void) is forbidden"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
argv.push(recv_vm.clone());
|
argv.push(recv_vm.clone());
|
||||||
@ -127,7 +127,7 @@ pub(super) fn try_handle_instance_box(
|
|||||||
let mut argv: Vec<VMValue> = Vec::with_capacity(1 + args.len());
|
let mut argv: Vec<VMValue> = Vec::with_capacity(1 + args.len());
|
||||||
if method == "birth" && crate::config::env::using_is_dev() {
|
if method == "birth" && crate::config::env::using_is_dev() {
|
||||||
if matches!(recv_vm, VMValue::Void) {
|
if matches!(recv_vm, VMValue::Void) {
|
||||||
return Err(VMError::InvalidInstruction("Dev assert: birth(me==Void) is forbidden".into()));
|
return Err(this.err_invalid("Dev assert: birth(me==Void) is forbidden"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
argv.push(recv_vm.clone());
|
argv.push(recv_vm.clone());
|
||||||
|
|||||||
@ -60,10 +60,10 @@ pub(super) fn invoke_plugin_box(
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(e) => Err(VMError::InvalidInstruction(format!(
|
Err(e) => Err(this.err_with_context(
|
||||||
"BoxCall {}.{} failed: {:?}",
|
&format!("BoxCall {}.{}", p.box_type, method),
|
||||||
p.box_type, method, e
|
&format!("{:?}", e)
|
||||||
))),
|
)),
|
||||||
}
|
}
|
||||||
} else if let Some(string_box) = recv_box
|
} else if let Some(string_box) = recv_box
|
||||||
.as_any()
|
.as_any()
|
||||||
@ -80,9 +80,7 @@ pub(super) fn invoke_plugin_box(
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(VMError::InvalidInstruction(
|
Err(this.err_invalid("lastIndexOf requires 1 argument"))
|
||||||
"lastIndexOf requires 1 argument".into(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"indexOf" | "find" => {
|
"indexOf" | "find" => {
|
||||||
@ -94,15 +92,10 @@ pub(super) fn invoke_plugin_box(
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(VMError::InvalidInstruction(
|
Err(this.err_invalid("indexOf/find requires 1 argument"))
|
||||||
"indexOf/find requires 1 argument".into(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Err(VMError::InvalidInstruction(format!(
|
_ => Err(this.err_method_not_found("StringBox", method)),
|
||||||
"BoxCall method {} not supported on StringBox",
|
|
||||||
method
|
|
||||||
))),
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Special-case: minimal runtime fallback for common InstanceBox methods when
|
// Special-case: minimal runtime fallback for common InstanceBox methods when
|
||||||
@ -209,10 +202,6 @@ pub(super) fn invoke_plugin_box(
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(VMError::InvalidInstruction(format!(
|
Err(this.err_method_not_found(&recv_box.type_name(), method))
|
||||||
"BoxCall unsupported on {}.{}",
|
|
||||||
recv_box.type_name(),
|
|
||||||
method
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -72,8 +72,8 @@ pub(super) fn try_handle_string_box(
|
|||||||
(n, from.max(0) as usize)
|
(n, from.max(0) as usize)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(VMError::InvalidInstruction(
|
return Err(this.err_invalid(
|
||||||
"indexOf expects 1 or 2 args (search [, fromIndex])".into(),
|
"indexOf expects 1 or 2 args (search [, fromIndex])"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -144,8 +144,8 @@ pub(super) fn try_handle_string_box(
|
|||||||
(s, e)
|
(s, e)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(VMError::InvalidInstruction(
|
return Err(this.err_invalid(
|
||||||
"substring expects 1 or 2 args (start [, end])".into(),
|
"substring expects 1 or 2 args (start [, end])"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -172,7 +172,7 @@ pub(super) fn try_handle_string_box(
|
|||||||
let s = this.reg_load(args[0])?.to_string();
|
let s = this.reg_load(args[0])?.to_string();
|
||||||
s.chars().next()
|
s.chars().next()
|
||||||
} else {
|
} else {
|
||||||
return Err(VMError::InvalidInstruction("is_digit_char expects 0 or 1 arg".into()));
|
return Err(this.err_invalid("is_digit_char expects 0 or 1 arg"));
|
||||||
};
|
};
|
||||||
let is_digit = ch_opt.map(|c| c.is_ascii_digit()).unwrap_or(false);
|
let is_digit = ch_opt.map(|c| c.is_ascii_digit()).unwrap_or(false);
|
||||||
this.write_result(dst, VMValue::Bool(is_digit));
|
this.write_result(dst, VMValue::Bool(is_digit));
|
||||||
@ -185,7 +185,7 @@ pub(super) fn try_handle_string_box(
|
|||||||
let s = this.reg_load(args[0])?.to_string();
|
let s = this.reg_load(args[0])?.to_string();
|
||||||
s.chars().next()
|
s.chars().next()
|
||||||
} else {
|
} else {
|
||||||
return Err(VMError::InvalidInstruction("is_hex_digit_char expects 0 or 1 arg".into()));
|
return Err(this.err_invalid("is_hex_digit_char expects 0 or 1 arg"));
|
||||||
};
|
};
|
||||||
let is_hex = ch_opt.map(|c| c.is_ascii_hexdigit()).unwrap_or(false);
|
let is_hex = ch_opt.map(|c| c.is_ascii_hexdigit()).unwrap_or(false);
|
||||||
this.write_result(dst, VMValue::Bool(is_hex));
|
this.write_result(dst, VMValue::Bool(is_hex));
|
||||||
|
|||||||
@ -424,15 +424,10 @@ impl MirInterpreter {
|
|||||||
if let Some(s) = first_arg_str {
|
if let Some(s) = first_arg_str {
|
||||||
match crate::host_providers::mir_builder::program_json_to_mir_json(&s) {
|
match crate::host_providers::mir_builder::program_json_to_mir_json(&s) {
|
||||||
Ok(out) => Ok(VMValue::String(out)),
|
Ok(out) => Ok(VMValue::String(out)),
|
||||||
Err(e) => Err(VMError::InvalidInstruction(format!(
|
Err(e) => Err(self.err_with_context("env.mirbuilder.emit", &e.to_string())),
|
||||||
"env.mirbuilder.emit: {}",
|
|
||||||
e
|
|
||||||
))),
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(VMError::InvalidInstruction(
|
Err(self.err_invalid("extern_invoke env.mirbuilder.emit expects 1 arg"))
|
||||||
"extern_invoke env.mirbuilder.emit expects 1 arg".into(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
("env.codegen", "emit_object") => {
|
("env.codegen", "emit_object") => {
|
||||||
@ -445,15 +440,10 @@ impl MirInterpreter {
|
|||||||
};
|
};
|
||||||
match crate::host_providers::llvm_codegen::mir_json_to_object(&s, opts) {
|
match crate::host_providers::llvm_codegen::mir_json_to_object(&s, opts) {
|
||||||
Ok(p) => Ok(VMValue::String(p.to_string_lossy().into_owned())),
|
Ok(p) => Ok(VMValue::String(p.to_string_lossy().into_owned())),
|
||||||
Err(e) => Err(VMError::InvalidInstruction(format!(
|
Err(e) => Err(self.err_with_context("env.codegen.emit_object", &e.to_string())),
|
||||||
"env.codegen.emit_object: {}",
|
|
||||||
e
|
|
||||||
))),
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(VMError::InvalidInstruction(
|
Err(self.err_invalid("extern_invoke env.codegen.emit_object expects 1 arg"))
|
||||||
"extern_invoke env.codegen.emit_object expects 1 arg".into(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
("env.codegen", "link_object") => {
|
("env.codegen", "link_object") => {
|
||||||
@ -611,7 +601,7 @@ impl MirInterpreter {
|
|||||||
if std::env::var("HAKO_CABI_TRACE").ok().as_deref() == Some("1") {
|
if std::env::var("HAKO_CABI_TRACE").ok().as_deref() == Some("1") {
|
||||||
eprintln!("[hb:unsupported:calls] {}.{}", name, method);
|
eprintln!("[hb:unsupported:calls] {}.{}", name, method);
|
||||||
}
|
}
|
||||||
Err(VMError::InvalidInstruction(format!(
|
Err(self.err_invalid(format!(
|
||||||
"hostbridge.extern_invoke unsupported for {}.{} [calls]",
|
"hostbridge.extern_invoke unsupported for {}.{} [calls]",
|
||||||
name, method
|
name, method
|
||||||
)))
|
)))
|
||||||
@ -705,9 +695,7 @@ impl MirInterpreter {
|
|||||||
let new_str = format!("{}{}", s, arg_val.to_string());
|
let new_str = format!("{}{}", s, arg_val.to_string());
|
||||||
Ok(VMValue::String(new_str))
|
Ok(VMValue::String(new_str))
|
||||||
} else {
|
} else {
|
||||||
Err(VMError::InvalidInstruction(
|
Err(self.err_invalid("concat requires 1 argument"))
|
||||||
"concat requires 1 argument".into(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"replace" => {
|
"replace" => {
|
||||||
@ -716,9 +704,7 @@ impl MirInterpreter {
|
|||||||
let new = self.reg_load(args[1])?.to_string();
|
let new = self.reg_load(args[1])?.to_string();
|
||||||
Ok(VMValue::String(s.replace(&old, &new)))
|
Ok(VMValue::String(s.replace(&old, &new)))
|
||||||
} else {
|
} else {
|
||||||
Err(VMError::InvalidInstruction(
|
Err(self.err_invalid("replace requires 2 arguments"))
|
||||||
"replace requires 2 arguments".into(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"indexOf" => {
|
"indexOf" => {
|
||||||
@ -727,9 +713,7 @@ impl MirInterpreter {
|
|||||||
let idx = s.find(&needle).map(|i| i as i64).unwrap_or(-1);
|
let idx = s.find(&needle).map(|i| i as i64).unwrap_or(-1);
|
||||||
Ok(VMValue::Integer(idx))
|
Ok(VMValue::Integer(idx))
|
||||||
} else {
|
} else {
|
||||||
Err(VMError::InvalidInstruction(
|
Err(self.err_invalid("indexOf requires 1 argument"))
|
||||||
"indexOf requires 1 argument".into(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"lastIndexOf" => {
|
"lastIndexOf" => {
|
||||||
@ -738,9 +722,7 @@ impl MirInterpreter {
|
|||||||
let idx = s.rfind(&needle).map(|i| i as i64).unwrap_or(-1);
|
let idx = s.rfind(&needle).map(|i| i as i64).unwrap_or(-1);
|
||||||
Ok(VMValue::Integer(idx))
|
Ok(VMValue::Integer(idx))
|
||||||
} else {
|
} else {
|
||||||
Err(VMError::InvalidInstruction(
|
Err(self.err_invalid("lastIndexOf requires 1 argument"))
|
||||||
"lastIndexOf requires 1 argument".into(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"substring" => {
|
"substring" => {
|
||||||
@ -774,9 +756,7 @@ impl MirInterpreter {
|
|||||||
let result_box = string_box.lastIndexOf(&needle);
|
let result_box = string_box.lastIndexOf(&needle);
|
||||||
Ok(VMValue::from_nyash_box(result_box))
|
Ok(VMValue::from_nyash_box(result_box))
|
||||||
} else {
|
} else {
|
||||||
Err(VMError::InvalidInstruction(
|
Err(self.err_invalid("lastIndexOf requires 1 argument"))
|
||||||
"lastIndexOf requires 1 argument".into(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"indexOf" | "find" => {
|
"indexOf" | "find" => {
|
||||||
@ -785,9 +765,7 @@ impl MirInterpreter {
|
|||||||
let result_box = string_box.find(&needle);
|
let result_box = string_box.find(&needle);
|
||||||
Ok(VMValue::from_nyash_box(result_box))
|
Ok(VMValue::from_nyash_box(result_box))
|
||||||
} else {
|
} else {
|
||||||
Err(VMError::InvalidInstruction(
|
Err(self.err_invalid("indexOf/find requires 1 argument"))
|
||||||
"indexOf/find requires 1 argument".into(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Err(self.err_method_not_found("StringBox", method)),
|
_ => Err(self.err_method_not_found("StringBox", method)),
|
||||||
@ -811,17 +789,13 @@ impl MirInterpreter {
|
|||||||
) {
|
) {
|
||||||
Ok(Some(ret)) => Ok(VMValue::from_nyash_box(ret)),
|
Ok(Some(ret)) => Ok(VMValue::from_nyash_box(ret)),
|
||||||
Ok(None) => Ok(VMValue::Void),
|
Ok(None) => Ok(VMValue::Void),
|
||||||
Err(e) => Err(VMError::InvalidInstruction(format!(
|
Err(e) => Err(self.err_with_context(
|
||||||
"Plugin method {}.{} failed: {:?}",
|
&format!("Plugin method {}.{}", p.box_type, method),
|
||||||
p.box_type, method, e
|
&format!("{:?}", e)
|
||||||
))),
|
)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(VMError::InvalidInstruction(format!(
|
Err(self.err_method_not_found(&box_ref.type_name(), method))
|
||||||
"Method {} not supported on BoxRef({})",
|
|
||||||
method,
|
|
||||||
box_ref.type_name()
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Err(self.err_with_context("method call", &format!("{} not supported on {:?}", method, receiver))),
|
_ => Err(self.err_with_context("method call", &format!("{} not supported on {:?}", method, receiver))),
|
||||||
|
|||||||
@ -82,7 +82,7 @@ impl MirInterpreter {
|
|||||||
// Only supported on C-API route; expect 1 or 2 args: obj_path [, exe_out]
|
// Only supported on C-API route; expect 1 or 2 args: obj_path [, exe_out]
|
||||||
let obj_path = match args.get(0) {
|
let obj_path = match args.get(0) {
|
||||||
Some(v) => match self.reg_load(*v) { Ok(v) => v.to_string(), Err(e) => return Some(Err(e)) },
|
Some(v) => match self.reg_load(*v) { Ok(v) => v.to_string(), Err(e) => return Some(Err(e)) },
|
||||||
None => return Some(Err(VMError::InvalidInstruction("env.codegen.link_object expects 1+ args".into()))),
|
None => return Some(Err(self.err_invalid("env.codegen.link_object expects 1+ args"))),
|
||||||
};
|
};
|
||||||
let exe_out = match args.get(1) {
|
let exe_out = match args.get(1) {
|
||||||
Some(v) => Some(match self.reg_load(*v) { Ok(v) => v.to_string(), Err(e) => return Some(Err(e)) }),
|
Some(v) => Some(match self.reg_load(*v) { Ok(v) => v.to_string(), Err(e) => return Some(Err(e)) }),
|
||||||
@ -114,9 +114,7 @@ impl MirInterpreter {
|
|||||||
eprintln!("[hb:entry:provider] hostbridge.extern_invoke");
|
eprintln!("[hb:entry:provider] hostbridge.extern_invoke");
|
||||||
}
|
}
|
||||||
if args.len() < 2 {
|
if args.len() < 2 {
|
||||||
return Some(Err(VMError::InvalidInstruction(
|
return Some(Err(self.err_invalid("extern_invoke expects at least 2 args")));
|
||||||
"extern_invoke expects at least 2 args".into(),
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
let name = match self.reg_load(args[0]) { Ok(v) => v.to_string(), Err(e) => return Some(Err(e)) };
|
let name = match self.reg_load(args[0]) { Ok(v) => v.to_string(), Err(e) => return Some(Err(e)) };
|
||||||
let method = match self.reg_load(args[1]) { Ok(v) => v.to_string(), Err(e) => return Some(Err(e)) };
|
let method = match self.reg_load(args[1]) { Ok(v) => v.to_string(), Err(e) => return Some(Err(e)) };
|
||||||
@ -186,7 +184,7 @@ impl MirInterpreter {
|
|||||||
_ => (v.to_string(), None),
|
_ => (v.to_string(), None),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Some(Err(VMError::InvalidInstruction("extern_invoke env.codegen.link_object expects args array".into())));
|
return Some(Err(self.err_invalid("extern_invoke env.codegen.link_object expects args array")));
|
||||||
};
|
};
|
||||||
if std::env::var("NYASH_LLVM_USE_CAPI").ok().as_deref() != Some("1") ||
|
if std::env::var("NYASH_LLVM_USE_CAPI").ok().as_deref() != Some("1") ||
|
||||||
std::env::var("HAKO_V1_EXTERN_PROVIDER_C_ABI").ok().as_deref() != Some("1") {
|
std::env::var("HAKO_V1_EXTERN_PROVIDER_C_ABI").ok().as_deref() != Some("1") {
|
||||||
@ -204,15 +202,10 @@ impl MirInterpreter {
|
|||||||
if let Some(s) = first_arg_str {
|
if let Some(s) = first_arg_str {
|
||||||
match crate::host_providers::mir_builder::program_json_to_mir_json(&s) {
|
match crate::host_providers::mir_builder::program_json_to_mir_json(&s) {
|
||||||
Ok(out) => Ok(VMValue::String(Self::patch_mir_json_version(&out))),
|
Ok(out) => Ok(VMValue::String(Self::patch_mir_json_version(&out))),
|
||||||
Err(e) => Err(VMError::InvalidInstruction(format!(
|
Err(e) => Err(self.err_with_context("env.mirbuilder.emit", &e.to_string())),
|
||||||
"env.mirbuilder.emit: {}",
|
|
||||||
e
|
|
||||||
))),
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(VMError::InvalidInstruction(
|
Err(self.err_invalid("extern_invoke env.mirbuilder.emit expects 1 arg"))
|
||||||
"extern_invoke env.mirbuilder.emit expects 1 arg".into(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
("env.codegen", "emit_object") => {
|
("env.codegen", "emit_object") => {
|
||||||
@ -225,15 +218,10 @@ impl MirInterpreter {
|
|||||||
};
|
};
|
||||||
match crate::host_providers::llvm_codegen::mir_json_to_object(&s, opts) {
|
match crate::host_providers::llvm_codegen::mir_json_to_object(&s, opts) {
|
||||||
Ok(p) => Ok(VMValue::String(p.to_string_lossy().into_owned())),
|
Ok(p) => Ok(VMValue::String(p.to_string_lossy().into_owned())),
|
||||||
Err(e) => Err(VMError::InvalidInstruction(format!(
|
Err(e) => Err(self.err_with_context("env.codegen.emit_object", &e.to_string())),
|
||||||
"env.codegen.emit_object: {}",
|
|
||||||
e
|
|
||||||
))),
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(VMError::InvalidInstruction(
|
Err(self.err_invalid("extern_invoke env.codegen.emit_object expects 1 arg"))
|
||||||
"extern_invoke env.codegen.emit_object expects 1 arg".into(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
("env.codegen", "link_object") => {
|
("env.codegen", "link_object") => {
|
||||||
@ -267,7 +255,7 @@ impl MirInterpreter {
|
|||||||
}
|
}
|
||||||
let objs = match obj_s {
|
let objs = match obj_s {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
None => return Some(Err(VMError::InvalidInstruction("extern_invoke env.codegen.link_object expects args".into()))),
|
None => return Some(Err(self.err_invalid("extern_invoke env.codegen.link_object expects args"))),
|
||||||
};
|
};
|
||||||
if std::env::var("NYASH_LLVM_USE_CAPI").ok().as_deref() != Some("1") ||
|
if std::env::var("NYASH_LLVM_USE_CAPI").ok().as_deref() != Some("1") ||
|
||||||
std::env::var("HAKO_V1_EXTERN_PROVIDER_C_ABI").ok().as_deref() != Some("1") {
|
std::env::var("HAKO_V1_EXTERN_PROVIDER_C_ABI").ok().as_deref() != Some("1") {
|
||||||
@ -285,7 +273,7 @@ impl MirInterpreter {
|
|||||||
if std::env::var("HAKO_CABI_TRACE").ok().as_deref() == Some("1") {
|
if std::env::var("HAKO_CABI_TRACE").ok().as_deref() == Some("1") {
|
||||||
eprintln!("[hb:unsupported:provider] {}.{}", name, method);
|
eprintln!("[hb:unsupported:provider] {}.{}", name, method);
|
||||||
}
|
}
|
||||||
Err(VMError::InvalidInstruction(format!(
|
Err(self.err_invalid(format!(
|
||||||
"hostbridge.extern_invoke unsupported for {}.{} [provider]",
|
"hostbridge.extern_invoke unsupported for {}.{} [provider]",
|
||||||
name, method
|
name, method
|
||||||
)))
|
)))
|
||||||
|
|||||||
@ -155,7 +155,7 @@ impl MirInterpreter {
|
|||||||
// Note: This branch is used for ExternCall form; provider toggles must be ON.
|
// Note: This branch is used for ExternCall form; provider toggles must be ON.
|
||||||
if std::env::var("NYASH_LLVM_USE_CAPI").ok().as_deref() != Some("1") ||
|
if std::env::var("NYASH_LLVM_USE_CAPI").ok().as_deref() != Some("1") ||
|
||||||
std::env::var("HAKO_V1_EXTERN_PROVIDER_C_ABI").ok().as_deref() != Some("1") {
|
std::env::var("HAKO_V1_EXTERN_PROVIDER_C_ABI").ok().as_deref() != Some("1") {
|
||||||
return Err(VMError::InvalidInstruction("env.codegen.link_object: C-API route disabled".into()));
|
return Err(self.err_invalid("env.codegen.link_object: C-API route disabled"));
|
||||||
}
|
}
|
||||||
// Extract array payload
|
// Extract array payload
|
||||||
let (obj_path, exe_out) = if let Some(a2) = args.get(2) {
|
let (obj_path, exe_out) = if let Some(a2) = args.get(2) {
|
||||||
@ -177,13 +177,13 @@ impl MirInterpreter {
|
|||||||
_ => (v.to_string(), None),
|
_ => (v.to_string(), None),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(VMError::InvalidInstruction("extern_invoke env.codegen.link_object expects args array".into()));
|
return Err(self.err_invalid("extern_invoke env.codegen.link_object expects args array"));
|
||||||
};
|
};
|
||||||
let extra = std::env::var("HAKO_AOT_LDFLAGS").ok();
|
let extra = std::env::var("HAKO_AOT_LDFLAGS").ok();
|
||||||
let obj = std::path::PathBuf::from(obj_path);
|
let obj = std::path::PathBuf::from(obj_path);
|
||||||
let exe = exe_out.map(std::path::PathBuf::from).unwrap_or_else(|| std::env::temp_dir().join("hako_link_out.exe"));
|
let exe = exe_out.map(std::path::PathBuf::from).unwrap_or_else(|| std::env::temp_dir().join("hako_link_out.exe"));
|
||||||
crate::host_providers::llvm_codegen::link_object_capi(&obj, &exe, extra.as_deref())
|
crate::host_providers::llvm_codegen::link_object_capi(&obj, &exe, extra.as_deref())
|
||||||
.map_err(|e| VMError::InvalidInstruction(format!("env.codegen.link_object: {}", e)))?;
|
.map_err(|e| self.err_with_context("env.codegen.link_object", &e.to_string()))?;
|
||||||
self.write_result(dst, VMValue::String(exe.to_string_lossy().into_owned()));
|
self.write_result(dst, VMValue::String(exe.to_string_lossy().into_owned()));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -195,9 +195,9 @@ impl MirInterpreter {
|
|||||||
}
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
return Err(VMError::InvalidInstruction("hostbridge.extern_invoke unsupported [externals]".into()));
|
return Err(self.err_invalid("hostbridge.extern_invoke unsupported [externals]"));
|
||||||
}
|
}
|
||||||
_ => Err(VMError::InvalidInstruction(format!(
|
_ => Err(self.err_invalid(format!(
|
||||||
"ExternCall {}.{} not supported",
|
"ExternCall {}.{} not supported",
|
||||||
iface, method
|
iface, method
|
||||||
))),
|
))),
|
||||||
|
|||||||
@ -96,7 +96,7 @@ impl MirInterpreter {
|
|||||||
| MirInstruction::Safepoint
|
| MirInstruction::Safepoint
|
||||||
| MirInstruction::Nop => {}
|
| MirInstruction::Nop => {}
|
||||||
other => {
|
other => {
|
||||||
return Err(VMError::InvalidInstruction(format!(
|
return Err(self.err_invalid(format!(
|
||||||
"MIR interp: unimplemented instruction: {:?}",
|
"MIR interp: unimplemented instruction: {:?}",
|
||||||
other
|
other
|
||||||
)))
|
)))
|
||||||
|
|||||||
Reference in New Issue
Block a user