Files
hakorune/src/interpreter/expressions.rs
Moe Charm 80c911d3c8 🚨 Critical Issue #76: SocketBox Method Call Deadlock Investigation
## 🎯 Problem Identification Complete
- SocketBox method calls (bind, isServer, toString) cause infinite blocking
- Root cause: Method resolution pipeline deadlock before execute_socket_method
- Other Box types (ArrayBox, StringBox, MapBox) work normally
- Arc<Mutex> reference sharing confirmed working (Arc addresses match = true)

## 🔧 Debug Infrastructure Added
- Comprehensive debug logging in socket_box.rs (bind, isServer, clone, toString)
- Method call tracing in http_methods.rs
- Deadlock detection points identified at interpreter expressions.rs:462-464

## 📋 Issue #76 Created for Copilot Investigation
- Systematic root cause analysis requirements (Architecture→Parser→Runtime levels)
- Comprehensive test cases: minimal/comprehensive/comparison scenarios
- Strict prohibition of band-aid fixes - architectural analysis required
- Hypothesis: Multiple Arc<Mutex> combinations causing circular deadlock

## 🧪 Test Suite Added
- test_socket_deadlock_minimal.nyash: Minimal reproduction case
- test_socket_methods_comprehensive.nyash: All methods deadlock verification
- test_other_boxes_working.nyash: Normal Box operation confirmation
- SOCKETBOX_ISSUE_REPRODUCTION.md: Complete reproduction guide

## 📊 Impact Assessment
- Phase 9 HTTP server implementation completely blocked
- SocketBox functionality entirely non-functional
- Critical blocker for production readiness
- Requires immediate systematic investigation

🔥 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-14 20:55:33 +09:00

