Files
hakorune/src/interpreter/expressions/access.rs

170 lines
7.5 KiB
Rust
Raw Normal View History

/*!
* 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));
}
}
feat: Implement field visibility (public/private) system ## Major Features Added ### Field Visibility System - Added `private { ... }` and `public { ... }` blocks in box declarations - Default visibility is now handled explicitly (fields must be in either block) - Visibility checks enforced at both interpreter and VM levels ### Parser Enhancements - Extended AST with public_fields and private_fields vectors - Added parsing for visibility blocks in box definitions - Maintained backward compatibility with existing `init { ... }` syntax ### Interpreter Implementation - Added visibility checks in field access (get_field/set_field) - External access to private fields now throws appropriate errors - Internal access (within methods) always allowed ### VM Implementation - Extended VM with object_class tracking for visibility checks - RefGet/RefSet instructions now enforce field visibility - Fixed nested box declaration collection (boxes defined inside methods) ### Test Examples Added - docs/examples/visibility_ok.nyash - demonstrates correct usage - docs/examples/visibility_error.nyash - tests private field access errors ## Technical Details ### Error Messages - Interpreter: "Field 'X' is private in Y" - VM: Same error message for consistency ### Current Limitations - All RefGet/RefSet treated as external access in VM (internal flag future work) - Legacy `init { ... }` fields treated as having unspecified visibility ## Test Results ✅ Interpreter: Both test cases pass correctly ✅ VM: Both test cases pass correctly after nested declaration fix This implements the foundation for proper encapsulation in Nyash, following the "explicit is better than implicit" philosophy. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-21 03:08:13 +09:00
// 外からのフィールドアクセスか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>() {
feat: Implement field visibility (public/private) system ## Major Features Added ### Field Visibility System - Added `private { ... }` and `public { ... }` blocks in box declarations - Default visibility is now handled explicitly (fields must be in either block) - Visibility checks enforced at both interpreter and VM levels ### Parser Enhancements - Extended AST with public_fields and private_fields vectors - Added parsing for visibility blocks in box definitions - Maintained backward compatibility with existing `init { ... }` syntax ### Interpreter Implementation - Added visibility checks in field access (get_field/set_field) - External access to private fields now throws appropriate errors - Internal access (within methods) always allowed ### VM Implementation - Extended VM with object_class tracking for visibility checks - RefGet/RefSet instructions now enforce field visibility - Fixed nested box declaration collection (boxes defined inside methods) ### Test Examples Added - docs/examples/visibility_ok.nyash - demonstrates correct usage - docs/examples/visibility_error.nyash - tests private field access errors ## Technical Details ### Error Messages - Interpreter: "Field 'X' is private in Y" - VM: Same error message for consistency ### Current Limitations - All RefGet/RefSet treated as external access in VM (internal flag future work) - Legacy `init { ... }` fields treated as having unspecified visibility ## Test Results ✅ Interpreter: Both test cases pass correctly ✅ VM: Both test cases pass correctly after nested declaration fix This implements the foundation for proper encapsulation in Nyash, following the "explicit is better than implicit" philosophy. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-21 03:08:13 +09:00
// 可視性チェック(互換性: 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
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)
}
}
feat: Implement field visibility (public/private) system ## Major Features Added ### Field Visibility System - Added `private { ... }` and `public { ... }` blocks in box declarations - Default visibility is now handled explicitly (fields must be in either block) - Visibility checks enforced at both interpreter and VM levels ### Parser Enhancements - Extended AST with public_fields and private_fields vectors - Added parsing for visibility blocks in box definitions - Maintained backward compatibility with existing `init { ... }` syntax ### Interpreter Implementation - Added visibility checks in field access (get_field/set_field) - External access to private fields now throws appropriate errors - Internal access (within methods) always allowed ### VM Implementation - Extended VM with object_class tracking for visibility checks - RefGet/RefSet instructions now enforce field visibility - Fixed nested box declaration collection (boxes defined inside methods) ### Test Examples Added - docs/examples/visibility_ok.nyash - demonstrates correct usage - docs/examples/visibility_error.nyash - tests private field access errors ## Technical Details ### Error Messages - Interpreter: "Field 'X' is private in Y" - VM: Same error message for consistency ### Current Limitations - All RefGet/RefSet treated as external access in VM (internal flag future work) - Legacy `init { ... }` fields treated as having unspecified visibility ## Test Results ✅ Interpreter: Both test cases pass correctly ✅ VM: Both test cases pass correctly after nested declaration fix This implements the foundation for proper encapsulation in Nyash, following the "explicit is better than implicit" philosophy. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-21 03:08:13 +09:00
}