🔥 Phase 2 Complete: Comprehensive fini system with ChatGPT5 design
Co-authored-by: moe-charm <217100418+moe-charm@users.noreply.github.com>
This commit is contained in:
119
src/instance.rs
119
src/instance.rs
@ -34,14 +34,24 @@ pub struct InstanceBox {
|
||||
|
||||
/// 解放済みフラグ
|
||||
finalized: Arc<Mutex<bool>>,
|
||||
|
||||
/// 🔥 Phase 2: finiシステム完全実装 - ChatGPT5設計
|
||||
/// init宣言順序(決定的カスケード用)
|
||||
init_field_order: Vec<String>,
|
||||
|
||||
/// weak フィールド高速判定用
|
||||
weak_fields_union: std::collections::HashSet<String>,
|
||||
|
||||
/// 解放中フラグ(再入防止)
|
||||
in_finalization: Arc<Mutex<bool>>,
|
||||
}
|
||||
|
||||
impl InstanceBox {
|
||||
pub fn new(class_name: String, fields: Vec<String>, methods: HashMap<String, ASTNode>) -> Self {
|
||||
// フィールドをVoidBoxで初期化
|
||||
let mut field_map = HashMap::new();
|
||||
for field in fields {
|
||||
field_map.insert(field, Box::new(VoidBox::new()) as Box<dyn NyashBox>);
|
||||
for field in &fields {
|
||||
field_map.insert(field.clone(), Box::new(VoidBox::new()) as Box<dyn NyashBox>);
|
||||
}
|
||||
|
||||
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<String>,
|
||||
methods: HashMap<String, ASTNode>,
|
||||
init_field_order: Vec<String>,
|
||||
weak_fields: Vec<String>
|
||||
) -> Self {
|
||||
// フィールドをVoidBoxで初期化
|
||||
let mut field_map = HashMap::new();
|
||||
for field in &fields {
|
||||
field_map.insert(field.clone(), Box::new(VoidBox::new()) as Box<dyn NyashBox>);
|
||||
}
|
||||
|
||||
// Weak fields をHashSetに変換(高速判定用)
|
||||
let weak_fields_union: std::collections::HashSet<String> = 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::<InstanceBox>() {
|
||||
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 {
|
||||
|
||||
@ -498,8 +498,37 @@ impl NyashInterpreter {
|
||||
|
||||
// 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()));
|
||||
@ -625,6 +654,13 @@ impl NyashInterpreter {
|
||||
|
||||
// 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 {
|
||||
|
||||
@ -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<dyn NyashBox>;
|
||||
|
||||
@ -275,6 +275,13 @@ impl NyashInterpreter {
|
||||
let obj_value = self.execute_expression(object)?;
|
||||
|
||||
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(),
|
||||
});
|
||||
}
|
||||
|
||||
// 🔗 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::<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(),
|
||||
});
|
||||
}
|
||||
|
||||
// 既存の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::<InstanceBox>() {
|
||||
@ -341,6 +355,13 @@ impl NyashInterpreter {
|
||||
})?;
|
||||
|
||||
if let Some(instance) = me_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(),
|
||||
});
|
||||
}
|
||||
|
||||
// 既存の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::<InstanceBox>() {
|
||||
|
||||
119
test_fini_system.nyash
Normal file
119
test_fini_system.nyash
Normal file
@ -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"
|
||||
}
|
||||
}
|
||||
51
test_fini_violations.nyash
Normal file
51
test_fini_violations.nyash
Normal file
@ -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"
|
||||
}
|
||||
}
|
||||
37
test_weak_fini_prohibition.nyash
Normal file
37
test_weak_fini_prohibition.nyash
Normal file
@ -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"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user