diff --git a/src/boxes/socket_box.rs b/src/boxes/socket_box.rs index db9aa9a6..0864a618 100644 --- a/src/boxes/socket_box.rs +++ b/src/boxes/socket_box.rs @@ -56,13 +56,25 @@ pub struct SocketBox { impl Clone for SocketBox { fn clone(&self) -> Self { - Self { + eprintln!("🔄 SOCKETBOX CLONE: Creating clone of Socket ID={}", self.base.id); + eprintln!("🔄 Original Arc pointer = {:p}", &self.is_server); + eprintln!("🔄 Original Arc data pointer = {:p}", self.is_server.as_ref()); + eprintln!("🔄 Original Arc strong_count = {}", std::sync::Arc::strong_count(&self.is_server)); + + let cloned = Self { base: BoxBase::new(), // New unique ID for clone (for debugging/identity) listener: Arc::clone(&self.listener), // Share the same listener stream: Arc::clone(&self.stream), // Share the same stream is_server: Arc::clone(&self.is_server), // Share the same state container is_connected: Arc::clone(&self.is_connected), // Share the same state container - } + }; + + eprintln!("🔄 New clone ID = {}", cloned.base.id); + eprintln!("🔄 New Arc pointer = {:p}", &cloned.is_server); + eprintln!("🔄 New Arc data pointer = {:p}", cloned.is_server.as_ref()); + eprintln!("🔄 New Arc strong_count = {}", std::sync::Arc::strong_count(&cloned.is_server)); + + cloned } } @@ -358,6 +370,7 @@ impl SocketBox { eprintln!("🔥 SOCKETBOX DEBUG: is_server() called"); eprintln!("🔥 Socket ID = {}", self.base.id); eprintln!("🔥 Arc pointer = {:p}", &self.is_server); + eprintln!("🔥 Arc data pointer = {:p}", self.is_server.as_ref()); match self.is_server.lock() { Ok(is_server_guard) => { diff --git a/src/interpreter/expressions.rs b/src/interpreter/expressions.rs index ece493a1..6b3c315c 100644 --- a/src/interpreter/expressions.rs +++ b/src/interpreter/expressions.rs @@ -467,28 +467,69 @@ impl NyashInterpreter { // 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") { + eprintln!("🔧 DEBUG: Stateful method '{}' called, updating stored instance", method); let updated_instance = socket_box.clone(); + eprintln!("🔧 DEBUG: Updated instance created with ID={}", updated_instance.box_id()); match object { ASTNode::Variable { name, .. } => { + eprintln!("🔧 DEBUG: Updating local variable '{}'", name); // Handle local variables if let Some(stored_var) = self.local_vars.get_mut(name) { + eprintln!("🔧 DEBUG: Found local variable '{}', updating from id={} to id={}", + name, stored_var.box_id(), updated_instance.box_id()); *stored_var = Arc::new(updated_instance); + } else { + eprintln!("🔧 DEBUG: Local variable '{}' not found", name); } }, ASTNode::FieldAccess { object: field_obj, field, .. } => { + eprintln!("🔧 DEBUG: Updating field access '{}'", 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::() { - let _ = instance.set_field(field, Arc::new(updated_instance)); + match field_obj.as_ref() { + ASTNode::Variable { name, .. } => { + eprintln!("🔧 DEBUG: Field object is variable '{}'", name); + if name == "me" { + eprintln!("🔧 DEBUG: Updating me.{} (via variable)", field); + if let Ok(me_instance) = self.resolve_variable("me") { + eprintln!("🔧 DEBUG: Resolved 'me' instance id={}", me_instance.box_id()); + if let Some(instance) = (*me_instance).as_any().downcast_ref::() { + eprintln!("🔧 DEBUG: me is InstanceBox, setting field '{}' to updated instance id={}", field, updated_instance.box_id()); + let result = instance.set_field(field, Arc::new(updated_instance)); + eprintln!("🔧 DEBUG: set_field result: {:?}", result); + } else { + eprintln!("🔧 DEBUG: me is not an InstanceBox, type: {}", me_instance.type_name()); + } + } else { + eprintln!("🔧 DEBUG: Failed to resolve 'me'"); } + } else { + eprintln!("🔧 DEBUG: Field object is not 'me', it's '{}'", name); } + }, + ASTNode::Me { .. } => { + eprintln!("🔧 DEBUG: Field object is Me node, updating me.{}", field); + if let Ok(me_instance) = self.resolve_variable("me") { + eprintln!("🔧 DEBUG: Resolved 'me' instance id={}", me_instance.box_id()); + if let Some(instance) = (*me_instance).as_any().downcast_ref::() { + eprintln!("🔧 DEBUG: me is InstanceBox, setting field '{}' to updated instance id={}", field, updated_instance.box_id()); + let result = instance.set_field(field, Arc::new(updated_instance)); + eprintln!("🔧 DEBUG: set_field result: {:?}", result); + } else { + eprintln!("🔧 DEBUG: me is not an InstanceBox, type: {}", me_instance.type_name()); + } + } else { + eprintln!("🔧 DEBUG: Failed to resolve 'me'"); + } + }, + _ => { + eprintln!("🔧 DEBUG: Field object is not a variable or me, type: {:?}", field_obj); } } }, - _ => {} + _ => { + eprintln!("🔧 DEBUG: Object type not handled: {:?}", object); + } } } diff --git a/test_debug_clone_state.nyash b/test_debug_clone_state.nyash new file mode 100644 index 00000000..976ecb98 --- /dev/null +++ b/test_debug_clone_state.nyash @@ -0,0 +1,34 @@ +# Diagnostic test to understand clone state sharing +static box Main { + init { console, socket1, socket2 } + + main() { + me.console = new ConsoleBox() + me.console.log("🔬 Clone State Diagnostic Test") + + # Create original SocketBox + me.socket1 = new SocketBox() + + # Set state via bind + local bindResult = me.socket1.bind("127.0.0.1", 19001) + me.console.log("✅ bind() result: " + bindResult.toString()) + + # Check state immediately + local isServer1 = me.socket1.isServer() + me.console.log("🔍 socket1.isServer() after bind: " + isServer1.toString()) + + # Now check toString to see the socket ID + local socketStr1 = me.socket1.toString() + me.console.log("🆔 socket1 ID after bind: " + socketStr1) + + # Check state again to see if we get the same socket ID + local isServer2 = me.socket1.isServer() + me.console.log("🔍 socket1.isServer() second call: " + isServer2.toString()) + + # Check toString again + local socketStr2 = me.socket1.toString() + me.console.log("🆔 socket1 ID second call: " + socketStr2) + + return "DIAGNOSTIC_COMPLETE" + } +} \ No newline at end of file