//! Method call handlers for MIR builder //! //! This module contains specialized handlers for different types of method calls, //! following the Single Responsibility Principle. use crate::ast::ASTNode; use crate::mir::builder::{MirBuilder, ValueId}; use crate::mir::builder::builder_calls::CallTarget; use crate::mir::{MirInstruction, TypeOpKind, MirType}; impl MirBuilder { /// Handle static method calls: BoxName.method(args) pub(super) fn handle_static_method_call( &mut self, box_name: &str, method: &str, arguments: &[ASTNode], ) -> Result { // Build argument values let mut arg_values = Vec::new(); for arg in arguments { arg_values.push(self.build_expression(arg.clone())?); } // Compose lowered function name: BoxName.method/N let func_name = format!("{}.{}/{}", box_name, method, arg_values.len()); let dst = self.value_gen.next(); if std::env::var("NYASH_STATIC_CALL_TRACE").ok().as_deref() == Some("1") { eprintln!("[builder] static-call {}", func_name); } // Use legacy global-call emission to avoid unified builtin/extern constraints self.emit_legacy_call(Some(dst), CallTarget::Global(func_name), arg_values)?; Ok(dst) } /// Handle TypeOp method calls: value.is("Type") and value.as("Type") pub(super) fn handle_typeop_method( &mut self, object_value: ValueId, method: &str, type_name: &str, ) -> Result { let mir_ty = Self::parse_type_name_to_mir(type_name); let dst = self.value_gen.next(); let op = if method == "is" { TypeOpKind::Check } else { TypeOpKind::Cast }; self.emit_instruction(MirInstruction::TypeOp { dst, op, value: object_value, ty: mir_ty, })?; Ok(dst) } /// Check if this is a TypeOp method call pub(super) fn is_typeop_method(method: &str, arguments: &[ASTNode]) -> Option { if (method == "is" || method == "as") && arguments.len() == 1 { Self::extract_string_literal(&arguments[0]) } else { None } } /// Handle me.method() calls within static box context pub(super) fn handle_me_method_call( &mut self, method: &str, arguments: &[ASTNode], ) -> Result, String> { // Convert slice to Vec for compatibility let args_vec = arguments.to_vec(); // Delegate to existing try_handle_me_direct_call match self.try_handle_me_direct_call(method, &args_vec) { Some(result) => result.map(Some), None => Ok(None), } } /// Handle standard Box/Plugin method calls (fallback) pub(super) fn handle_standard_method_call( &mut self, object_value: ValueId, method: String, arguments: &[ASTNode], ) -> Result { // Build argument values let mut arg_values = Vec::new(); for arg in arguments { arg_values.push(self.build_expression(arg.clone())?); } let result_id = self.value_gen.next(); self.emit_box_or_plugin_call( Some(result_id), object_value, method, None, arg_values, crate::mir::EffectMask::READ.add(crate::mir::Effect::ReadHeap), )?; Ok(result_id) } }