diff --git a/src/instance.rs b/src/instance.rs index f3d9c515..0fe438ad 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -34,14 +34,24 @@ pub struct InstanceBox { /// 解放済みフラグ finalized: Arc>, + + /// 🔥 Phase 2: finiシステム完全実装 - ChatGPT5設計 + /// init宣言順序(決定的カスケード用) + init_field_order: Vec, + + /// weak フィールド高速判定用 + weak_fields_union: std::collections::HashSet, + + /// 解放中フラグ(再入防止) + in_finalization: Arc>, } impl InstanceBox { pub fn new(class_name: String, fields: Vec, methods: HashMap) -> Self { // フィールドをVoidBoxで初期化 let mut field_map = HashMap::new(); - for field in fields { - field_map.insert(field, Box::new(VoidBox::new()) as Box); + for field in &fields { + field_map.insert(field.clone(), Box::new(VoidBox::new()) as Box); } Self { @@ -51,6 +61,39 @@ impl InstanceBox { methods: Arc::new(methods), base: BoxBase::new(), finalized: Arc::new(Mutex::new(false)), + init_field_order: fields.clone(), // 🔥 Basic field order for backwards compatibility + weak_fields_union: std::collections::HashSet::new(), // 🔥 Empty for backwards compatibility + in_finalization: Arc::new(Mutex::new(false)), // 🔥 Initialize finalization guard + } + } + + /// 🔥 Enhanced constructor with complete fini system support + pub fn new_with_box_info( + class_name: String, + fields: Vec, + methods: HashMap, + init_field_order: Vec, + weak_fields: Vec + ) -> Self { + // フィールドをVoidBoxで初期化 + let mut field_map = HashMap::new(); + for field in &fields { + field_map.insert(field.clone(), Box::new(VoidBox::new()) as Box); + } + + // Weak fields をHashSetに変換(高速判定用) + let weak_fields_union: std::collections::HashSet = weak_fields.into_iter().collect(); + + Self { + class_name, + fields: Arc::new(Mutex::new(field_map)), + fields_ng: Arc::new(Mutex::new(HashMap::new())), + methods: Arc::new(methods), + base: BoxBase::new(), + finalized: Arc::new(Mutex::new(false)), + init_field_order, // 🔥 決定的カスケード順序 + weak_fields_union, // 🔥 高速weak判定 + in_finalization: Arc::new(Mutex::new(false)), // 🔥 再入防止 } } @@ -290,19 +333,75 @@ impl InstanceBox { Ok(()) } - /// fini()メソッド - インスタンスの解放 + /// 🔥 Enhanced fini()メソッド - ChatGPT5設計による完全実装 pub fn fini(&self) -> Result<(), String> { + // 1) finalized チェック(idempotent) let mut finalized = self.finalized.lock().unwrap(); if *finalized { // 既に解放済みなら何もしない return Ok(()); } - *finalized = true; + // 2) in_finalization = true(再入防止) + let mut in_finalization = self.in_finalization.lock().unwrap(); + if *in_finalization { + return Err("Circular finalization detected - fini() called recursively".to_string()); + } + *in_finalization = true; - // フィールドをクリア + // 3) TODO: ユーザー定義fini()実行(インタープリター側で実装予定) + // このメソッドは低レベルなfini処理なので、高レベルなユーザー定義fini()は + // インタープリター側で先に呼び出される想定 + + // 4) 自動カスケード: init_field_order の強参照フィールドに child.fini() + self.cascade_finalize_fields()?; + + // 5) 全フィールドクリア + finalized = true let mut fields = self.fields.lock().unwrap(); fields.clear(); + let mut fields_ng = self.fields_ng.lock().unwrap(); + fields_ng.clear(); + + *finalized = true; + *in_finalization = false; // 再入フラグをクリア + + eprintln!("🔥 fini(): Instance {} (ID: {}) finalized", self.class_name, self.base.id); + Ok(()) + } + + /// 🔥 自動カスケード解放 - init宣言順でフィールドをfini + fn cascade_finalize_fields(&self) -> Result<(), String> { + let fields_ng = self.fields_ng.lock().unwrap(); + + // init_field_order の逆順でfiniを実行(LIFO - Last In First Out) + for field_name in self.init_field_order.iter().rev() { + // weak フィールドはスキップ + if self.weak_fields_union.contains(field_name) { + eprintln!("🔥 fini(): Skipping weak field '{}' (non-owning reference)", field_name); + continue; + } + + // フィールドの値を取得してfini呼び出し + if let Some(field_value) = fields_ng.get(field_name) { + match field_value { + crate::value::NyashValue::Box(arc_box) => { + if let Ok(inner_box) = arc_box.try_lock() { + // InstanceBoxならfini()を呼び出し + if let Some(instance) = inner_box.as_any().downcast_ref::() { + eprintln!("🔥 fini(): Cascading finalization to field '{}'", field_name); + if let Err(e) = instance.fini() { + eprintln!("🔥 fini(): Warning - failed to finalize field '{}': {}", field_name, e); + // エラーは警告として記録するが、続行する + } + } + } + } + _ => { + // non-Box値はfini不要 + } + } + } + } Ok(()) } @@ -311,6 +410,16 @@ impl InstanceBox { pub fn is_finalized(&self) -> bool { *self.finalized.lock().unwrap() } + + /// 🔥 解放中かチェック + pub fn is_in_finalization(&self) -> bool { + *self.in_finalization.lock().unwrap() + } + + /// 🔥 指定フィールドがweakかチェック + pub fn is_weak_field(&self, field_name: &str) -> bool { + self.weak_fields_union.contains(field_name) + } } impl NyashBox for InstanceBox { diff --git a/src/interpreter/expressions.rs b/src/interpreter/expressions.rs index 9b7b713c..cf890634 100644 --- a/src/interpreter/expressions.rs +++ b/src/interpreter/expressions.rs @@ -498,8 +498,37 @@ impl NyashInterpreter { // InstanceBox method calls if let Some(instance) = obj_value.as_any().downcast_ref::() { + // 🔥 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..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::() { + 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())); @@ -625,6 +654,13 @@ impl NyashInterpreter { // InstanceBoxにキャスト if let Some(instance) = obj_value.as_any().downcast_ref::() { + // 🔥 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 { diff --git a/src/interpreter/objects.rs b/src/interpreter/objects.rs index ec79e2e4..b03c5e88 100644 --- a/src/interpreter/objects.rs +++ b/src/interpreter/objects.rs @@ -650,11 +650,17 @@ impl NyashInterpreter { // 継承チェーンを解決してフィールドとメソッドを収集(init_fieldsも含む) let (all_fields, all_methods) = self.resolve_inheritance(&final_box_decl)?; - // インスタンスを作成 - let instance = InstanceBox::new( + // 🔥 フィールド順序と weak フィールドを準備(finiシステム用) + let init_field_order = final_box_decl.init_fields.clone(); + let weak_fields = final_box_decl.weak_fields.clone(); + + // インスタンスを作成(Enhanced fini system対応) + let instance = InstanceBox::new_with_box_info( actual_class_name.clone(), all_fields, - all_methods + all_methods, + init_field_order, + weak_fields ); let instance_box = Box::new(instance) as Box; diff --git a/src/interpreter/statements.rs b/src/interpreter/statements.rs index 6148e808..ad8c6067 100644 --- a/src/interpreter/statements.rs +++ b/src/interpreter/statements.rs @@ -275,6 +275,13 @@ impl NyashInterpreter { let obj_value = self.execute_expression(object)?; if let Some(instance) = obj_value.as_any().downcast_ref::() { + // 🔥 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(), + }); + } + // 🔗 Weak Reference Assignment Check let box_decls = self.shared.box_declarations.read().unwrap(); if let Some(box_decl) = box_decls.get(&instance.class_name) { @@ -315,6 +322,13 @@ impl NyashInterpreter { })?; if let Some(instance) = this_value.as_any().downcast_ref::() { + // 🔥 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(), + }); + } + // 既存のthis.field値があればfini()を呼ぶ if let Some(old_field_value) = instance.get_field(field) { if let Some(old_instance) = old_field_value.as_any().downcast_ref::() { @@ -341,6 +355,13 @@ impl NyashInterpreter { })?; if let Some(instance) = me_value.as_any().downcast_ref::() { + // 🔥 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(), + }); + } + // 既存のme.field値があればfini()を呼ぶ if let Some(old_field_value) = instance.get_field(field) { if let Some(old_instance) = old_field_value.as_any().downcast_ref::() { diff --git a/test_fini_system.nyash b/test_fini_system.nyash new file mode 100644 index 00000000..77338fc2 --- /dev/null +++ b/test_fini_system.nyash @@ -0,0 +1,119 @@ +// 🔥 Comprehensive fini System Test - ChatGPT5 Design Validation + +// Test Case 1: Basic finalization and usage prohibition +box SimpleResource { + init { name, value } + + pack(resourceName) { + me.name = resourceName + me.value = 42 + } + + getValue() { + return me.value + } + + fini() { + print("🔥 SimpleResource.fini(): Cleaning up " + me.name.toString()) + } +} + +// Test Case 2: Circular reference with weak fields +box Parent { + init { name, weak child } + + pack(parentName) { + me.name = parentName + } + + setChild(c) { + me.child = c + } + + getName() { + return me.name + } +} + +box Child { + init { id, parent } + + pack(childId, p) { + me.id = childId + me.parent = p + } + + // Test Case 3: weak-fini prohibition + fini() { + print("🔥 Child.fini(): Cleaning up child " + me.id.toString()) + // me.parent.fini() // This should be caught and prevented + } +} + +// Test Case 4: Deterministic cascade finalization +box Pipeline { + init { r1, r2, r3, weak monitor } + + pack(name) { + me.r1 = new SimpleResource(name + "_r1") + me.r2 = new SimpleResource(name + "_r2") + me.r3 = new SimpleResource(name + "_r3") + } + + setMonitor(m) { + me.monitor = m + } + + // Custom fini with specific order control + fini() { + print("🔥 Pipeline.fini(): Custom cleanup order") + // Reverse dependency order: r3 → r2 (r1 will be auto-cascade) + me.r3.fini() + me.r2.fini() + // r1 should be automatically finalized by cascade + // monitor is weak, so it's not finalized + } +} + +static box Main { + main() { + print("=== 🔥 Comprehensive fini System Test ===") + + // Test 1: Basic finalization + print("\n📋 Test 1: Basic finalization and usage prohibition") + local resource = new SimpleResource("TestResource") + print("Resource value before fini: " + resource.getValue().toString()) + + resource.fini() + print("Resource finalized") + + // This should throw an error - usage after finalization + // print("Trying to access finalized resource...") + // resource.getValue() // Should fail with "Instance was finalized" + + // Test 2: Circular reference handling + print("\n📋 Test 2: Circular reference with weak fields") + local parent = new Parent("TestParent") + local child = new Child("child1", parent) + parent.setChild(child) + + print("Parent: " + parent.getName().toString()) + print("Before parent finalization") + + parent.fini() + print("Parent finalized - child's weak reference should be safe") + + // Test 3: Deterministic cascade finalization + print("\n📋 Test 3: Deterministic cascade finalization") + local pipeline = new Pipeline("TestPipeline") + local monitor = new SimpleResource("Monitor") + pipeline.setMonitor(monitor) + + print("Pipeline created with resources and monitor") + pipeline.fini() + print("Pipeline finalized with custom order + auto-cascade") + + print("\n✅ fini System Test Completed!") + return "All tests passed" + } +} \ No newline at end of file diff --git a/test_fini_violations.nyash b/test_fini_violations.nyash new file mode 100644 index 00000000..38820b09 --- /dev/null +++ b/test_fini_violations.nyash @@ -0,0 +1,51 @@ +// 🔥 fini System Violation Tests - Testing guards and prohibitions + +box TestResource { + init { name } + + pack(resourceName) { + me.name = resourceName + } + + getData() { + return "Resource: " + me.name.toString() + } + + fini() { + print("🔥 TestResource.fini(): Finalizing " + me.name.toString()) + } +} + +box BadExample { + init { weak weakRef, strongRef } + + pack(name) { + me.strongRef = new TestResource(name + "_strong") + me.weakRef = new TestResource(name + "_weak") // Will be set as weak + } + + // This should trigger weak-fini prohibition + badFini() { + print("🔥 BadExample.badFini(): Attempting illegal operations") + me.weakRef.fini() // Should fail with "Cannot finalize weak field" + } +} + +static box Main { + main() { + print("=== 🔥 fini System Violation Tests ===") + + // Test 1: Usage after finalization prohibition + print("\n📋 Test 1: Usage after finalization (should fail)") + local resource = new TestResource("TestViolation") + print("Before fini: " + resource.getData()) + + resource.fini() + print("Resource finalized") + + print("Attempting to access finalized resource...") + resource.getData() // Should fail with "Instance was finalized" + + return "Test should have failed before reaching here" + } +} \ No newline at end of file diff --git a/test_weak_fini_prohibition.nyash b/test_weak_fini_prohibition.nyash new file mode 100644 index 00000000..ae1baa6c --- /dev/null +++ b/test_weak_fini_prohibition.nyash @@ -0,0 +1,37 @@ +// 🔥 Weak-fini Prohibition Test - Should catch me.weakField.fini() + +box SimpleResource { + init { name } + + pack(resourceName) { + me.name = resourceName + } +} + +box BadParent { + init { weak weakChild } + + pack() { + me.weakChild = new SimpleResource("WeakChild") + } + + // This should trigger weak-fini prohibition + fini() { + print("🔥 BadParent.fini(): Attempting to finalize weak field") + me.weakChild.fini() // Should fail: "Cannot finalize weak field 'weakChild'" + } +} + +static box Main { + main() { + print("=== 🔥 Weak-fini Prohibition Test ===") + + local badParent = new BadParent() + print("BadParent created with weak child") + + print("Attempting to finalize BadParent (should detect illegal weak-fini)...") + badParent.fini() // Should fail during execution of user fini() + + return "Test should have failed before reaching here" + } +} \ No newline at end of file