Files
hakorune/src/interpreter/box_methods.rs
Moe Charm 0bed0c0271 🎉 initial commit: Nyash Programming Language完成版
🚀 主要機能:
• Everything is Box哲学による革新的アーキテクチャ
• WebAssemblyブラウザー対応プレイグラウンド
• アーティスト協同制作デモ - 複数Boxインスタンス実証
• 視覚的デバッグシステム - DebugBox完全統合
• static box Mainパターン - メモリ安全設計

 言語機能:
• NOT/AND/OR/除算演算子完全実装
• ジェネリクス/テンプレートシステム
• 非同期処理(nowait/await)
• try/catchエラーハンドリング
• Canvas統合グラフィックス

🎨 ブラウザー体験:
• 9種類のインタラクティブデモ
• リアルタイムコード実行
• WebCanvas/WebConsole/WebDisplay
• モバイル対応完了

🤖 Built with Claude Code collaboration
Ready for public release!
2025-08-09 15:14:44 +09:00

1823 lines
76 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*!
* Box Method Handlers Module
*
* Extracted from interpreter.rs lines 1389-2515 (1,126 lines)
* Contains all Box type-specific method implementations:
* - execute_string_method
* - execute_array_method
* - execute_file_method
* - execute_result_method
* - execute_future_method
* - execute_channel_method
* - execute_math_method
* - execute_time_method
* - execute_datetime_method
* - execute_timer_method
* - execute_map_method
* - execute_random_method
* - execute_sound_method
* - execute_debug_method
* - execute_method_box_method
*/
use super::*;
use crate::box_trait::{StringBox, IntegerBox};
use crate::boxes::null_box::NullBox;
impl NyashInterpreter {
/// StringBoxのメソッド呼び出しを実行
pub(super) fn execute_string_method(&mut self, string_box: &StringBox, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
// This will be filled with the actual implementation
// Complete for now to test modular structure
match method {
"split" => {
if arguments.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("split() expects 1 argument, got {}", arguments.len()),
});
}
let delimiter_value = self.execute_expression(&arguments[0])?;
if let Some(delimiter_str) = delimiter_value.as_any().downcast_ref::<StringBox>() {
Ok(string_box.split(&delimiter_str.value))
} else {
Err(RuntimeError::TypeError {
message: "split() requires string delimiter".to_string(),
})
}
}
"toString" => {
if !arguments.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("toString() expects 0 arguments, got {}", arguments.len()),
});
}
// StringBoxは自分自身を返す
Ok(Box::new(string_box.clone()))
}
"length" => {
if !arguments.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("length() expects 0 arguments, got {}", arguments.len()),
});
}
Ok(string_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])?;
if let Some(index_int) = index_value.as_any().downcast_ref::<IntegerBox>() {
match string_box.get(index_int.value as usize) {
Some(char_box) => Ok(char_box),
None => Ok(Box::new(VoidBox::new())),
}
} else {
Err(RuntimeError::TypeError {
message: "get() requires integer index".to_string(),
})
}
}
_ => {
Err(RuntimeError::InvalidOperation {
message: format!("Unknown method '{}' for StringBox", method),
})
}
}
}
/// IntegerBoxのメソッド呼び出しを実行
pub(super) fn execute_integer_method(&mut self, integer_box: &IntegerBox, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
match method {
"toString" => {
if !arguments.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("toString() expects 0 arguments, got {}", arguments.len()),
});
}
Ok(Box::new(StringBox::new(integer_box.value.to_string())))
}
"abs" => {
if !arguments.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("abs() expects 0 arguments, got {}", arguments.len()),
});
}
Ok(Box::new(IntegerBox::new(integer_box.value.abs())))
}
"max" => {
if arguments.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("max() expects 1 argument, got {}", arguments.len()),
});
}
let other_value = self.execute_expression(&arguments[0])?;
if let Some(other_int) = other_value.as_any().downcast_ref::<IntegerBox>() {
Ok(Box::new(IntegerBox::new(integer_box.value.max(other_int.value))))
} else {
Err(RuntimeError::TypeError {
message: "max() requires integer argument".to_string(),
})
}
}
"min" => {
if arguments.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("min() expects 1 argument, got {}", arguments.len()),
});
}
let other_value = self.execute_expression(&arguments[0])?;
if let Some(other_int) = other_value.as_any().downcast_ref::<IntegerBox>() {
Ok(Box::new(IntegerBox::new(integer_box.value.min(other_int.value))))
} else {
Err(RuntimeError::TypeError {
message: "min() requires integer argument".to_string(),
})
}
}
_ => {
Err(RuntimeError::InvalidOperation {
message: format!("Unknown method '{}' for IntegerBox", method),
})
}
}
}
/// ArrayBoxのメソッド呼び出しを実行
pub(super) 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])?;
if let Some(index_int) = index_value.as_any().downcast_ref::<IntegerBox>() {
if let Some(element) = array_box.get(index_int.value as usize) {
Ok(element)
} else {
Ok(Box::new(StringBox::new("Index out of bounds")))
}
} else {
Err(RuntimeError::TypeError {
message: "get() requires integer index".to_string(),
})
}
}
_ => {
Err(RuntimeError::InvalidOperation {
message: format!("Unknown method '{}' for ArrayBox", method),
})
}
}
}
/// FileBoxのメソッド呼び出しを実行
pub(super) fn execute_file_method(&mut self, file_box: &FileBox, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
match method {
"read" => {
if !arguments.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("read() expects 0 arguments, got {}", arguments.len()),
});
}
Ok(file_box.read())
}
"write" => {
if arguments.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("write() expects 1 argument, got {}", arguments.len()),
});
}
let content = self.execute_expression(&arguments[0])?;
Ok(file_box.write(content))
}
"exists" => {
if !arguments.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("exists() expects 0 arguments, got {}", arguments.len()),
});
}
Ok(file_box.exists())
}
"delete" => {
if !arguments.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("delete() expects 0 arguments, got {}", arguments.len()),
});
}
Ok(file_box.delete())
}
"copy" => {
if arguments.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("copy() expects 1 argument, got {}", arguments.len()),
});
}
let dest_value = self.execute_expression(&arguments[0])?;
if let Some(dest_str) = dest_value.as_any().downcast_ref::<StringBox>() {
Ok(file_box.copy(&dest_str.value))
} else {
Err(RuntimeError::TypeError {
message: "copy() requires string destination path".to_string(),
})
}
}
_ => Err(RuntimeError::InvalidOperation {
message: format!("Unknown method '{}' for FileBox", method),
})
}
}
pub(super) fn execute_result_method(&mut self, result_box: &ResultBox, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
match method {
"isOk" => {
if !arguments.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("isOk() expects 0 arguments, got {}", arguments.len()),
});
}
Ok(result_box.is_ok())
}
"getValue" => {
if !arguments.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("getValue() expects 0 arguments, got {}", arguments.len()),
});
}
Ok(result_box.get_value())
}
"getError" => {
if !arguments.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("getError() expects 0 arguments, got {}", arguments.len()),
});
}
Ok(result_box.get_error())
}
_ => Err(RuntimeError::InvalidOperation {
message: format!("Unknown method '{}' for ResultBox", method),
})
}
}
pub(super) fn execute_future_method(&mut self, future_box: &FutureBox, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
match method {
"get" => {
if !arguments.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("get() expects 0 arguments, got {}", arguments.len()),
});
}
Ok(future_box.get())
}
"ready" => {
if !arguments.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("ready() expects 0 arguments, got {}", arguments.len()),
});
}
Ok(future_box.ready())
}
"equals" => {
if arguments.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("equals() expects 1 argument, got {}", arguments.len()),
});
}
let other = self.execute_expression(&arguments[0])?;
Ok(Box::new(future_box.equals(other.as_ref())))
}
_ => Err(RuntimeError::InvalidOperation {
message: format!("Unknown method '{}' for FutureBox", method),
})
}
}
pub(super) fn execute_channel_method(&mut self, channel_box: &ChannelBox, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
// 引数を評価
let mut arg_values = Vec::new();
for arg in arguments {
arg_values.push(self.execute_expression(arg)?);
}
// メソッドを実行
match method {
"sendMessage" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("sendMessage() expects 1 argument, got {}", arg_values.len()),
});
}
// 簡易実装:メッセージを作成して返す
let content = arg_values[0].to_string_box().value;
let msg = MessageBox::new(&channel_box.sender_name, &content);
Ok(Box::new(msg))
}
"announce" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("announce() expects 1 argument, got {}", arg_values.len()),
});
}
let content = arg_values[0].to_string_box().value;
Ok(Box::new(StringBox::new(&format!("Broadcast from {}: {}", channel_box.sender_name, content))))
}
"toString" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("toString() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(Box::new(channel_box.to_string_box()))
}
"sender" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("sender() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(channel_box.sender())
}
"receiver" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("receiver() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(channel_box.receiver())
}
_ => {
// その他のメソッドはChannelBoxに委譲
Ok(channel_box.invoke(method, arg_values))
}
}
}
pub(super) fn execute_math_method(&mut self, math_box: &MathBox, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
// 引数を評価
let mut arg_values = Vec::new();
for arg in arguments {
arg_values.push(self.execute_expression(arg)?);
}
// メソッドを実行
match method {
"abs" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("abs() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(math_box.abs(arg_values[0].clone_box()))
}
"max" => {
if arg_values.len() != 2 {
return Err(RuntimeError::InvalidOperation {
message: format!("max() expects 2 arguments, got {}", arg_values.len()),
});
}
Ok(math_box.max(arg_values[0].clone_box(), arg_values[1].clone_box()))
}
"min" => {
if arg_values.len() != 2 {
return Err(RuntimeError::InvalidOperation {
message: format!("min() expects 2 arguments, got {}", arg_values.len()),
});
}
Ok(math_box.min(arg_values[0].clone_box(), arg_values[1].clone_box()))
}
"pow" => {
if arg_values.len() != 2 {
return Err(RuntimeError::InvalidOperation {
message: format!("pow() expects 2 arguments, got {}", arg_values.len()),
});
}
Ok(math_box.pow(arg_values[0].clone_box(), arg_values[1].clone_box()))
}
"sqrt" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("sqrt() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(math_box.sqrt(arg_values[0].clone_box()))
}
"getPi" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("getPi() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(math_box.getPi())
}
"getE" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("getE() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(math_box.getE())
}
"sin" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("sin() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(math_box.sin(arg_values[0].clone_box()))
}
"cos" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("cos() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(math_box.cos(arg_values[0].clone_box()))
}
"tan" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("tan() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(math_box.tan(arg_values[0].clone_box()))
}
"log" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("log() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(math_box.log(arg_values[0].clone_box()))
}
"log10" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("log10() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(math_box.log10(arg_values[0].clone_box()))
}
"exp" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("exp() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(math_box.exp(arg_values[0].clone_box()))
}
"floor" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("floor() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(math_box.floor(arg_values[0].clone_box()))
}
"ceil" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("ceil() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(math_box.ceil(arg_values[0].clone_box()))
}
"round" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("round() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(math_box.round(arg_values[0].clone_box()))
}
_ => {
Err(RuntimeError::InvalidOperation {
message: format!("Unknown MathBox method: {}", method),
})
}
}
}
/// NullBoxのメソッド呼び出しを実行
pub(super) fn execute_null_method(&mut self, _null_box: &NullBox, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
// 引数を評価
let mut arg_values = Vec::new();
for arg in arguments {
arg_values.push(self.execute_expression(arg)?);
}
// メソッドを実行
match method {
"is_null" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("is_null() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(Box::new(BoolBox::new(true)))
}
"is_not_null" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("is_not_null() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(Box::new(BoolBox::new(false)))
}
"equals" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("equals() expects 1 argument, got {}", arg_values.len()),
});
}
let other = &arg_values[0];
// NullBoxは他のNullBoxとのみ等しい
let is_equal = other.as_any().downcast_ref::<NullBox>().is_some();
Ok(Box::new(BoolBox::new(is_equal)))
}
"get_or_default" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("get_or_default() expects 1 argument, got {}", arg_values.len()),
});
}
// nullの場合はデフォルト値を返す
Ok(arg_values[0].clone_box())
}
_ => {
Err(RuntimeError::InvalidOperation {
message: format!("Unknown NullBox method: {}", method),
})
}
}
}
pub(super) fn execute_time_method(&mut self, time_box: &TimeBox, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
// 引数を評価
let mut arg_values = Vec::new();
for arg in arguments {
arg_values.push(self.execute_expression(arg)?);
}
// メソッドを実行
match method {
"now" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("now() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(time_box.now())
}
"fromTimestamp" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("fromTimestamp() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(time_box.fromTimestamp(arg_values[0].clone_box()))
}
"parse" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("parse() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(time_box.parse(arg_values[0].clone_box()))
}
"sleep" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("sleep() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(time_box.sleep(arg_values[0].clone_box()))
}
"format" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("format() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(time_box.format(arg_values[0].clone_box()))
}
_ => {
Err(RuntimeError::InvalidOperation {
message: format!("Unknown TimeBox method: {}", method),
})
}
}
}
pub(super) fn execute_datetime_method(&mut self, datetime_box: &DateTimeBox, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
// 引数を評価
let mut arg_values = Vec::new();
for arg in arguments {
arg_values.push(self.execute_expression(arg)?);
}
// メソッドを実行
match method {
"year" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("year() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(datetime_box.year())
}
"month" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("month() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(datetime_box.month())
}
"day" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("day() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(datetime_box.day())
}
"hour" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("hour() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(datetime_box.hour())
}
"minute" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("minute() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(datetime_box.minute())
}
"second" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("second() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(datetime_box.second())
}
"timestamp" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("timestamp() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(datetime_box.timestamp())
}
"toISOString" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("toISOString() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(datetime_box.toISOString())
}
"format" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("format() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(datetime_box.format(arg_values[0].clone_box()))
}
"addDays" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("addDays() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(datetime_box.addDays(arg_values[0].clone_box()))
}
"addHours" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("addHours() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(datetime_box.addHours(arg_values[0].clone_box()))
}
_ => {
Err(RuntimeError::InvalidOperation {
message: format!("Unknown DateTimeBox method: {}", method),
})
}
}
}
pub(super) fn execute_timer_method(&mut self, timer_box: &TimerBox, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
// 引数を評価
let mut arg_values = Vec::new();
for arg in arguments {
arg_values.push(self.execute_expression(arg)?);
}
// メソッドを実行
match method {
"elapsed" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("elapsed() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(timer_box.elapsed())
}
"reset" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("reset() expects 0 arguments, got {}", arg_values.len()),
});
}
// NOTE: resetはmutableメソッドなので、ここでは新しいTimerBoxを作成
let timer_box = Box::new(TimerBox::new()) as Box<dyn NyashBox>;
// 🌍 革命的実装Environment tracking廃止
Ok(timer_box)
}
_ => {
Err(RuntimeError::InvalidOperation {
message: format!("Unknown TimerBox method: {}", method),
})
}
}
}
pub(super) fn execute_map_method(&mut self, map_box: &MapBox, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
// 引数を評価
let mut arg_values = Vec::new();
for arg in arguments {
arg_values.push(self.execute_expression(arg)?);
}
// メソッドを実行
match method {
"set" => {
if arg_values.len() != 2 {
return Err(RuntimeError::InvalidOperation {
message: format!("set() expects 2 arguments, got {}", arg_values.len()),
});
}
Ok(map_box.set(arg_values[0].clone_box(), arg_values[1].clone_box()))
}
"get" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("get() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(map_box.get(arg_values[0].clone_box()))
}
"has" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("has() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(map_box.has(arg_values[0].clone_box()))
}
"delete" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("delete() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(map_box.delete(arg_values[0].clone_box()))
}
"keys" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("keys() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(map_box.keys())
}
"values" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("values() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(map_box.values())
}
"size" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("size() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(map_box.size())
}
"clear" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("clear() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(map_box.clear())
}
"forEach" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("forEach() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(map_box.forEach(arg_values[0].clone_box()))
}
"toJSON" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("toJSON() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(map_box.toJSON())
}
_ => {
Err(RuntimeError::InvalidOperation {
message: format!("Unknown MapBox method: {}", method),
})
}
}
}
pub(super) fn execute_random_method(&mut self, random_box: &RandomBox, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
// 引数を評価
let mut arg_values = Vec::new();
for arg in arguments {
arg_values.push(self.execute_expression(arg)?);
}
// メソッドを実行
match method {
"seed" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("seed() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(random_box.seed(arg_values[0].clone_box()))
}
"random" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("random() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(random_box.random())
}
"randInt" => {
if arg_values.len() != 2 {
return Err(RuntimeError::InvalidOperation {
message: format!("randInt() expects 2 arguments, got {}", arg_values.len()),
});
}
Ok(random_box.randInt(arg_values[0].clone_box(), arg_values[1].clone_box()))
}
"randBool" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("randBool() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(random_box.randBool())
}
"choice" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("choice() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(random_box.choice(arg_values[0].clone_box()))
}
"shuffle" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("shuffle() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(random_box.shuffle(arg_values[0].clone_box()))
}
"randString" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("randString() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(random_box.randString(arg_values[0].clone_box()))
}
"probability" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("probability() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(random_box.probability(arg_values[0].clone_box()))
}
_ => {
Err(RuntimeError::InvalidOperation {
message: format!("Unknown RandomBox method: {}", method),
})
}
}
}
pub(super) fn execute_sound_method(&mut self, sound_box: &SoundBox, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
// 引数を評価
let mut arg_values = Vec::new();
for arg in arguments {
arg_values.push(self.execute_expression(arg)?);
}
// メソッドを実行
match method {
"beep" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("beep() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(sound_box.beep())
}
"beeps" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("beeps() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(sound_box.beeps(arg_values[0].clone_box()))
}
"tone" => {
if arg_values.len() != 2 {
return Err(RuntimeError::InvalidOperation {
message: format!("tone() expects 2 arguments, got {}", arg_values.len()),
});
}
Ok(sound_box.tone(arg_values[0].clone_box(), arg_values[1].clone_box()))
}
"alert" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("alert() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(sound_box.alert())
}
"success" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("success() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(sound_box.success())
}
"error" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("error() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(sound_box.error())
}
"pattern" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("pattern() expects 1 argument, got {}", arg_values.len()),
});
}
Ok(sound_box.pattern(arg_values[0].clone_box()))
}
"volumeTest" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("volumeTest() expects 0 arguments, got {}", arg_values.len()),
});
}
Ok(sound_box.volumeTest())
}
"interval" => {
if arg_values.len() != 2 {
return Err(RuntimeError::InvalidOperation {
message: format!("interval() expects 2 arguments, got {}", arg_values.len()),
});
}
Ok(sound_box.interval(arg_values[0].clone_box(), arg_values[1].clone_box()))
}
_ => {
Err(RuntimeError::InvalidOperation {
message: format!("Unknown SoundBox method: {}", method),
})
}
}
}
pub(super) fn execute_debug_method(&mut self, debug_box: &DebugBox, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
// 引数を評価
let mut arg_values = Vec::new();
for arg in arguments {
arg_values.push(self.execute_expression(arg)?);
}
// メソッドを実行
match method {
"startTracking" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("startTracking() expects 0 arguments, got {}", arg_values.len()),
});
}
debug_box.start_tracking()
}
"stopTracking" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("stopTracking() expects 0 arguments, got {}", arg_values.len()),
});
}
debug_box.stop_tracking()
}
"trackBox" => {
if arg_values.len() != 2 {
return Err(RuntimeError::InvalidOperation {
message: format!("trackBox() expects 2 arguments, got {}", arg_values.len()),
});
}
// 第2引数をStringBoxとして取得
let name = if let Some(str_box) = arg_values[1].as_any().downcast_ref::<StringBox>() {
str_box.value.clone()
} else {
return Err(RuntimeError::InvalidOperation {
message: "trackBox() second argument must be a string".to_string(),
});
};
debug_box.track_box(arg_values[0].as_ref(), &name)
}
"dumpAll" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("dumpAll() expects 0 arguments, got {}", arg_values.len()),
});
}
debug_box.dump_all()
}
"saveToFile" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("saveToFile() expects 1 argument, got {}", arg_values.len()),
});
}
let filename = if let Some(str_box) = arg_values[0].as_any().downcast_ref::<StringBox>() {
str_box.value.clone()
} else {
return Err(RuntimeError::InvalidOperation {
message: "saveToFile() argument must be a string".to_string(),
});
};
debug_box.save_to_file(&filename)
}
"watch" => {
if arg_values.len() != 2 {
return Err(RuntimeError::InvalidOperation {
message: format!("watch() expects 2 arguments, got {}", arg_values.len()),
});
}
let name = if let Some(str_box) = arg_values[1].as_any().downcast_ref::<StringBox>() {
str_box.value.clone()
} else {
return Err(RuntimeError::InvalidOperation {
message: "watch() second argument must be a string".to_string(),
});
};
debug_box.watch(arg_values[0].as_ref(), &name)
}
"memoryReport" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("memoryReport() expects 0 arguments, got {}", arg_values.len()),
});
}
debug_box.memory_report()
}
"setBreakpoint" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("setBreakpoint() expects 1 argument, got {}", arg_values.len()),
});
}
let func_name = if let Some(str_box) = arg_values[0].as_any().downcast_ref::<StringBox>() {
str_box.value.clone()
} else {
return Err(RuntimeError::InvalidOperation {
message: "setBreakpoint() argument must be a string".to_string(),
});
};
debug_box.set_breakpoint(&func_name)
}
"traceCall" => {
if arg_values.len() < 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("traceCall() expects at least 1 argument, got {}", arg_values.len()),
});
}
let func_name = if let Some(str_box) = arg_values[0].as_any().downcast_ref::<StringBox>() {
str_box.value.clone()
} else {
return Err(RuntimeError::InvalidOperation {
message: "traceCall() first argument must be a string".to_string(),
});
};
// 残りの引数を文字列として収集
let args: Vec<String> = arg_values[1..].iter()
.map(|v| v.to_string_box().value)
.collect();
debug_box.trace_call(&func_name, args)
}
"showCallStack" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("showCallStack() expects 0 arguments, got {}", arg_values.len()),
});
}
debug_box.show_call_stack()
}
"clear" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("clear() expects 0 arguments, got {}", arg_values.len()),
});
}
debug_box.clear()
}
"isTracking" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("isTracking() expects 0 arguments, got {}", arg_values.len()),
});
}
debug_box.is_tracking()
}
"getTrackedCount" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("getTrackedCount() expects 0 arguments, got {}", arg_values.len()),
});
}
debug_box.get_tracked_count()
}
_ => {
Err(RuntimeError::InvalidOperation {
message: format!("Unknown DebugBox method: {}", method),
})
}
}
}
/// ConsoleBoxのメソッド呼び出しを実行
pub(super) fn execute_console_method(&mut self, console_box: &crate::boxes::console_box::ConsoleBox, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
// 引数を評価
let mut arg_values = Vec::new();
for arg in arguments {
arg_values.push(self.execute_expression(arg)?);
}
// メソッドを実行
match method {
"log" => {
if arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: "console.log() requires at least 1 argument".to_string(),
});
}
// 引数をすべて文字列に変換
let messages: Vec<String> = arg_values.iter()
.map(|arg| arg.to_string_box().value)
.collect();
let combined_message = messages.join(" ");
console_box.log(&combined_message);
Ok(Box::new(VoidBox::new()))
}
"warn" => {
if arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: "console.warn() requires at least 1 argument".to_string(),
});
}
let messages: Vec<String> = arg_values.iter()
.map(|arg| arg.to_string_box().value)
.collect();
let combined_message = messages.join(" ");
console_box.warn(&combined_message);
Ok(Box::new(VoidBox::new()))
}
"error" => {
if arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: "console.error() requires at least 1 argument".to_string(),
});
}
let messages: Vec<String> = arg_values.iter()
.map(|arg| arg.to_string_box().value)
.collect();
let combined_message = messages.join(" ");
console_box.error(&combined_message);
Ok(Box::new(VoidBox::new()))
}
"clear" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("console.clear() expects 0 arguments, got {}", arg_values.len()),
});
}
console_box.clear();
Ok(Box::new(VoidBox::new()))
}
_ => {
Err(RuntimeError::InvalidOperation {
message: format!("Unknown ConsoleBox method: {}", method),
})
}
}
}
/// MethodBoxのメソッド呼び出しを実行
pub(super) fn execute_method_box_method(&mut self, method_box: &crate::method_box::MethodBox, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
match method {
"invoke" => {
// 引数を評価
let mut arg_values = Vec::new();
for arg in arguments {
arg_values.push(self.execute_expression(arg)?);
}
// MethodBoxのinvokeを呼び出す
self.invoke_method_box(method_box, arg_values)
}
_ => {
Err(RuntimeError::InvalidOperation {
message: format!("Unknown MethodBox method: {}", method),
})
}
}
}
/// MethodBoxでメソッドを実際に呼び出す
fn invoke_method_box(&mut self, method_box: &crate::method_box::MethodBox, args: Vec<Box<dyn NyashBox>>)
-> Result<Box<dyn NyashBox>, RuntimeError> {
// インスタンスを取得
let instance_arc = method_box.get_instance();
let instance = instance_arc.lock().unwrap();
// InstanceBoxにダウンキャスト
if let Some(instance_box) = instance.as_any().downcast_ref::<crate::instance::InstanceBox>() {
// メソッドを取得
let method_ast = instance_box.get_method(&method_box.method_name)
.ok_or(RuntimeError::InvalidOperation {
message: format!("Method '{}' not found", method_box.method_name),
})?
.clone();
// メソッド呼び出しを実行
if let ASTNode::FunctionDeclaration { params, body, .. } = method_ast {
// パラメータ数チェック
if args.len() != params.len() {
return Err(RuntimeError::InvalidOperation {
message: format!("Method {} expects {} arguments, got {}",
method_box.method_name, params.len(), args.len()),
});
}
// local変数スタックを保存
let saved_locals = self.save_local_vars();
self.local_vars.clear();
// meをlocal変数として設定インスタンス自体
self.declare_local_variable("me", instance.clone_box());
// パラメータをlocal変数として設定
for (param, arg) in params.iter().zip(args.iter()) {
self.declare_local_variable(param, arg.clone_box());
}
// メソッド本体を実行
let mut result = Box::new(crate::box_trait::VoidBox::new()) as Box<dyn NyashBox>;
for statement in &body {
result = self.execute_statement(statement)?;
// return文チェック
if let super::ControlFlow::Return(ret_val) = &self.control_flow {
result = ret_val.clone_box();
self.control_flow = super::ControlFlow::None;
break;
}
}
// local変数スタックを復元
self.restore_local_vars(saved_locals);
Ok(result)
} else {
Err(RuntimeError::InvalidOperation {
message: format!("Method '{}' is not a valid function declaration", method_box.method_name),
})
}
} else {
Err(RuntimeError::TypeError {
message: "MethodBox instance is not an InstanceBox".to_string(),
})
}
}
/// WebDisplayBoxメソッド実行 (WASM環境のみ)
#[cfg(target_arch = "wasm32")]
pub(super) fn execute_web_display_method(&mut self, web_display_box: &crate::boxes::WebDisplayBox, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
// 引数を評価
let mut arg_values = Vec::new();
for arg in arguments {
arg_values.push(self.execute_expression(arg)?);
}
// メソッドを実行
match method {
"print" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("print() expects 1 argument, got {}", arg_values.len()),
});
}
let message = arg_values[0].to_string_box().value;
web_display_box.print(&message);
Ok(Box::new(VoidBox::new()))
}
"println" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("println() expects 1 argument, got {}", arg_values.len()),
});
}
let message = arg_values[0].to_string_box().value;
web_display_box.println(&message);
Ok(Box::new(VoidBox::new()))
}
"setHTML" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("setHTML() expects 1 argument, got {}", arg_values.len()),
});
}
let html_content = arg_values[0].to_string_box().value;
web_display_box.set_html(&html_content);
Ok(Box::new(VoidBox::new()))
}
"appendHTML" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("appendHTML() expects 1 argument, got {}", arg_values.len()),
});
}
let html_content = arg_values[0].to_string_box().value;
web_display_box.append_html(&html_content);
Ok(Box::new(VoidBox::new()))
}
"setCSS" => {
if arg_values.len() != 2 {
return Err(RuntimeError::InvalidOperation {
message: format!("setCSS() expects 2 arguments (property, value), got {}", arg_values.len()),
});
}
let property = arg_values[0].to_string_box().value;
let value = arg_values[1].to_string_box().value;
web_display_box.set_css(&property, &value);
Ok(Box::new(VoidBox::new()))
}
"addClass" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("addClass() expects 1 argument, got {}", arg_values.len()),
});
}
let class_name = arg_values[0].to_string_box().value;
web_display_box.add_class(&class_name);
Ok(Box::new(VoidBox::new()))
}
"removeClass" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("removeClass() expects 1 argument, got {}", arg_values.len()),
});
}
let class_name = arg_values[0].to_string_box().value;
web_display_box.remove_class(&class_name);
Ok(Box::new(VoidBox::new()))
}
"clear" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("clear() expects 0 arguments, got {}", arg_values.len()),
});
}
web_display_box.clear();
Ok(Box::new(VoidBox::new()))
}
"show" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("show() expects 0 arguments, got {}", arg_values.len()),
});
}
web_display_box.show();
Ok(Box::new(VoidBox::new()))
}
"hide" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("hide() expects 0 arguments, got {}", arg_values.len()),
});
}
web_display_box.hide();
Ok(Box::new(VoidBox::new()))
}
"scrollToBottom" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("scrollToBottom() expects 0 arguments, got {}", arg_values.len()),
});
}
web_display_box.scroll_to_bottom();
Ok(Box::new(VoidBox::new()))
}
_ => {
Err(RuntimeError::InvalidOperation {
message: format!("Unknown method '{}' for WebDisplayBox", method),
})
}
}
}
/// WebConsoleBoxメソッド実行 (WASM環境のみ)
#[cfg(target_arch = "wasm32")]
pub(super) fn execute_web_console_method(&mut self, web_console_box: &crate::boxes::WebConsoleBox, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
// 引数を評価
let mut arg_values = Vec::new();
for arg in arguments {
arg_values.push(self.execute_expression(arg)?);
}
// メソッドを実行
match method {
"log" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("log() expects 1 argument, got {}", arg_values.len()),
});
}
let message = arg_values[0].to_string_box().value;
web_console_box.log(&message);
Ok(Box::new(VoidBox::new()))
}
"warn" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("warn() expects 1 argument, got {}", arg_values.len()),
});
}
let message = arg_values[0].to_string_box().value;
web_console_box.warn(&message);
Ok(Box::new(VoidBox::new()))
}
"error" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("error() expects 1 argument, got {}", arg_values.len()),
});
}
let message = arg_values[0].to_string_box().value;
web_console_box.error(&message);
Ok(Box::new(VoidBox::new()))
}
"info" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("info() expects 1 argument, got {}", arg_values.len()),
});
}
let message = arg_values[0].to_string_box().value;
web_console_box.info(&message);
Ok(Box::new(VoidBox::new()))
}
"debug" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("debug() expects 1 argument, got {}", arg_values.len()),
});
}
let message = arg_values[0].to_string_box().value;
web_console_box.debug(&message);
Ok(Box::new(VoidBox::new()))
}
"clear" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("clear() expects 0 arguments, got {}", arg_values.len()),
});
}
web_console_box.clear();
Ok(Box::new(VoidBox::new()))
}
"separator" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("separator() expects 0 arguments, got {}", arg_values.len()),
});
}
web_console_box.separator();
Ok(Box::new(VoidBox::new()))
}
"group" => {
if arg_values.len() != 1 {
return Err(RuntimeError::InvalidOperation {
message: format!("group() expects 1 argument, got {}", arg_values.len()),
});
}
let title = arg_values[0].to_string_box().value;
web_console_box.group(&title);
Ok(Box::new(VoidBox::new()))
}
"groupEnd" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("groupEnd() expects 0 arguments, got {}", arg_values.len()),
});
}
web_console_box.group_end();
Ok(Box::new(VoidBox::new()))
}
_ => {
Err(RuntimeError::InvalidOperation {
message: format!("Unknown method '{}' for WebConsoleBox", method),
})
}
}
}
/// WebCanvasBoxメソッド実行 (WASM環境のみ)
#[cfg(target_arch = "wasm32")]
pub(super) fn execute_web_canvas_method(&mut self, web_canvas_box: &crate::boxes::WebCanvasBox, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
// 引数を評価
let mut arg_values = Vec::new();
for arg in arguments {
arg_values.push(self.execute_expression(arg)?);
}
// メソッドを実行
match method {
"clear" => {
if !arg_values.is_empty() {
return Err(RuntimeError::InvalidOperation {
message: format!("clear() expects 0 arguments, got {}", arg_values.len()),
});
}
web_canvas_box.clear();
Ok(Box::new(VoidBox::new()))
}
"fillRect" => {
if arg_values.len() != 5 {
return Err(RuntimeError::InvalidOperation {
message: format!("fillRect() expects 5 arguments (x, y, width, height, color), got {}", arg_values.len()),
});
}
let x = if let Some(n) = arg_values[0].as_any().downcast_ref::<IntegerBox>() {
n.value as f64
} else if let Some(n) = arg_values[0].as_any().downcast_ref::<FloatBox>() {
n.value
} else {
return Err(RuntimeError::TypeError {
message: "fillRect() x must be a number".to_string(),
});
};
let y = if let Some(n) = arg_values[1].as_any().downcast_ref::<IntegerBox>() {
n.value as f64
} else if let Some(n) = arg_values[1].as_any().downcast_ref::<FloatBox>() {
n.value
} else {
return Err(RuntimeError::TypeError {
message: "fillRect() y must be a number".to_string(),
});
};
let width = if let Some(n) = arg_values[2].as_any().downcast_ref::<IntegerBox>() {
n.value as f64
} else if let Some(n) = arg_values[2].as_any().downcast_ref::<FloatBox>() {
n.value
} else {
return Err(RuntimeError::TypeError {
message: "fillRect() width must be a number".to_string(),
});
};
let height = if let Some(n) = arg_values[3].as_any().downcast_ref::<IntegerBox>() {
n.value as f64
} else if let Some(n) = arg_values[3].as_any().downcast_ref::<FloatBox>() {
n.value
} else {
return Err(RuntimeError::TypeError {
message: "fillRect() height must be a number".to_string(),
});
};
let color = arg_values[4].to_string_box().value;
web_canvas_box.fill_rect(x, y, width, height, &color);
Ok(Box::new(VoidBox::new()))
}
"strokeRect" => {
if arg_values.len() != 6 {
return Err(RuntimeError::InvalidOperation {
message: format!("strokeRect() expects 6 arguments (x, y, width, height, color, lineWidth), got {}", arg_values.len()),
});
}
let x = if let Some(n) = arg_values[0].as_any().downcast_ref::<IntegerBox>() {
n.value as f64
} else if let Some(n) = arg_values[0].as_any().downcast_ref::<FloatBox>() {
n.value
} else {
return Err(RuntimeError::TypeError {
message: "strokeRect() x must be a number".to_string(),
});
};
let y = if let Some(n) = arg_values[1].as_any().downcast_ref::<IntegerBox>() {
n.value as f64
} else if let Some(n) = arg_values[1].as_any().downcast_ref::<FloatBox>() {
n.value
} else {
return Err(RuntimeError::TypeError {
message: "strokeRect() y must be a number".to_string(),
});
};
let width = if let Some(n) = arg_values[2].as_any().downcast_ref::<IntegerBox>() {
n.value as f64
} else if let Some(n) = arg_values[2].as_any().downcast_ref::<FloatBox>() {
n.value
} else {
return Err(RuntimeError::TypeError {
message: "strokeRect() width must be a number".to_string(),
});
};
let height = if let Some(n) = arg_values[3].as_any().downcast_ref::<IntegerBox>() {
n.value as f64
} else if let Some(n) = arg_values[3].as_any().downcast_ref::<FloatBox>() {
n.value
} else {
return Err(RuntimeError::TypeError {
message: "strokeRect() height must be a number".to_string(),
});
};
let color = arg_values[4].to_string_box().value;
let line_width = if let Some(n) = arg_values[5].as_any().downcast_ref::<IntegerBox>() {
n.value as f64
} else if let Some(n) = arg_values[5].as_any().downcast_ref::<FloatBox>() {
n.value
} else {
return Err(RuntimeError::TypeError {
message: "strokeRect() lineWidth must be a number".to_string(),
});
};
web_canvas_box.stroke_rect(x, y, width, height, &color, line_width);
Ok(Box::new(VoidBox::new()))
}
"fillCircle" => {
if arg_values.len() != 4 {
return Err(RuntimeError::InvalidOperation {
message: format!("fillCircle() expects 4 arguments (x, y, radius, color), got {}", arg_values.len()),
});
}
let x = if let Some(n) = arg_values[0].as_any().downcast_ref::<IntegerBox>() {
n.value as f64
} else if let Some(n) = arg_values[0].as_any().downcast_ref::<FloatBox>() {
n.value
} else {
return Err(RuntimeError::TypeError {
message: "fillCircle() x must be a number".to_string(),
});
};
let y = if let Some(n) = arg_values[1].as_any().downcast_ref::<IntegerBox>() {
n.value as f64
} else if let Some(n) = arg_values[1].as_any().downcast_ref::<FloatBox>() {
n.value
} else {
return Err(RuntimeError::TypeError {
message: "fillCircle() y must be a number".to_string(),
});
};
let radius = if let Some(n) = arg_values[2].as_any().downcast_ref::<IntegerBox>() {
n.value as f64
} else if let Some(n) = arg_values[2].as_any().downcast_ref::<FloatBox>() {
n.value
} else {
return Err(RuntimeError::TypeError {
message: "fillCircle() radius must be a number".to_string(),
});
};
let color = arg_values[3].to_string_box().value;
web_canvas_box.fill_circle(x, y, radius, &color);
Ok(Box::new(VoidBox::new()))
}
"fillText" => {
if arg_values.len() != 5 {
return Err(RuntimeError::InvalidOperation {
message: format!("fillText() expects 5 arguments (text, x, y, font, color), got {}", arg_values.len()),
});
}
let text = arg_values[0].to_string_box().value;
let x = if let Some(n) = arg_values[1].as_any().downcast_ref::<IntegerBox>() {
n.value as f64
} else if let Some(n) = arg_values[1].as_any().downcast_ref::<FloatBox>() {
n.value
} else {
return Err(RuntimeError::TypeError {
message: "fillText() x must be a number".to_string(),
});
};
let y = if let Some(n) = arg_values[2].as_any().downcast_ref::<IntegerBox>() {
n.value as f64
} else if let Some(n) = arg_values[2].as_any().downcast_ref::<FloatBox>() {
n.value
} else {
return Err(RuntimeError::TypeError {
message: "fillText() y must be a number".to_string(),
});
};
let font = arg_values[3].to_string_box().value;
let color = arg_values[4].to_string_box().value;
web_canvas_box.fill_text(&text, x, y, &font, &color);
Ok(Box::new(VoidBox::new()))
}
_ => {
Err(RuntimeError::InvalidOperation {
message: format!("Unknown method '{}' for WebCanvasBox", method),
})
}
}
}
}