Phase 25.1 完了成果: - ✅ LoopForm v2 テスト・ドキュメント・コメント完備 - 4ケース(A/B/C/D)完全テストカバレッジ - 最小再現ケース作成(SSAバグ調査用) - SSOT文書作成(loopform_ssot.md) - 全ソースに [LoopForm] コメントタグ追加 - ✅ Stage-1 CLI デバッグ環境構築 - stage1_cli.hako 実装 - stage1_bridge.rs ブリッジ実装 - デバッグツール作成(stage1_debug.sh/stage1_minimal.sh) - アーキテクチャ改善提案文書 - ✅ 環境変数削減計画策定 - 25変数の完全調査・分類 - 6段階削減ロードマップ(25→5、80%削減) - 即時削除可能変数特定(NYASH_CONFIG/NYASH_DEBUG) Phase 26-D からの累積変更: - PHI実装改善(ExitPhiBuilder/HeaderPhiBuilder等) - MIRビルダーリファクタリング - 型伝播・最適化パス改善 - その他約300ファイルの累積変更 🎯 技術的成果: - SSAバグ根本原因特定(条件分岐内loop変数変更) - Region+next_iパターン適用完了(UsingCollectorBox等) - LoopFormパターン文書化・テスト化完了 - セルフホスティング基盤強化 Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: ChatGPT <noreply@openai.com> Co-Authored-By: Task Assistant <task@anthropic.com>
612 lines
20 KiB
Rust
612 lines
20 KiB
Rust
/*!
|
|
* Box Operator Implementations - Trait-Based Operator Overloading
|
|
*
|
|
* This module implements the new trait-based operator system for basic Box types.
|
|
* It provides implementations of NyashAdd, NyashSub, etc. for IntegerBox, StringBox,
|
|
* and other fundamental types.
|
|
*
|
|
* Based on AI consultation decision (2025-08-10): Rust-style traits with
|
|
* static/dynamic hybrid dispatch for optimal performance.
|
|
*
|
|
* ## Refactored Architecture (Phase 1 Complete)
|
|
*
|
|
* - Phase 1 ✅: Macros and helpers extracted to separate modules
|
|
* - Phase 2-4: Static/Dynamic implementations and resolver (TODO)
|
|
*/
|
|
|
|
use crate::box_trait::{BoolBox, IntegerBox, NyashBox, StringBox};
|
|
use crate::boxes::FloatBox;
|
|
use crate::operator_traits::{DynamicAdd, DynamicDiv, DynamicMul, DynamicSub, OperatorError};
|
|
|
|
// Phase 1-2: Import macros, helpers, and static implementations from separate modules
|
|
mod helpers;
|
|
mod macros;
|
|
mod static_ops;
|
|
|
|
pub use helpers::{can_repeat, concat_result};
|
|
pub use macros::impl_static_numeric_ops;
|
|
|
|
// Phase 2: Static implementations are now in static_ops.rs
|
|
|
|
/// Dynamic dispatch implementation for IntegerBox
|
|
impl DynamicAdd for IntegerBox {
|
|
fn try_add(&self, other: &dyn NyashBox) -> Option<Box<dyn NyashBox>> {
|
|
// IntegerBox + IntegerBox
|
|
if let Some(other_int) = other.as_any().downcast_ref::<IntegerBox>() {
|
|
return Some(Box::new(IntegerBox::new(self.value + other_int.value)));
|
|
}
|
|
|
|
// IntegerBox + FloatBox -> FloatBox
|
|
if let Some(other_float) = other.as_any().downcast_ref::<FloatBox>() {
|
|
return Some(Box::new(FloatBox::new(
|
|
self.value as f64 + other_float.value,
|
|
)));
|
|
}
|
|
|
|
// Fallback: Convert both to strings and concatenate (existing AddBox behavior)
|
|
Some(concat_result(self, other))
|
|
}
|
|
|
|
fn can_add_with(&self, other_type: &str) -> bool {
|
|
matches!(other_type, "IntegerBox" | "FloatBox" | "StringBox")
|
|
}
|
|
}
|
|
|
|
impl DynamicSub for IntegerBox {
|
|
fn try_sub(&self, other: &dyn NyashBox) -> Option<Box<dyn NyashBox>> {
|
|
// IntegerBox - IntegerBox
|
|
if let Some(other_int) = other.as_any().downcast_ref::<IntegerBox>() {
|
|
return Some(Box::new(IntegerBox::new(self.value - other_int.value)));
|
|
}
|
|
|
|
// IntegerBox - FloatBox -> FloatBox
|
|
if let Some(other_float) = other.as_any().downcast_ref::<FloatBox>() {
|
|
return Some(Box::new(FloatBox::new(
|
|
self.value as f64 - other_float.value,
|
|
)));
|
|
}
|
|
|
|
None // Subtraction not supported for other types
|
|
}
|
|
|
|
fn can_sub_with(&self, other_type: &str) -> bool {
|
|
matches!(other_type, "IntegerBox" | "FloatBox")
|
|
}
|
|
}
|
|
|
|
impl DynamicMul for IntegerBox {
|
|
fn try_mul(&self, other: &dyn NyashBox) -> Option<Box<dyn NyashBox>> {
|
|
// IntegerBox * IntegerBox
|
|
if let Some(other_int) = other.as_any().downcast_ref::<IntegerBox>() {
|
|
return Some(Box::new(IntegerBox::new(self.value * other_int.value)));
|
|
}
|
|
|
|
// IntegerBox * FloatBox -> FloatBox
|
|
if let Some(other_float) = other.as_any().downcast_ref::<FloatBox>() {
|
|
return Some(Box::new(FloatBox::new(
|
|
self.value as f64 * other_float.value,
|
|
)));
|
|
}
|
|
|
|
// IntegerBox * StringBox -> Repeated string
|
|
if let Some(other_str) = other.as_any().downcast_ref::<StringBox>() {
|
|
if can_repeat(self.value) {
|
|
let repeated = other_str.value.repeat(self.value as usize);
|
|
return Some(Box::new(StringBox::new(repeated)));
|
|
}
|
|
}
|
|
|
|
None
|
|
}
|
|
|
|
fn can_mul_with(&self, other_type: &str) -> bool {
|
|
matches!(other_type, "IntegerBox" | "FloatBox" | "StringBox")
|
|
}
|
|
}
|
|
|
|
impl DynamicDiv for IntegerBox {
|
|
fn try_div(&self, other: &dyn NyashBox) -> Option<Box<dyn NyashBox>> {
|
|
// IntegerBox / IntegerBox -> FloatBox (for precision)
|
|
if let Some(other_int) = other.as_any().downcast_ref::<IntegerBox>() {
|
|
if other_int.value == 0 {
|
|
return None; // Division by zero
|
|
}
|
|
return Some(Box::new(FloatBox::new(
|
|
self.value as f64 / other_int.value as f64,
|
|
)));
|
|
}
|
|
|
|
// IntegerBox / FloatBox -> FloatBox
|
|
if let Some(other_float) = other.as_any().downcast_ref::<FloatBox>() {
|
|
if other_float.value == 0.0 {
|
|
return None; // Division by zero
|
|
}
|
|
return Some(Box::new(FloatBox::new(
|
|
self.value as f64 / other_float.value,
|
|
)));
|
|
}
|
|
|
|
None
|
|
}
|
|
|
|
fn can_div_with(&self, other_type: &str) -> bool {
|
|
matches!(other_type, "IntegerBox" | "FloatBox")
|
|
}
|
|
}
|
|
|
|
// FloatBox static implementations moved to static_ops.rs
|
|
|
|
// ===== FloatBox Dynamic Operator Implementations =====
|
|
|
|
impl DynamicAdd for FloatBox {
|
|
fn try_add(&self, other: &dyn NyashBox) -> Option<Box<dyn NyashBox>> {
|
|
// FloatBox + FloatBox
|
|
if let Some(other_float) = other.as_any().downcast_ref::<FloatBox>() {
|
|
return Some(Box::new(FloatBox::new(self.value + other_float.value)));
|
|
}
|
|
|
|
// FloatBox + IntegerBox -> FloatBox
|
|
if let Some(other_int) = other.as_any().downcast_ref::<IntegerBox>() {
|
|
return Some(Box::new(FloatBox::new(self.value + other_int.value as f64)));
|
|
}
|
|
|
|
// Fallback: Convert both to strings and concatenate
|
|
Some(concat_result(self, other))
|
|
}
|
|
|
|
fn can_add_with(&self, other_type: &str) -> bool {
|
|
matches!(other_type, "FloatBox" | "IntegerBox" | "StringBox")
|
|
}
|
|
}
|
|
|
|
impl DynamicSub for FloatBox {
|
|
fn try_sub(&self, other: &dyn NyashBox) -> Option<Box<dyn NyashBox>> {
|
|
// FloatBox - FloatBox
|
|
if let Some(other_float) = other.as_any().downcast_ref::<FloatBox>() {
|
|
return Some(Box::new(FloatBox::new(self.value - other_float.value)));
|
|
}
|
|
|
|
// FloatBox - IntegerBox -> FloatBox
|
|
if let Some(other_int) = other.as_any().downcast_ref::<IntegerBox>() {
|
|
return Some(Box::new(FloatBox::new(self.value - other_int.value as f64)));
|
|
}
|
|
|
|
None // Subtraction not supported for other types
|
|
}
|
|
|
|
fn can_sub_with(&self, other_type: &str) -> bool {
|
|
matches!(other_type, "FloatBox" | "IntegerBox")
|
|
}
|
|
}
|
|
|
|
impl DynamicMul for FloatBox {
|
|
fn try_mul(&self, other: &dyn NyashBox) -> Option<Box<dyn NyashBox>> {
|
|
// FloatBox * FloatBox
|
|
if let Some(other_float) = other.as_any().downcast_ref::<FloatBox>() {
|
|
return Some(Box::new(FloatBox::new(self.value * other_float.value)));
|
|
}
|
|
|
|
// FloatBox * IntegerBox -> FloatBox
|
|
if let Some(other_int) = other.as_any().downcast_ref::<IntegerBox>() {
|
|
return Some(Box::new(FloatBox::new(self.value * other_int.value as f64)));
|
|
}
|
|
|
|
None
|
|
}
|
|
|
|
fn can_mul_with(&self, other_type: &str) -> bool {
|
|
matches!(other_type, "FloatBox" | "IntegerBox")
|
|
}
|
|
}
|
|
|
|
impl DynamicDiv for FloatBox {
|
|
fn try_div(&self, other: &dyn NyashBox) -> Option<Box<dyn NyashBox>> {
|
|
// FloatBox / FloatBox
|
|
if let Some(other_float) = other.as_any().downcast_ref::<FloatBox>() {
|
|
if other_float.value == 0.0 {
|
|
return None; // Division by zero
|
|
}
|
|
return Some(Box::new(FloatBox::new(self.value / other_float.value)));
|
|
}
|
|
|
|
// FloatBox / IntegerBox -> FloatBox
|
|
if let Some(other_int) = other.as_any().downcast_ref::<IntegerBox>() {
|
|
if other_int.value == 0 {
|
|
return None; // Division by zero
|
|
}
|
|
return Some(Box::new(FloatBox::new(self.value / other_int.value as f64)));
|
|
}
|
|
|
|
None
|
|
}
|
|
|
|
fn can_div_with(&self, other_type: &str) -> bool {
|
|
matches!(other_type, "FloatBox" | "IntegerBox")
|
|
}
|
|
}
|
|
|
|
// ===== StringBox Operator Implementations =====
|
|
// StringBox static implementations moved to static_ops.rs
|
|
|
|
/// Dynamic dispatch implementation for StringBox
|
|
impl DynamicAdd for StringBox {
|
|
fn try_add(&self, other: &dyn NyashBox) -> Option<Box<dyn NyashBox>> {
|
|
// StringBox + StringBox
|
|
if let Some(other_str) = other.as_any().downcast_ref::<StringBox>() {
|
|
return Some(Box::new(StringBox::new(format!(
|
|
"{}{}",
|
|
self.value, other_str.value
|
|
))));
|
|
}
|
|
|
|
// StringBox + any other type -> Convert to string and concatenate
|
|
Some(concat_result(self, other))
|
|
}
|
|
|
|
fn can_add_with(&self, _other_type: &str) -> bool {
|
|
true // StringBox can concatenate with anything via to_string_box()
|
|
}
|
|
}
|
|
|
|
impl DynamicSub for StringBox {
|
|
fn try_sub(&self, _other: &dyn NyashBox) -> Option<Box<dyn NyashBox>> {
|
|
None // Subtraction not defined for strings
|
|
}
|
|
|
|
fn can_sub_with(&self, _other_type: &str) -> bool {
|
|
false
|
|
}
|
|
}
|
|
|
|
impl DynamicMul for StringBox {
|
|
fn try_mul(&self, other: &dyn NyashBox) -> Option<Box<dyn NyashBox>> {
|
|
// StringBox * IntegerBox -> Repeated string
|
|
if let Some(other_int) = other.as_any().downcast_ref::<IntegerBox>() {
|
|
if can_repeat(other_int.value) {
|
|
let repeated = self.value.repeat(other_int.value as usize);
|
|
return Some(Box::new(StringBox::new(repeated)));
|
|
}
|
|
}
|
|
|
|
None
|
|
}
|
|
|
|
fn can_mul_with(&self, other_type: &str) -> bool {
|
|
matches!(other_type, "IntegerBox")
|
|
}
|
|
}
|
|
|
|
impl DynamicDiv for StringBox {
|
|
fn try_div(&self, _other: &dyn NyashBox) -> Option<Box<dyn NyashBox>> {
|
|
None // Division not defined for strings
|
|
}
|
|
|
|
fn can_div_with(&self, _other_type: &str) -> bool {
|
|
false
|
|
}
|
|
}
|
|
|
|
// ===== BoolBox Operator Implementations =====
|
|
// BoolBox static implementations moved to static_ops.rs
|
|
|
|
impl DynamicAdd for BoolBox {
|
|
fn try_add(&self, other: &dyn NyashBox) -> Option<Box<dyn NyashBox>> {
|
|
// BoolBox + BoolBox
|
|
if let Some(other_bool) = other.as_any().downcast_ref::<BoolBox>() {
|
|
let result = (self.value as i64) + (other_bool.value as i64);
|
|
return Some(Box::new(IntegerBox::new(result)));
|
|
}
|
|
|
|
// BoolBox + IntegerBox
|
|
if let Some(other_int) = other.as_any().downcast_ref::<IntegerBox>() {
|
|
let result = (self.value as i64) + other_int.value;
|
|
return Some(Box::new(IntegerBox::new(result)));
|
|
}
|
|
|
|
// Fallback to string concatenation
|
|
let left_str = self.to_string_box();
|
|
let right_str = other.to_string_box();
|
|
Some(Box::new(StringBox::new(format!(
|
|
"{}{}",
|
|
left_str.value, right_str.value
|
|
))))
|
|
}
|
|
|
|
fn can_add_with(&self, other_type: &str) -> bool {
|
|
matches!(other_type, "BoolBox" | "IntegerBox" | "StringBox")
|
|
}
|
|
}
|
|
|
|
impl DynamicSub for BoolBox {
|
|
fn try_sub(&self, other: &dyn NyashBox) -> Option<Box<dyn NyashBox>> {
|
|
// BoolBox - BoolBox
|
|
if let Some(other_bool) = other.as_any().downcast_ref::<BoolBox>() {
|
|
let result = (self.value as i64) - (other_bool.value as i64);
|
|
return Some(Box::new(IntegerBox::new(result)));
|
|
}
|
|
|
|
// BoolBox - IntegerBox
|
|
if let Some(other_int) = other.as_any().downcast_ref::<IntegerBox>() {
|
|
let result = (self.value as i64) - other_int.value;
|
|
return Some(Box::new(IntegerBox::new(result)));
|
|
}
|
|
|
|
None
|
|
}
|
|
|
|
fn can_sub_with(&self, other_type: &str) -> bool {
|
|
matches!(other_type, "BoolBox" | "IntegerBox")
|
|
}
|
|
}
|
|
|
|
impl DynamicMul for BoolBox {
|
|
fn try_mul(&self, other: &dyn NyashBox) -> Option<Box<dyn NyashBox>> {
|
|
// BoolBox * BoolBox -> logical AND
|
|
if let Some(other_bool) = other.as_any().downcast_ref::<BoolBox>() {
|
|
let result = (self.value as i64) * (other_bool.value as i64);
|
|
return Some(Box::new(IntegerBox::new(result)));
|
|
}
|
|
|
|
// BoolBox * IntegerBox
|
|
if let Some(other_int) = other.as_any().downcast_ref::<IntegerBox>() {
|
|
let result = (self.value as i64) * other_int.value;
|
|
return Some(Box::new(IntegerBox::new(result)));
|
|
}
|
|
|
|
None
|
|
}
|
|
|
|
fn can_mul_with(&self, other_type: &str) -> bool {
|
|
matches!(other_type, "BoolBox" | "IntegerBox")
|
|
}
|
|
}
|
|
|
|
impl DynamicDiv for BoolBox {
|
|
fn try_div(&self, other: &dyn NyashBox) -> Option<Box<dyn NyashBox>> {
|
|
// BoolBox / IntegerBox
|
|
if let Some(other_int) = other.as_any().downcast_ref::<IntegerBox>() {
|
|
if other_int.value == 0 {
|
|
return None; // Division by zero
|
|
}
|
|
let result = (self.value as i64) / other_int.value;
|
|
return Some(Box::new(IntegerBox::new(result)));
|
|
}
|
|
|
|
None
|
|
}
|
|
|
|
fn can_div_with(&self, other_type: &str) -> bool {
|
|
matches!(other_type, "IntegerBox")
|
|
}
|
|
}
|
|
|
|
// ===== High-level Operator Resolution =====
|
|
|
|
/// High-level operator resolution that tries static dispatch first,
|
|
/// then falls back to dynamic dispatch
|
|
pub struct OperatorResolver;
|
|
|
|
impl OperatorResolver {
|
|
#[inline]
|
|
fn try_dyn_left_add(left: &dyn NyashBox, right: &dyn NyashBox) -> Option<Box<dyn NyashBox>> {
|
|
if let Some(int_box) = left.as_any().downcast_ref::<crate::box_trait::IntegerBox>() {
|
|
if let Some(result) = int_box.try_add(right) {
|
|
return Some(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 Some(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 Some(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 Some(result);
|
|
}
|
|
}
|
|
None
|
|
}
|
|
|
|
#[inline]
|
|
fn try_dyn_left_sub(left: &dyn NyashBox, right: &dyn NyashBox) -> Option<Box<dyn NyashBox>> {
|
|
if let Some(int_box) = left.as_any().downcast_ref::<crate::box_trait::IntegerBox>() {
|
|
if let Some(result) = int_box.try_sub(right) {
|
|
return Some(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 Some(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 Some(result);
|
|
}
|
|
}
|
|
None
|
|
}
|
|
|
|
#[inline]
|
|
fn try_dyn_left_mul(left: &dyn NyashBox, right: &dyn NyashBox) -> Option<Box<dyn NyashBox>> {
|
|
if let Some(int_box) = left.as_any().downcast_ref::<crate::box_trait::IntegerBox>() {
|
|
if let Some(result) = int_box.try_mul(right) {
|
|
return Some(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 Some(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 Some(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 Some(result);
|
|
}
|
|
}
|
|
None
|
|
}
|
|
|
|
#[inline]
|
|
fn try_dyn_left_div(left: &dyn NyashBox, right: &dyn NyashBox) -> Option<Box<dyn NyashBox>> {
|
|
if let Some(int_box) = left.as_any().downcast_ref::<crate::box_trait::IntegerBox>() {
|
|
return int_box.try_div(right);
|
|
}
|
|
if let Some(float_box) = left
|
|
.as_any()
|
|
.downcast_ref::<crate::boxes::math_box::FloatBox>()
|
|
{
|
|
return float_box.try_div(right);
|
|
}
|
|
if let Some(bool_box) = left.as_any().downcast_ref::<crate::box_trait::BoolBox>() {
|
|
return bool_box.try_div(right);
|
|
}
|
|
None
|
|
}
|
|
/// 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
|
|
|
|
if let Some(result) = Self::try_dyn_left_add(left, 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> {
|
|
if let Some(result) = Self::try_dyn_left_sub(left, 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> {
|
|
if let Some(result) = Self::try_dyn_left_mul(left, 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> {
|
|
if let Some(result) = Self::try_dyn_left_div(left, right) {
|
|
return Ok(result);
|
|
}
|
|
|
|
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::*;
|
|
use crate::operator_traits::{NyashAdd, NyashMul};
|
|
|
|
#[test]
|
|
fn test_integer_addition() {
|
|
let a = IntegerBox::new(5);
|
|
let b = IntegerBox::new(3);
|
|
let result = NyashAdd::add(a, b);
|
|
assert_eq!(result.value, 8);
|
|
}
|
|
|
|
#[test]
|
|
fn test_string_concatenation() {
|
|
let a = StringBox::new("Hello");
|
|
let b = StringBox::new(" World");
|
|
let result = NyashAdd::add(a, b);
|
|
assert_eq!(result.value, "Hello World");
|
|
}
|
|
|
|
#[test]
|
|
fn test_string_repetition() {
|
|
let s = StringBox::new("Hi");
|
|
let n = IntegerBox::new(3);
|
|
let result = NyashMul::mul(s, n);
|
|
assert_eq!(result.value, "HiHiHi");
|
|
}
|
|
|
|
#[test]
|
|
fn test_dynamic_addition() {
|
|
let a = IntegerBox::new(10);
|
|
let b = StringBox::new("20");
|
|
|
|
// Test dynamic dispatch
|
|
let result = a.try_add(&b).unwrap();
|
|
let result_str = result.to_string_box();
|
|
assert_eq!(result_str.value, "1020"); // String concatenation fallback
|
|
}
|
|
|
|
#[test]
|
|
fn test_boolean_arithmetic() {
|
|
let a = BoolBox::new(true);
|
|
let b = BoolBox::new(false);
|
|
let result = NyashAdd::add(a, b);
|
|
assert_eq!(result.value, 1); // true + false = 1 + 0 = 1
|
|
}
|
|
|
|
#[test]
|
|
fn test_can_add_with() {
|
|
let int_box = IntegerBox::new(42);
|
|
assert!(int_box.can_add_with("IntegerBox"));
|
|
assert!(int_box.can_add_with("StringBox"));
|
|
|
|
let str_box = StringBox::new("test");
|
|
assert!(str_box.can_add_with("IntegerBox"));
|
|
assert!(str_box.can_add_with("StringBox"));
|
|
}
|
|
}
|