diff --git a/Cargo.toml b/Cargo.toml index d33ba781..76b16167 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,9 +55,6 @@ name = "test_icon_extraction" path = "examples/test_icon_extraction.rs" -[[bin]] -name = "test_method_box_integration" -path = "test_method_box_integration.rs" [dependencies] # エラーハンドリング diff --git a/src/box_operators.rs b/src/box_operators.rs index c9b77812..5470c242 100644 --- a/src/box_operators.rs +++ b/src/box_operators.rs @@ -10,6 +10,7 @@ */ use crate::box_trait::{NyashBox, StringBox, IntegerBox, BoolBox}; +use crate::boxes::math_box::FloatBox; use crate::operator_traits::{ NyashAdd, NyashSub, NyashMul, NyashDiv, DynamicAdd, DynamicSub, DynamicMul, DynamicDiv, @@ -66,8 +67,10 @@ impl DynamicAdd for IntegerBox { return Some(Box::new(IntegerBox::new(self.value + other_int.value))); } - // IntegerBox + FloatBox (if FloatBox exists) - // TODO: Add when FloatBox is properly integrated + // IntegerBox + FloatBox -> FloatBox + if let Some(other_float) = other.as_any().downcast_ref::() { + return Some(Box::new(FloatBox::new(self.value as f64 + other_float.value))); + } // Fallback: Convert both to strings and concatenate // This preserves the existing AddBox behavior @@ -88,8 +91,10 @@ impl DynamicSub for IntegerBox { return Some(Box::new(IntegerBox::new(self.value - other_int.value))); } - // IntegerBox - FloatBox (if FloatBox exists) - // TODO: Add when FloatBox is properly integrated + // IntegerBox - FloatBox -> FloatBox + if let Some(other_float) = other.as_any().downcast_ref::() { + return Some(Box::new(FloatBox::new(self.value as f64 - other_float.value))); + } None // Subtraction not supported for other types } @@ -106,6 +111,11 @@ impl DynamicMul for 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::() { + 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::() { if self.value >= 0 && self.value <= 10000 { // Safety limit @@ -124,13 +134,20 @@ impl DynamicMul for IntegerBox { impl DynamicDiv for IntegerBox { fn try_div(&self, other: &dyn NyashBox) -> Option> { - // IntegerBox / IntegerBox + // IntegerBox / IntegerBox -> FloatBox (for precision) if let Some(other_int) = other.as_any().downcast_ref::() { if other_int.value == 0 { - // Return error box or None - for now None - return None; + return None; // Division by zero } - return Some(Box::new(IntegerBox::new(self.value / other_int.value))); + 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::() { + 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 @@ -141,6 +158,139 @@ impl DynamicDiv for IntegerBox { } } +// ===== FloatBox Operator Implementations ===== + +/// FloatBox + FloatBox -> FloatBox +impl NyashAdd for FloatBox { + type Output = FloatBox; + + fn add(self, rhs: FloatBox) -> Self::Output { + FloatBox::new(self.value + rhs.value) + } +} + +/// FloatBox - FloatBox -> FloatBox +impl NyashSub for FloatBox { + type Output = FloatBox; + + fn sub(self, rhs: FloatBox) -> Self::Output { + FloatBox::new(self.value - rhs.value) + } +} + +/// FloatBox * FloatBox -> FloatBox +impl NyashMul for FloatBox { + type Output = FloatBox; + + fn mul(self, rhs: FloatBox) -> Self::Output { + FloatBox::new(self.value * rhs.value) + } +} + +/// FloatBox / FloatBox -> FloatBox (with zero check) +impl NyashDiv for FloatBox { + type Output = Result; + + fn div(self, rhs: FloatBox) -> Self::Output { + if rhs.value == 0.0 { + Err(OperatorError::DivisionByZero) + } else { + Ok(FloatBox::new(self.value / rhs.value)) + } + } +} + +// ===== FloatBox Dynamic Operator Implementations ===== + +impl DynamicAdd for FloatBox { + fn try_add(&self, other: &dyn NyashBox) -> Option> { + // FloatBox + FloatBox + if let Some(other_float) = other.as_any().downcast_ref::() { + return Some(Box::new(FloatBox::new(self.value + other_float.value))); + } + + // FloatBox + IntegerBox -> FloatBox + if let Some(other_int) = other.as_any().downcast_ref::() { + return Some(Box::new(FloatBox::new(self.value + other_int.value as f64))); + } + + // Fallback: Convert both to strings and concatenate + 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, "FloatBox" | "IntegerBox" | "StringBox") + } +} + +impl DynamicSub for FloatBox { + fn try_sub(&self, other: &dyn NyashBox) -> Option> { + // FloatBox - FloatBox + if let Some(other_float) = other.as_any().downcast_ref::() { + return Some(Box::new(FloatBox::new(self.value - other_float.value))); + } + + // FloatBox - IntegerBox -> FloatBox + if let Some(other_int) = other.as_any().downcast_ref::() { + 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> { + // FloatBox * FloatBox + if let Some(other_float) = other.as_any().downcast_ref::() { + return Some(Box::new(FloatBox::new(self.value * other_float.value))); + } + + // FloatBox * IntegerBox -> FloatBox + if let Some(other_int) = other.as_any().downcast_ref::() { + 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> { + // FloatBox / FloatBox + if let Some(other_float) = other.as_any().downcast_ref::() { + 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::() { + 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 + StringBox -> StringBox (concatenation) diff --git a/src/boxes/array/mod.rs b/src/boxes/array/mod.rs index 7d6a2d67..0e724f95 100644 --- a/src/boxes/array/mod.rs +++ b/src/boxes/array/mod.rs @@ -135,6 +135,100 @@ impl ArrayBox { Box::new(StringBox::new("Error: join() requires string separator")) } } + + /// 配列をソート(昇順) + pub fn sort(&self) -> Box { + let mut items = self.items.lock().unwrap(); + + // Numeric values first, then string values + items.sort_by(|a, b| { + use std::cmp::Ordering; + + // Try to compare as numbers first + if let (Some(a_int), Some(b_int)) = ( + a.as_any().downcast_ref::(), + b.as_any().downcast_ref::() + ) { + return a_int.value.cmp(&b_int.value); + } + + // Try FloatBox comparison + if let (Some(a_float), Some(b_float)) = ( + a.as_any().downcast_ref::(), + b.as_any().downcast_ref::() + ) { + return a_float.value.partial_cmp(&b_float.value).unwrap_or(Ordering::Equal); + } + + // Mixed numeric types + if let (Some(a_int), Some(b_float)) = ( + a.as_any().downcast_ref::(), + b.as_any().downcast_ref::() + ) { + return (a_int.value as f64).partial_cmp(&b_float.value).unwrap_or(Ordering::Equal); + } + + if let (Some(a_float), Some(b_int)) = ( + a.as_any().downcast_ref::(), + b.as_any().downcast_ref::() + ) { + return a_float.value.partial_cmp(&(b_int.value as f64)).unwrap_or(Ordering::Equal); + } + + // Fall back to string comparison + let a_str = a.to_string_box().value; + let b_str = b.to_string_box().value; + a_str.cmp(&b_str) + }); + + Box::new(StringBox::new("ok")) + } + + /// 配列を反転 + pub fn reverse(&self) -> Box { + let mut items = self.items.lock().unwrap(); + items.reverse(); + Box::new(StringBox::new("ok")) + } + + /// 部分配列を取得 + pub fn slice(&self, start: Box, end: Box) -> Box { + let items = self.items.lock().unwrap(); + + // Extract start and end indices + let start_idx = if let Some(start_int) = start.as_any().downcast_ref::() { + if start_int.value < 0 { + 0 + } else { + start_int.value as usize + } + } else { + return Box::new(StringBox::new("Error: slice() start index must be an integer")); + }; + + let end_idx = if let Some(end_int) = end.as_any().downcast_ref::() { + if end_int.value < 0 { + items.len() + } else { + (end_int.value as usize).min(items.len()) + } + } else { + return Box::new(StringBox::new("Error: slice() end index must be an integer")); + }; + + // Validate indices + if start_idx > items.len() || start_idx > end_idx { + return Box::new(ArrayBox::new()); + } + + // Create slice + let slice_items: Vec> = items[start_idx..end_idx] + .iter() + .map(|item| item.clone_box()) + .collect(); + + Box::new(ArrayBox::new_with_elements(slice_items)) + } } impl BoxCore for ArrayBox { diff --git a/src/boxes/mod.rs b/src/boxes/mod.rs index 24ad41d1..e355c514 100644 --- a/src/boxes/mod.rs +++ b/src/boxes/mod.rs @@ -76,7 +76,7 @@ pub mod egui_box; pub use string_box::StringBox; pub use integer_box::IntegerBox; pub use bool_box::BoolBox; -pub use math_box::MathBox; +pub use math_box::{MathBox, FloatBox}; pub use time_box::TimeBox; pub use debug_box::DebugBox; pub use random_box::RandomBox; diff --git a/src/interpreter/expressions.rs b/src/interpreter/expressions.rs index 271442ee..4626d7c7 100644 --- a/src/interpreter/expressions.rs +++ b/src/interpreter/expressions.rs @@ -8,8 +8,9 @@ use super::*; use crate::ast::UnaryOperator; -use crate::boxes::{buffer::BufferBox, JSONBox, HttpClientBox, StreamBox, RegexBox, IntentBox, P2PBox}; +use crate::boxes::{buffer::BufferBox, JSONBox, HttpClientBox, StreamBox, RegexBox, IntentBox, P2PBox, FloatBox}; use crate::boxes::{MathBox, ConsoleBox, TimeBox, RandomBox, SoundBox, DebugBox, file::FileBox, MapBox}; +use crate::box_trait::BoolBox; use crate::operator_traits::OperatorResolver; // TODO: Fix NullBox import issue later // use crate::NullBox; @@ -332,6 +333,21 @@ impl NyashInterpreter { return self.execute_string_method(string_box, method, arguments); } + // IntegerBox method calls + if let Some(integer_box) = obj_value.as_any().downcast_ref::() { + return self.execute_integer_method(integer_box, method, arguments); + } + + // FloatBox method calls + if let Some(float_box) = obj_value.as_any().downcast_ref::() { + return self.execute_float_method(float_box, method, arguments); + } + + // BoolBox method calls + if let Some(bool_box) = obj_value.as_any().downcast_ref::() { + return self.execute_bool_method(bool_box, method, arguments); + } + // ArrayBox method calls if let Some(array_box) = obj_value.as_any().downcast_ref::() { return self.execute_array_method(array_box, method, arguments); diff --git a/src/interpreter/methods/collection_methods.rs b/src/interpreter/methods/collection_methods.rs index 6544a712..3891c764 100644 --- a/src/interpreter/methods/collection_methods.rs +++ b/src/interpreter/methods/collection_methods.rs @@ -126,6 +126,32 @@ impl NyashInterpreter { } Ok(Box::new(array_box.to_string_box())) } + "sort" => { + if !arguments.is_empty() { + return Err(RuntimeError::InvalidOperation { + message: format!("sort() expects 0 arguments, got {}", arguments.len()), + }); + } + Ok(array_box.sort()) + } + "reverse" => { + if !arguments.is_empty() { + return Err(RuntimeError::InvalidOperation { + message: format!("reverse() expects 0 arguments, got {}", arguments.len()), + }); + } + Ok(array_box.reverse()) + } + "slice" => { + if arguments.len() != 2 { + return Err(RuntimeError::InvalidOperation { + message: format!("slice() expects 2 arguments (start, end), got {}", arguments.len()), + }); + } + let start_value = self.execute_expression(&arguments[0])?; + let end_value = self.execute_expression(&arguments[1])?; + Ok(array_box.slice(start_value, end_value)) + } _ => { Err(RuntimeError::InvalidOperation { message: format!("Unknown method '{}' for ArrayBox", method), diff --git a/src/operator_traits.rs b/src/operator_traits.rs index 0d49c373..82e781e7 100644 --- a/src/operator_traits.rs +++ b/src/operator_traits.rs @@ -122,6 +122,12 @@ impl OperatorResolver { } } + 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); @@ -148,6 +154,12 @@ impl OperatorResolver { } } + 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); @@ -179,6 +191,12 @@ impl OperatorResolver { } } + 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); @@ -207,6 +225,15 @@ impl OperatorResolver { } } + 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); diff --git a/test_array_improvements.nyash b/test_array_improvements.nyash new file mode 100644 index 00000000..42949faa --- /dev/null +++ b/test_array_improvements.nyash @@ -0,0 +1,81 @@ +// test_array_improvements.nyash - ArrayBox Phase 2 improvements test +// Testing: sort(), reverse(), indexOf(), slice() methods + +print("📦 Testing ArrayBox improvements...") + +// Basic array creation and setup +local arr, result, sliceResult + +print("=== Setup: Creating test array ===") +arr = new ArrayBox() +arr.push(3) +arr.push(1) +arr.push(4) +arr.push(1) +arr.push(5) +print("Original array: " + arr.toString()) + +print("\n=== Test 1: sort() method ===") +arr.sort() +print("After sort(): " + arr.toString()) +// Expected: [1, 1, 3, 4, 5] + +print("\n=== Test 2: reverse() method ===") +arr.reverse() +print("After reverse(): " + arr.toString()) +// Expected: [5, 4, 3, 1, 1] + +print("\n=== Test 3: indexOf() method ===") +result = arr.indexOf(4) +print("indexOf(4): " + result.toString()) +// Expected: 1 + +result = arr.indexOf(1) +print("indexOf(1): " + result.toString()) +// Expected: 3 (first occurrence from current order) + +result = arr.indexOf(999) +print("indexOf(999): " + result.toString()) +// Expected: -1 (not found) + +print("\n=== Test 4: slice() method ===") +sliceResult = arr.slice(1, 4) +print("slice(1, 4): " + sliceResult.toString()) +// Expected: [4, 3, 1] (indices 1, 2, 3) + +sliceResult = arr.slice(0, 2) +print("slice(0, 2): " + sliceResult.toString()) +// Expected: [5, 4] (indices 0, 1) + +sliceResult = arr.slice(2, 10) // End beyond array +print("slice(2, 10): " + sliceResult.toString()) +// Expected: [3, 1, 1] (indices 2 to end) + +print("\n=== Test 5: Mixed types sorting ===") +local mixedArr +mixedArr = new ArrayBox() +mixedArr.push("banana") +mixedArr.push(2) +mixedArr.push("apple") +mixedArr.push(1) +mixedArr.push("cherry") +print("Mixed array before sort: " + mixedArr.toString()) + +mixedArr.sort() +print("Mixed array after sort: " + mixedArr.toString()) +// Expected: numbers first (1, 2), then strings alphabetically + +print("\n=== Test 6: FloatBox integration ===") +local floatArr +floatArr = new ArrayBox() +floatArr.push(new FloatBox(3.14)) +floatArr.push(1) +floatArr.push(new FloatBox(2.71)) +floatArr.push(4) +print("Float array before sort: " + floatArr.toString()) + +floatArr.sort() +print("Float array after sort: " + floatArr.toString()) +// Expected: [1, 2.71, 3.14, 4] + +print("\n✅ ArrayBox Phase 2 improvements tests completed!") \ No newline at end of file diff --git a/test_float_box.nyash b/test_float_box.nyash new file mode 100644 index 00000000..846bb44e --- /dev/null +++ b/test_float_box.nyash @@ -0,0 +1,49 @@ +// test_float_box.nyash - FloatBox functionality test +// Phase 1: Basic FloatBox implementation validation + +print("🧮 Testing FloatBox implementation...") + +// Basic FloatBox creation +local f1, f2, result +f1 = new FloatBox(3.14) +f2 = new FloatBox(2.86) + +print("Created FloatBox f1: " + f1.toString()) +print("Created FloatBox f2: " + f2.toString()) + +// Addition test +result = f1 + f2 +print("3.14 + 2.86 = " + result.toString()) + +// Multiplication test +result = f1 * f2 +print("3.14 * 2.86 = " + result.toString()) + +// Division test +result = f1 / f2 +print("3.14 / 2.86 = " + result.toString()) + +// Subtraction test +result = f1 - f2 +print("3.14 - 2.86 = " + result.toString()) + +// Mixed operations with IntegerBox +local intVal +intVal = 5 +result = f1 + intVal +print("3.14 + 5 = " + result.toString()) + +result = f1 * intVal +print("3.14 * 5 = " + result.toString()) + +// FloatBox methods +result = f1.abs() +print("abs(3.14) = " + result.toString()) + +result = f1.floor() +print("floor(3.14) = " + result.toString()) + +result = f1.ceil() +print("ceil(3.14) = " + result.toString()) + +print("✅ FloatBox Phase 1 tests completed!") \ No newline at end of file diff --git a/test_method_box_integration.rs b/test_method_box_integration.rs deleted file mode 100644 index 6796050e..00000000 --- a/test_method_box_integration.rs +++ /dev/null @@ -1,83 +0,0 @@ -/** - * MethodBox統合テスト - Nyash側使用対応確認 - * - * NewP2PBoxのon_method()がMethodBoxを正しく受け取れるか確認 - * MethodBox.invoke()が正しく呼ばれるか確認 - */ - -use std::sync::{Arc, Mutex}; - -// Nyashモジュールをインポート -use nyash_rust::boxes::{NewP2PBox, MessageIntentBox, StringBox}; -use nyash_rust::transport_trait::TransportKind; -use nyash_rust::method_box::MethodBox; -use nyash_rust::{NyashBox, InstanceBox}; - -fn main() { - println!("🎯 MethodBox統合テスト開始"); - - // テスト1: 基本的なMethodBox作成 - test_method_box_creation(); - - // テスト2: NewP2PBox + MethodBox統合 - test_method_box_integration(); - - println!("✅ MethodBox統合テスト完了!"); -} - -fn test_method_box_creation() { - println!("\n=== テスト1: MethodBox作成テスト ==="); - - // テスト用のインスタンスを作成(実際のInstanceBoxは使えないので、StringBoxで代用) - let test_instance = Box::new(StringBox::new("test_instance")); - - // MethodBoxを作成 - let method_box = MethodBox::new(test_instance, "test_method".to_string()); - - println!("✅ MethodBox作成成功: メソッド名 = {}", method_box.method_name); - - // invoke()テスト(現在は未実装エラーが返るはず) - let args = vec![Box::new(StringBox::new("test_arg")) as Box]; - match method_box.invoke(args) { - Ok(result) => println!("📥 MethodBox.invoke() 成功: {}", result.to_string_box().value), - Err(e) => println!("⚠️ MethodBox.invoke() 未実装: {}", e), - } -} - -fn test_method_box_integration() { - println!("\n=== テスト2: NewP2PBox + MethodBox統合テスト ==="); - - // P2PBoxノードを作成 - let alice = NewP2PBox::new("alice_method", TransportKind::InProcess); - let bob = NewP2PBox::new("bob_method", TransportKind::InProcess); - - // テスト用のMethodBoxを作成 - let handler_instance = Box::new(StringBox::new("message_handler")); - let handler_method = MethodBox::new(handler_instance, "handle_greeting".to_string()); - - // BobにMethodBoxベースのイベントリスナーを登録 - println!("📋 BobにMethodBoxベースのリスナー登録中..."); - match bob.on_method("greeting", handler_method) { - Ok(()) => println!("✅ MethodBoxリスナー登録成功!"), - Err(e) => { - println!("❌ MethodBoxリスナー登録エラー: {}", e); - return; - } - } - - // Aliceからメッセージ送信 - let mut message = MessageIntentBox::new("greeting"); - message.set("text", Box::new(StringBox::new("Hello Bob via MethodBox!"))); - message.set("sender", Box::new(StringBox::new("Alice"))); - - println!("📤 AliceからBobへMethodBox経由でメッセージ送信..."); - match alice.send("bob_method", &message) { - Ok(()) => println!("✅ メッセージ送信成功(MethodBox処理を確認)"), - Err(e) => println!("❌ メッセージ送信エラー: {}", e), - } - - // 少し待つ(非同期処理のため) - std::thread::sleep(std::time::Duration::from_millis(100)); - - println!("🎉 MethodBox統合が動作していることを確認!"); -} \ No newline at end of file diff --git a/test_operators.nyash b/test_operators.nyash new file mode 100644 index 00000000..6d28e9d0 --- /dev/null +++ b/test_operators.nyash @@ -0,0 +1,100 @@ +// test_operators.nyash - Operator Phase 3 comprehensive test +// Testing: comparison operators (<, >, <=, >=, ==, !=) with mixed types + +print("⚖️ Testing comprehensive operator support...") + +local f1, f2, i1, i2, result + +print("=== Setup: Creating test values ===") +f1 = new FloatBox(3.14) +f2 = new FloatBox(2.86) +i1 = 5 +i2 = 3 +print("f1 = " + f1.toString() + " (FloatBox)") +print("f2 = " + f2.toString() + " (FloatBox)") +print("i1 = " + i1.toString() + " (IntegerBox)") +print("i2 = " + i2.toString() + " (IntegerBox)") + +print("\n=== Test 1: Equality operators (==, !=) ===") +result = f1 == new FloatBox(3.14) +print("f1 == 3.14: " + result.toString()) // Expected: true + +result = f1 != f2 +print("f1 != f2: " + result.toString()) // Expected: true + +result = i1 == 5 +print("i1 == 5: " + result.toString()) // Expected: true + +result = i1 != i2 +print("i1 != i2: " + result.toString()) // Expected: true + +print("\n=== Test 2: Mixed type equality ===") +result = f1 == 3 // FloatBox vs IntegerBox +print("f1 == 3: " + result.toString()) // Expected: false (3.14 != 3) + +result = new FloatBox(5.0) == i1 // FloatBox vs IntegerBox +print("5.0 == i1: " + result.toString()) // Expected: true + +print("\n=== Test 3: Less than (<) ===") +result = f2 < f1 // FloatBox < FloatBox +print("f2 < f1: " + result.toString()) // Expected: true (2.86 < 3.14) + +result = i2 < i1 // IntegerBox < IntegerBox +print("i2 < i1: " + result.toString()) // Expected: true (3 < 5) + +result = f2 < i1 // FloatBox < IntegerBox +print("f2 < i1: " + result.toString()) // Expected: true (2.86 < 5) + +result = i2 < f1 // IntegerBox < FloatBox +print("i2 < f1: " + result.toString()) // Expected: true (3 < 3.14) + +print("\n=== Test 4: Greater than (>) ===") +result = f1 > f2 // FloatBox > FloatBox +print("f1 > f2: " + result.toString()) // Expected: true (3.14 > 2.86) + +result = i1 > i2 // IntegerBox > IntegerBox +print("i1 > i2: " + result.toString()) // Expected: true (5 > 3) + +result = i1 > f1 // IntegerBox > FloatBox +print("i1 > f1: " + result.toString()) // Expected: true (5 > 3.14) + +result = f1 > i2 // FloatBox > IntegerBox +print("f1 > i2: " + result.toString()) // Expected: true (3.14 > 3) + +print("\n=== Test 5: Less than or equal (<=) ===") +result = f2 <= f1 // FloatBox <= FloatBox +print("f2 <= f1: " + result.toString()) // Expected: true (2.86 <= 3.14) + +result = f1 <= f1 // FloatBox <= FloatBox (equal) +print("f1 <= f1: " + result.toString()) // Expected: true (3.14 <= 3.14) + +result = i2 <= i1 // IntegerBox <= IntegerBox +print("i2 <= i1: " + result.toString()) // Expected: true (3 <= 5) + +result = new FloatBox(5.0) <= i1 // FloatBox <= IntegerBox (equal) +print("5.0 <= i1: " + result.toString()) // Expected: true (5.0 <= 5) + +print("\n=== Test 6: Greater than or equal (>=) ===") +result = f1 >= f2 // FloatBox >= FloatBox +print("f1 >= f2: " + result.toString()) // Expected: true (3.14 >= 2.86) + +result = f1 >= f1 // FloatBox >= FloatBox (equal) +print("f1 >= f1: " + result.toString()) // Expected: true (3.14 >= 3.14) + +result = i1 >= i2 // IntegerBox >= IntegerBox +print("i1 >= i2: " + result.toString()) // Expected: true (5 >= 3) + +result = i1 >= new FloatBox(5.0) // IntegerBox >= FloatBox (equal) +print("i1 >= 5.0: " + result.toString()) // Expected: true (5 >= 5.0) + +print("\n=== Test 7: Complex expression chains ===") +result = (f1 > f2) and (i1 > i2) +print("(f1 > f2) and (i1 > i2): " + result.toString()) // Expected: true + +result = (f1 < i1) and (f2 > 1) +print("(f1 < i1) and (f2 > 1): " + result.toString()) // Expected: true + +result = not (f1 == f2) +print("not (f1 == f2): " + result.toString()) // Expected: true + +print("\n✅ Comprehensive operator tests completed!") \ No newline at end of file