## 🎯 実装内容 - ArrayBoxにNyashBoxトレイト完全実装 - Arc<Mutex>による内部可変性実現(MapBoxと同じパターン) - 全メソッド実装: push/pop/get/set/length/indexOf/contains/join/clear/remove - 包括的なテストスイート作成 ## 🔧 技術的改善 - GitHub Copilot作成の基本構造をNyash対応に拡張 - execute_array_methodを&self参照に修正 - collection_methods.rsとの統合完了 ## ✅ テスト結果 - 全機能正常動作確認 - 異なる型の要素混在可能(Everything is Box哲学) - インデックス範囲外アクセスでNullBox返却 ## 📝 残課題 - BufferBox, ResultBox, FileBox等は基本構造のみ(未実装) - RegexBoxはNyashBoxトレイト実装済みだがregex依存関係未追加 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
278 lines
12 KiB
Rust
278 lines
12 KiB
Rust
/*!
|
|
* Collection Methods Module
|
|
*
|
|
* Extracted from box_methods.rs
|
|
* Contains method implementations for collection types:
|
|
* - ArrayBox (execute_array_method)
|
|
* - MapBox (execute_map_method)
|
|
*/
|
|
|
|
use super::super::*;
|
|
use crate::box_trait::{StringBox, IntegerBox, NyashBox, BoolBox};
|
|
use crate::boxes::array::ArrayBox;
|
|
use crate::boxes::map_box::MapBox;
|
|
|
|
impl NyashInterpreter {
|
|
/// ArrayBoxのメソッド呼び出しを実行
|
|
pub(in crate::interpreter) fn execute_array_method(&mut self, array_box: &ArrayBox, method: &str, arguments: &[ASTNode])
|
|
-> Result<Box<dyn NyashBox>, RuntimeError> {
|
|
match method {
|
|
"push" => {
|
|
if arguments.len() != 1 {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("push() expects 1 argument, got {}", arguments.len()),
|
|
});
|
|
}
|
|
let element = self.execute_expression(&arguments[0])?;
|
|
Ok(array_box.push(element))
|
|
}
|
|
"pop" => {
|
|
if !arguments.is_empty() {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("pop() expects 0 arguments, got {}", arguments.len()),
|
|
});
|
|
}
|
|
Ok(array_box.pop())
|
|
}
|
|
"length" => {
|
|
if !arguments.is_empty() {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("length() expects 0 arguments, got {}", arguments.len()),
|
|
});
|
|
}
|
|
Ok(array_box.length())
|
|
}
|
|
"get" => {
|
|
if arguments.len() != 1 {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("get() expects 1 argument, got {}", arguments.len()),
|
|
});
|
|
}
|
|
let index_value = self.execute_expression(&arguments[0])?;
|
|
Ok(array_box.get(index_value))
|
|
}
|
|
"set" => {
|
|
if arguments.len() != 2 {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("set() expects 2 arguments, got {}", arguments.len()),
|
|
});
|
|
}
|
|
let index_value = self.execute_expression(&arguments[0])?;
|
|
let element_value = self.execute_expression(&arguments[1])?;
|
|
Ok(array_box.set(index_value, element_value))
|
|
}
|
|
"remove" => {
|
|
if arguments.len() != 1 {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("remove() expects 1 argument, got {}", arguments.len()),
|
|
});
|
|
}
|
|
let index_value = self.execute_expression(&arguments[0])?;
|
|
Ok(array_box.remove(index_value))
|
|
}
|
|
"indexOf" => {
|
|
if arguments.len() != 1 {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("indexOf() expects 1 argument, got {}", arguments.len()),
|
|
});
|
|
}
|
|
let element = self.execute_expression(&arguments[0])?;
|
|
Ok(array_box.indexOf(element))
|
|
}
|
|
"contains" => {
|
|
if arguments.len() != 1 {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("contains() expects 1 argument, got {}", arguments.len()),
|
|
});
|
|
}
|
|
let element = self.execute_expression(&arguments[0])?;
|
|
Ok(array_box.contains(element))
|
|
}
|
|
"clear" => {
|
|
if !arguments.is_empty() {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("clear() expects 0 arguments, got {}", arguments.len()),
|
|
});
|
|
}
|
|
Ok(array_box.clear())
|
|
}
|
|
"join" => {
|
|
if arguments.len() != 1 {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("join() expects 1 argument, got {}", arguments.len()),
|
|
});
|
|
}
|
|
let delimiter_value = self.execute_expression(&arguments[0])?;
|
|
Ok(array_box.join(delimiter_value))
|
|
}
|
|
"isEmpty" => {
|
|
if !arguments.is_empty() {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("isEmpty() expects 0 arguments, got {}", arguments.len()),
|
|
});
|
|
}
|
|
let length = array_box.length();
|
|
if let Some(int_box) = length.as_any().downcast_ref::<IntegerBox>() {
|
|
Ok(Box::new(BoolBox::new(int_box.value == 0)))
|
|
} else {
|
|
Ok(Box::new(BoolBox::new(false)))
|
|
}
|
|
}
|
|
"toString" => {
|
|
if !arguments.is_empty() {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("toString() expects 0 arguments, got {}", arguments.len()),
|
|
});
|
|
}
|
|
Ok(Box::new(array_box.to_string_box()))
|
|
}
|
|
_ => {
|
|
Err(RuntimeError::InvalidOperation {
|
|
message: format!("Unknown method '{}' for ArrayBox", method),
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
/// MapBoxのメソッド呼び出しを実行
|
|
pub(in crate::interpreter) fn execute_map_method(&mut self, map_box: &MapBox, method: &str, arguments: &[ASTNode])
|
|
-> Result<Box<dyn NyashBox>, RuntimeError> {
|
|
|
|
// メソッドを実行(必要時評価方式)
|
|
match method {
|
|
"set" => {
|
|
if arguments.len() != 2 {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("set() expects 2 arguments, got {}", arguments.len()),
|
|
});
|
|
}
|
|
let key_value = self.execute_expression(&arguments[0])?;
|
|
let value_value = self.execute_expression(&arguments[1])?;
|
|
Ok(map_box.set(key_value, value_value))
|
|
}
|
|
"get" => {
|
|
if arguments.len() != 1 {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("get() expects 1 argument, got {}", arguments.len()),
|
|
});
|
|
}
|
|
let key_value = self.execute_expression(&arguments[0])?;
|
|
Ok(map_box.get(key_value))
|
|
}
|
|
"has" => {
|
|
if arguments.len() != 1 {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("has() expects 1 argument, got {}", arguments.len()),
|
|
});
|
|
}
|
|
let key_value = self.execute_expression(&arguments[0])?;
|
|
Ok(map_box.has(key_value))
|
|
}
|
|
"delete" => {
|
|
if arguments.len() != 1 {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("delete() expects 1 argument, got {}", arguments.len()),
|
|
});
|
|
}
|
|
let key_value = self.execute_expression(&arguments[0])?;
|
|
Ok(map_box.delete(key_value))
|
|
}
|
|
"keys" => {
|
|
if !arguments.is_empty() {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("keys() expects 0 arguments, got {}", arguments.len()),
|
|
});
|
|
}
|
|
Ok(map_box.keys())
|
|
}
|
|
"values" => {
|
|
if !arguments.is_empty() {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("values() expects 0 arguments, got {}", arguments.len()),
|
|
});
|
|
}
|
|
Ok(map_box.values())
|
|
}
|
|
"size" => {
|
|
if !arguments.is_empty() {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("size() expects 0 arguments, got {}", arguments.len()),
|
|
});
|
|
}
|
|
Ok(map_box.size())
|
|
}
|
|
"clear" => {
|
|
if !arguments.is_empty() {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("clear() expects 0 arguments, got {}", arguments.len()),
|
|
});
|
|
}
|
|
Ok(map_box.clear())
|
|
}
|
|
"isEmpty" => {
|
|
if !arguments.is_empty() {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("isEmpty() expects 0 arguments, got {}", arguments.len()),
|
|
});
|
|
}
|
|
let size = map_box.size();
|
|
if let Some(int_box) = size.as_any().downcast_ref::<IntegerBox>() {
|
|
Ok(Box::new(BoolBox::new(int_box.value == 0)))
|
|
} else {
|
|
Ok(Box::new(BoolBox::new(false)))
|
|
}
|
|
}
|
|
"containsKey" => {
|
|
if arguments.len() != 1 {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("containsKey() expects 1 argument, got {}", arguments.len()),
|
|
});
|
|
}
|
|
let key_value = self.execute_expression(&arguments[0])?;
|
|
Ok(map_box.has(key_value))
|
|
}
|
|
"containsValue" => {
|
|
if arguments.len() != 1 {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("containsValue() expects 1 argument, got {}", arguments.len()),
|
|
});
|
|
}
|
|
let _value = self.execute_expression(&arguments[0])?;
|
|
// Simple implementation: check if any value equals the given value
|
|
Ok(Box::new(BoolBox::new(false))) // TODO: implement proper value search
|
|
}
|
|
"forEach" => {
|
|
if arguments.len() != 1 {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("forEach() expects 1 argument, got {}", arguments.len()),
|
|
});
|
|
}
|
|
let callback_value = self.execute_expression(&arguments[0])?;
|
|
Ok(map_box.forEach(callback_value))
|
|
}
|
|
"toJSON" => {
|
|
if !arguments.is_empty() {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("toJSON() expects 0 arguments, got {}", arguments.len()),
|
|
});
|
|
}
|
|
Ok(map_box.toJSON())
|
|
}
|
|
// Note: merge, filter, map methods not implemented in MapBox yet
|
|
// These would require more complex callback handling
|
|
"toString" => {
|
|
if !arguments.is_empty() {
|
|
return Err(RuntimeError::InvalidOperation {
|
|
message: format!("toString() expects 0 arguments, got {}", arguments.len()),
|
|
});
|
|
}
|
|
Ok(Box::new(map_box.to_string_box()))
|
|
}
|
|
_ => {
|
|
Err(RuntimeError::InvalidOperation {
|
|
message: format!("Unknown MapBox method: {}", method),
|
|
})
|
|
}
|
|
}
|
|
}
|
|
} |