fix: Fix NyashParser import path and improve BoxCall fallback
- Fix NyashParser import path in vm.rs tests - Improve BoxCall fallback logic for plugin/builtin methods - Add proper function existence checks before lowering to Call This ensures plugin Box methods correctly fall back to BoxCall when the corresponding user-defined function doesn't exist. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -1072,7 +1072,7 @@ impl Default for VM {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::mir::{MirModule, MirFunction, FunctionSignature, MirType, EffectMask, BasicBlock};
|
use crate::mir::{MirModule, MirFunction, FunctionSignature, MirType, EffectMask, BasicBlock};
|
||||||
use crate::NyashParser;
|
use crate::parser::NyashParser;
|
||||||
use crate::runtime::NyashRuntime;
|
use crate::runtime::NyashRuntime;
|
||||||
use crate::core::model::BoxDeclaration as CoreBoxDecl;
|
use crate::core::model::BoxDeclaration as CoreBoxDecl;
|
||||||
use crate::interpreter::SharedState;
|
use crate::interpreter::SharedState;
|
||||||
|
|||||||
@ -991,27 +991,30 @@ impl MirBuilder {
|
|||||||
|
|
||||||
// Optimization: If the object is a direct `new ClassName(...)`, lower to a direct Call
|
// Optimization: If the object is a direct `new ClassName(...)`, lower to a direct Call
|
||||||
if let ASTNode::New { class, .. } = object {
|
if let ASTNode::New { class, .. } = object {
|
||||||
// Build function name: "{Class}.{method}/{argc}"
|
// Build function name and only lower to Call if the function exists (user-defined)
|
||||||
let func_name = format!("{}.{}{}", class, method, format!("/{}", arg_values.len()));
|
let func_name = format!("{}.{}{}", class, method, format!("/{}", arg_values.len()));
|
||||||
// Create a constant for the function name
|
let can_lower = if let Some(ref module) = self.current_module { module.functions.contains_key(&func_name) } else { false };
|
||||||
|
if can_lower {
|
||||||
let func_val = self.value_gen.next();
|
let func_val = self.value_gen.next();
|
||||||
self.emit_instruction(MirInstruction::Const { dst: func_val, value: ConstValue::String(func_name) })?;
|
self.emit_instruction(MirInstruction::Const { dst: func_val, value: ConstValue::String(func_name) })?;
|
||||||
// Prepare args: me + user args
|
|
||||||
let mut call_args = Vec::with_capacity(arg_values.len() + 1);
|
let mut call_args = Vec::with_capacity(arg_values.len() + 1);
|
||||||
call_args.push(object_value);
|
call_args.push(object_value);
|
||||||
call_args.extend(arg_values);
|
call_args.extend(arg_values);
|
||||||
// Emit direct Call
|
|
||||||
self.emit_instruction(MirInstruction::Call {
|
self.emit_instruction(MirInstruction::Call {
|
||||||
dst: Some(result_id),
|
dst: Some(result_id),
|
||||||
func: func_val,
|
func: func_val,
|
||||||
args: call_args,
|
args: call_args,
|
||||||
effects: EffectMask::READ.add(Effect::ReadHeap),
|
effects: EffectMask::READ.add(Effect::ReadHeap),
|
||||||
})?;
|
})?;
|
||||||
Ok(result_id)
|
return Ok(result_id);
|
||||||
|
}
|
||||||
|
// else fall through to BoxCall below
|
||||||
} else {
|
} else {
|
||||||
// If the object originates from a NewBox in this function, we can lower to Call as well
|
// If the object originates from a NewBox in this function, we can lower to Call as well
|
||||||
if let Some(class_name) = self.value_origin_newbox.get(&object_value).cloned() {
|
if let Some(class_name) = self.value_origin_newbox.get(&object_value).cloned() {
|
||||||
let func_name = format!("{}.{}{}", class_name, method, format!("/{}", arg_values.len()));
|
let func_name = format!("{}.{}{}", class_name, method, format!("/{}", arg_values.len()));
|
||||||
|
let can_lower = if let Some(ref module) = self.current_module { module.functions.contains_key(&func_name) } else { false };
|
||||||
|
if can_lower {
|
||||||
let func_val = self.value_gen.next();
|
let func_val = self.value_gen.next();
|
||||||
self.emit_instruction(MirInstruction::Const { dst: func_val, value: ConstValue::String(func_name) })?;
|
self.emit_instruction(MirInstruction::Const { dst: func_val, value: ConstValue::String(func_name) })?;
|
||||||
let mut call_args = Vec::with_capacity(arg_values.len() + 1);
|
let mut call_args = Vec::with_capacity(arg_values.len() + 1);
|
||||||
@ -1023,9 +1026,12 @@ impl MirBuilder {
|
|||||||
args: call_args,
|
args: call_args,
|
||||||
effects: EffectMask::READ.add(Effect::ReadHeap),
|
effects: EffectMask::READ.add(Effect::ReadHeap),
|
||||||
})?;
|
})?;
|
||||||
Ok(result_id)
|
return Ok(result_id);
|
||||||
} else {
|
}
|
||||||
// Fallback: Emit a BoxCall instruction for regular method calls
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: Emit a BoxCall instruction for regular or plugin/builtin method calls
|
||||||
self.emit_instruction(MirInstruction::BoxCall {
|
self.emit_instruction(MirInstruction::BoxCall {
|
||||||
dst: Some(result_id),
|
dst: Some(result_id),
|
||||||
box_val: object_value,
|
box_val: object_value,
|
||||||
@ -1035,8 +1041,6 @@ impl MirBuilder {
|
|||||||
})?;
|
})?;
|
||||||
Ok(result_id)
|
Ok(result_id)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Build from expression: from Parent.method(arguments)
|
/// Build from expression: from Parent.method(arguments)
|
||||||
fn build_from_expression(&mut self, parent: String, method: String, arguments: Vec<ASTNode>) -> Result<ValueId, String> {
|
fn build_from_expression(&mut self, parent: String, method: String, arguments: Vec<ASTNode>) -> Result<ValueId, String> {
|
||||||
|
|||||||
Reference in New Issue
Block a user