1167 lines
53 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*!
* Expression Processing Module
*
* Extracted from core.rs lines 408-787 (~380 lines)
* Handles expression evaluation, binary operations, method calls, and field access
* Core philosophy: "Everything is Box" with clean expression evaluation
*/
use super::*;
use crate::ast::UnaryOperator;
use crate::boxes::{buffer::BufferBox, JSONBox, HttpClientBox, StreamBox, RegexBox, IntentBox, SocketBox, HTTPServerBox, HTTPRequestBox, HTTPResponseBox};
use crate::boxes::{FloatBox, MathBox, ConsoleBox, TimeBox, DateTimeBox, RandomBox, SoundBox, DebugBox, file::FileBox, MapBox};
use crate::box_trait::{BoolBox, SharedNyashBox};
use crate::operator_traits::OperatorResolver;
use std::sync::Arc;
// TODO: Fix NullBox import issue later
// use crate::NullBox;
impl NyashInterpreter {
/// 式を実行 - Expression evaluation engine
pub(super) fn execute_expression(&mut self, expression: &ASTNode) -> Result<Box<dyn NyashBox>, RuntimeError> {
match expression {
ASTNode::Literal { value, .. } => {
Ok(value.to_nyash_box())
}
ASTNode::Variable { name, .. } => {
// 🌍 革命的変数解決local変数 → GlobalBoxフィールド → エラー
let shared_var = self.resolve_variable(name)
.map_err(|_| RuntimeError::UndefinedVariableAt {
name: name.clone(),
span: expression.span()
})?;
Ok((*shared_var).clone_box()) // Convert for external interface
}
ASTNode::BinaryOp { operator, left, right, .. } => {
self.execute_binary_op(operator, left, right)
}
ASTNode::UnaryOp { operator, operand, .. } => {
self.execute_unary_op(operator, operand)
}
ASTNode::AwaitExpression { expression, .. } => {
self.execute_await(expression)
}
ASTNode::MethodCall { object, method, arguments, .. } => {
let result = self.execute_method_call(object, method, arguments);
result
}
ASTNode::FieldAccess { object, field, .. } => {
let shared_result = self.execute_field_access(object, field)?;
Ok((*shared_result).clone_box()) // Convert Arc to Box for external interface
}
ASTNode::New { class, arguments, type_arguments, .. } => {
self.execute_new(class, arguments, type_arguments)
}
ASTNode::This { .. } => {
// 🌍 革命的this解決local変数から取得
let shared_this = self.resolve_variable("me")
.map_err(|_| RuntimeError::InvalidOperation {
message: "'this' is only available inside methods".to_string(),
})?;
Ok((*shared_this).clone_box()) // Convert for external interface
}
ASTNode::Me { .. } => {
// 🌍 革命的me解決local変数から取得thisと同じ
let shared_me = self.resolve_variable("me")
.map_err(|_| RuntimeError::InvalidOperation {
message: "'me' is only available inside methods".to_string(),
})?;
Ok((*shared_me).clone_box()) // Convert for external interface
}
ASTNode::ThisField { field, .. } => {
// 🌍 革命的this.fieldアクセスlocal変数から取得
let this_value = self.resolve_variable("me")
.map_err(|_| RuntimeError::InvalidOperation {
message: "'this' is not bound in the current context".to_string(),
})?;
if let Some(instance) = (*this_value).as_any().downcast_ref::<InstanceBox>() {
let shared_field = instance.get_field(field)
.ok_or_else(|| RuntimeError::InvalidOperation {
message: format!("Field '{}' not found on this", field)
})?;
Ok((*shared_field).clone_box()) // Convert for external interface
} else {
Err(RuntimeError::TypeError {
message: "'this' is not an instance".to_string(),
})
}
}
ASTNode::MeField { field, .. } => {
// 🌍 革命的me.fieldアクセスlocal変数から取得
let me_value = self.resolve_variable("me")
.map_err(|_| RuntimeError::InvalidOperation {
message: "'this' is not bound in the current context".to_string(),
})?;
if let Some(instance) = (*me_value).as_any().downcast_ref::<InstanceBox>() {
let shared_field = instance.get_field(field)
.ok_or_else(|| RuntimeError::InvalidOperation {
message: format!("Field '{}' not found on me", field)
})?;
Ok((*shared_field).clone_box()) // Convert for external interface
} else {
Err(RuntimeError::TypeError {
message: "'this' is not an instance".to_string(),
})
}
}
ASTNode::FunctionCall { name, arguments, .. } => {
self.execute_function_call(name, arguments)
}
ASTNode::Arrow { sender, receiver, .. } => {
self.execute_arrow(sender, receiver)
}
ASTNode::Include { filename, .. } => {
self.execute_include(filename)?;
Ok(Box::new(VoidBox::new()))
}
ASTNode::FromCall { parent, method, arguments, .. } => {
self.execute_from_call(parent, method, arguments)
}
_ => Err(RuntimeError::InvalidOperation {
message: format!("Cannot execute {:?} as expression", expression.node_type()),
}),
}
}
/// 二項演算を実行 - Binary operation processing
pub(super) fn execute_binary_op(&mut self, op: &BinaryOperator, left: &ASTNode, right: &ASTNode)
-> Result<Box<dyn NyashBox>, RuntimeError> {
let left_val = self.execute_expression(left)?;
let right_val = self.execute_expression(right)?;
match op {
BinaryOperator::Add => {
// 🚀 New trait-based operator resolution system!
OperatorResolver::resolve_add(left_val.as_ref(), right_val.as_ref())
.map_err(|e| RuntimeError::InvalidOperation { message: e.to_string() })
}
BinaryOperator::Equal => {
let result = left_val.equals(right_val.as_ref());
Ok(Box::new(result))
}
BinaryOperator::NotEqual => {
let result = left_val.equals(right_val.as_ref());
Ok(Box::new(BoolBox::new(!result.value)))
}
BinaryOperator::And => {
let left_bool = self.is_truthy(&left_val);
if !left_bool {
Ok(Box::new(BoolBox::new(false)))
} else {
let right_bool = self.is_truthy(&right_val);
Ok(Box::new(BoolBox::new(right_bool)))
}
}
BinaryOperator::Or => {
let left_bool = self.is_truthy(&left_val);
if left_bool {
Ok(Box::new(BoolBox::new(true)))
} else {
let right_bool = self.is_truthy(&right_val);
Ok(Box::new(BoolBox::new(right_bool)))
}
}
BinaryOperator::Subtract => {
// 🚀 New trait-based subtraction
OperatorResolver::resolve_sub(left_val.as_ref(), right_val.as_ref())
.map_err(|e| RuntimeError::InvalidOperation { message: e.to_string() })
}
BinaryOperator::Multiply => {
// 🚀 New trait-based multiplication
OperatorResolver::resolve_mul(left_val.as_ref(), right_val.as_ref())
.map_err(|e| RuntimeError::InvalidOperation { message: e.to_string() })
}
BinaryOperator::Divide => {
// 🚀 New trait-based division
OperatorResolver::resolve_div(left_val.as_ref(), right_val.as_ref())
.map_err(|e| RuntimeError::InvalidOperation { message: e.to_string() })
}
BinaryOperator::Less => {
let result = CompareBox::less(left_val.as_ref(), right_val.as_ref());
Ok(Box::new(result))
}
BinaryOperator::Greater => {
let result = CompareBox::greater(left_val.as_ref(), right_val.as_ref());
Ok(Box::new(result))
}
BinaryOperator::LessEqual => {
let result = CompareBox::less_equal(left_val.as_ref(), right_val.as_ref());
Ok(Box::new(result))
}
BinaryOperator::GreaterEqual => {
let result = CompareBox::greater_equal(left_val.as_ref(), right_val.as_ref());
Ok(Box::new(result))
}
}
}
/// 単項演算を実行 - Unary operation processing
pub(super) fn execute_unary_op(&mut self, operator: &UnaryOperator, operand: &ASTNode)
-> Result<Box<dyn NyashBox>, RuntimeError> {
let operand_val = self.execute_expression(operand)?;
match operator {
UnaryOperator::Minus => {
// 数値の符号反転
if let Some(int_box) = operand_val.as_any().downcast_ref::<IntegerBox>() {
Ok(Box::new(IntegerBox::new(-int_box.value)))
} else if let Some(float_box) = operand_val.as_any().downcast_ref::<FloatBox>() {
Ok(Box::new(FloatBox::new(-float_box.value)))
} else {
Err(RuntimeError::TypeError {
message: "Unary minus can only be applied to Integer or Float".to_string(),
})
}
}
UnaryOperator::Not => {
// 論理否定
if let Some(bool_box) = operand_val.as_any().downcast_ref::<BoolBox>() {
Ok(Box::new(BoolBox::new(!bool_box.value)))
} else {
// どんな値でもtruthyness判定してnot演算を適用
let is_truthy = self.is_truthy(&operand_val);
Ok(Box::new(BoolBox::new(!is_truthy)))
}
}
}
}
/// メソッド呼び出しを実行 - Method call processing
pub(super) fn execute_method_call(&mut self, object: &ASTNode, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
// 🔥 static関数のチェック
if let ASTNode::Variable { name, .. } = object {
// static関数が存在するかチェック
let static_func = {
let static_funcs = self.shared.static_functions.read().unwrap();
if let Some(box_statics) = static_funcs.get(name) {
if let Some(func) = box_statics.get(method) {
Some(func.clone())
} else {
None
}
} else {
None
}
};
if let Some(static_func) = static_func {
// static関数を実行
if let ASTNode::FunctionDeclaration { params, body, .. } = static_func {
// 引数を評価
let mut arg_values = Vec::new();
for arg in arguments {
arg_values.push(self.execute_expression(arg)?);
}
// パラメータ数チェック
if arg_values.len() != params.len() {
return Err(RuntimeError::InvalidOperation {
message: format!("Static method {}.{} expects {} arguments, got {}",
name, method, params.len(), arg_values.len()),
});
}
// 🌍 local変数スタックを保存・クリアstatic関数呼び出し開始
let saved_locals = self.save_local_vars();
self.local_vars.clear();
// 📤 outbox変数スタックも保存・クリアstatic関数専用
let saved_outbox = self.save_outbox_vars();
self.outbox_vars.clear();
// 引数をlocal変数として設定
for (param, value) in params.iter().zip(arg_values.iter()) {
self.declare_local_variable(param, value.clone_box());
}
// static関数の本体を実行
let mut result = Box::new(VoidBox::new()) as Box<dyn NyashBox>;
for statement in &body {
result = self.execute_statement(statement)?;
// return文チェック
if let super::ControlFlow::Return(return_val) = &self.control_flow {
result = return_val.clone_box();
self.control_flow = super::ControlFlow::None;
break;
}
}
// local変数スタックを復元
self.restore_local_vars(saved_locals);
// outbox変数スタックを復元
self.restore_outbox_vars(saved_outbox);
return Ok(result);
}
}
}
// オブジェクトを評価(通常のメソッド呼び出し)
let obj_value = self.execute_expression(object)?;
// StringBox method calls
if let Some(string_box) = obj_value.as_any().downcast_ref::<StringBox>() {
return self.execute_string_method(string_box, method, arguments);
}
// IntegerBox method calls
if let Some(integer_box) = obj_value.as_any().downcast_ref::<IntegerBox>() {
return self.execute_integer_method(integer_box, method, arguments);
}
// FloatBox method calls
if let Some(float_box) = obj_value.as_any().downcast_ref::<FloatBox>() {
return self.execute_float_method(float_box, method, arguments);
}
// BoolBox method calls
if let Some(bool_box) = obj_value.as_any().downcast_ref::<BoolBox>() {
return self.execute_bool_method(bool_box, method, arguments);
}
// ArrayBox method calls
if let Some(array_box) = obj_value.as_any().downcast_ref::<ArrayBox>() {
return self.execute_array_method(array_box, method, arguments);
}
// BufferBox method calls
if let Some(buffer_box) = obj_value.as_any().downcast_ref::<BufferBox>() {
return self.execute_buffer_method(buffer_box, method, arguments);
}
// FileBox method calls
if let Some(file_box) = obj_value.as_any().downcast_ref::<crate::boxes::file::FileBox>() {
return self.execute_file_method(file_box, method, arguments);
}
// ResultBox method calls
if let Some(result_box) = obj_value.as_any().downcast_ref::<ResultBox>() {
return self.execute_result_method(result_box, method, arguments);
}
// FutureBox method calls
if let Some(future_box) = obj_value.as_any().downcast_ref::<FutureBox>() {
return self.execute_future_method(future_box, method, arguments);
}
// ChannelBox method calls
if let Some(channel_box) = obj_value.as_any().downcast_ref::<ChannelBox>() {
return self.execute_channel_method(channel_box, method, arguments);
}
// JSONBox method calls
if let Some(json_box) = obj_value.as_any().downcast_ref::<JSONBox>() {
return self.execute_json_method(json_box, method, arguments);
}
// HttpClientBox method calls
if let Some(http_box) = obj_value.as_any().downcast_ref::<HttpClientBox>() {
return self.execute_http_method(http_box, method, arguments);
}
// StreamBox method calls
if let Some(stream_box) = obj_value.as_any().downcast_ref::<StreamBox>() {
return self.execute_stream_method(stream_box, method, arguments);
}
// RegexBox method calls
if let Some(regex_box) = obj_value.as_any().downcast_ref::<RegexBox>() {
return self.execute_regex_method(regex_box, method, arguments);
}
// MathBox method calls
if let Some(math_box) = obj_value.as_any().downcast_ref::<MathBox>() {
return self.execute_math_method(math_box, method, arguments);
}
// NullBox method calls
if let Some(null_box) = obj_value.as_any().downcast_ref::<crate::boxes::null_box::NullBox>() {
return self.execute_null_method(null_box, method, arguments);
}
// TimeBox method calls
if let Some(time_box) = obj_value.as_any().downcast_ref::<TimeBox>() {
return self.execute_time_method(time_box, method, arguments);
}
// DateTimeBox method calls
if let Some(datetime_box) = obj_value.as_any().downcast_ref::<DateTimeBox>() {
return self.execute_datetime_method(datetime_box, method, arguments);
}
// TimerBox method calls
if let Some(timer_box) = obj_value.as_any().downcast_ref::<TimerBox>() {
return self.execute_timer_method(timer_box, method, arguments);
}
// MapBox method calls
if let Some(map_box) = obj_value.as_any().downcast_ref::<MapBox>() {
return self.execute_map_method(map_box, method, arguments);
}
// RandomBox method calls
if let Some(random_box) = obj_value.as_any().downcast_ref::<RandomBox>() {
return self.execute_random_method(random_box, method, arguments);
}
// SoundBox method calls
if let Some(sound_box) = obj_value.as_any().downcast_ref::<SoundBox>() {
return self.execute_sound_method(sound_box, method, arguments);
}
// DebugBox method calls
if let Some(debug_box) = obj_value.as_any().downcast_ref::<DebugBox>() {
return self.execute_debug_method(debug_box, method, arguments);
}
// ConsoleBox method calls
if let Some(console_box) = obj_value.as_any().downcast_ref::<crate::boxes::console_box::ConsoleBox>() {
return self.execute_console_method(console_box, method, arguments);
}
// IntentBox method calls
if let Some(intent_box) = obj_value.as_any().downcast_ref::<IntentBox>() {
return self.execute_intent_box_method(intent_box, method, arguments);
}
// SocketBox method calls
if let Some(socket_box) = obj_value.as_any().downcast_ref::<SocketBox>() {
let result = self.execute_socket_method(socket_box, method, arguments)?;
// 🔧 FIX: Update stored variable for stateful SocketBox methods
// These methods modify the SocketBox internal state, so we need to update
// the stored variable/field to ensure subsequent accesses get the updated state
if matches!(method, "bind" | "connect" | "close") {
let updated_instance = socket_box.clone();
match object {
ASTNode::Variable { name, .. } => {
// Handle local variables
if let Some(stored_var) = self.local_vars.get_mut(name) {
*stored_var = Arc::new(updated_instance);
}
},
ASTNode::FieldAccess { object: field_obj, field, .. } => {
// Handle StaticBox fields like me.server
if let ASTNode::Variable { name, .. } = field_obj.as_ref() {
if name == "me" {
if let Ok(me_instance) = self.resolve_variable("me") {
if let Some(instance) = (*me_instance).as_any().downcast_ref::<InstanceBox>() {
let _ = instance.set_field(field, Arc::new(updated_instance));
}
}
}
}
},
_ => {}
}
}
return Ok(result);
}
// HTTPServerBox method calls
if let Some(http_server_box) = obj_value.as_any().downcast_ref::<HTTPServerBox>() {
return self.execute_http_server_method(http_server_box, method, arguments);
}
// HTTPRequestBox method calls
if let Some(http_request_box) = obj_value.as_any().downcast_ref::<HTTPRequestBox>() {
return self.execute_http_request_method(http_request_box, method, arguments);
}
// HTTPResponseBox method calls
if let Some(http_response_box) = obj_value.as_any().downcast_ref::<HTTPResponseBox>() {
return self.execute_http_response_method(http_response_box, method, arguments);
}
// P2PBox method calls - Temporarily disabled
// if let Some(p2p_box) = obj_value.as_any().downcast_ref::<P2PBox>() {
// return self.execute_p2p_box_method(p2p_box, method, arguments);
// }
// EguiBox method calls (非WASM環境のみ)
#[cfg(all(feature = "gui", not(target_arch = "wasm32")))]
if let Some(egui_box) = obj_value.as_any().downcast_ref::<crate::boxes::EguiBox>() {
return self.execute_egui_method(egui_box, method, arguments);
}
// WebDisplayBox method calls (WASM環境のみ)
#[cfg(target_arch = "wasm32")]
if let Some(web_display_box) = obj_value.as_any().downcast_ref::<crate::boxes::WebDisplayBox>() {
return self.execute_web_display_method(web_display_box, method, arguments);
}
// WebConsoleBox method calls (WASM環境のみ)
#[cfg(target_arch = "wasm32")]
if let Some(web_console_box) = obj_value.as_any().downcast_ref::<crate::boxes::WebConsoleBox>() {
return self.execute_web_console_method(web_console_box, method, arguments);
}
// WebCanvasBox method calls (WASM環境のみ)
#[cfg(target_arch = "wasm32")]
if let Some(web_canvas_box) = obj_value.as_any().downcast_ref::<crate::boxes::WebCanvasBox>() {
return self.execute_web_canvas_method(web_canvas_box, method, arguments);
}
// MethodBox method calls
if let Some(method_box) = obj_value.as_any().downcast_ref::<crate::method_box::MethodBox>() {
return self.execute_method_box_method(method_box, method, arguments);
}
// IntegerBox method calls
if let Some(integer_box) = obj_value.as_any().downcast_ref::<IntegerBox>() {
return self.execute_integer_method(integer_box, method, arguments);
}
// FloatBox method calls (将来的に追加予定)
// RangeBox method calls (将来的に追加予定)
// InstanceBox method calls
if let Some(instance) = obj_value.as_any().downcast_ref::<InstanceBox>() {
// 🔥 Usage prohibition guard - check if instance is finalized
if instance.is_finalized() {
return Err(RuntimeError::InvalidOperation {
message: "Instance was finalized; further use is prohibited".to_string(),
});
}
// fini()は特別処理
if method == "fini" {
// 🔥 weak-fini prohibition check - prevent fini() on weak fields
if let ASTNode::FieldAccess { object: field_object, field, .. } = object {
// Check if this is me.<field>.fini() pattern
if let ASTNode::Variable { name, .. } = field_object.as_ref() {
if name == "me" {
// Get current instance to check if field is weak
if let Ok(current_me) = self.resolve_variable("me") {
if let Some(current_instance) = (*current_me).as_any().downcast_ref::<InstanceBox>() {
if current_instance.is_weak_field(field) {
return Err(RuntimeError::InvalidOperation {
message: format!(
"Cannot finalize weak field '{}' (non-owning reference)",
field
),
});
}
}
}
}
}
}
// 既に解放済みの場合は何もしない二重fini()対策)
if instance.is_finalized() {
return Ok(Box::new(VoidBox::new()));
}
// まず、Box内で定義されたfini()メソッドがあれば実行
if let Some(fini_method) = instance.get_method("fini") {
if let ASTNode::FunctionDeclaration { body, .. } = fini_method.clone() {
// 🌍 革命的メソッド実行local変数スタックを使用
let saved_locals = self.save_local_vars();
self.local_vars.clear();
// thisをlocal変数として設定
self.declare_local_variable("me", obj_value.clone_box());
// fini()メソッドの本体を実行
let mut _result = Box::new(VoidBox::new()) as Box<dyn NyashBox>;
for statement in &body {
_result = self.execute_statement(statement)?;
// return文チェック
if let super::ControlFlow::Return(_) = &self.control_flow {
self.control_flow = super::ControlFlow::None;
break;
}
}
// local変数スタックを復元
self.restore_local_vars(saved_locals);
}
}
// インスタンスの内部的な解放処理
instance.fini().map_err(|e| RuntimeError::InvalidOperation {
message: e,
})?;
finalization::mark_as_finalized(instance.box_id());
return Ok(Box::new(VoidBox::new()));
}
// メソッドを取得
let method_ast = instance.get_method(method)
.ok_or(RuntimeError::InvalidOperation {
message: format!("Method '{}' not found in {}", method, instance.class_name),
})?
.clone();
// メソッドが関数宣言の形式であることを確認
if let ASTNode::FunctionDeclaration { params, body, .. } = method_ast {
// 🚨 FIX: 引数評価を完全に現在のコンテキストで完了させる
let mut arg_values = Vec::new();
for (i, arg) in arguments.iter().enumerate() {
let arg_value = self.execute_expression(arg)?;
arg_values.push(arg_value);
}
// パラメータ数チェック
if arg_values.len() != params.len() {
return Err(RuntimeError::InvalidOperation {
message: format!("Method {} expects {} arguments, got {}",
method, params.len(), arg_values.len()),
});
}
// 🌍 NOW SAFE: すべての引数評価完了後にコンテキスト切り替え
let saved_locals = self.save_local_vars();
self.local_vars.clear();
// thisをlocal変数として設定
self.declare_local_variable("me", obj_value.clone_box());
// パラメータをlocal変数として設定
for (param, value) in params.iter().zip(arg_values.iter()) {
self.declare_local_variable(param, value.clone_box());
}
// メソッド本体を実行
let mut result: Box<dyn NyashBox> = Box::new(VoidBox::new());
for statement in &body {
result = self.execute_statement(statement)?;
// return文チェック
if let super::ControlFlow::Return(return_val) = &self.control_flow {
result = return_val.clone_box();
self.control_flow = super::ControlFlow::None;
break;
}
}
// local変数スタックを復元
self.restore_local_vars(saved_locals);
Ok(result)
} else {
Err(RuntimeError::InvalidOperation {
message: format!("Method '{}' is not a valid function declaration", method),
})
}
} else {
Err(RuntimeError::TypeError {
message: format!("Cannot call method '{}' on non-instance type", method),
})
}
}
/// フィールドアクセスを実行 - Field access processing with weak reference support
pub(super) fn execute_field_access(&mut self, object: &ASTNode, field: &str)
-> Result<SharedNyashBox, RuntimeError> {
// 🔥 Static Boxアクセスチェック
if let ASTNode::Variable { name, .. } = object {
// Static boxの可能性をチェック
if self.is_static_box(name) {
let static_result = self.execute_static_field_access(name, field)?;
return Ok(Arc::from(static_result));
}
}
// オブジェクトを評価(通常のフィールドアクセス)
let obj_value = self.execute_expression(object);
let obj_value = obj_value?;
// InstanceBoxにキャスト
if let Some(instance) = obj_value.as_any().downcast_ref::<InstanceBox>() {
// 🔥 Usage prohibition guard - check if instance is finalized
if instance.is_finalized() {
return Err(RuntimeError::InvalidOperation {
message: "Instance was finalized; further use is prohibited".to_string(),
});
}
// フィールドの値を取得
let field_value = instance.get_field(field)
.ok_or(RuntimeError::InvalidOperation {
message: format!("Field '{}' not found in {}", field, instance.class_name),
})?;
eprintln!("✅ FIELD ACCESS: Returning shared reference id={}", field_value.box_id());
// 🔗 Weak Reference Check: Use unified accessor for weak fields
let box_decls = self.shared.box_declarations.read().unwrap();
if let Some(box_decl) = box_decls.get(&instance.class_name) {
if box_decl.weak_fields.contains(&field.to_string()) {
eprintln!("🔗 DEBUG: Accessing weak field '{}' in class '{}'", field, instance.class_name);
// 🎯 PHASE 2: Use unified accessor for auto-nil weak reference handling
if let Some(weak_value) = instance.get_weak_field(field, self) { // Pass self
match &weak_value {
crate::value::NyashValue::Null => {
eprintln!("🔗 DEBUG: Weak field '{}' is null (reference dropped)", field);
// Return null box for compatibility
return Ok(Arc::new(crate::boxes::null_box::NullBox::new()));
}
_ => {
eprintln!("🔗 DEBUG: Weak field '{}' still has valid reference", field);
// Convert back to Box<dyn NyashBox> for now
if let Ok(box_value) = weak_value.to_box() {
if let Ok(inner_box) = box_value.try_lock() {
return Ok(Arc::from(inner_box.clone_box()));
}
}
}
}
}
// If weak field access failed, fall through to normal access
}
}
// Return the shared Arc reference directly
Ok(field_value)
} else {
Err(RuntimeError::TypeError {
message: format!("Cannot access field '{}' on non-instance type. Type: {}", field, obj_value.type_name()),
})
}
}
/// 🔥 Static Box名前空間のフィールドアクセス
fn execute_static_field_access(&mut self, static_box_name: &str, field: &str)
-> Result<Box<dyn NyashBox>, RuntimeError> {
// 1. Static Boxの初期化を確実に実行
self.ensure_static_box_initialized(static_box_name)?;
// 2. GlobalBox.statics.{static_box_name} からインスタンスを取得
let global_box = self.shared.global_box.lock()
.map_err(|_| RuntimeError::RuntimeFailure {
message: "Failed to acquire global box lock".to_string()
})?;
let statics_box = global_box.get_field("statics")
.ok_or(RuntimeError::RuntimeFailure {
message: "statics namespace not found in GlobalBox".to_string()
})?;
let statics_instance = statics_box.as_any()
.downcast_ref::<InstanceBox>()
.ok_or(RuntimeError::TypeError {
message: "statics field is not an InstanceBox".to_string()
})?;
let static_box_instance = statics_instance.get_field(static_box_name)
.ok_or(RuntimeError::RuntimeFailure {
message: format!("Static box '{}' instance not found in statics namespace", static_box_name)
})?;
let instance = static_box_instance.as_any()
.downcast_ref::<InstanceBox>()
.ok_or(RuntimeError::TypeError {
message: format!("Static box '{}' is not an InstanceBox", static_box_name)
})?;
// 3. フィールドアクセス
let shared_field = instance.get_field(field)
.ok_or(RuntimeError::InvalidOperation {
message: format!("Field '{}' not found in static box '{}'", field, static_box_name),
})?;
// Convert Arc to Box for compatibility
Ok((*shared_field).clone_box())
}
/// await式を実行 - Execute await expression
pub(super) fn execute_await(&mut self, expression: &ASTNode) -> Result<Box<dyn NyashBox>, RuntimeError> {
let value = self.execute_expression(expression)?;
// FutureBoxなら待機して結果を取得
if let Some(future) = value.as_any().downcast_ref::<FutureBox>() {
future.wait_and_get()
.map_err(|msg| RuntimeError::InvalidOperation { message: msg })
} else {
// FutureBoxでなければそのまま返す
Ok(value)
}
}
/// 🔄 循環参照検出: オブジェクトの一意IDを取得
fn get_object_id(&self, node: &ASTNode) -> Option<usize> {
match node {
ASTNode::Variable { name, .. } => {
// 変数名のハッシュをIDとして使用
Some(self.hash_string(name))
}
ASTNode::Me { .. } => {
// 'me'参照の特別なID
Some(usize::MAX)
}
ASTNode::This { .. } => {
// 'this'参照の特別なID
Some(usize::MAX - 1)
}
_ => None, // 他のードタイプはID追跡しない
}
}
/// 🔄 文字列のシンプルなハッシュ関数
fn hash_string(&self, s: &str) -> usize {
let mut hash = 0usize;
for byte in s.bytes() {
hash = hash.wrapping_mul(31).wrapping_add(byte as usize);
}
hash
}
/// 🔗 Convert NyashBox to NyashValue for weak reference operations
// fn box_to_nyash_value(&self, box_val: &Box<dyn NyashBox>) -> Option<nyash_rust::value::NyashValue> {
// // Try to convert the box back to NyashValue for weak reference operations
// // This is a simplified conversion - in reality we might need more sophisticated logic
// use nyash_rust::value::NyashValue;
// use crate::box_trait::{StringBox, IntegerBox, BoolBox, VoidBox};
//
// if let Some(string_box) = box_val.as_any().downcast_ref::<StringBox>() {
// Some(NyashValue::String(string_box.value.clone()))
// } else if let Some(int_box) = box_val.as_any().downcast_ref::<IntegerBox>() {
// Some(NyashValue::Integer(int_box.value))
// } else if let Some(bool_box) = box_val.as_any().downcast_ref::<BoolBox>() {
// Some(NyashValue::Bool(bool_box.value))
// } else if box_val.as_any().downcast_ref::<VoidBox>().is_some() {
// Some(NyashValue::Void)
// } else if box_val.as_any().downcast_ref::<crate::boxes::null_box::NullBox>().is_some() {
// Some(NyashValue::Null)
// } else {
// // For complex types, create a Box variant
// // Note: This is where we'd store the weak reference
// None // Simplified for now
// }
// }
/// 🔥 FromCall実行処理 - from Parent.method(arguments) or from Parent.constructor(arguments)
pub(super) fn execute_from_call(&mut self, parent: &str, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
// 1. 現在のコンテキストで'me'変数を取得(現在のインスタンス)
let current_instance_val = self.resolve_variable("me")
.map_err(|_| RuntimeError::InvalidOperation {
message: "'from' can only be used inside methods".to_string(),
})?;
let current_instance = (*current_instance_val).as_any().downcast_ref::<InstanceBox>()
.ok_or(RuntimeError::TypeError {
message: "'from' requires current instance to be InstanceBox".to_string(),
})?;
// 2. 現在のクラスのデリゲーション関係を検証
let current_class = &current_instance.class_name;
let box_declarations = self.shared.box_declarations.read().unwrap();
let current_box_decl = box_declarations.get(current_class)
.ok_or(RuntimeError::UndefinedClass {
name: current_class.clone()
})?;
// extendsまたはimplementsでparentが指定されているか確認 (Multi-delegation) 🚀
let is_valid_delegation = current_box_decl.extends.contains(&parent.to_string()) ||
current_box_decl.implements.contains(&parent.to_string());
if !is_valid_delegation {
return Err(RuntimeError::InvalidOperation {
message: format!("Class '{}' does not delegate to '{}'. Use 'box {} from {}' to establish delegation.",
current_class, parent, current_class, parent),
});
}
// 🔥 ビルトインBoxかチェック
let mut builtin_boxes = vec![
"IntegerBox", "StringBox", "BoolBox", "ArrayBox", "MapBox",
"FileBox", "ResultBox", "FutureBox", "ChannelBox", "MathBox",
"TimeBox", "DateTimeBox", "TimerBox", "RandomBox", "SoundBox",
"DebugBox", "MethodBox", "NullBox", "ConsoleBox", "FloatBox",
"BufferBox", "RegexBox", "JSONBox", "StreamBox", "HTTPClientBox",
"IntentBox", "P2PBox", "SocketBox", "HTTPServerBox", "HTTPRequestBox", "HTTPResponseBox"
];
#[cfg(all(feature = "gui", not(target_arch = "wasm32")))]
builtin_boxes.push("EguiBox");
let is_builtin = builtin_boxes.contains(&parent);
if is_builtin {
// ビルトインBoxの場合、ロックを解放してからメソッド呼び出し
drop(box_declarations);
return self.execute_builtin_box_method(parent, method, current_instance_val.clone_box(), arguments);
}
// 3. 親クラスのBox宣言を取得ユーザー定義Boxの場合
let parent_box_decl = box_declarations.get(parent)
.ok_or(RuntimeError::UndefinedClass {
name: parent.to_string()
})?
.clone();
drop(box_declarations); // ロック早期解放
// 4. constructorまたはinitまたはpackの場合の特別処理
if method == "constructor" || method == "init" || method == "pack" || method == parent {
return self.execute_from_parent_constructor(parent, &parent_box_decl, current_instance_val.clone_box(), arguments);
}
// 5. 親クラスのメソッドを取得
let parent_method = parent_box_decl.methods.get(method)
.ok_or(RuntimeError::InvalidOperation {
message: format!("Method '{}' not found in parent class '{}'", method, parent),
})?
.clone();
// 6. 引数を評価
let mut arg_values = Vec::new();
for arg in arguments {
arg_values.push(self.execute_expression(arg)?);
}
// 7. 親メソッドを実行
if let ASTNode::FunctionDeclaration { params, body, .. } = parent_method {
// パラメータ数チェック
if arg_values.len() != params.len() {
return Err(RuntimeError::InvalidOperation {
message: format!("Parent method {}.{} expects {} arguments, got {}",
parent, method, params.len(), arg_values.len()),
});
}
// 🌍 local変数スタックを保存・クリア親メソッド実行開始
let saved_locals = self.save_local_vars();
self.local_vars.clear();
// 'me'を現在のインスタンスに設定(重要:現在のインスタンスを維持)
self.declare_local_variable("me", current_instance_val.clone_box());
// 引数をlocal変数として設定
for (param, value) in params.iter().zip(arg_values.iter()) {
self.declare_local_variable(param, value.clone_box());
}
// 親メソッドの本体を実行
let mut result: Box<dyn NyashBox> = Box::new(VoidBox::new());
for statement in &body {
result = self.execute_statement(statement)?;
// return文チェック
if let super::ControlFlow::Return(return_val) = &self.control_flow {
result = return_val.clone_box();
self.control_flow = super::ControlFlow::None;
break;
}
}
// 🔍 DEBUG: FromCall実行結果をログ出力
eprintln!("🔍 DEBUG: FromCall {}.{} result: {}", parent, method, result.to_string_box().value);
// local変数スタックを復元
self.restore_local_vars(saved_locals);
Ok(result)
} else {
Err(RuntimeError::InvalidOperation {
message: format!("Parent method '{}' is not a valid function declaration", method),
})
}
}
/// 🔥 fromCall専用親コンストラクタ実行処理 - from Parent.constructor(arguments)
fn execute_from_parent_constructor(&mut self, parent: &str, parent_box_decl: &super::BoxDeclaration,
current_instance: Box<dyn NyashBox>, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
// 1. 親クラスのコンストラクタを取得(引数の数でキーを作成)
// "pack/引数数"、"init/引数数"、"Box名/引数数" の順で試す
let pack_key = format!("pack/{}", arguments.len());
let init_key = format!("init/{}", arguments.len());
let box_name_key = format!("{}/{}", parent, arguments.len());
let parent_constructor = parent_box_decl.constructors.get(&pack_key)
.or_else(|| parent_box_decl.constructors.get(&init_key))
.or_else(|| parent_box_decl.constructors.get(&box_name_key))
.ok_or(RuntimeError::InvalidOperation {
message: format!("No constructor found for parent class '{}' with {} arguments", parent, arguments.len()),
})?
.clone();
// 2. 引数を評価
let mut arg_values = Vec::new();
for arg in arguments {
arg_values.push(self.execute_expression(arg)?);
}
// 3. 親コンストラクタを実行
if let ASTNode::FunctionDeclaration { params, body, .. } = parent_constructor {
// パラメータ数チェック
if arg_values.len() != params.len() {
return Err(RuntimeError::InvalidOperation {
message: format!("Parent constructor {} expects {} arguments, got {}",
parent, params.len(), arg_values.len()),
});
}
// 🌍 local変数スタックを保存・クリア親コンストラクタ実行開始
let saved_locals = self.save_local_vars();
self.local_vars.clear();
// 'me'を現在のインスタンスに設定
self.declare_local_variable("me", current_instance.clone_box());
// 引数をlocal変数として設定
for (param, value) in params.iter().zip(arg_values.iter()) {
self.declare_local_variable(param, value.clone_box());
}
// 親コンストラクタの本体を実行
let mut result: Box<dyn NyashBox> = Box::new(VoidBox::new());
for statement in &body {
result = self.execute_statement(statement)?;
// return文チェック
if let super::ControlFlow::Return(return_val) = &self.control_flow {
result = return_val.clone_box();
self.control_flow = super::ControlFlow::None;
break;
}
}
// local変数スタックを復元
self.restore_local_vars(saved_locals);
// 親コンストラクタは通常現在のインスタンスを返す
Ok(current_instance)
} else {
Err(RuntimeError::InvalidOperation {
message: format!("Parent constructor is not a valid function declaration"),
})
}
}
/// 🔥 ビルトインBoxのメソッド呼び出し
fn execute_builtin_box_method(&mut self, parent: &str, method: &str, mut current_instance: Box<dyn NyashBox>, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
// ビルトインBoxのインスタンスを作成または取得
// 現在のインスタンスからビルトインBoxのデータを取得し、ビルトインBoxとしてメソッド実行
match parent {
"StringBox" => {
// StringBoxのインスタンスを作成デフォルト値
let string_box = StringBox::new("");
self.execute_string_method(&string_box, method, arguments)
}
"IntegerBox" => {
// IntegerBoxのインスタンスを作成デフォルト値
let integer_box = IntegerBox::new(0);
self.execute_integer_method(&integer_box, method, arguments)
}
"ArrayBox" => {
let array_box = ArrayBox::new();
self.execute_array_method(&array_box, method, arguments)
}
"MapBox" => {
let map_box = MapBox::new();
self.execute_map_method(&map_box, method, arguments)
}
"MathBox" => {
let math_box = MathBox::new();
self.execute_math_method(&math_box, method, arguments)
}
"P2PBox" => {
// P2PBoxの場合、現在のインスタンスからP2PBoxインスタンスを取得する必要がある
// TODO: 現在のインスタンスのフィールドからP2PBoxを取得
return Err(RuntimeError::InvalidOperation {
message: format!("P2PBox delegation not yet fully implemented: {}.{}", parent, method),
});
}
"FileBox" => {
let file_box = crate::boxes::file::FileBox::new();
self.execute_file_method(&file_box, method, arguments)
}
"ConsoleBox" => {
let console_box = ConsoleBox::new();
self.execute_console_method(&console_box, method, arguments)
}
"TimeBox" => {
let time_box = TimeBox::new();
self.execute_time_method(&time_box, method, arguments)
}
"RandomBox" => {
let random_box = RandomBox::new();
self.execute_random_method(&random_box, method, arguments)
}
"DebugBox" => {
let debug_box = DebugBox::new();
self.execute_debug_method(&debug_box, method, arguments)
}
"SoundBox" => {
let sound_box = SoundBox::new();
self.execute_sound_method(&sound_box, method, arguments)
}
"SocketBox" => {
let socket_box = SocketBox::new();
self.execute_socket_method(&socket_box, method, arguments)
}
"HTTPServerBox" => {
let http_server_box = HTTPServerBox::new();
self.execute_http_server_method(&http_server_box, method, arguments)
}
"HTTPRequestBox" => {
let http_request_box = HTTPRequestBox::new();
self.execute_http_request_method(&http_request_box, method, arguments)
}
"HTTPResponseBox" => {
let http_response_box = HTTPResponseBox::new();
self.execute_http_response_method(&http_response_box, method, arguments)
}
_ => {
Err(RuntimeError::InvalidOperation {
message: format!("Unknown built-in Box type for delegation: {}", parent),
})
}
}
}
}