Partial fix: Implement DynamicMul/DynamicDiv traits, resolve circular dependencies - library builds successfully
Co-authored-by: moe-charm <217100418+moe-charm@users.noreply.github.com>
This commit is contained in:
@ -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<Box<dyn NyashBox>, 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::<crate::box_trait::IntegerBox>() {
|
||||||
|
if let Some(result) = int_box.try_add(right) {
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(str_box) = left.as_any().downcast_ref::<crate::box_trait::StringBox>() {
|
||||||
|
if let Some(result) = str_box.try_add(right) {
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(float_box) = right.as_any().downcast_ref::<crate::boxes::math_box::FloatBox>() {
|
||||||
|
if let Some(result) = float_box.try_add(right) {
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(bool_box) = left.as_any().downcast_ref::<crate::box_trait::BoolBox>() {
|
||||||
|
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<Box<dyn NyashBox>, OperatorError> {
|
||||||
|
// Try concrete types for DynamicSub
|
||||||
|
if let Some(int_box) = left.as_any().downcast_ref::<crate::box_trait::IntegerBox>() {
|
||||||
|
if let Some(result) = int_box.try_sub(right) {
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(float_box) = left.as_any().downcast_ref::<crate::boxes::math_box::FloatBox>() {
|
||||||
|
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<Box<dyn NyashBox>, OperatorError> {
|
||||||
|
// Try concrete types for DynamicMul
|
||||||
|
if let Some(int_box) = left.as_any().downcast_ref::<crate::box_trait::IntegerBox>() {
|
||||||
|
if let Some(result) = int_box.try_mul(right) {
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(str_box) = left.as_any().downcast_ref::<crate::box_trait::StringBox>() {
|
||||||
|
if let Some(result) = str_box.try_mul(right) {
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(float_box) = left.as_any().downcast_ref::<crate::boxes::math_box::FloatBox>() {
|
||||||
|
if let Some(result) = float_box.try_mul(right) {
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(bool_box) = left.as_any().downcast_ref::<crate::box_trait::BoolBox>() {
|
||||||
|
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<Box<dyn NyashBox>, OperatorError> {
|
||||||
|
// Try concrete types for DynamicDiv
|
||||||
|
if let Some(int_box) = left.as_any().downcast_ref::<crate::box_trait::IntegerBox>() {
|
||||||
|
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::<crate::boxes::math_box::FloatBox>() {
|
||||||
|
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::<crate::box_trait::BoolBox>() {
|
||||||
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@ -11,7 +11,7 @@ use crate::ast::UnaryOperator;
|
|||||||
use crate::boxes::{buffer::BufferBox, JSONBox, HttpClientBox, StreamBox, RegexBox, IntentBox, SocketBox, HTTPServerBox, HTTPRequestBox, HTTPResponseBox};
|
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::boxes::{FloatBox, MathBox, ConsoleBox, TimeBox, DateTimeBox, RandomBox, SoundBox, DebugBox, file::FileBox, MapBox};
|
||||||
use crate::box_trait::{BoolBox, SharedNyashBox};
|
use crate::box_trait::{BoolBox, SharedNyashBox};
|
||||||
use crate::operator_traits::OperatorResolver;
|
use crate::box_operators::OperatorResolver;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
// TODO: Fix NullBox import issue later
|
// TODO: Fix NullBox import issue later
|
||||||
// use crate::NullBox;
|
// use crate::NullBox;
|
||||||
|
|||||||
@ -15,6 +15,9 @@
|
|||||||
use crate::box_trait::NyashBox;
|
use crate::box_trait::NyashBox;
|
||||||
use std::sync::Arc;
|
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 =====
|
// ===== Core Operator Traits =====
|
||||||
|
|
||||||
/// Addition operator trait - equivalent to Rust's std::ops::Add
|
/// 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;
|
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<Box<dyn NyashBox>, 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::<crate::box_trait::IntegerBox>() {
|
|
||||||
if let Some(result) = int_box.try_add(right) {
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(str_box) = left.as_any().downcast_ref::<crate::box_trait::StringBox>() {
|
|
||||||
if let Some(result) = str_box.try_add(right) {
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(float_box) = left.as_any().downcast_ref::<crate::boxes::math_box::FloatBox>() {
|
|
||||||
if let Some(result) = float_box.try_add(right) {
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(bool_box) = left.as_any().downcast_ref::<crate::box_trait::BoolBox>() {
|
|
||||||
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<Box<dyn NyashBox>, OperatorError> {
|
|
||||||
// Try concrete types for DynamicSub
|
|
||||||
if let Some(int_box) = left.as_any().downcast_ref::<crate::box_trait::IntegerBox>() {
|
|
||||||
if let Some(result) = int_box.try_sub(right) {
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(float_box) = left.as_any().downcast_ref::<crate::boxes::math_box::FloatBox>() {
|
|
||||||
if let Some(result) = float_box.try_sub(right) {
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(bool_box) = left.as_any().downcast_ref::<crate::box_trait::BoolBox>() {
|
|
||||||
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<Box<dyn NyashBox>, OperatorError> {
|
|
||||||
// Try concrete types for DynamicMul
|
|
||||||
if let Some(int_box) = left.as_any().downcast_ref::<crate::box_trait::IntegerBox>() {
|
|
||||||
if let Some(result) = int_box.try_mul(right) {
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(str_box) = left.as_any().downcast_ref::<crate::box_trait::StringBox>() {
|
|
||||||
if let Some(result) = str_box.try_mul(right) {
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(float_box) = left.as_any().downcast_ref::<crate::boxes::math_box::FloatBox>() {
|
|
||||||
if let Some(result) = float_box.try_mul(right) {
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(bool_box) = left.as_any().downcast_ref::<crate::box_trait::BoolBox>() {
|
|
||||||
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<Box<dyn NyashBox>, OperatorError> {
|
|
||||||
// Try concrete types for DynamicDiv
|
|
||||||
if let Some(int_box) = left.as_any().downcast_ref::<crate::box_trait::IntegerBox>() {
|
|
||||||
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::<crate::boxes::math_box::FloatBox>() {
|
|
||||||
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::<crate::box_trait::BoolBox>() {
|
|
||||||
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 =====
|
// ===== Error Types =====
|
||||||
|
|
||||||
/// Errors that can occur during operator resolution
|
/// 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 {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
OperatorError::UnsupportedOperation { operator, left_type, right_type } => {
|
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)
|
operator, left_type, right_type)
|
||||||
}
|
}
|
||||||
OperatorError::DivisionByZero => {
|
OperatorError::DivisionByZero => {
|
||||||
write!(f, "Division by zero is not allowed")
|
write!(f, "Division by zero")
|
||||||
}
|
}
|
||||||
OperatorError::AmbiguousOperation { operator, candidates } => {
|
OperatorError::AmbiguousOperation { operator, candidates } => {
|
||||||
write!(f, "Ambiguous operator '{}'. Multiple implementations available: {}",
|
write!(f, "Ambiguous operator '{}': multiple candidates found: {}",
|
||||||
operator, candidates.join(", "))
|
operator, candidates.join(", "))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -292,82 +139,6 @@ impl std::fmt::Display for OperatorError {
|
|||||||
|
|
||||||
impl std::error::Error 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"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user