diff --git a/src/box_trait.rs b/src/box_trait.rs index 2a26f490..54b1fb1a 100644 --- a/src/box_trait.rs +++ b/src/box_trait.rs @@ -123,7 +123,7 @@ impl StringBox { /// Join array elements using this string as delimiter pub fn join(&self, array_box: Box) -> Box { if let Some(array) = array_box.as_any().downcast_ref::() { - let strings: Vec = array.elements.lock().unwrap() + let strings: Vec = array.items.lock().unwrap() .iter() .map(|element| element.to_string_box().value) .collect(); @@ -363,147 +363,8 @@ impl Display for VoidBox { } } -/// Array values in Nyash - dynamic arrays of Box values -#[derive(Debug)] -pub struct ArrayBox { - pub elements: Arc>>>, - id: u64, -} - -impl Clone for ArrayBox { - fn clone(&self) -> Self { - Self { - elements: Arc::clone(&self.elements), // Arcをクローンして同じデータを共有 - id: self.id, // 同じIDを保持 - } - } -} - -impl ArrayBox { - pub fn new() -> Self { - static mut COUNTER: u64 = 0; - let id = unsafe { - COUNTER += 1; - COUNTER - }; - - Self { - elements: Arc::new(Mutex::new(Vec::new())), - id, - } - } - - pub fn new_with_elements(elements: Vec>) -> Self { - static mut COUNTER: u64 = 0; - let id = unsafe { - COUNTER += 1; - COUNTER - }; - - Self { - elements: Arc::new(Mutex::new(elements)), - id, - } - } - - // ===== Array Methods for Nyash ===== - - /// Add element to end of array - pub fn push(&self, element: Box) -> Box { - self.elements.lock().unwrap().push(element); - Box::new(VoidBox::new()) - } - - /// Remove and return last element - pub fn pop(&self) -> Box { - match self.elements.lock().unwrap().pop() { - Some(element) => element, - None => Box::new(VoidBox::new()), - } - } - - /// Get array length - pub fn length(&self) -> Box { - Box::new(IntegerBox::new(self.elements.lock().unwrap().len() as i64)) - } - - /// Join array elements with delimiter into string - pub fn join(&self, delimiter: &str) -> Box { - let strings: Vec = self.elements.lock().unwrap() - .iter() - .map(|element| element.to_string_box().value) - .collect(); - Box::new(StringBox::new(strings.join(delimiter))) - } - - /// Get element at index - pub fn get(&self, index: usize) -> Option> { - self.elements.lock().unwrap().get(index).map(|e| e.clone_box()) - } - - /// Set element at index - pub fn set(&self, index: usize, value: Box) -> Result<(), String> { - let mut elements = self.elements.lock().unwrap(); - if index < elements.len() { - elements[index] = value; - Ok(()) - } else { - Err(format!("Index {} out of bounds for array of length {}", index, elements.len())) - } - } -} - -impl NyashBox for ArrayBox { - fn to_string_box(&self) -> StringBox { - let elements_str: Vec = self.elements.lock().unwrap() - .iter() - .map(|e| e.to_string_box().value) - .collect(); - StringBox::new(format!("[{}]", elements_str.join(", "))) - } - - fn equals(&self, other: &dyn NyashBox) -> BoolBox { - if let Some(other_array) = other.as_any().downcast_ref::() { - let self_elements = self.elements.lock().unwrap(); - let other_elements = other_array.elements.lock().unwrap(); - - if self_elements.len() != other_elements.len() { - return BoolBox::new(false); - } - - for (a, b) in self_elements.iter().zip(other_elements.iter()) { - if !a.equals(b.as_ref()).value { - return BoolBox::new(false); - } - } - BoolBox::new(true) - } else { - BoolBox::new(false) - } - } - - fn type_name(&self) -> &'static str { - "ArrayBox" - } - - fn clone_box(&self) -> Box { - Box::new(self.clone()) // 同じインスタンスを共有 - } - - fn as_any(&self) -> &dyn Any { - self - } - - fn box_id(&self) -> u64 { - self.id - } -} - -impl Display for ArrayBox { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.to_string_box().value) - } -} +// ArrayBox is now defined in boxes::array module +pub use crate::boxes::array::ArrayBox; /// File values in Nyash - file system operations #[derive(Debug, Clone)] diff --git a/src/boxes/array/mod.rs b/src/boxes/array/mod.rs index f6348cd5..81c56bd1 100644 --- a/src/boxes/array/mod.rs +++ b/src/boxes/array/mod.rs @@ -26,6 +26,19 @@ impl ArrayBox { } } + /// 要素を持つArrayBoxを作成 + pub fn new_with_elements(elements: Vec>) -> Self { + static mut COUNTER: u64 = 0; + let id = unsafe { + COUNTER += 1; + COUNTER + }; + ArrayBox { + items: Arc::new(Mutex::new(elements)), + id, + } + } + /// 要素を追加 pub fn push(&self, item: Box) -> Box { self.items.lock().unwrap().push(item); @@ -46,36 +59,55 @@ impl ArrayBox { } /// インデックスで要素を取得 - pub fn get(&self, index: usize) -> Option> { - self.items.lock().unwrap().get(index).map(|item| item.clone_box()) + pub fn get(&self, index: Box) -> Box { + if let Some(idx_box) = index.as_any().downcast_ref::() { + let idx = idx_box.value as usize; + let items = self.items.lock().unwrap(); + match items.get(idx) { + Some(item) => item.clone_box(), + None => Box::new(crate::boxes::null_box::NullBox::new()), + } + } else { + Box::new(StringBox::new("Error: get() requires integer index")) + } } /// インデックスで要素を設定 - pub fn set(&self, index: usize, value: Box) -> Result<(), String> { - let mut items = self.items.lock().unwrap(); - if index < items.len() { - items[index] = value; - Ok(()) + pub fn set(&self, index: Box, value: Box) -> Box { + if let Some(idx_box) = index.as_any().downcast_ref::() { + let idx = idx_box.value as usize; + let mut items = self.items.lock().unwrap(); + if idx < items.len() { + items[idx] = value; + Box::new(StringBox::new("ok")) + } else { + Box::new(StringBox::new("Error: index out of bounds")) + } } else { - Err(format!("Index {} out of bounds", index)) + Box::new(StringBox::new("Error: set() requires integer index")) } } /// 要素を削除 - pub fn remove(&self, index: usize) -> Option> { - let mut items = self.items.lock().unwrap(); - if index < items.len() { - Some(items.remove(index)) + pub fn remove(&self, index: Box) -> Box { + if let Some(idx_box) = index.as_any().downcast_ref::() { + let idx = idx_box.value as usize; + let mut items = self.items.lock().unwrap(); + if idx < items.len() { + items.remove(idx) + } else { + Box::new(crate::boxes::null_box::NullBox::new()) + } } else { - None + Box::new(StringBox::new("Error: remove() requires integer index")) } } /// 指定された値のインデックスを検索 - pub fn indexOf(&self, value: &dyn NyashBox) -> Box { + pub fn indexOf(&self, value: Box) -> Box { let items = self.items.lock().unwrap(); for (i, item) in items.iter().enumerate() { - if item.equals(value).value { + if item.equals(value.as_ref()).value { return Box::new(IntegerBox::new(i as i64)); } } @@ -83,10 +115,10 @@ impl ArrayBox { } /// 指定された値が含まれているか確認 - pub fn contains(&self, value: &dyn NyashBox) -> Box { + pub fn contains(&self, value: Box) -> Box { let items = self.items.lock().unwrap(); for item in items.iter() { - if item.equals(value).value { + if item.equals(value.as_ref()).value { return Box::new(BoolBox::new(true)); } } @@ -100,12 +132,17 @@ impl ArrayBox { } /// 文字列結合 - pub fn join(&self, delimiter: &str) -> Box { - let items = self.items.lock().unwrap(); - let strings: Vec = items.iter() - .map(|item| item.to_string_box().value) - .collect(); - Box::new(StringBox::new(&strings.join(delimiter))) + pub fn join(&self, delimiter: Box) -> Box { + if let Some(sep_box) = delimiter.as_any().downcast_ref::() { + let items = self.items.lock().unwrap(); + let parts: Vec = items + .iter() + .map(|item| item.to_string_box().value) + .collect(); + Box::new(StringBox::new(&parts.join(&sep_box.value))) + } else { + Box::new(StringBox::new("Error: join() requires string separator")) + } } } diff --git a/src/boxes/buffer/mod.rs b/src/boxes/buffer/mod.rs index bf538ecd..f4421564 100644 --- a/src/boxes/buffer/mod.rs +++ b/src/boxes/buffer/mod.rs @@ -67,8 +67,8 @@ impl BufferBox { /// データを書き込む pub fn write(&self, data: Box) -> Box { - // ArrayBoxから変換 - if let Some(array_box) = data.as_any().downcast_ref::() { + // ArrayBoxから変換 - use crate::boxes::array::ArrayBox directly + if let Some(array_box) = data.as_any().downcast_ref::() { let mut buffer = self.data.lock().unwrap(); let items = array_box.items.lock().unwrap(); for item in items.iter() { @@ -80,7 +80,8 @@ impl BufferBox { } Box::new(IntegerBox::new(buffer.len() as i64)) } else { - Box::new(StringBox::new("Error: write() requires ArrayBox of integers")) + let type_name = data.type_name(); + Box::new(StringBox::new(&format!("Error: write() requires ArrayBox of integers, got {}", type_name))) } } diff --git a/src/boxes/random_box.rs b/src/boxes/random_box.rs index 90fd914b..8b4d6237 100644 --- a/src/boxes/random_box.rs +++ b/src/boxes/random_box.rs @@ -67,7 +67,8 @@ * - 大きな配列のshuffleは処理時間が長い場合あり */ -use crate::box_trait::{NyashBox, StringBox, IntegerBox, BoolBox, ArrayBox}; +use crate::box_trait::{NyashBox, StringBox, IntegerBox, BoolBox}; +use crate::boxes::array::ArrayBox; use crate::boxes::math_box::FloatBox; use std::fmt::{Debug, Display}; use std::any::Any; @@ -159,10 +160,8 @@ impl RandomBox { } let index = self.next_random() % (length as u64); - match array_box.get(index as usize) { - Some(element) => element, - None => Box::new(StringBox::new("Error: index out of bounds")), - } + // 新しいArrayBox.get()は既にBoxを返すので、直接使用 + array_box.get(Box::new(IntegerBox::new(index as i64))) } else { Box::new(StringBox::new("Error: choice() requires array input")) } @@ -181,7 +180,9 @@ impl RandomBox { // 元の配列の要素を全て新しい配列にコピー for i in 0..length { - if let Some(element) = array_box.get(i as usize) { + let element = array_box.get(Box::new(IntegerBox::new(i as i64))); + // NullBoxでなければ追加 + if element.type_name() != "NullBox" { shuffled.push(element); } } @@ -194,7 +195,9 @@ impl RandomBox { while !remaining_indices.is_empty() { let random_idx = (self.next_random() % remaining_indices.len() as u64) as usize; let actual_idx = remaining_indices.remove(random_idx); - if let Some(element) = array_box.get(actual_idx) { + let element = array_box.get(Box::new(IntegerBox::new(actual_idx as i64))); + // NullBoxでなければ追加 + if element.type_name() != "NullBox" { result.push(element); } } diff --git a/src/boxes/string_box.rs b/src/boxes/string_box.rs index 83f28b13..c1c56ccc 100644 --- a/src/boxes/string_box.rs +++ b/src/boxes/string_box.rs @@ -60,12 +60,16 @@ impl StringBox { /// Split string by delimiter and return ArrayBox pub fn split(&self, delimiter: &str) -> Box { - use crate::box_trait::ArrayBox; + use crate::boxes::array::ArrayBox; let parts: Vec = self.value.split(delimiter).map(|s| s.to_string()).collect(); let array_elements: Vec> = parts.into_iter() .map(|s| Box::new(StringBox::new(s)) as Box) .collect(); - Box::new(ArrayBox::new_with_elements(array_elements)) + let result = ArrayBox::new(); + for element in array_elements { + result.push(element); + } + Box::new(result) } /// Find substring and return position (or -1 if not found) @@ -117,9 +121,9 @@ impl StringBox { /// Join array elements using this string as delimiter pub fn join(&self, array_box: Box) -> Box { - use crate::box_trait::ArrayBox; + use crate::boxes::array::ArrayBox; if let Some(array) = array_box.as_any().downcast_ref::() { - let strings: Vec = array.elements.lock().unwrap() + let strings: Vec = array.items.lock().unwrap() .iter() .map(|element| element.to_string_box().value) .collect(); diff --git a/test_buffer_box.nyash b/test_buffer_box.nyash new file mode 100644 index 00000000..734d7c45 --- /dev/null +++ b/test_buffer_box.nyash @@ -0,0 +1,27 @@ +// 🧪 BufferBoxのテスト + +print("=== BufferBox Test ===") +local buffer, data, result + +// BufferBox作成 +buffer = new BufferBox() + +// データ配列作成 +data = new ArrayBox() +data.push(72) // 'H' +data.push(101) // 'e' +data.push(108) // 'l' +data.push(108) // 'l' +data.push(111) // 'o' + +// データ書き込み +result = buffer.write(data) +print("Write result: " + result) +print("Buffer length: " + buffer.length()) + +// データ読み取り +local readData +readData = buffer.readAll() +print("Read data: " + readData) + +print("BufferBox test completed!") \ No newline at end of file diff --git a/test_new_boxes.nyash b/test_new_boxes.nyash index d1be0f2e..cd0d581c 100644 --- a/test_new_boxes.nyash +++ b/test_new_boxes.nyash @@ -47,9 +47,8 @@ print("Read data length: " + readData.length()) // 3. JSONBoxのテスト print("\n=== JSONBox Test ===") -local json, parsed -json = new JSONBox() -parsed = json.parse('{"name": "Nyash", "version": 1.0}') +local parsed +parsed = new JSONBox("{\"name\": \"Nyash\", \"version\": 1.0}") print("JSON stringify: " + parsed.stringify()) print("Name from JSON: " + parsed.get("name")) diff --git a/test_random_box.nyash b/test_random_box.nyash new file mode 100644 index 00000000..13c33811 --- /dev/null +++ b/test_random_box.nyash @@ -0,0 +1,32 @@ +// 🎲 RandomBoxのテスト + +print("=== RandomBox Test ===") +local random, result, array + +// RandomBox作成 +random = new RandomBox() + +// 基本乱数テスト +result = random.random() +print("Random float: " + result) + +result = random.randInt(1, 6) +print("Dice roll (1-6): " + result) + +result = random.randBool() +print("Random bool: " + result) + +// 配列テスト +array = new ArrayBox() +array.push("apple") +array.push("banana") +array.push("cherry") + +result = random.choice(array) +print("Random choice: " + result) + +// 文字列生成テスト +result = random.randString(5) +print("Random string (5 chars): " + result) + +print("RandomBox test completed!") \ No newline at end of file