Files
hakorune/src/interpreter/methods/collection_methods.rs
Moe Charm cbee14809d feat: ArrayBox完全実装 - Nyash初の動的配列コレクション!
## 🎯 実装内容
- 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>
2025-08-10 12:24:59 +09:00

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),
})
}
}
}
}