2025-08-09 15:14:44 +09:00
|
|
|
|
/*!
|
|
|
|
|
|
* Object Processing Module
|
|
|
|
|
|
*
|
|
|
|
|
|
* Extracted from core.rs - object creation, construction, and inheritance
|
|
|
|
|
|
* Handles Box declarations, instantiation, constructors, and inheritance system
|
|
|
|
|
|
* Core philosophy: "Everything is Box" with complete OOP support
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
use super::*;
|
2025-08-11 20:38:39 +00:00
|
|
|
|
use crate::boxes::{NullBox, ConsoleBox, FloatBox, DateTimeBox};
|
2025-08-10 07:54:03 +09:00
|
|
|
|
// use crate::boxes::intent_box_wrapper::IntentBoxWrapper;
|
|
|
|
|
|
use std::sync::Arc;
|
2025-08-09 15:14:44 +09:00
|
|
|
|
|
|
|
|
|
|
impl NyashInterpreter {
|
|
|
|
|
|
/// new式を実行 - Object creation engine
|
|
|
|
|
|
pub(super) fn execute_new(&mut self, class: &str, arguments: &[ASTNode], type_arguments: &[String])
|
|
|
|
|
|
-> Result<Box<dyn NyashBox>, RuntimeError> {
|
|
|
|
|
|
// 組み込みBox型のチェック
|
|
|
|
|
|
match class {
|
2025-08-12 08:14:28 +00:00
|
|
|
|
// Basic Box constructors (CRITICAL - these were missing!)
|
|
|
|
|
|
"StringBox" => {
|
|
|
|
|
|
// StringBoxは引数1個(文字列値)で作成
|
|
|
|
|
|
if arguments.len() != 1 {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("StringBox constructor expects 1 argument, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let value = self.execute_expression(&arguments[0])?;
|
|
|
|
|
|
let string_value = value.to_string_box().value;
|
|
|
|
|
|
let string_box = Box::new(StringBox::new(string_value)) as Box<dyn NyashBox>;
|
|
|
|
|
|
return Ok(string_box);
|
|
|
|
|
|
}
|
|
|
|
|
|
"IntegerBox" => {
|
|
|
|
|
|
// IntegerBoxは引数1個(整数値)で作成
|
|
|
|
|
|
if arguments.len() != 1 {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("IntegerBox constructor expects 1 argument, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let value = self.execute_expression(&arguments[0])?;
|
|
|
|
|
|
if let Some(int_box) = value.as_any().downcast_ref::<IntegerBox>() {
|
|
|
|
|
|
let integer_box = Box::new(IntegerBox::new(int_box.value)) as Box<dyn NyashBox>;
|
|
|
|
|
|
return Ok(integer_box);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// Try to parse from string or other types
|
|
|
|
|
|
let int_value = value.to_string_box().value.parse::<i64>()
|
|
|
|
|
|
.map_err(|_| RuntimeError::TypeError {
|
|
|
|
|
|
message: format!("Cannot convert '{}' to integer", value.to_string_box().value),
|
|
|
|
|
|
})?;
|
|
|
|
|
|
let integer_box = Box::new(IntegerBox::new(int_value)) as Box<dyn NyashBox>;
|
|
|
|
|
|
return Ok(integer_box);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
"BoolBox" => {
|
|
|
|
|
|
// BoolBoxは引数1個(真偽値)で作成
|
|
|
|
|
|
if arguments.len() != 1 {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("BoolBox constructor expects 1 argument, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let value = self.execute_expression(&arguments[0])?;
|
|
|
|
|
|
if let Some(bool_box) = value.as_any().downcast_ref::<BoolBox>() {
|
|
|
|
|
|
let bool_box_new = Box::new(BoolBox::new(bool_box.value)) as Box<dyn NyashBox>;
|
|
|
|
|
|
return Ok(bool_box_new);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// Try to convert from string or other types
|
|
|
|
|
|
let bool_value = match value.to_string_box().value.to_lowercase().as_str() {
|
|
|
|
|
|
"true" => true,
|
|
|
|
|
|
"false" => false,
|
|
|
|
|
|
_ => return Err(RuntimeError::TypeError {
|
|
|
|
|
|
message: format!("Cannot convert '{}' to boolean", value.to_string_box().value),
|
|
|
|
|
|
}),
|
|
|
|
|
|
};
|
|
|
|
|
|
let bool_box_new = Box::new(BoolBox::new(bool_value)) as Box<dyn NyashBox>;
|
|
|
|
|
|
return Ok(bool_box_new);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-08-09 15:14:44 +09:00
|
|
|
|
"ArrayBox" => {
|
|
|
|
|
|
// ArrayBoxは引数なしで作成
|
|
|
|
|
|
if !arguments.is_empty() {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("ArrayBox constructor expects 0 arguments, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let array_box = Box::new(ArrayBox::new()) as Box<dyn NyashBox>;
|
|
|
|
|
|
// 🌍 革命的実装:Environment tracking廃止
|
|
|
|
|
|
return Ok(array_box);
|
|
|
|
|
|
}
|
|
|
|
|
|
"FileBox" => {
|
|
|
|
|
|
// FileBoxは引数1個(ファイルパス)で作成
|
|
|
|
|
|
if arguments.len() != 1 {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("FileBox constructor expects 1 argument, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let path_value = self.execute_expression(&arguments[0])?;
|
|
|
|
|
|
if let Some(path_str) = path_value.as_any().downcast_ref::<StringBox>() {
|
|
|
|
|
|
let file_box = Box::new(FileBox::new(&path_str.value)) as Box<dyn NyashBox>;
|
|
|
|
|
|
// 🌍 革命的実装:Environment tracking廃止
|
|
|
|
|
|
return Ok(file_box);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return Err(RuntimeError::TypeError {
|
|
|
|
|
|
message: "FileBox constructor requires string path argument".to_string(),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
"ResultBox" => {
|
|
|
|
|
|
// ResultBoxは引数1個(成功値)で作成
|
|
|
|
|
|
if arguments.len() != 1 {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("ResultBox constructor expects 1 argument, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let value = self.execute_expression(&arguments[0])?;
|
|
|
|
|
|
let result_box = Box::new(ResultBox::new_success(value)) as Box<dyn NyashBox>;
|
|
|
|
|
|
// 🌍 革命的実装:Environment tracking廃止
|
|
|
|
|
|
return Ok(result_box);
|
|
|
|
|
|
}
|
|
|
|
|
|
"ErrorBox" => {
|
|
|
|
|
|
// ErrorBoxは引数2個(エラータイプ、メッセージ)で作成
|
|
|
|
|
|
if arguments.len() != 2 {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("ErrorBox constructor expects 2 arguments, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let error_type_value = self.execute_expression(&arguments[0])?;
|
|
|
|
|
|
let message_value = self.execute_expression(&arguments[1])?;
|
|
|
|
|
|
|
|
|
|
|
|
if let (Some(error_type_str), Some(message_str)) = (
|
|
|
|
|
|
error_type_value.as_any().downcast_ref::<StringBox>(),
|
|
|
|
|
|
message_value.as_any().downcast_ref::<StringBox>()
|
|
|
|
|
|
) {
|
|
|
|
|
|
let error_box = Box::new(ErrorBox::new(&error_type_str.value, &message_str.value)) as Box<dyn NyashBox>;
|
|
|
|
|
|
// 🌍 革命的実装:Environment tracking廃止
|
|
|
|
|
|
return Ok(error_box);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return Err(RuntimeError::TypeError {
|
|
|
|
|
|
message: "ErrorBox constructor requires two string arguments".to_string(),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
"MathBox" => {
|
|
|
|
|
|
// MathBoxは引数なしで作成
|
|
|
|
|
|
if !arguments.is_empty() {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("MathBox constructor expects 0 arguments, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let math_box = Box::new(MathBox::new()) as Box<dyn NyashBox>;
|
|
|
|
|
|
// 🌍 革命的実装:Environment tracking廃止
|
|
|
|
|
|
return Ok(math_box);
|
|
|
|
|
|
}
|
|
|
|
|
|
"NullBox" => {
|
|
|
|
|
|
// NullBoxは引数なしで作成
|
|
|
|
|
|
if !arguments.is_empty() {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("NullBox constructor expects 0 arguments, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let null_box = Box::new(NullBox::new()) as Box<dyn NyashBox>;
|
|
|
|
|
|
return Ok(null_box);
|
|
|
|
|
|
}
|
|
|
|
|
|
"ConsoleBox" => {
|
|
|
|
|
|
// ConsoleBoxは引数なしで作成(ブラウザconsole連携用)
|
|
|
|
|
|
if !arguments.is_empty() {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("ConsoleBox constructor expects 0 arguments, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let console_box = Box::new(ConsoleBox::new()) as Box<dyn NyashBox>;
|
|
|
|
|
|
return Ok(console_box);
|
|
|
|
|
|
}
|
2025-08-10 07:54:03 +09:00
|
|
|
|
// "IntentBox" => {
|
|
|
|
|
|
// // IntentBoxは引数なしで作成(メッセージバス)
|
|
|
|
|
|
// if !arguments.is_empty() {
|
|
|
|
|
|
// return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
// message: format!("IntentBox constructor expects 0 arguments, got {}", arguments.len()),
|
|
|
|
|
|
// });
|
|
|
|
|
|
// }
|
|
|
|
|
|
// let intent_box = Arc::new(crate::boxes::IntentBox::new());
|
|
|
|
|
|
// let intent_box_wrapped = Box::new(IntentBoxWrapper {
|
|
|
|
|
|
// inner: intent_box
|
|
|
|
|
|
// }) as Box<dyn NyashBox>;
|
|
|
|
|
|
// return Ok(intent_box_wrapped);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// "P2PBox" => {
|
|
|
|
|
|
// // P2PBoxは引数2個(node_id, intent_box)で作成
|
|
|
|
|
|
// if arguments.len() != 2 {
|
|
|
|
|
|
// return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
// message: format!("P2PBox constructor expects 2 arguments (node_id, intent_box), got {}", arguments.len()),
|
|
|
|
|
|
// });
|
|
|
|
|
|
// }
|
|
|
|
|
|
//
|
|
|
|
|
|
// // node_id
|
|
|
|
|
|
// let node_id_value = self.execute_expression(&arguments[0])?;
|
|
|
|
|
|
// let node_id = if let Some(id_str) = node_id_value.as_any().downcast_ref::<StringBox>() {
|
|
|
|
|
|
// id_str.value.clone()
|
|
|
|
|
|
// } else {
|
|
|
|
|
|
// return Err(RuntimeError::TypeError {
|
|
|
|
|
|
// message: "P2PBox constructor requires string node_id as first argument".to_string(),
|
|
|
|
|
|
// });
|
|
|
|
|
|
// };
|
|
|
|
|
|
//
|
|
|
|
|
|
// // intent_box
|
|
|
|
|
|
// let intent_box_value = self.execute_expression(&arguments[1])?;
|
|
|
|
|
|
// let intent_box = if let Some(wrapper) = intent_box_value.as_any().downcast_ref::<IntentBoxWrapper>() {
|
|
|
|
|
|
// wrapper.inner.clone()
|
|
|
|
|
|
// } else {
|
|
|
|
|
|
// return Err(RuntimeError::TypeError {
|
|
|
|
|
|
// message: "P2PBox constructor requires IntentBox as second argument".to_string(),
|
|
|
|
|
|
// });
|
|
|
|
|
|
// };
|
|
|
|
|
|
//
|
|
|
|
|
|
// let p2p_box = Box::new(crate::boxes::P2PBox::new(node_id, intent_box)) as Box<dyn NyashBox>;
|
|
|
|
|
|
// return Ok(p2p_box);
|
|
|
|
|
|
// }
|
|
|
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
|
|
|
|
"EguiBox" => {
|
|
|
|
|
|
// EguiBoxは引数なしで作成(GUIアプリケーション用)
|
|
|
|
|
|
if !arguments.is_empty() {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("EguiBox constructor expects 0 arguments, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let egui_box = Box::new(crate::boxes::EguiBox::new()) as Box<dyn NyashBox>;
|
|
|
|
|
|
return Ok(egui_box);
|
|
|
|
|
|
}
|
2025-08-09 15:14:44 +09:00
|
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
|
|
|
|
"WebDisplayBox" => {
|
|
|
|
|
|
// WebDisplayBoxは引数1個(要素ID)で作成(ブラウザHTML操作用)
|
|
|
|
|
|
if arguments.len() != 1 {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("WebDisplayBox constructor expects 1 argument (element_id), got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let element_id_value = self.execute_expression(&arguments[0])?;
|
|
|
|
|
|
if let Some(id_str) = element_id_value.as_any().downcast_ref::<StringBox>() {
|
|
|
|
|
|
let web_display_box = Box::new(crate::boxes::WebDisplayBox::new(id_str.value.clone())) as Box<dyn NyashBox>;
|
|
|
|
|
|
return Ok(web_display_box);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return Err(RuntimeError::TypeError {
|
|
|
|
|
|
message: "WebDisplayBox constructor requires string element_id argument".to_string(),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
|
|
|
|
"WebConsoleBox" => {
|
|
|
|
|
|
// WebConsoleBoxは引数1個(要素ID)で作成(ブラウザコンソール風出力用)
|
|
|
|
|
|
if arguments.len() != 1 {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("WebConsoleBox constructor expects 1 argument (element_id), got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let element_id_value = self.execute_expression(&arguments[0])?;
|
|
|
|
|
|
if let Some(id_str) = element_id_value.as_any().downcast_ref::<StringBox>() {
|
|
|
|
|
|
let web_console_box = Box::new(crate::boxes::WebConsoleBox::new(id_str.value.clone())) as Box<dyn NyashBox>;
|
|
|
|
|
|
return Ok(web_console_box);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return Err(RuntimeError::TypeError {
|
|
|
|
|
|
message: "WebConsoleBox constructor requires string element_id argument".to_string(),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
|
|
|
|
"WebCanvasBox" => {
|
|
|
|
|
|
// WebCanvasBoxは引数3個(canvas ID、幅、高さ)で作成
|
|
|
|
|
|
if arguments.len() != 3 {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("WebCanvasBox constructor expects 3 arguments (canvas_id, width, height), got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Canvas ID
|
|
|
|
|
|
let canvas_id_value = self.execute_expression(&arguments[0])?;
|
|
|
|
|
|
let canvas_id = if let Some(id_str) = canvas_id_value.as_any().downcast_ref::<StringBox>() {
|
|
|
|
|
|
id_str.value.clone()
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return Err(RuntimeError::TypeError {
|
|
|
|
|
|
message: "WebCanvasBox constructor requires string canvas_id as first argument".to_string(),
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Width
|
|
|
|
|
|
let width_value = self.execute_expression(&arguments[1])?;
|
|
|
|
|
|
let width = if let Some(int_box) = width_value.as_any().downcast_ref::<IntegerBox>() {
|
|
|
|
|
|
int_box.value as u32
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return Err(RuntimeError::TypeError {
|
|
|
|
|
|
message: "WebCanvasBox constructor requires integer width as second argument".to_string(),
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Height
|
|
|
|
|
|
let height_value = self.execute_expression(&arguments[2])?;
|
|
|
|
|
|
let height = if let Some(int_box) = height_value.as_any().downcast_ref::<IntegerBox>() {
|
|
|
|
|
|
int_box.value as u32
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return Err(RuntimeError::TypeError {
|
|
|
|
|
|
message: "WebCanvasBox constructor requires integer height as third argument".to_string(),
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let web_canvas_box = Box::new(crate::boxes::WebCanvasBox::new(canvas_id, width, height)) as Box<dyn NyashBox>;
|
|
|
|
|
|
return Ok(web_canvas_box);
|
|
|
|
|
|
}
|
|
|
|
|
|
"FloatBox" => {
|
|
|
|
|
|
// FloatBoxは引数1個(数値)で作成
|
|
|
|
|
|
if arguments.len() != 1 {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("FloatBox constructor expects 1 argument, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let value = self.execute_expression(&arguments[0])?;
|
|
|
|
|
|
if let Some(int_box) = value.as_any().downcast_ref::<IntegerBox>() {
|
|
|
|
|
|
let float_box = Box::new(FloatBox::new(int_box.value as f64)) as Box<dyn NyashBox>;
|
|
|
|
|
|
// 🌍 革命的実装:Environment tracking廃止
|
|
|
|
|
|
return Ok(float_box);
|
|
|
|
|
|
} else if let Some(float_box) = value.as_any().downcast_ref::<FloatBox>() {
|
|
|
|
|
|
let new_float_box = Box::new(FloatBox::new(float_box.value)) as Box<dyn NyashBox>;
|
|
|
|
|
|
// 🌍 革命的実装:Environment tracking廃止
|
|
|
|
|
|
return Ok(new_float_box);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return Err(RuntimeError::TypeError {
|
|
|
|
|
|
message: "FloatBox constructor requires numeric argument".to_string(),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
"RangeBox" => {
|
|
|
|
|
|
// RangeBoxは引数2-3個(start, end, [step])で作成
|
|
|
|
|
|
if arguments.len() < 2 || arguments.len() > 3 {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("RangeBox constructor expects 2-3 arguments, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let start_value = self.execute_expression(&arguments[0])?;
|
|
|
|
|
|
let end_value = self.execute_expression(&arguments[1])?;
|
|
|
|
|
|
let step_value = if arguments.len() == 3 {
|
|
|
|
|
|
self.execute_expression(&arguments[2])?
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Box::new(IntegerBox::new(1))
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if let (Some(start_int), Some(end_int), Some(step_int)) = (
|
|
|
|
|
|
start_value.as_any().downcast_ref::<IntegerBox>(),
|
|
|
|
|
|
end_value.as_any().downcast_ref::<IntegerBox>(),
|
|
|
|
|
|
step_value.as_any().downcast_ref::<IntegerBox>()
|
|
|
|
|
|
) {
|
|
|
|
|
|
let range_box = Box::new(RangeBox::new(start_int.value, end_int.value, step_int.value)) as Box<dyn NyashBox>;
|
|
|
|
|
|
// 🌍 革命的実装:Environment tracking廃止
|
|
|
|
|
|
return Ok(range_box);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return Err(RuntimeError::TypeError {
|
|
|
|
|
|
message: "RangeBox constructor requires integer arguments".to_string(),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
"TimeBox" => {
|
|
|
|
|
|
// TimeBoxは引数なしで作成
|
|
|
|
|
|
if !arguments.is_empty() {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("TimeBox constructor expects 0 arguments, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let time_box = Box::new(TimeBox::new()) as Box<dyn NyashBox>;
|
|
|
|
|
|
// 🌍 革命的実装:Environment tracking廃止
|
|
|
|
|
|
return Ok(time_box);
|
|
|
|
|
|
}
|
|
|
|
|
|
"DateTimeBox" => {
|
|
|
|
|
|
// DateTimeBoxは引数なしで現在時刻、または引数1個でタイムスタンプ
|
|
|
|
|
|
match arguments.len() {
|
|
|
|
|
|
0 => {
|
|
|
|
|
|
let datetime_box = Box::new(DateTimeBox::now()) as Box<dyn NyashBox>;
|
|
|
|
|
|
// 🌍 革命的実装:Environment tracking廃止
|
|
|
|
|
|
return Ok(datetime_box);
|
|
|
|
|
|
}
|
|
|
|
|
|
1 => {
|
|
|
|
|
|
let timestamp_value = self.execute_expression(&arguments[0])?;
|
|
|
|
|
|
if let Some(int_box) = timestamp_value.as_any().downcast_ref::<IntegerBox>() {
|
|
|
|
|
|
let datetime_box = Box::new(DateTimeBox::from_timestamp(int_box.value)) as Box<dyn NyashBox>;
|
|
|
|
|
|
// 🌍 革命的実装:Environment tracking廃止
|
|
|
|
|
|
return Ok(datetime_box);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return Err(RuntimeError::TypeError {
|
|
|
|
|
|
message: "DateTimeBox constructor requires integer timestamp".to_string(),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
_ => {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("DateTimeBox constructor expects 0-1 arguments, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
"TimerBox" => {
|
|
|
|
|
|
// TimerBoxは引数なしで作成
|
|
|
|
|
|
if !arguments.is_empty() {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("TimerBox constructor expects 0 arguments, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let timer_box = Box::new(TimerBox::new()) as Box<dyn NyashBox>;
|
|
|
|
|
|
// 🌍 革命的実装:Environment tracking廃止
|
|
|
|
|
|
return Ok(timer_box);
|
|
|
|
|
|
}
|
|
|
|
|
|
"MapBox" => {
|
|
|
|
|
|
// MapBoxは引数なしで作成
|
|
|
|
|
|
if !arguments.is_empty() {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("MapBox constructor expects 0 arguments, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let map_box = Box::new(MapBox::new()) as Box<dyn NyashBox>;
|
|
|
|
|
|
// 🌍 革命的実装:Environment tracking廃止
|
|
|
|
|
|
return Ok(map_box);
|
|
|
|
|
|
}
|
|
|
|
|
|
"RandomBox" => {
|
|
|
|
|
|
// RandomBoxは引数なしで作成
|
|
|
|
|
|
if !arguments.is_empty() {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("RandomBox constructor expects 0 arguments, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let random_box = Box::new(RandomBox::new()) as Box<dyn NyashBox>;
|
|
|
|
|
|
// 🌍 革命的実装:Environment tracking廃止
|
|
|
|
|
|
return Ok(random_box);
|
|
|
|
|
|
}
|
|
|
|
|
|
"SoundBox" => {
|
|
|
|
|
|
// SoundBoxは引数なしで作成
|
|
|
|
|
|
if !arguments.is_empty() {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("SoundBox constructor expects 0 arguments, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let sound_box = Box::new(SoundBox::new()) as Box<dyn NyashBox>;
|
|
|
|
|
|
// 🌍 革命的実装:Environment tracking廃止
|
|
|
|
|
|
return Ok(sound_box);
|
|
|
|
|
|
}
|
|
|
|
|
|
"DebugBox" => {
|
|
|
|
|
|
// DebugBoxは引数なしで作成
|
|
|
|
|
|
if !arguments.is_empty() {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("DebugBox constructor expects 0 arguments, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let debug_box = Box::new(DebugBox::new()) as Box<dyn NyashBox>;
|
|
|
|
|
|
// 🌍 革命的実装:Environment tracking廃止
|
|
|
|
|
|
return Ok(debug_box);
|
|
|
|
|
|
}
|
2025-08-10 15:15:10 +09:00
|
|
|
|
"BufferBox" => {
|
|
|
|
|
|
// BufferBoxは引数なしで作成
|
|
|
|
|
|
if !arguments.is_empty() {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("BufferBox constructor expects 0 arguments, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let buffer_box = Box::new(crate::boxes::buffer::BufferBox::new()) as Box<dyn NyashBox>;
|
|
|
|
|
|
return Ok(buffer_box);
|
|
|
|
|
|
}
|
|
|
|
|
|
"RegexBox" => {
|
|
|
|
|
|
// RegexBoxは引数1個(パターン)で作成
|
|
|
|
|
|
if arguments.len() != 1 {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("RegexBox constructor expects 1 argument, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let pattern_value = self.execute_expression(&arguments[0])?;
|
|
|
|
|
|
if let Some(pattern_str) = pattern_value.as_any().downcast_ref::<StringBox>() {
|
|
|
|
|
|
match crate::boxes::regex::RegexBox::new(&pattern_str.value) {
|
|
|
|
|
|
Ok(regex_box) => return Ok(Box::new(regex_box)),
|
|
|
|
|
|
Err(e) => return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("Invalid regex pattern: {}", e),
|
|
|
|
|
|
}),
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return Err(RuntimeError::TypeError {
|
|
|
|
|
|
message: "RegexBox constructor requires string pattern argument".to_string(),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
"JSONBox" => {
|
|
|
|
|
|
// JSONBoxは引数1個(JSON文字列)で作成
|
|
|
|
|
|
if arguments.len() != 1 {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("JSONBox constructor expects 1 argument, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let json_value = self.execute_expression(&arguments[0])?;
|
|
|
|
|
|
if let Some(json_str) = json_value.as_any().downcast_ref::<StringBox>() {
|
|
|
|
|
|
match crate::boxes::json::JSONBox::from_str(&json_str.value) {
|
|
|
|
|
|
Ok(json_box) => return Ok(Box::new(json_box)),
|
|
|
|
|
|
Err(e) => return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("Invalid JSON: {}", e),
|
|
|
|
|
|
}),
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return Err(RuntimeError::TypeError {
|
|
|
|
|
|
message: "JSONBox constructor requires string JSON argument".to_string(),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-08-11 05:11:52 +09:00
|
|
|
|
|
|
|
|
|
|
"IntentBox" => {
|
2025-08-12 01:35:36 +00:00
|
|
|
|
// IntentBoxは引数2個(name, payload)で作成
|
|
|
|
|
|
if arguments.len() != 2 {
|
2025-08-11 05:11:52 +09:00
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
2025-08-12 01:35:36 +00:00
|
|
|
|
message: format!("IntentBox constructor expects 2 arguments (name, payload), got {}", arguments.len()),
|
2025-08-11 05:11:52 +09:00
|
|
|
|
});
|
|
|
|
|
|
}
|
2025-08-12 01:35:36 +00:00
|
|
|
|
|
|
|
|
|
|
// メッセージ名
|
|
|
|
|
|
let name_value = self.execute_expression(&arguments[0])?;
|
|
|
|
|
|
let name = if let Some(name_str) = name_value.as_any().downcast_ref::<StringBox>() {
|
|
|
|
|
|
name_str.value.clone()
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return Err(RuntimeError::TypeError {
|
|
|
|
|
|
message: "IntentBox constructor requires string name as first argument".to_string(),
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// ペイロード(JSON形式)
|
|
|
|
|
|
let payload_value = self.execute_expression(&arguments[1])?;
|
|
|
|
|
|
let payload = match payload_value.to_string_box().value.parse::<serde_json::Value>() {
|
|
|
|
|
|
Ok(json) => json,
|
|
|
|
|
|
Err(_) => {
|
|
|
|
|
|
// 文字列として保存
|
|
|
|
|
|
serde_json::Value::String(payload_value.to_string_box().value)
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let intent_box = crate::boxes::intent_box::IntentBoxData::new(name, payload);
|
2025-08-11 05:11:52 +09:00
|
|
|
|
return Ok(Box::new(intent_box) as Box<dyn NyashBox>);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
"P2PBox" => {
|
2025-08-12 01:35:36 +00:00
|
|
|
|
// P2PBoxは引数2個(node_id, transport_type)で作成
|
|
|
|
|
|
if arguments.len() != 2 {
|
2025-08-11 05:11:52 +09:00
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
2025-08-12 01:35:36 +00:00
|
|
|
|
message: format!("P2PBox constructor expects 2 arguments (node_id, transport_type), got {}", arguments.len()),
|
2025-08-11 05:11:52 +09:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-12 01:35:36 +00:00
|
|
|
|
// ノードID
|
|
|
|
|
|
let node_id_value = self.execute_expression(&arguments[0])?;
|
|
|
|
|
|
let node_id = if let Some(id_str) = node_id_value.as_any().downcast_ref::<StringBox>() {
|
|
|
|
|
|
id_str.value.clone()
|
2025-08-11 05:11:52 +09:00
|
|
|
|
} else {
|
|
|
|
|
|
return Err(RuntimeError::TypeError {
|
2025-08-12 01:35:36 +00:00
|
|
|
|
message: "P2PBox constructor requires string node_id as first argument".to_string(),
|
2025-08-11 05:11:52 +09:00
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-08-12 01:35:36 +00:00
|
|
|
|
// トランスポート種類
|
|
|
|
|
|
let transport_value = self.execute_expression(&arguments[1])?;
|
|
|
|
|
|
let transport_str = if let Some(t_str) = transport_value.as_any().downcast_ref::<StringBox>() {
|
|
|
|
|
|
t_str.value.clone()
|
2025-08-11 05:11:52 +09:00
|
|
|
|
} else {
|
2025-08-12 01:35:36 +00:00
|
|
|
|
return Err(RuntimeError::TypeError {
|
|
|
|
|
|
message: "P2PBox constructor requires string transport_type as second argument".to_string(),
|
|
|
|
|
|
});
|
2025-08-11 05:11:52 +09:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-08-12 08:12:26 +00:00
|
|
|
|
// TODO: Re-enable P2PBox after fixing transport/messaging imports
|
|
|
|
|
|
return Err(RuntimeError::TypeError {
|
|
|
|
|
|
message: "P2PBox temporarily disabled due to import issues".to_string(),
|
|
|
|
|
|
});
|
2025-08-11 05:11:52 +09:00
|
|
|
|
}
|
2025-08-10 15:15:10 +09:00
|
|
|
|
"StreamBox" => {
|
|
|
|
|
|
// StreamBoxは引数なしで作成
|
|
|
|
|
|
if !arguments.is_empty() {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("StreamBox constructor expects 0 arguments, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let stream_box = Box::new(crate::boxes::stream::StreamBox::new()) as Box<dyn NyashBox>;
|
|
|
|
|
|
return Ok(stream_box);
|
|
|
|
|
|
}
|
|
|
|
|
|
"HTTPClientBox" => {
|
|
|
|
|
|
// HTTPClientBoxは引数なしで作成
|
|
|
|
|
|
if !arguments.is_empty() {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("HTTPClientBox constructor expects 0 arguments, got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
let http_box = Box::new(crate::boxes::http::HttpClientBox::new()) as Box<dyn NyashBox>;
|
|
|
|
|
|
return Ok(http_box);
|
|
|
|
|
|
}
|
2025-08-09 15:14:44 +09:00
|
|
|
|
"MethodBox" => {
|
|
|
|
|
|
// MethodBoxは引数2個(インスタンス、メソッド名)で作成
|
|
|
|
|
|
if arguments.len() != 2 {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("MethodBox constructor expects 2 arguments (instance, method_name), got {}", arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// インスタンスを評価
|
|
|
|
|
|
let instance = self.execute_expression(&arguments[0])?;
|
|
|
|
|
|
|
|
|
|
|
|
// メソッド名を評価
|
|
|
|
|
|
let method_name_value = self.execute_expression(&arguments[1])?;
|
|
|
|
|
|
if let Some(method_name_str) = method_name_value.as_any().downcast_ref::<StringBox>() {
|
|
|
|
|
|
let method_box = Box::new(MethodBox::new(instance, method_name_str.value.clone())) as Box<dyn NyashBox>;
|
|
|
|
|
|
return Ok(method_box);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return Err(RuntimeError::TypeError {
|
|
|
|
|
|
message: "MethodBox constructor requires string method name as second argument".to_string(),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
_ => {}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 🔥 Static Boxインスタンス化禁止チェック
|
|
|
|
|
|
if self.is_static_box(class) {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("Cannot instantiate static box '{}'. Static boxes cannot be instantiated.", class),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ユーザー定義Box宣言を探す
|
|
|
|
|
|
let box_decl = {
|
|
|
|
|
|
let box_decls = self.shared.box_declarations.read().unwrap();
|
|
|
|
|
|
box_decls.get(class)
|
|
|
|
|
|
.ok_or(RuntimeError::UndefinedClass { name: class.to_string() })?
|
|
|
|
|
|
.clone()
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 🔥 ジェネリクス型引数の検証
|
|
|
|
|
|
if !box_decl.type_parameters.is_empty() || !type_arguments.is_empty() {
|
|
|
|
|
|
self.validate_generic_arguments(&box_decl, type_arguments)?;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// インターフェースはインスタンス化できない
|
|
|
|
|
|
if box_decl.is_interface {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("Cannot instantiate interface '{}'", class),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 🚀 ジェネリクス型の特殊化処理
|
|
|
|
|
|
let (final_box_decl, actual_class_name) = if !type_arguments.is_empty() {
|
|
|
|
|
|
// ジェネリクス型を特殊化
|
|
|
|
|
|
let specialized = self.specialize_generic_class(&box_decl, type_arguments)?;
|
|
|
|
|
|
let specialized_name = specialized.name.clone();
|
|
|
|
|
|
(specialized, specialized_name)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
(box_decl.clone(), class.to_string())
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 継承チェーンを解決してフィールドとメソッドを収集(init_fieldsも含む)
|
|
|
|
|
|
let (all_fields, all_methods) = self.resolve_inheritance(&final_box_decl)?;
|
|
|
|
|
|
|
2025-08-13 02:22:20 +00:00
|
|
|
|
// 🔥 フィールド順序と weak フィールドを準備(finiシステム用)
|
|
|
|
|
|
let init_field_order = final_box_decl.init_fields.clone();
|
|
|
|
|
|
let weak_fields = final_box_decl.weak_fields.clone();
|
|
|
|
|
|
|
|
|
|
|
|
// インスタンスを作成(Enhanced fini system対応)
|
|
|
|
|
|
let instance = InstanceBox::new_with_box_info(
|
2025-08-09 15:14:44 +09:00
|
|
|
|
actual_class_name.clone(),
|
|
|
|
|
|
all_fields,
|
2025-08-13 02:22:20 +00:00
|
|
|
|
all_methods,
|
|
|
|
|
|
init_field_order,
|
|
|
|
|
|
weak_fields
|
2025-08-09 15:14:44 +09:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
let instance_box = Box::new(instance) as Box<dyn NyashBox>;
|
|
|
|
|
|
|
|
|
|
|
|
// 現在のスコープでBoxを追跡(自動解放のため)
|
|
|
|
|
|
// 🌍 革命的実装:Environment tracking廃止
|
|
|
|
|
|
|
|
|
|
|
|
// コンストラクタを呼び出す
|
2025-08-11 09:40:24 +09:00
|
|
|
|
// "pack/引数数"、"init/引数数"、"Box名/引数数" の順で試す
|
|
|
|
|
|
let pack_key = format!("pack/{}", arguments.len());
|
|
|
|
|
|
let init_key = format!("init/{}", arguments.len());
|
|
|
|
|
|
let box_name_key = format!("{}/{}", actual_class_name, arguments.len());
|
|
|
|
|
|
|
|
|
|
|
|
if let Some(constructor) = final_box_decl.constructors.get(&pack_key)
|
|
|
|
|
|
.or_else(|| final_box_decl.constructors.get(&init_key))
|
|
|
|
|
|
.or_else(|| final_box_decl.constructors.get(&box_name_key)) {
|
2025-08-09 15:14:44 +09:00
|
|
|
|
// コンストラクタを実行
|
|
|
|
|
|
self.execute_constructor(&instance_box, constructor, arguments, &final_box_decl)?;
|
|
|
|
|
|
} else if !arguments.is_empty() {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("No constructor found for {} with {} arguments", class, arguments.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Ok(instance_box)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// コンストラクタを実行 - Constructor execution
|
|
|
|
|
|
pub(super) fn execute_constructor(
|
|
|
|
|
|
&mut self,
|
|
|
|
|
|
instance: &Box<dyn NyashBox>,
|
|
|
|
|
|
constructor: &ASTNode,
|
|
|
|
|
|
arguments: &[ASTNode],
|
|
|
|
|
|
box_decl: &BoxDeclaration
|
|
|
|
|
|
) -> Result<(), RuntimeError> {
|
|
|
|
|
|
if let ASTNode::FunctionDeclaration { name: _, params, body, .. } = constructor {
|
|
|
|
|
|
// 引数を評価
|
|
|
|
|
|
let mut arg_values = Vec::new();
|
|
|
|
|
|
for arg in arguments {
|
|
|
|
|
|
arg_values.push(self.execute_expression(arg)?);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// パラメータ数チェック
|
|
|
|
|
|
if params.len() != arg_values.len() {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("Constructor expects {} arguments, got {}", params.len(), arg_values.len()),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 🌍 革命的コンストラクタ実行:local変数スタックを使用
|
|
|
|
|
|
let saved_locals = self.save_local_vars();
|
|
|
|
|
|
self.local_vars.clear();
|
|
|
|
|
|
|
|
|
|
|
|
// パラメータをlocal変数として設定
|
|
|
|
|
|
for (param, value) in params.iter().zip(arg_values.iter()) {
|
|
|
|
|
|
self.declare_local_variable(param, value.clone_box());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// this(me)をlocal変数として設定
|
|
|
|
|
|
self.declare_local_variable("me", instance.clone_box());
|
|
|
|
|
|
|
|
|
|
|
|
// コンストラクタコンテキストを設定
|
|
|
|
|
|
let old_context = self.current_constructor_context.clone();
|
|
|
|
|
|
self.current_constructor_context = Some(ConstructorContext {
|
|
|
|
|
|
class_name: box_decl.name.clone(),
|
2025-08-12 08:29:25 +00:00
|
|
|
|
parent_class: box_decl.extends.first().cloned(), // Use first parent for context
|
2025-08-09 15:14:44 +09:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// コンストラクタを実行
|
|
|
|
|
|
let mut result = Ok(());
|
|
|
|
|
|
for statement in body.iter() {
|
|
|
|
|
|
if let Err(e) = self.execute_statement(statement) {
|
|
|
|
|
|
result = Err(e);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// local変数スタックとコンテキストを復元
|
|
|
|
|
|
self.restore_local_vars(saved_locals);
|
|
|
|
|
|
self.current_constructor_context = old_context;
|
|
|
|
|
|
|
|
|
|
|
|
result
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: "Invalid constructor node".to_string(),
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-11 07:55:41 +09:00
|
|
|
|
/// Box宣言を登録 - 🔥 コンストラクタオーバーロード禁止対応
|
2025-08-09 15:14:44 +09:00
|
|
|
|
pub(super) fn register_box_declaration(
|
|
|
|
|
|
&mut self,
|
|
|
|
|
|
name: String,
|
|
|
|
|
|
fields: Vec<String>,
|
|
|
|
|
|
methods: HashMap<String, ASTNode>,
|
|
|
|
|
|
constructors: HashMap<String, ASTNode>,
|
|
|
|
|
|
init_fields: Vec<String>,
|
2025-08-12 20:36:00 +00:00
|
|
|
|
weak_fields: Vec<String>, // 🔗 weak修飾子が付いたフィールドのリスト
|
2025-08-09 15:14:44 +09:00
|
|
|
|
is_interface: bool,
|
2025-08-12 08:29:25 +00:00
|
|
|
|
extends: Vec<String>, // 🚀 Multi-delegation: Changed from Option<String> to Vec<String>
|
2025-08-09 15:14:44 +09:00
|
|
|
|
implements: Vec<String>,
|
|
|
|
|
|
type_parameters: Vec<String> // 🔥 ジェネリクス型パラメータ追加
|
2025-08-11 07:55:41 +09:00
|
|
|
|
) -> Result<(), RuntimeError> {
|
|
|
|
|
|
|
|
|
|
|
|
// 🚨 コンストラクタオーバーロード禁止:複数コンストラクタ検出
|
|
|
|
|
|
if constructors.len() > 1 {
|
|
|
|
|
|
let constructor_names: Vec<String> = constructors.keys().cloned().collect();
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!(
|
|
|
|
|
|
"🚨 CONSTRUCTOR OVERLOAD FORBIDDEN: Box '{}' has {} constructors: [{}].\n\
|
|
|
|
|
|
🌟 Nyash's explicit philosophy: One Box, One Constructor!\n\
|
|
|
|
|
|
💡 Use different Box classes for different initialization patterns.\n\
|
|
|
|
|
|
📖 Example: UserBox, AdminUserBox, GuestUserBox instead of User(type)",
|
|
|
|
|
|
name,
|
|
|
|
|
|
constructors.len(),
|
|
|
|
|
|
constructor_names.join(", ")
|
|
|
|
|
|
)
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2025-08-09 15:14:44 +09:00
|
|
|
|
let box_decl = super::BoxDeclaration {
|
|
|
|
|
|
name: name.clone(),
|
|
|
|
|
|
fields,
|
|
|
|
|
|
methods,
|
|
|
|
|
|
constructors,
|
|
|
|
|
|
init_fields,
|
2025-08-12 20:36:00 +00:00
|
|
|
|
weak_fields, // 🔗 Add weak_fields to the construction
|
2025-08-09 15:14:44 +09:00
|
|
|
|
is_interface,
|
|
|
|
|
|
extends,
|
|
|
|
|
|
implements,
|
|
|
|
|
|
type_parameters, // 🔥 ジェネリクス型パラメータを正しく使用
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
let mut box_decls = self.shared.box_declarations.write().unwrap();
|
|
|
|
|
|
box_decls.insert(name, box_decl);
|
|
|
|
|
|
}
|
2025-08-11 07:55:41 +09:00
|
|
|
|
|
|
|
|
|
|
Ok(()) // 🔥 正常終了
|
2025-08-09 15:14:44 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 🔥 ジェネリクス型引数の検証
|
|
|
|
|
|
fn validate_generic_arguments(&self, box_decl: &BoxDeclaration, type_arguments: &[String])
|
|
|
|
|
|
-> Result<(), RuntimeError> {
|
|
|
|
|
|
// 型パラメータと型引数の数が一致するかチェック
|
|
|
|
|
|
if box_decl.type_parameters.len() != type_arguments.len() {
|
|
|
|
|
|
return Err(RuntimeError::TypeError {
|
|
|
|
|
|
message: format!(
|
|
|
|
|
|
"Generic class '{}' expects {} type parameters, got {}. Expected: <{}>, Got: <{}>",
|
|
|
|
|
|
box_decl.name,
|
|
|
|
|
|
box_decl.type_parameters.len(),
|
|
|
|
|
|
type_arguments.len(),
|
|
|
|
|
|
box_decl.type_parameters.join(", "),
|
|
|
|
|
|
type_arguments.join(", ")
|
|
|
|
|
|
),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 型引数がジェネリクスでない場合、型パラメータがあってはならない
|
|
|
|
|
|
if box_decl.type_parameters.is_empty() && !type_arguments.is_empty() {
|
|
|
|
|
|
return Err(RuntimeError::TypeError {
|
|
|
|
|
|
message: format!(
|
|
|
|
|
|
"Class '{}' is not generic, but got type arguments <{}>",
|
|
|
|
|
|
box_decl.name,
|
|
|
|
|
|
type_arguments.join(", ")
|
|
|
|
|
|
),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 各型引数が有効なBox型かチェック(基本型のみチェック)
|
|
|
|
|
|
for type_arg in type_arguments {
|
|
|
|
|
|
if !self.is_valid_type(type_arg) {
|
|
|
|
|
|
return Err(RuntimeError::TypeError {
|
|
|
|
|
|
message: format!("Unknown type '{}'", type_arg),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 型が有効かどうかをチェック
|
|
|
|
|
|
fn is_valid_type(&self, type_name: &str) -> bool {
|
|
|
|
|
|
// 基本的なビルトイン型
|
|
|
|
|
|
let is_builtin = matches!(type_name,
|
|
|
|
|
|
"IntegerBox" | "StringBox" | "BoolBox" | "ArrayBox" | "MapBox" |
|
|
|
|
|
|
"FileBox" | "ResultBox" | "FutureBox" | "ChannelBox" | "MathBox" |
|
|
|
|
|
|
"TimeBox" | "DateTimeBox" | "TimerBox" | "RandomBox" | "SoundBox" |
|
2025-08-10 15:15:10 +09:00
|
|
|
|
"DebugBox" | "MethodBox" | "NullBox" | "ConsoleBox" | "FloatBox" |
|
2025-08-11 05:11:52 +09:00
|
|
|
|
"BufferBox" | "RegexBox" | "JSONBox" | "StreamBox" | "HTTPClientBox" |
|
|
|
|
|
|
"IntentBox" | "P2PBox"
|
2025-08-09 15:14:44 +09:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// Web専用Box(WASM環境のみ)
|
|
|
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
|
|
|
|
let is_web_box = matches!(type_name, "WebDisplayBox" | "WebConsoleBox" | "WebCanvasBox");
|
|
|
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
|
|
|
|
let is_web_box = false;
|
|
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
// GUI専用Box(非WASM環境のみ)
|
|
|
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
|
|
|
|
let is_gui_box = matches!(type_name, "EguiBox");
|
|
|
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
|
|
|
|
let is_gui_box = false;
|
|
|
|
|
|
|
|
|
|
|
|
is_builtin || is_web_box || is_gui_box ||
|
2025-08-09 15:14:44 +09:00
|
|
|
|
// または登録済みのユーザー定義Box
|
|
|
|
|
|
self.shared.box_declarations.read().unwrap().contains_key(type_name)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 親コンストラクタを実行 - Parent constructor execution
|
|
|
|
|
|
pub(super) fn execute_parent_constructor(&mut self, parent_class: &str, arguments: &[ASTNode])
|
|
|
|
|
|
-> Result<Box<dyn NyashBox>, RuntimeError> {
|
|
|
|
|
|
// 親クラスの宣言を取得
|
|
|
|
|
|
let parent_decl = {
|
|
|
|
|
|
let box_decls = self.shared.box_declarations.read().unwrap();
|
|
|
|
|
|
box_decls.get(parent_class)
|
|
|
|
|
|
.ok_or(RuntimeError::UndefinedClass { name: parent_class.to_string() })?
|
|
|
|
|
|
.clone()
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 親コンストラクタを探す
|
2025-08-11 09:40:24 +09:00
|
|
|
|
// まず "init/引数数" を試し、なければ "Box名/引数数" を試す
|
|
|
|
|
|
let init_key = format!("init/{}", arguments.len());
|
|
|
|
|
|
let box_name_key = format!("{}/{}", parent_class, arguments.len());
|
|
|
|
|
|
|
|
|
|
|
|
if let Some(parent_constructor) = parent_decl.constructors.get(&init_key)
|
|
|
|
|
|
.or_else(|| parent_decl.constructors.get(&box_name_key)) {
|
2025-08-09 15:14:44 +09:00
|
|
|
|
// 現在のthis参照を取得
|
|
|
|
|
|
// 🌍 革命的this取得:local変数から
|
|
|
|
|
|
let this_instance = self.resolve_variable("me")
|
|
|
|
|
|
.map_err(|_| RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: "'this' not available in parent constructor call".to_string(),
|
|
|
|
|
|
})?;
|
|
|
|
|
|
|
|
|
|
|
|
// 親コンストラクタを実行
|
|
|
|
|
|
self.execute_constructor(&this_instance, parent_constructor, arguments, &parent_decl)?;
|
|
|
|
|
|
|
|
|
|
|
|
// VoidBoxを返す(コンストラクタ呼び出しは値を返さない)
|
|
|
|
|
|
Ok(Box::new(VoidBox::new()))
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("No constructor found for parent class {} with {} arguments", parent_class, arguments.len()),
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 継承チェーンを解決してフィールドとメソッドを収集 - Inheritance resolution
|
|
|
|
|
|
pub(super) fn resolve_inheritance(&self, box_decl: &BoxDeclaration)
|
|
|
|
|
|
-> Result<(Vec<String>, HashMap<String, ASTNode>), RuntimeError> {
|
|
|
|
|
|
let mut all_fields = Vec::new();
|
|
|
|
|
|
let mut all_methods = HashMap::new();
|
|
|
|
|
|
|
2025-08-12 08:29:25 +00:00
|
|
|
|
// 親クラスの継承チェーンを再帰的に解決 (Multi-delegation) 🚀
|
|
|
|
|
|
for parent_name in &box_decl.extends {
|
2025-08-11 15:01:11 +09:00
|
|
|
|
// 🔥 ビルトインBoxかチェック
|
|
|
|
|
|
let is_builtin = matches!(parent_name.as_str(),
|
|
|
|
|
|
"IntegerBox" | "StringBox" | "BoolBox" | "ArrayBox" | "MapBox" |
|
|
|
|
|
|
"FileBox" | "ResultBox" | "FutureBox" | "ChannelBox" | "MathBox" |
|
|
|
|
|
|
"TimeBox" | "DateTimeBox" | "TimerBox" | "RandomBox" | "SoundBox" |
|
|
|
|
|
|
"DebugBox" | "MethodBox" | "NullBox" | "ConsoleBox" | "FloatBox" |
|
|
|
|
|
|
"BufferBox" | "RegexBox" | "JSONBox" | "StreamBox" | "HTTPClientBox" |
|
|
|
|
|
|
"IntentBox" | "P2PBox" | "EguiBox"
|
|
|
|
|
|
);
|
2025-08-09 15:14:44 +09:00
|
|
|
|
|
2025-08-11 15:01:11 +09:00
|
|
|
|
if is_builtin {
|
|
|
|
|
|
// ビルトインBoxの場合、フィールドやメソッドは継承しない
|
|
|
|
|
|
// (ビルトインBoxのメソッドはfrom構文でアクセス可能)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let parent_decl = {
|
|
|
|
|
|
let box_decls = self.shared.box_declarations.read().unwrap();
|
|
|
|
|
|
box_decls.get(parent_name)
|
|
|
|
|
|
.ok_or(RuntimeError::UndefinedClass { name: parent_name.clone() })?
|
|
|
|
|
|
.clone()
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// インターフェースは継承できない
|
|
|
|
|
|
if parent_decl.is_interface {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("Cannot extend interface '{}'. Use 'implements' instead.", parent_name),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 親クラスの継承チェーンを再帰的に解決
|
|
|
|
|
|
let (parent_fields, parent_methods) = self.resolve_inheritance(&parent_decl)?;
|
|
|
|
|
|
|
|
|
|
|
|
// 親のフィールドとメソッドを追加
|
|
|
|
|
|
all_fields.extend(parent_fields);
|
|
|
|
|
|
all_methods.extend(parent_methods);
|
2025-08-09 15:14:44 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 現在のクラスのフィールドとメソッドを追加(オーバーライド可能)
|
|
|
|
|
|
all_fields.extend(box_decl.fields.clone());
|
|
|
|
|
|
|
|
|
|
|
|
// init_fieldsも追加(重複チェック)
|
|
|
|
|
|
for init_field in &box_decl.init_fields {
|
|
|
|
|
|
if !all_fields.contains(init_field) {
|
|
|
|
|
|
all_fields.push(init_field.clone());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (method_name, method_ast) in &box_decl.methods {
|
|
|
|
|
|
all_methods.insert(method_name.clone(), method_ast.clone()); // オーバーライド
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// インターフェース実装の検証
|
|
|
|
|
|
for interface_name in &box_decl.implements {
|
|
|
|
|
|
let interface_decl = {
|
|
|
|
|
|
let box_decls = self.shared.box_declarations.read().unwrap();
|
|
|
|
|
|
box_decls.get(interface_name)
|
|
|
|
|
|
.ok_or(RuntimeError::UndefinedClass { name: interface_name.clone() })?
|
|
|
|
|
|
.clone()
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if !interface_decl.is_interface {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("'{}' is not an interface", interface_name),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// インターフェースの全メソッドが実装されているかチェック
|
|
|
|
|
|
for (required_method, _) in &interface_decl.methods {
|
|
|
|
|
|
if !all_methods.contains_key(required_method) {
|
|
|
|
|
|
return Err(RuntimeError::InvalidOperation {
|
|
|
|
|
|
message: format!("Class '{}' must implement method '{}' from interface '{}'",
|
|
|
|
|
|
box_decl.name, required_method, interface_name),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Ok((all_fields, all_methods))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 🚀 ジェネリクス型を特殊化してBoxDeclarationを生成
|
|
|
|
|
|
fn specialize_generic_class(
|
|
|
|
|
|
&self,
|
|
|
|
|
|
generic_decl: &BoxDeclaration,
|
|
|
|
|
|
type_arguments: &[String]
|
|
|
|
|
|
) -> Result<BoxDeclaration, RuntimeError> {
|
|
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
|
|
|
|
|
|
// 特殊化されたクラス名を生成
|
|
|
|
|
|
let specialized_name = format!(
|
|
|
|
|
|
"{}_{}",
|
|
|
|
|
|
generic_decl.name,
|
|
|
|
|
|
type_arguments.join("_")
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// 型パラメータ → 具体型のマッピングを作成
|
|
|
|
|
|
let mut type_mapping = HashMap::new();
|
|
|
|
|
|
for (i, param) in generic_decl.type_parameters.iter().enumerate() {
|
|
|
|
|
|
type_mapping.insert(param.clone(), type_arguments[i].clone());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 特殊化されたBoxDeclarationを作成
|
|
|
|
|
|
let mut specialized = generic_decl.clone();
|
|
|
|
|
|
specialized.name = specialized_name.clone();
|
|
|
|
|
|
specialized.type_parameters.clear(); // 特殊化後は型パラメータなし
|
|
|
|
|
|
|
|
|
|
|
|
// 🔄 フィールドの型を置換
|
|
|
|
|
|
specialized.init_fields = self.substitute_types_in_fields(
|
|
|
|
|
|
&specialized.init_fields,
|
|
|
|
|
|
&type_mapping
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// 🔧 コンストラクタキーを新しいクラス名で更新
|
|
|
|
|
|
let mut updated_constructors = HashMap::new();
|
|
|
|
|
|
for (old_key, constructor_node) in &generic_decl.constructors {
|
|
|
|
|
|
// "Container/1" -> "Container_IntegerBox/1" に変更
|
|
|
|
|
|
if let Some(args_count) = old_key.split('/').nth(1) {
|
|
|
|
|
|
let new_key = format!("{}/{}", specialized_name, args_count);
|
|
|
|
|
|
updated_constructors.insert(new_key, constructor_node.clone());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
specialized.constructors = updated_constructors;
|
|
|
|
|
|
|
|
|
|
|
|
// 🔄 メソッドの型を置換(現在はプレースホルダー実装)
|
|
|
|
|
|
// TODO: メソッド内部のコードも置換が必要
|
|
|
|
|
|
|
|
|
|
|
|
Ok(specialized)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// フィールドの型置換
|
|
|
|
|
|
fn substitute_types_in_fields(
|
|
|
|
|
|
&self,
|
|
|
|
|
|
fields: &[String],
|
|
|
|
|
|
_type_mapping: &HashMap<String, String>
|
|
|
|
|
|
) -> Vec<String> {
|
|
|
|
|
|
// TODO: フィールド型の置換実装
|
|
|
|
|
|
// 現在はシンプルにコピー
|
|
|
|
|
|
fields.to_vec()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|