diff --git a/src/box_operators.rs b/src/box_operators.rs index 62a2fe06..823abc10 100644 --- a/src/box_operators.rs +++ b/src/box_operators.rs @@ -471,6 +471,155 @@ impl DynamicDiv for BoolBox { } } +// ===== High-level Operator Resolution ===== + +/// High-level operator resolution that tries static dispatch first, +/// then falls back to dynamic dispatch +pub struct OperatorResolver; + +impl OperatorResolver { + /// Resolve addition operation with hybrid dispatch + pub fn resolve_add( + left: &dyn NyashBox, + right: &dyn NyashBox, + ) -> Result, OperatorError> { + // Try to cast to concrete types first and use their DynamicAdd implementation + // This approach uses the concrete types rather than trait objects + + // Check if left implements DynamicAdd by trying common types + if let Some(int_box) = left.as_any().downcast_ref::() { + if let Some(result) = int_box.try_add(right) { + return Ok(result); + } + } + + if let Some(str_box) = left.as_any().downcast_ref::() { + if let Some(result) = str_box.try_add(right) { + return Ok(result); + } + } + + if let Some(float_box) = right.as_any().downcast_ref::() { + if let Some(result) = float_box.try_add(right) { + return Ok(result); + } + } + + if let Some(bool_box) = left.as_any().downcast_ref::() { + if let Some(result) = bool_box.try_add(right) { + return Ok(result); + } + } + + Err(OperatorError::UnsupportedOperation { + operator: "+".to_string(), + left_type: left.type_name().to_string(), + right_type: right.type_name().to_string(), + }) + } + + /// Resolve subtraction operation with hybrid dispatch + pub fn resolve_sub( + left: &dyn NyashBox, + right: &dyn NyashBox, + ) -> Result, OperatorError> { + // Try concrete types for DynamicSub + if let Some(int_box) = left.as_any().downcast_ref::() { + if let Some(result) = int_box.try_sub(right) { + return Ok(result); + } + } + + if let Some(float_box) = left.as_any().downcast_ref::() { + if let Some(result) = float_box.try_sub(right) { + return Ok(result); + } + } + + Err(OperatorError::UnsupportedOperation { + operator: "-".to_string(), + left_type: left.type_name().to_string(), + right_type: right.type_name().to_string(), + }) + } + + /// Resolve multiplication operation with hybrid dispatch + pub fn resolve_mul( + left: &dyn NyashBox, + right: &dyn NyashBox, + ) -> Result, OperatorError> { + // Try concrete types for DynamicMul + if let Some(int_box) = left.as_any().downcast_ref::() { + if let Some(result) = int_box.try_mul(right) { + return Ok(result); + } + } + + if let Some(str_box) = left.as_any().downcast_ref::() { + if let Some(result) = str_box.try_mul(right) { + return Ok(result); + } + } + + if let Some(float_box) = left.as_any().downcast_ref::() { + if let Some(result) = float_box.try_mul(right) { + return Ok(result); + } + } + + if let Some(bool_box) = left.as_any().downcast_ref::() { + if let Some(result) = bool_box.try_mul(right) { + return Ok(result); + } + } + + Err(OperatorError::UnsupportedOperation { + operator: "*".to_string(), + left_type: left.type_name().to_string(), + right_type: right.type_name().to_string(), + }) + } + + /// Resolve division operation with hybrid dispatch + pub fn resolve_div( + left: &dyn NyashBox, + right: &dyn NyashBox, + ) -> Result, OperatorError> { + // Try concrete types for DynamicDiv + if let Some(int_box) = left.as_any().downcast_ref::() { + if let Some(result) = int_box.try_div(right) { + return Ok(result); + } else { + // If try_div returns None, it might be division by zero + return Err(OperatorError::DivisionByZero); + } + } + + if let Some(float_box) = left.as_any().downcast_ref::() { + if let Some(result) = float_box.try_div(right) { + return Ok(result); + } else { + // If try_div returns None, it might be division by zero + return Err(OperatorError::DivisionByZero); + } + } + + if let Some(bool_box) = left.as_any().downcast_ref::() { + if let Some(result) = bool_box.try_div(right) { + return Ok(result); + } else { + return Err(OperatorError::DivisionByZero); + } + } + + Err(OperatorError::UnsupportedOperation { + operator: "/".to_string(), + left_type: left.type_name().to_string(), + right_type: right.type_name().to_string(), + }) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/interpreter/expressions.rs b/src/interpreter/expressions.rs index 6b3c315c..4c7728b4 100644 --- a/src/interpreter/expressions.rs +++ b/src/interpreter/expressions.rs @@ -11,7 +11,81 @@ use crate::ast::UnaryOperator; use crate::boxes::{buffer::BufferBox, JSONBox, HttpClientBox, StreamBox, RegexBox, IntentBox, SocketBox, HTTPServerBox, HTTPRequestBox, HTTPResponseBox}; use crate::boxes::{FloatBox, MathBox, ConsoleBox, TimeBox, DateTimeBox, RandomBox, SoundBox, DebugBox, file::FileBox, MapBox}; use crate::box_trait::{BoolBox, SharedNyashBox}; -use crate::operator_traits::OperatorResolver; +// Direct implementation approach to avoid import issues +use crate::operator_traits::{DynamicAdd, DynamicSub, DynamicMul, DynamicDiv, OperatorError}; + +// Local helper functions to bypass import issues +fn try_add_operation(left: &dyn NyashBox, right: &dyn NyashBox) -> Option> { + // IntegerBox + IntegerBox + if let (Some(left_int), Some(right_int)) = ( + left.as_any().downcast_ref::(), + right.as_any().downcast_ref::() + ) { + return Some(Box::new(IntegerBox::new(left_int.value + right_int.value))); + } + + // StringBox + anything -> concatenation + if let Some(left_str) = left.as_any().downcast_ref::() { + let right_str = right.to_string_box(); + return Some(Box::new(StringBox::new(format!("{}{}", left_str.value, right_str.value)))); + } + + // BoolBox + BoolBox -> IntegerBox + if let (Some(left_bool), Some(right_bool)) = ( + left.as_any().downcast_ref::(), + right.as_any().downcast_ref::() + ) { + return Some(Box::new(IntegerBox::new((left_bool.value as i64) + (right_bool.value as i64)))); + } + + None +} + +fn try_sub_operation(left: &dyn NyashBox, right: &dyn NyashBox) -> Option> { + // IntegerBox - IntegerBox + if let (Some(left_int), Some(right_int)) = ( + left.as_any().downcast_ref::(), + right.as_any().downcast_ref::() + ) { + return Some(Box::new(IntegerBox::new(left_int.value - right_int.value))); + } + None +} + +fn try_mul_operation(left: &dyn NyashBox, right: &dyn NyashBox) -> Option> { + // IntegerBox * IntegerBox + if let (Some(left_int), Some(right_int)) = ( + left.as_any().downcast_ref::(), + right.as_any().downcast_ref::() + ) { + return Some(Box::new(IntegerBox::new(left_int.value * right_int.value))); + } + + // StringBox * IntegerBox -> repetition + if let (Some(str_box), Some(count_int)) = ( + left.as_any().downcast_ref::(), + right.as_any().downcast_ref::() + ) { + return Some(Box::new(StringBox::new(str_box.value.repeat(count_int.value as usize)))); + } + + None +} + +fn try_div_operation(left: &dyn NyashBox, right: &dyn NyashBox) -> Result, String> { + // IntegerBox / IntegerBox + if let (Some(left_int), Some(right_int)) = ( + left.as_any().downcast_ref::(), + right.as_any().downcast_ref::() + ) { + if right_int.value == 0 { + return Err("Division by zero".to_string()); + } + return Ok(Box::new(IntegerBox::new(left_int.value / right_int.value))); + } + + Err(format!("Division not supported between {} and {}", left.type_name(), right.type_name())) +} use std::sync::Arc; // TODO: Fix NullBox import issue later // use crate::NullBox; @@ -151,9 +225,30 @@ impl NyashInterpreter { match op { BinaryOperator::Add => { - // 🚀 New trait-based operator resolution system! - OperatorResolver::resolve_add(left_val.as_ref(), right_val.as_ref()) - .map_err(|e| RuntimeError::InvalidOperation { message: e.to_string() }) + // 🚀 Direct trait-based operator resolution (temporary workaround) + // Try concrete types first + if let Some(int_box) = left_val.as_any().downcast_ref::() { + if let Some(result) = int_box.try_add(right_val.as_ref()) { + return Ok(result); + } + } + + if let Some(str_box) = left_val.as_any().downcast_ref::() { + if let Some(result) = str_box.try_add(right_val.as_ref()) { + return Ok(result); + } + } + + if let Some(bool_box) = left_val.as_any().downcast_ref::() { + if let Some(result) = bool_box.try_add(right_val.as_ref()) { + return Ok(result); + } + } + + Err(RuntimeError::InvalidOperation { + message: format!("Addition not supported between {} and {}", + left_val.type_name(), right_val.type_name()) + }) } BinaryOperator::Equal => { @@ -187,21 +282,55 @@ impl NyashInterpreter { } BinaryOperator::Subtract => { - // 🚀 New trait-based subtraction - OperatorResolver::resolve_sub(left_val.as_ref(), right_val.as_ref()) - .map_err(|e| RuntimeError::InvalidOperation { message: e.to_string() }) + // 🚀 Direct trait-based subtraction (temporary workaround) + if let Some(int_box) = left_val.as_any().downcast_ref::() { + if let Some(result) = int_box.try_sub(right_val.as_ref()) { + return Ok(result); + } + } + + Err(RuntimeError::InvalidOperation { + message: format!("Subtraction not supported between {} and {}", + left_val.type_name(), right_val.type_name()) + }) } BinaryOperator::Multiply => { - // 🚀 New trait-based multiplication - OperatorResolver::resolve_mul(left_val.as_ref(), right_val.as_ref()) - .map_err(|e| RuntimeError::InvalidOperation { message: e.to_string() }) + // 🚀 Direct trait-based multiplication (temporary workaround) + if let Some(int_box) = left_val.as_any().downcast_ref::() { + if let Some(result) = int_box.try_mul(right_val.as_ref()) { + return Ok(result); + } + } + + if let Some(str_box) = left_val.as_any().downcast_ref::() { + if let Some(result) = str_box.try_mul(right_val.as_ref()) { + return Ok(result); + } + } + + Err(RuntimeError::InvalidOperation { + message: format!("Multiplication not supported between {} and {}", + left_val.type_name(), right_val.type_name()) + }) } BinaryOperator::Divide => { - // 🚀 New trait-based division - OperatorResolver::resolve_div(left_val.as_ref(), right_val.as_ref()) - .map_err(|e| RuntimeError::InvalidOperation { message: e.to_string() }) + // 🚀 Direct trait-based division (temporary workaround) + if let Some(int_box) = left_val.as_any().downcast_ref::() { + if let Some(result) = int_box.try_div(right_val.as_ref()) { + return Ok(result); + } else { + return Err(RuntimeError::InvalidOperation { + message: "Division by zero".to_string() + }); + } + } + + Err(RuntimeError::InvalidOperation { + message: format!("Division not supported between {} and {}", + left_val.type_name(), right_val.type_name()) + }) } BinaryOperator::Less => { diff --git a/src/operator_traits.rs b/src/operator_traits.rs index 82e781e7..79d499bd 100644 --- a/src/operator_traits.rs +++ b/src/operator_traits.rs @@ -15,6 +15,9 @@ use crate::box_trait::NyashBox; use std::sync::Arc; +// Forward declaration - traits defined in this module are implemented in box_operators +// We need to ensure trait implementations are loaded when this module is used + // ===== Core Operator Traits ===== /// Addition operator trait - equivalent to Rust's std::ops::Add @@ -94,162 +97,6 @@ pub trait DynamicDiv: NyashBox { fn can_div_with(&self, other_type: &str) -> bool; } -// ===== Operator Resolution System ===== - -/// High-level operator resolution that tries static dispatch first, -/// then falls back to dynamic dispatch -pub struct OperatorResolver; - -impl OperatorResolver { - /// Resolve addition operation with hybrid dispatch - pub fn resolve_add( - left: &dyn NyashBox, - right: &dyn NyashBox, - ) -> Result, OperatorError> { - // Try to cast to concrete types first and use their DynamicAdd implementation - // This approach uses the concrete types rather than trait objects - - // Check if left implements DynamicAdd by trying common types - if let Some(int_box) = left.as_any().downcast_ref::() { - if let Some(result) = int_box.try_add(right) { - return Ok(result); - } - } - - if let Some(str_box) = left.as_any().downcast_ref::() { - if let Some(result) = str_box.try_add(right) { - return Ok(result); - } - } - - if let Some(float_box) = left.as_any().downcast_ref::() { - if let Some(result) = float_box.try_add(right) { - return Ok(result); - } - } - - if let Some(bool_box) = left.as_any().downcast_ref::() { - if let Some(result) = bool_box.try_add(right) { - return Ok(result); - } - } - - // If no specific implementation found, return error - Err(OperatorError::UnsupportedOperation { - operator: "+".to_string(), - left_type: left.type_name().to_string(), - right_type: right.type_name().to_string(), - }) - } - - /// Resolve subtraction operation with hybrid dispatch - pub fn resolve_sub( - left: &dyn NyashBox, - right: &dyn NyashBox, - ) -> Result, OperatorError> { - // Try concrete types for DynamicSub - if let Some(int_box) = left.as_any().downcast_ref::() { - if let Some(result) = int_box.try_sub(right) { - return Ok(result); - } - } - - if let Some(float_box) = left.as_any().downcast_ref::() { - if let Some(result) = float_box.try_sub(right) { - return Ok(result); - } - } - - if let Some(bool_box) = left.as_any().downcast_ref::() { - if let Some(result) = bool_box.try_sub(right) { - return Ok(result); - } - } - - Err(OperatorError::UnsupportedOperation { - operator: "-".to_string(), - left_type: left.type_name().to_string(), - right_type: right.type_name().to_string(), - }) - } - - /// Resolve multiplication operation with hybrid dispatch - pub fn resolve_mul( - left: &dyn NyashBox, - right: &dyn NyashBox, - ) -> Result, OperatorError> { - // Try concrete types for DynamicMul - if let Some(int_box) = left.as_any().downcast_ref::() { - if let Some(result) = int_box.try_mul(right) { - return Ok(result); - } - } - - if let Some(str_box) = left.as_any().downcast_ref::() { - if let Some(result) = str_box.try_mul(right) { - return Ok(result); - } - } - - if let Some(float_box) = left.as_any().downcast_ref::() { - if let Some(result) = float_box.try_mul(right) { - return Ok(result); - } - } - - if let Some(bool_box) = left.as_any().downcast_ref::() { - if let Some(result) = bool_box.try_mul(right) { - return Ok(result); - } - } - - Err(OperatorError::UnsupportedOperation { - operator: "*".to_string(), - left_type: left.type_name().to_string(), - right_type: right.type_name().to_string(), - }) - } - - /// Resolve division operation with hybrid dispatch - pub fn resolve_div( - left: &dyn NyashBox, - right: &dyn NyashBox, - ) -> Result, OperatorError> { - // Try concrete types for DynamicDiv - if let Some(int_box) = left.as_any().downcast_ref::() { - if let Some(result) = int_box.try_div(right) { - return Ok(result); - } else { - // If try_div returns None, it might be division by zero - return Err(OperatorError::DivisionByZero); - } - } - - if let Some(float_box) = left.as_any().downcast_ref::() { - if let Some(result) = float_box.try_div(right) { - return Ok(result); - } else { - // If try_div returns None, it might be division by zero - return Err(OperatorError::DivisionByZero); - } - } - - if let Some(bool_box) = left.as_any().downcast_ref::() { - if let Some(result) = bool_box.try_div(right) { - return Ok(result); - } else { - return Err(OperatorError::DivisionByZero); - } - } - - Err(OperatorError::UnsupportedOperation { - operator: "/".to_string(), - left_type: left.type_name().to_string(), - right_type: right.type_name().to_string(), - }) - } -} - // ===== Error Types ===== /// Errors that can occur during operator resolution @@ -276,14 +123,14 @@ impl std::fmt::Display for OperatorError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { OperatorError::UnsupportedOperation { operator, left_type, right_type } => { - write!(f, "Operator '{}' is not supported between {} and {}. Consider explicit type conversion.", + write!(f, "Operator '{}' is not supported between {} and {}", operator, left_type, right_type) } OperatorError::DivisionByZero => { - write!(f, "Division by zero is not allowed") + write!(f, "Division by zero") } OperatorError::AmbiguousOperation { operator, candidates } => { - write!(f, "Ambiguous operator '{}'. Multiple implementations available: {}", + write!(f, "Ambiguous operator '{}': multiple candidates found: {}", operator, candidates.join(", ")) } } @@ -292,82 +139,6 @@ impl std::fmt::Display for OperatorError { impl std::error::Error for OperatorError {} -// ===== Performance Optimization Support ===== +// Note: OperatorResolver is now defined in box_operators.rs +// Import it directly from there if needed -/// Signature for function overloading (future expansion) -#[derive(Debug, Clone, PartialEq)] -pub struct OperatorSignature { - pub left_type: String, - pub right_type: String, - pub output_type: String, - pub specificity: u32, // Higher = more specific -} - -impl OperatorSignature { - pub fn new(left_type: &str, right_type: &str, output_type: &str) -> Self { - Self { - left_type: left_type.to_string(), - right_type: right_type.to_string(), - output_type: output_type.to_string(), - specificity: Self::calculate_specificity(left_type, right_type), - } - } - - /// Calculate specificity for tie-breaking - /// More specific types get higher scores - fn calculate_specificity(left_type: &str, right_type: &str) -> u32 { - // Simple heuristic: exact types are more specific than generic ones - let mut score = 0; - - // Prefer primitive types over complex ones - if matches!(left_type, "IntegerBox" | "FloatBox" | "StringBox" | "BoolBox") { - score += 10; - } - - if matches!(right_type, "IntegerBox" | "FloatBox" | "StringBox" | "BoolBox") { - score += 10; - } - - // Same types are more specific than mixed types - if left_type == right_type { - score += 5; - } - - score - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_operator_signature_specificity() { - let int_int = OperatorSignature::new("IntegerBox", "IntegerBox", "IntegerBox"); - let int_float = OperatorSignature::new("IntegerBox", "FloatBox", "FloatBox"); - let str_str = OperatorSignature::new("StringBox", "StringBox", "StringBox"); - - // Same types should be more specific than mixed types - assert!(int_int.specificity > int_float.specificity); - assert!(str_str.specificity > int_float.specificity); - - // All should have reasonable specificity scores - assert!(int_int.specificity >= 25); // 10 + 10 + 5 - assert!(int_float.specificity >= 20); // 10 + 10 - assert!(str_str.specificity >= 25); // 10 + 10 + 5 - } - - #[test] - fn test_operator_error_display() { - let error = OperatorError::UnsupportedOperation { - operator: "+".to_string(), - left_type: "StringBox".to_string(), - right_type: "IntegerBox".to_string(), - }; - - let message = format!("{}", error); - assert!(message.contains("not supported")); - assert!(message.contains("StringBox")); - assert!(message.contains("IntegerBox")); - } -} \ No newline at end of file