2025-09-25 02:58:43 +09:00
|
|
|
|
//! 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;
|
2025-11-13 16:40:58 +09:00
|
|
|
|
use crate::mir::{MirInstruction, TypeOpKind};
|
2025-11-17 20:26:32 +09:00
|
|
|
|
use crate::mir::builder::calls::function_lowering;
|
2025-09-25 02:58:43 +09:00
|
|
|
|
|
2025-11-20 06:38:43 +09:00
|
|
|
|
/// Me-call 専用のポリシー箱。
|
|
|
|
|
|
///
|
|
|
|
|
|
/// - 責務:
|
|
|
|
|
|
/// - me.method(...) を「インスタンス呼び出し」か「static メソッド呼び出し」か判定する。
|
|
|
|
|
|
/// - static box 文脈で実体のない receiver を生まないように、静的メソッド降下にフォールバックする。
|
|
|
|
|
|
struct MeCallPolicyBox;
|
|
|
|
|
|
|
|
|
|
|
|
impl MeCallPolicyBox {
|
|
|
|
|
|
fn resolve_me_call(
|
|
|
|
|
|
builder: &mut MirBuilder,
|
|
|
|
|
|
method: &str,
|
|
|
|
|
|
arguments: &[ASTNode],
|
|
|
|
|
|
) -> Result<Option<ValueId>, String> {
|
|
|
|
|
|
// Instance box: prefer enclosing box method (lowered function) if存在
|
|
|
|
|
|
let enclosing_cls: Option<String> = builder
|
|
|
|
|
|
.current_function
|
|
|
|
|
|
.as_ref()
|
|
|
|
|
|
.and_then(|f| f.signature.name.split('.').next().map(|s| s.to_string()));
|
|
|
|
|
|
|
|
|
|
|
|
if let Some(cls) = enclosing_cls.as_ref() {
|
|
|
|
|
|
let mut arg_values = Vec::with_capacity(arguments.len());
|
|
|
|
|
|
for a in arguments {
|
|
|
|
|
|
arg_values.push(builder.build_expression(a.clone())?);
|
|
|
|
|
|
}
|
|
|
|
|
|
let arity = arg_values.len();
|
|
|
|
|
|
let fname =
|
|
|
|
|
|
function_lowering::generate_method_function_name(cls, method, arity);
|
|
|
|
|
|
let exists = if let Some(ref module) = builder.current_module {
|
|
|
|
|
|
module.functions.contains_key(&fname)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
false
|
|
|
|
|
|
};
|
|
|
|
|
|
if exists {
|
|
|
|
|
|
// Pass 'me' as first arg
|
|
|
|
|
|
let me_id = builder.build_me_expression()?;
|
|
|
|
|
|
let mut call_args = Vec::with_capacity(arity + 1);
|
|
|
|
|
|
call_args.push(me_id);
|
|
|
|
|
|
call_args.extend(arg_values.into_iter());
|
|
|
|
|
|
let dst = builder.next_value_id();
|
|
|
|
|
|
// Emit as unified global call to lowered function
|
|
|
|
|
|
builder.emit_unified_call(
|
|
|
|
|
|
Some(dst),
|
|
|
|
|
|
CallTarget::Global(fname.clone()),
|
|
|
|
|
|
call_args,
|
|
|
|
|
|
)?;
|
|
|
|
|
|
builder.annotate_call_result_from_func_name(dst, &fname);
|
|
|
|
|
|
return Ok(Some(dst));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Fallback: treat me.method(...) as a static method on the enclosing box.
|
|
|
|
|
|
// - 旧挙動では me を Box 値として Method 呼び出ししようとしていたが、
|
|
|
|
|
|
// static box 文脈では実体インスタンスが存在しないため UndefinedValue を生みやすい。
|
|
|
|
|
|
// - ここでは receiver を持たない Global call に揃え、FuncScannerBox などの
|
|
|
|
|
|
// static ヘルパー呼び出しを安全に扱う。
|
|
|
|
|
|
let static_dst =
|
|
|
|
|
|
builder.handle_static_method_call(cls, method, arguments)?;
|
|
|
|
|
|
return Ok(Some(static_dst));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Ok(None)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-25 02:58:43 +09:00
|
|
|
|
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<ValueId, String> {
|
|
|
|
|
|
// 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());
|
2025-11-17 00:48:18 +09:00
|
|
|
|
let dst = self.next_value_id();
|
2025-09-25 02:58:43 +09:00
|
|
|
|
|
|
|
|
|
|
if std::env::var("NYASH_STATIC_CALL_TRACE").ok().as_deref() == Some("1") {
|
|
|
|
|
|
eprintln!("[builder] static-call {}", func_name);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-13 16:40:58 +09:00
|
|
|
|
// Emit unified global call to the static-lowered function (module-local)
|
|
|
|
|
|
self.emit_unified_call(Some(dst), CallTarget::Global(func_name), arg_values)?;
|
2025-09-25 02:58:43 +09:00
|
|
|
|
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<ValueId, String> {
|
|
|
|
|
|
let mir_ty = Self::parse_type_name_to_mir(type_name);
|
2025-11-17 00:48:18 +09:00
|
|
|
|
let dst = self.next_value_id();
|
2025-09-25 02:58:43 +09:00
|
|
|
|
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
|
2025-11-18 18:56:35 +09:00
|
|
|
|
#[allow(dead_code)]
|
2025-09-25 02:58:43 +09:00
|
|
|
|
pub(super) fn is_typeop_method(method: &str, arguments: &[ASTNode]) -> Option<String> {
|
|
|
|
|
|
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<Option<ValueId>, String> {
|
2025-11-20 06:38:43 +09:00
|
|
|
|
MeCallPolicyBox::resolve_me_call(self, method, arguments)
|
2025-09-25 02:58:43 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Handle standard Box/Plugin method calls (fallback)
|
|
|
|
|
|
pub(super) fn handle_standard_method_call(
|
|
|
|
|
|
&mut self,
|
|
|
|
|
|
object_value: ValueId,
|
|
|
|
|
|
method: String,
|
|
|
|
|
|
arguments: &[ASTNode],
|
|
|
|
|
|
) -> Result<ValueId, String> {
|
|
|
|
|
|
// Build argument values
|
|
|
|
|
|
let mut arg_values = Vec::new();
|
|
|
|
|
|
for arg in arguments {
|
|
|
|
|
|
arg_values.push(self.build_expression(arg.clone())?);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-28 20:38:09 +09:00
|
|
|
|
// Receiver class hintは emit_unified_call 側で起源/型から判断する(重複回避)
|
|
|
|
|
|
// 統一経路: emit_unified_call に委譲(RouterPolicy と rewrite::* で安定化)
|
2025-11-17 00:48:18 +09:00
|
|
|
|
let dst = self.next_value_id();
|
2025-09-28 20:38:09 +09:00
|
|
|
|
self.emit_unified_call(
|
|
|
|
|
|
Some(dst),
|
|
|
|
|
|
CallTarget::Method { box_type: None, method, receiver: object_value },
|
2025-09-25 02:58:43 +09:00
|
|
|
|
arg_values,
|
|
|
|
|
|
)?;
|
2025-09-28 20:38:09 +09:00
|
|
|
|
Ok(dst)
|
2025-09-25 02:58:43 +09:00
|
|
|
|
}
|
2025-09-26 05:28:20 +09:00
|
|
|
|
}
|