- TypeBox ABI雛形: メソッドスロット管理システム追加 - Type Registry: Array/Map/StringBoxの基本メソッド定義 - Host API: C ABI逆呼び出しシステム実装 - Phase 12ドキュメント整理: 設計文書統合・アーカイブ化 - MIR Builder: クリーンアップと分離実装完了 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
180 lines
8.1 KiB
Rust
180 lines
8.1 KiB
Rust
/*!
|
||
* Field access operations
|
||
*/
|
||
|
||
// Removed super::* import - specific imports below
|
||
use crate::ast::ASTNode;
|
||
use crate::box_trait::{NyashBox, SharedNyashBox};
|
||
use crate::boxes::FutureBox;
|
||
use crate::instance_v2::InstanceBox;
|
||
use crate::interpreter::{NyashInterpreter, RuntimeError};
|
||
use std::sync::Arc;
|
||
|
||
// Conditional debug macro - only outputs if NYASH_DEBUG=1 environment variable is set
|
||
macro_rules! debug_trace {
|
||
($($arg:tt)*) => {
|
||
if std::env::var("NYASH_DEBUG").unwrap_or_default() == "1" {
|
||
eprintln!($($arg)*);
|
||
}
|
||
};
|
||
}
|
||
|
||
impl NyashInterpreter {
|
||
/// フィールドアクセスを実行 - 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));
|
||
}
|
||
}
|
||
|
||
|
||
// 外からのフィールドアクセスか(me/this以外)を判定
|
||
let is_internal_access = match object {
|
||
ASTNode::This { .. } | ASTNode::Me { .. } => true,
|
||
ASTNode::Variable { name, .. } if name == "me" => true,
|
||
_ => false,
|
||
};
|
||
|
||
// オブジェクトを評価(通常のフィールドアクセス)
|
||
let obj_value = self.execute_expression(object);
|
||
|
||
let obj_value = obj_value?;
|
||
|
||
// InstanceBoxにキャスト
|
||
if let Some(instance) = obj_value.as_any().downcast_ref::<InstanceBox>() {
|
||
// 可視性チェック(互換性: public/privateのどちらかが定義されていれば強制)
|
||
if !is_internal_access {
|
||
let box_decls = self.shared.box_declarations.read().unwrap();
|
||
if let Some(box_decl) = box_decls.get(&instance.class_name) {
|
||
let has_visibility = !box_decl.public_fields.is_empty() || !box_decl.private_fields.is_empty();
|
||
if has_visibility {
|
||
if !box_decl.public_fields.contains(&field.to_string()) {
|
||
return Err(RuntimeError::InvalidOperation {
|
||
message: format!("Field '{}' is private in {}", field, instance.class_name),
|
||
});
|
||
}
|
||
}
|
||
}
|
||
}
|
||
// 🔥 finiは何回呼ばれてもエラーにしない(ユーザー要求)
|
||
// is_finalized()チェックを削除
|
||
|
||
// フィールドの値を取得
|
||
let field_value = instance.get_field(field)
|
||
.ok_or(RuntimeError::InvalidOperation {
|
||
message: format!("Field '{}' not found in {}", field, instance.class_name),
|
||
})?;
|
||
|
||
// 🔗 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()) {
|
||
|
||
// 🎯 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 => {
|
||
debug_trace!("🔗 DEBUG: Weak field '{}' is null (reference dropped)", field);
|
||
// Return null box for compatibility
|
||
return Ok(Arc::new(crate::boxes::null_box::NullBox::new()));
|
||
}
|
||
_ => {
|
||
debug_trace!("🔗 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_or_share()));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
// 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_or_share())
|
||
}
|
||
|
||
|
||
/// await式を実行 - Execute await expression (Result.Ok/Err統一)
|
||
pub(super) fn execute_await(&mut self, expression: &ASTNode) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||
let value = self.execute_expression(expression)?;
|
||
if let Some(future) = value.as_any().downcast_ref::<FutureBox>() {
|
||
let max_ms: u64 = crate::config::env::await_max_ms();
|
||
let start = std::time::Instant::now();
|
||
let mut spins = 0usize;
|
||
while !future.ready() {
|
||
crate::runtime::global_hooks::safepoint_and_poll();
|
||
std::thread::yield_now();
|
||
spins += 1;
|
||
if spins % 1024 == 0 { std::thread::sleep(std::time::Duration::from_millis(1)); }
|
||
if start.elapsed() >= std::time::Duration::from_millis(max_ms) {
|
||
let err = Box::new(crate::box_trait::StringBox::new("Timeout"));
|
||
return Ok(Box::new(crate::boxes::result::NyashResultBox::new_err(err)));
|
||
}
|
||
}
|
||
let v = future.get();
|
||
Ok(Box::new(crate::boxes::result::NyashResultBox::new_ok(v)))
|
||
} else {
|
||
Ok(Box::new(crate::boxes::result::NyashResultBox::new_ok(value)))
|
||
}
|
||
}
|
||
}
|