🎉 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!
This commit is contained in:
1823
src/interpreter/box_methods.rs
Normal file
1823
src/interpreter/box_methods.rs
Normal file
File diff suppressed because it is too large
Load Diff
702
src/interpreter/core.rs
Normal file
702
src/interpreter/core.rs
Normal file
@ -0,0 +1,702 @@
|
||||
/*!
|
||||
* Nyash Interpreter - Rust Implementation
|
||||
*
|
||||
* Python版nyashc_v4.pyのインタープリターをRustで完全再実装
|
||||
* Everything is Box哲学に基づくAST実行エンジン
|
||||
*/
|
||||
|
||||
use crate::ast::{ASTNode, Span};
|
||||
use crate::box_trait::{NyashBox, StringBox, IntegerBox, BoolBox, VoidBox};
|
||||
use crate::instance::InstanceBox;
|
||||
use crate::parser::ParseError;
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use thiserror::Error;
|
||||
use super::{ControlFlow, BoxDeclaration, ConstructorContext, StaticBoxDefinition, StaticBoxState};
|
||||
|
||||
/// 実行時エラー
|
||||
#[derive(Error, Debug)]
|
||||
pub enum RuntimeError {
|
||||
#[error("Undefined variable '{name}'")]
|
||||
UndefinedVariable { name: String },
|
||||
|
||||
#[error("Undefined function '{name}'")]
|
||||
UndefinedFunction { name: String },
|
||||
|
||||
#[error("Undefined class '{name}'")]
|
||||
UndefinedClass { name: String },
|
||||
|
||||
#[error("Type error: {message}")]
|
||||
TypeError { message: String },
|
||||
|
||||
#[error("Invalid operation: {message}")]
|
||||
InvalidOperation { message: String },
|
||||
|
||||
#[error("Break outside of loop")]
|
||||
BreakOutsideLoop,
|
||||
|
||||
#[error("Return outside of function")]
|
||||
ReturnOutsideFunction,
|
||||
|
||||
#[error("Uncaught exception")]
|
||||
UncaughtException,
|
||||
|
||||
#[error("Parse error: {0}")]
|
||||
ParseError(#[from] ParseError),
|
||||
|
||||
#[error("Environment error: {0}")]
|
||||
EnvironmentError(String),
|
||||
|
||||
// === 🔥 Enhanced Errors with Span Information ===
|
||||
|
||||
#[error("Undefined variable '{name}' at {span}")]
|
||||
UndefinedVariableAt { name: String, span: Span },
|
||||
|
||||
#[error("Type error: {message} at {span}")]
|
||||
TypeErrorAt { message: String, span: Span },
|
||||
|
||||
#[error("Invalid operation: {message} at {span}")]
|
||||
InvalidOperationAt { message: String, span: Span },
|
||||
|
||||
#[error("Break outside of loop at {span}")]
|
||||
BreakOutsideLoopAt { span: Span },
|
||||
|
||||
#[error("Return outside of function at {span}")]
|
||||
ReturnOutsideFunctionAt { span: Span },
|
||||
|
||||
#[error("Runtime failure: {message}")]
|
||||
RuntimeFailure { message: String },
|
||||
}
|
||||
|
||||
impl RuntimeError {
|
||||
/// エラーの詳細な文脈付きメッセージを生成
|
||||
pub fn detailed_message(&self, source: Option<&str>) -> String {
|
||||
match self {
|
||||
// Enhanced errors with span information
|
||||
RuntimeError::UndefinedVariableAt { name, span } => {
|
||||
let mut msg = format!("⚠️ Undefined variable '{}'", name);
|
||||
if let Some(src) = source {
|
||||
msg.push('\n');
|
||||
msg.push_str(&span.error_context(src));
|
||||
} else {
|
||||
msg.push_str(&format!(" at {}", span));
|
||||
}
|
||||
msg
|
||||
}
|
||||
|
||||
RuntimeError::TypeErrorAt { message, span } => {
|
||||
let mut msg = format!("⚠️ Type error: {}", message);
|
||||
if let Some(src) = source {
|
||||
msg.push('\n');
|
||||
msg.push_str(&span.error_context(src));
|
||||
} else {
|
||||
msg.push_str(&format!(" at {}", span));
|
||||
}
|
||||
msg
|
||||
}
|
||||
|
||||
RuntimeError::InvalidOperationAt { message, span } => {
|
||||
let mut msg = format!("⚠️ Invalid operation: {}", message);
|
||||
if let Some(src) = source {
|
||||
msg.push('\n');
|
||||
msg.push_str(&span.error_context(src));
|
||||
} else {
|
||||
msg.push_str(&format!(" at {}", span));
|
||||
}
|
||||
msg
|
||||
}
|
||||
|
||||
RuntimeError::BreakOutsideLoopAt { span } => {
|
||||
let mut msg = "⚠️ Break statement outside of loop".to_string();
|
||||
if let Some(src) = source {
|
||||
msg.push('\n');
|
||||
msg.push_str(&span.error_context(src));
|
||||
} else {
|
||||
msg.push_str(&format!(" at {}", span));
|
||||
}
|
||||
msg
|
||||
}
|
||||
|
||||
RuntimeError::ReturnOutsideFunctionAt { span } => {
|
||||
let mut msg = "⚠️ Return statement outside of function".to_string();
|
||||
if let Some(src) = source {
|
||||
msg.push('\n');
|
||||
msg.push_str(&span.error_context(src));
|
||||
} else {
|
||||
msg.push_str(&format!(" at {}", span));
|
||||
}
|
||||
msg
|
||||
}
|
||||
|
||||
// Fallback for old error variants without span
|
||||
_ => format!("⚠️ {}", self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// スレッド間で共有される状態
|
||||
#[derive(Clone)]
|
||||
pub struct SharedState {
|
||||
/// 🌍 GlobalBox - すべてのトップレベル関数とグローバル変数を管理
|
||||
pub global_box: Arc<Mutex<InstanceBox>>,
|
||||
|
||||
/// Box宣言のレジストリ(読み込みが多いのでRwLock)
|
||||
pub box_declarations: Arc<RwLock<HashMap<String, BoxDeclaration>>>,
|
||||
|
||||
/// 🔥 静的関数のレジストリ(読み込みが多いのでRwLock)
|
||||
pub static_functions: Arc<RwLock<HashMap<String, HashMap<String, ASTNode>>>>,
|
||||
|
||||
/// 🔥 Static Box定義レジストリ(遅延初期化用)
|
||||
pub static_box_definitions: Arc<RwLock<HashMap<String, StaticBoxDefinition>>>,
|
||||
|
||||
/// 読み込み済みファイル(重複防止)
|
||||
pub included_files: Arc<Mutex<HashSet<String>>>,
|
||||
}
|
||||
|
||||
impl SharedState {
|
||||
/// 新しい共有状態を作成
|
||||
pub fn new() -> Self {
|
||||
let global_box = InstanceBox::new(
|
||||
"Global".to_string(),
|
||||
vec![], // フィールド名(空から始める)
|
||||
HashMap::new(), // メソッド(グローバル関数)
|
||||
);
|
||||
|
||||
Self {
|
||||
global_box: Arc::new(Mutex::new(global_box)),
|
||||
box_declarations: Arc::new(RwLock::new(HashMap::new())),
|
||||
static_functions: Arc::new(RwLock::new(HashMap::new())),
|
||||
static_box_definitions: Arc::new(RwLock::new(HashMap::new())),
|
||||
included_files: Arc::new(Mutex::new(HashSet::new())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Nyashインタープリター - AST実行エンジン
|
||||
pub struct NyashInterpreter {
|
||||
/// 共有状態(スレッド間で共有)
|
||||
pub(super) shared: SharedState,
|
||||
|
||||
/// 📦 local変数スタック(関数呼び出し時の一時変数)
|
||||
pub(super) local_vars: HashMap<String, Box<dyn NyashBox>>,
|
||||
|
||||
/// 📤 outbox変数スタック(static関数内の所有権移転変数)
|
||||
pub(super) outbox_vars: HashMap<String, Box<dyn NyashBox>>,
|
||||
|
||||
/// 制御フロー状態
|
||||
pub(super) control_flow: ControlFlow,
|
||||
|
||||
/// 現在実行中のコンストラクタ情報
|
||||
pub(super) current_constructor_context: Option<ConstructorContext>,
|
||||
}
|
||||
|
||||
impl NyashInterpreter {
|
||||
/// 新しいインタープリターを作成
|
||||
pub fn new() -> Self {
|
||||
let shared = SharedState::new();
|
||||
|
||||
Self {
|
||||
shared,
|
||||
local_vars: HashMap::new(),
|
||||
outbox_vars: HashMap::new(),
|
||||
control_flow: ControlFlow::None,
|
||||
current_constructor_context: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// 共有状態から新しいインタープリターを作成(非同期実行用)
|
||||
pub fn with_shared(shared: SharedState) -> Self {
|
||||
Self {
|
||||
shared,
|
||||
local_vars: HashMap::new(),
|
||||
outbox_vars: HashMap::new(),
|
||||
control_flow: ControlFlow::None,
|
||||
current_constructor_context: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// ASTを実行
|
||||
pub fn execute(&mut self, ast: ASTNode) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
self.execute_node(&ast)
|
||||
}
|
||||
|
||||
/// ノードを実行
|
||||
fn execute_node(&mut self, node: &ASTNode) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
match node {
|
||||
ASTNode::Program { statements, .. } => {
|
||||
let mut result: Box<dyn NyashBox> = Box::new(VoidBox::new());
|
||||
|
||||
for statement in statements {
|
||||
result = self.execute_statement(statement)?;
|
||||
|
||||
// 制御フローチェック
|
||||
match &self.control_flow {
|
||||
ControlFlow::Break => {
|
||||
return Err(RuntimeError::BreakOutsideLoop);
|
||||
}
|
||||
ControlFlow::Return(_) => {
|
||||
return Err(RuntimeError::ReturnOutsideFunction);
|
||||
}
|
||||
ControlFlow::Throw(_) => {
|
||||
return Err(RuntimeError::UncaughtException);
|
||||
}
|
||||
ControlFlow::None => {}
|
||||
}
|
||||
}
|
||||
|
||||
// 🎯 Static Box Main パターン - main()メソッドの自動実行
|
||||
let has_main_method = {
|
||||
if let Ok(definitions) = self.shared.static_box_definitions.read() {
|
||||
if let Some(main_definition) = definitions.get("Main") {
|
||||
main_definition.methods.contains_key("main")
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
if has_main_method {
|
||||
// Main static boxを初期化
|
||||
self.ensure_static_box_initialized("Main")?;
|
||||
|
||||
// Main.main() を呼び出し
|
||||
let main_call_ast = ASTNode::MethodCall {
|
||||
object: Box::new(ASTNode::FieldAccess {
|
||||
object: Box::new(ASTNode::Variable {
|
||||
name: "statics".to_string(),
|
||||
span: crate::ast::Span::unknown(),
|
||||
}),
|
||||
field: "Main".to_string(),
|
||||
span: crate::ast::Span::unknown(),
|
||||
}),
|
||||
method: "main".to_string(),
|
||||
arguments: vec![],
|
||||
span: crate::ast::Span::unknown(),
|
||||
};
|
||||
|
||||
// main()の戻り値を最終結果として使用
|
||||
result = self.execute_statement(&main_call_ast)?;
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
_ => self.execute_statement(node),
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 🌍 GlobalBox変数解決システム ==========
|
||||
|
||||
/// 革命的変数解決: local変数 → GlobalBoxフィールド → エラー
|
||||
pub(super) fn resolve_variable(&self, name: &str) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
// 1. outbox変数を最初にチェック(static関数内で優先)
|
||||
if let Some(outbox_value) = self.outbox_vars.get(name) {
|
||||
return Ok(outbox_value.clone_box());
|
||||
}
|
||||
|
||||
// 2. local変数をチェック
|
||||
if let Some(local_value) = self.local_vars.get(name) {
|
||||
return Ok(local_value.clone_box());
|
||||
}
|
||||
|
||||
// 3. GlobalBoxのフィールドをチェック
|
||||
let global_box = self.shared.global_box.lock().unwrap();
|
||||
if let Some(field_value) = global_box.get_field(name) {
|
||||
return Ok(field_value);
|
||||
}
|
||||
|
||||
// 4. エラー:見つからない
|
||||
Err(RuntimeError::UndefinedVariable {
|
||||
name: name.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
/// 🔥 厳密変数設定: 明示的宣言のみ許可 - Everything is Box哲学
|
||||
pub(super) fn set_variable(&mut self, name: &str, value: Box<dyn NyashBox>) -> Result<(), RuntimeError> {
|
||||
// 1. outbox変数が存在する場合は更新
|
||||
if self.outbox_vars.contains_key(name) {
|
||||
self.outbox_vars.insert(name.to_string(), value);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// 2. local変数が存在する場合は更新
|
||||
if self.local_vars.contains_key(name) {
|
||||
self.local_vars.insert(name.to_string(), value);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// 3. GlobalBoxのフィールドが既に存在する場合は更新
|
||||
{
|
||||
let global_box = self.shared.global_box.lock().unwrap();
|
||||
if global_box.get_field(name).is_some() {
|
||||
drop(global_box); // lockを解放
|
||||
let mut global_box = self.shared.global_box.lock().unwrap();
|
||||
global_box.set_field_dynamic(name.to_string(), value);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 🚨 未宣言変数への代入は厳密にエラー
|
||||
Err(RuntimeError::UndefinedVariable {
|
||||
name: format!(
|
||||
"{}\n💡 Suggestion: Declare the variable first:\n • For fields: Add '{}' to 'init {{ }}' block\n • For local variables: Use 'local {}'\n • For field access: Use 'me.{}'",
|
||||
name, name, name, name
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
/// local変数を宣言(関数内でのみ有効)
|
||||
pub(super) fn declare_local_variable(&mut self, name: &str, value: Box<dyn NyashBox>) {
|
||||
self.local_vars.insert(name.to_string(), value);
|
||||
}
|
||||
|
||||
/// outbox変数を宣言(static関数内で所有権移転)
|
||||
pub(super) fn declare_outbox_variable(&mut self, name: &str, value: Box<dyn NyashBox>) {
|
||||
self.outbox_vars.insert(name.to_string(), value);
|
||||
}
|
||||
|
||||
/// local変数スタックを保存・復元(関数呼び出し時)
|
||||
pub(super) fn save_local_vars(&self) -> HashMap<String, Box<dyn NyashBox>> {
|
||||
self.local_vars.iter()
|
||||
.map(|(k, v)| (k.clone(), v.clone_box()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(super) fn restore_local_vars(&mut self, saved: HashMap<String, Box<dyn NyashBox>>) {
|
||||
self.local_vars = saved;
|
||||
}
|
||||
|
||||
/// outbox変数スタックを保存・復元(static関数呼び出し時)
|
||||
pub(super) fn save_outbox_vars(&self) -> HashMap<String, Box<dyn NyashBox>> {
|
||||
self.outbox_vars.iter()
|
||||
.map(|(k, v)| (k.clone(), v.clone_box()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(super) fn restore_outbox_vars(&mut self, saved: HashMap<String, Box<dyn NyashBox>>) {
|
||||
self.outbox_vars = saved;
|
||||
}
|
||||
|
||||
/// トップレベル関数をGlobalBoxのメソッドとして登録
|
||||
pub(super) fn register_global_function(&mut self, name: String, func_ast: ASTNode) -> Result<(), RuntimeError> {
|
||||
let mut global_box = self.shared.global_box.lock().unwrap();
|
||||
global_box.add_method(name, func_ast);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// 値が真と評価されるかチェック
|
||||
pub(super) fn is_truthy(&self, value: &Box<dyn NyashBox>) -> bool {
|
||||
#[allow(unused_imports)]
|
||||
use std::any::Any;
|
||||
|
||||
if let Some(bool_box) = value.as_any().downcast_ref::<BoolBox>() {
|
||||
bool_box.value
|
||||
} else if let Some(int_box) = value.as_any().downcast_ref::<IntegerBox>() {
|
||||
int_box.value != 0
|
||||
} else if let Some(string_box) = value.as_any().downcast_ref::<StringBox>() {
|
||||
!string_box.value.is_empty()
|
||||
} else if value.as_any().downcast_ref::<VoidBox>().is_some() {
|
||||
false
|
||||
} else {
|
||||
true // 他のBoxは真とみなす
|
||||
}
|
||||
}
|
||||
|
||||
/// 🌍 革命的変数取得(テスト用):GlobalBoxのフィールドから取得
|
||||
pub fn get_variable(&self, name: &str) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
self.resolve_variable(name)
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Tests =====
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::parser::NyashParser;
|
||||
|
||||
#[test]
|
||||
fn test_simple_execution() {
|
||||
let code = r#"
|
||||
x = 42
|
||||
print(x)
|
||||
"#;
|
||||
|
||||
let ast = NyashParser::parse_from_string(code).unwrap();
|
||||
let mut interpreter = NyashInterpreter::new();
|
||||
let result = interpreter.execute(ast);
|
||||
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arithmetic() {
|
||||
let code = r#"
|
||||
result = 10 + 32
|
||||
"#;
|
||||
|
||||
let ast = NyashParser::parse_from_string(code).unwrap();
|
||||
let mut interpreter = NyashInterpreter::new();
|
||||
interpreter.execute(ast).unwrap();
|
||||
|
||||
// 🌍 革命的変数取得:GlobalBoxから
|
||||
let result = interpreter.get_variable("result").unwrap();
|
||||
assert_eq!(result.to_string_box().value, "42");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_if_statement() {
|
||||
let code = r#"
|
||||
x = true
|
||||
if x {
|
||||
y = "success"
|
||||
} else {
|
||||
y = "failure"
|
||||
}
|
||||
"#;
|
||||
|
||||
let ast = NyashParser::parse_from_string(code).unwrap();
|
||||
let mut interpreter = NyashInterpreter::new();
|
||||
interpreter.execute(ast).unwrap();
|
||||
|
||||
// 🌍 革命的変数取得:GlobalBoxから
|
||||
let result = interpreter.get_variable("y").unwrap();
|
||||
assert_eq!(result.to_string_box().value, "success");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_box_instance_creation() {
|
||||
let code = r#"
|
||||
box TestBox {
|
||||
value
|
||||
|
||||
getValue() {
|
||||
return this.value
|
||||
}
|
||||
|
||||
setValue(newValue) {
|
||||
this.value = newValue
|
||||
}
|
||||
}
|
||||
|
||||
obj = new TestBox()
|
||||
obj.value = "test123"
|
||||
result = obj.getValue()
|
||||
"#;
|
||||
|
||||
let ast = NyashParser::parse_from_string(code).unwrap();
|
||||
let mut interpreter = NyashInterpreter::new();
|
||||
interpreter.execute(ast).unwrap();
|
||||
|
||||
// 🌍 革命的変数取得:インスタンス作成確認
|
||||
let obj = interpreter.get_variable("obj").unwrap();
|
||||
assert!(obj.as_any().downcast_ref::<InstanceBox>().is_some());
|
||||
|
||||
// 🌍 革命的変数取得:メソッド呼び出し結果確認
|
||||
let result = interpreter.get_variable("result").unwrap();
|
||||
assert_eq!(result.to_string_box().value, "test123");
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 🔥 Static Box管理システム =====
|
||||
|
||||
impl NyashInterpreter {
|
||||
|
||||
/// Static Box定義を登録
|
||||
pub fn register_static_box(&mut self, definition: StaticBoxDefinition) -> Result<(), RuntimeError> {
|
||||
let mut definitions = self.shared.static_box_definitions.write()
|
||||
.map_err(|_| RuntimeError::RuntimeFailure {
|
||||
message: "Failed to acquire write lock for static box definitions".to_string()
|
||||
})?;
|
||||
|
||||
definitions.insert(definition.name.clone(), definition);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Static Box宣言を登録(AST処理から呼ばれる)
|
||||
pub fn register_static_box_declaration(
|
||||
&mut self,
|
||||
name: String,
|
||||
fields: Vec<String>,
|
||||
methods: HashMap<String, ASTNode>,
|
||||
init_fields: Vec<String>,
|
||||
static_init: Option<Vec<ASTNode>>,
|
||||
extends: Option<String>,
|
||||
implements: Vec<String>,
|
||||
type_parameters: Vec<String>
|
||||
) -> Result<(), RuntimeError> {
|
||||
// 🌍 Static Box定義時にstatics名前空間を確実に作成
|
||||
self.ensure_statics_namespace()?;
|
||||
|
||||
let definition = StaticBoxDefinition {
|
||||
name: name.clone(),
|
||||
fields,
|
||||
methods,
|
||||
init_fields,
|
||||
static_init,
|
||||
extends,
|
||||
implements,
|
||||
type_parameters,
|
||||
initialization_state: StaticBoxState::NotInitialized,
|
||||
};
|
||||
|
||||
eprintln!("🔥 Static Box '{}' definition registered in statics namespace", name);
|
||||
self.register_static_box(definition)
|
||||
}
|
||||
|
||||
/// Static Boxの初期化を実行(遅延初期化)
|
||||
pub fn ensure_static_box_initialized(&mut self, name: &str) -> Result<(), RuntimeError> {
|
||||
// 1. 定義を取得
|
||||
let definition = {
|
||||
let definitions = self.shared.static_box_definitions.read()
|
||||
.map_err(|_| RuntimeError::RuntimeFailure {
|
||||
message: "Failed to acquire read lock for static box definitions".to_string()
|
||||
})?;
|
||||
|
||||
match definitions.get(name) {
|
||||
Some(def) => def.clone(),
|
||||
None => return Err(RuntimeError::UndefinedClass { name: name.to_string() }),
|
||||
}
|
||||
};
|
||||
|
||||
// 2. 初期化状態をチェック
|
||||
if definition.initialization_state == StaticBoxState::Initialized {
|
||||
return Ok(()); // 既に初期化済み
|
||||
}
|
||||
|
||||
if definition.initialization_state == StaticBoxState::Initializing {
|
||||
return Err(RuntimeError::RuntimeFailure {
|
||||
message: format!("Circular dependency detected during initialization of static box '{}'", name)
|
||||
});
|
||||
}
|
||||
|
||||
// 3. 初期化開始をマーク
|
||||
self.set_static_box_state(name, StaticBoxState::Initializing)?;
|
||||
|
||||
// 4. 「statics」名前空間をGlobalBoxに作成(未存在の場合)
|
||||
self.ensure_statics_namespace()?;
|
||||
|
||||
// 5. シングルトンインスタンスを作成(メソッドも含む)
|
||||
let singleton = InstanceBox::new(
|
||||
format!("{}_singleton", name),
|
||||
definition.init_fields.clone(),
|
||||
definition.methods.clone(), // ★ メソッドを正しく設定
|
||||
);
|
||||
|
||||
// 6. GlobalBox.staticsに登録
|
||||
self.set_static_instance(name, singleton)?;
|
||||
|
||||
// 7. static初期化ブロックを実行(me変数をバインドして)
|
||||
if let Some(ref init_statements) = definition.static_init {
|
||||
// statics名前空間からシングルトンインスタンスを取得
|
||||
let static_instance = {
|
||||
let global_box = self.shared.global_box.lock().unwrap();
|
||||
let statics_box = global_box.get_field("statics").unwrap();
|
||||
let statics_instance = statics_box.as_any().downcast_ref::<InstanceBox>().unwrap();
|
||||
statics_instance.get_field(name).unwrap()
|
||||
};
|
||||
|
||||
// 🌍 this変数をバインドしてstatic初期化実行(me構文のため)
|
||||
self.declare_local_variable("me", static_instance);
|
||||
|
||||
for stmt in init_statements {
|
||||
self.execute_statement(stmt)?;
|
||||
}
|
||||
|
||||
// 🌍 this変数をクリーンアップ
|
||||
self.local_vars.remove("me");
|
||||
}
|
||||
|
||||
// 8. 初期化完了をマーク
|
||||
self.set_static_box_state(name, StaticBoxState::Initialized)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Static Box初期化状態を設定
|
||||
fn set_static_box_state(&mut self, name: &str, state: StaticBoxState) -> Result<(), RuntimeError> {
|
||||
let mut definitions = self.shared.static_box_definitions.write()
|
||||
.map_err(|_| RuntimeError::RuntimeFailure {
|
||||
message: "Failed to acquire write lock for static box definitions".to_string()
|
||||
})?;
|
||||
|
||||
if let Some(definition) = definitions.get_mut(name) {
|
||||
definition.initialization_state = state;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 「statics」名前空間をGlobalBoxに作成
|
||||
fn ensure_statics_namespace(&mut self) -> Result<(), RuntimeError> {
|
||||
let global_box = self.shared.global_box.lock()
|
||||
.map_err(|_| RuntimeError::RuntimeFailure {
|
||||
message: "Failed to acquire global box lock".to_string()
|
||||
})?;
|
||||
|
||||
// 既に存在する場合はスキップ
|
||||
if global_box.get_field("statics").is_some() {
|
||||
eprintln!("🌍 statics namespace already exists - skipping creation");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// 「statics」用のInstanceBoxを作成
|
||||
let statics_box = InstanceBox::new(
|
||||
"statics".to_string(),
|
||||
vec![],
|
||||
HashMap::new(),
|
||||
);
|
||||
|
||||
// GlobalBoxのfieldsに直接挿入
|
||||
{
|
||||
let mut fields = global_box.fields.lock().unwrap();
|
||||
fields.insert("statics".to_string(), Box::new(statics_box));
|
||||
}
|
||||
|
||||
eprintln!("🌍 statics namespace created in GlobalBox successfully");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Static Boxシングルトンインスタンスを設定
|
||||
fn set_static_instance(&mut self, name: &str, instance: InstanceBox) -> Result<(), RuntimeError> {
|
||||
let global_box = self.shared.global_box.lock()
|
||||
.map_err(|_| RuntimeError::RuntimeFailure {
|
||||
message: "Failed to acquire global box lock".to_string()
|
||||
})?;
|
||||
|
||||
// statics名前空間を取得
|
||||
let statics_box = global_box.get_field("statics")
|
||||
.ok_or(RuntimeError::TypeError {
|
||||
message: "statics namespace not found in GlobalBox".to_string()
|
||||
})?;
|
||||
|
||||
let statics_instance = statics_box.as_any()
|
||||
.downcast_ref::<InstanceBox>()
|
||||
.ok_or(RuntimeError::TypeError {
|
||||
message: "statics field is not an InstanceBox".to_string()
|
||||
})?;
|
||||
|
||||
// statics InstanceBoxのfieldsに直接挿入(動的フィールド追加)
|
||||
{
|
||||
let mut fields = statics_instance.fields.lock().unwrap();
|
||||
fields.insert(name.to_string(), Box::new(instance));
|
||||
}
|
||||
|
||||
eprintln!("🔥 Static box '{}' instance registered in statics namespace", name);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 🔥 Static Boxかどうかをチェック
|
||||
pub(super) fn is_static_box(&self, name: &str) -> bool {
|
||||
if let Ok(definitions) = self.shared.static_box_definitions.read() {
|
||||
definitions.contains_key(name)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
617
src/interpreter/expressions.rs
Normal file
617
src/interpreter/expressions.rs
Normal file
@ -0,0 +1,617 @@
|
||||
/*!
|
||||
* Expression Processing Module
|
||||
*
|
||||
* Extracted from core.rs lines 408-787 (~380 lines)
|
||||
* Handles expression evaluation, binary operations, method calls, and field access
|
||||
* Core philosophy: "Everything is Box" with clean expression evaluation
|
||||
*/
|
||||
|
||||
use super::*;
|
||||
use crate::ast::UnaryOperator;
|
||||
// TODO: Fix NullBox import issue later
|
||||
// use crate::NullBox;
|
||||
|
||||
impl NyashInterpreter {
|
||||
/// 式を実行 - Expression evaluation engine
|
||||
pub(super) fn execute_expression(&mut self, expression: &ASTNode) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
match expression {
|
||||
ASTNode::Literal { value, .. } => {
|
||||
Ok(value.to_nyash_box())
|
||||
}
|
||||
|
||||
ASTNode::Variable { name, .. } => {
|
||||
// 🌍 革命的変数解決:local変数 → GlobalBoxフィールド → エラー
|
||||
self.resolve_variable(name)
|
||||
.map_err(|_| RuntimeError::UndefinedVariableAt {
|
||||
name: name.clone(),
|
||||
span: expression.span()
|
||||
})
|
||||
}
|
||||
|
||||
ASTNode::BinaryOp { operator, left, right, .. } => {
|
||||
self.execute_binary_op(operator, left, right)
|
||||
}
|
||||
|
||||
ASTNode::UnaryOp { operator, operand, .. } => {
|
||||
self.execute_unary_op(operator, operand)
|
||||
}
|
||||
|
||||
ASTNode::AwaitExpression { expression, .. } => {
|
||||
self.execute_await(expression)
|
||||
}
|
||||
|
||||
ASTNode::MethodCall { object, method, arguments, .. } => {
|
||||
self.execute_method_call(object, method, arguments)
|
||||
}
|
||||
|
||||
ASTNode::FieldAccess { object, field, .. } => {
|
||||
self.execute_field_access(object, field)
|
||||
}
|
||||
|
||||
ASTNode::New { class, arguments, type_arguments, .. } => {
|
||||
self.execute_new(class, arguments, type_arguments)
|
||||
}
|
||||
|
||||
ASTNode::This { .. } => {
|
||||
// 🌍 革命的this解決:local変数から取得
|
||||
self.resolve_variable("me")
|
||||
.map_err(|_| RuntimeError::InvalidOperation {
|
||||
message: "'this' is only available inside methods".to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
ASTNode::Me { .. } => {
|
||||
// 🌍 革命的me解決:local変数から取得(thisと同じ)
|
||||
self.resolve_variable("me")
|
||||
.map_err(|_| RuntimeError::InvalidOperation {
|
||||
message: "'me' is only available inside methods".to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
ASTNode::ThisField { field, .. } => {
|
||||
// 🌍 革命的this.fieldアクセス:local変数から取得
|
||||
let this_value = self.resolve_variable("me")
|
||||
.map_err(|_| RuntimeError::InvalidOperation {
|
||||
message: "'this' is not bound in the current context".to_string(),
|
||||
})?;
|
||||
|
||||
if let Some(instance) = this_value.as_any().downcast_ref::<InstanceBox>() {
|
||||
instance.get_field(field)
|
||||
.ok_or_else(|| RuntimeError::InvalidOperation {
|
||||
message: format!("Field '{}' not found on this", field)
|
||||
})
|
||||
} else {
|
||||
Err(RuntimeError::TypeError {
|
||||
message: "'this' is not an instance".to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
ASTNode::MeField { field, .. } => {
|
||||
// 🌍 革命的me.fieldアクセス:local変数から取得
|
||||
let me_value = self.resolve_variable("me")
|
||||
.map_err(|_| RuntimeError::InvalidOperation {
|
||||
message: "'this' is not bound in the current context".to_string(),
|
||||
})?;
|
||||
|
||||
if let Some(instance) = me_value.as_any().downcast_ref::<InstanceBox>() {
|
||||
instance.get_field(field)
|
||||
.ok_or_else(|| RuntimeError::InvalidOperation {
|
||||
message: format!("Field '{}' not found on me", field)
|
||||
})
|
||||
} else {
|
||||
Err(RuntimeError::TypeError {
|
||||
message: "'this' is not an instance".to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
ASTNode::FunctionCall { name, arguments, .. } => {
|
||||
self.execute_function_call(name, arguments)
|
||||
}
|
||||
|
||||
ASTNode::Arrow { sender, receiver, .. } => {
|
||||
self.execute_arrow(sender, receiver)
|
||||
}
|
||||
|
||||
ASTNode::Include { filename, .. } => {
|
||||
self.execute_include(filename)?;
|
||||
Ok(Box::new(VoidBox::new()))
|
||||
}
|
||||
|
||||
_ => Err(RuntimeError::InvalidOperation {
|
||||
message: format!("Cannot execute {:?} as expression", expression.node_type()),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// 二項演算を実行 - Binary operation processing
|
||||
pub(super) fn execute_binary_op(&mut self, op: &BinaryOperator, left: &ASTNode, right: &ASTNode)
|
||||
-> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
let left_val = self.execute_expression(left)?;
|
||||
let right_val = self.execute_expression(right)?;
|
||||
|
||||
match op {
|
||||
BinaryOperator::Add => {
|
||||
let add_box = AddBox::new(left_val, right_val);
|
||||
Ok(add_box.execute())
|
||||
}
|
||||
|
||||
BinaryOperator::Equal => {
|
||||
let result = left_val.equals(right_val.as_ref());
|
||||
Ok(Box::new(result))
|
||||
}
|
||||
|
||||
BinaryOperator::NotEqual => {
|
||||
let result = left_val.equals(right_val.as_ref());
|
||||
Ok(Box::new(BoolBox::new(!result.value)))
|
||||
}
|
||||
|
||||
BinaryOperator::And => {
|
||||
let left_bool = self.is_truthy(&left_val);
|
||||
if !left_bool {
|
||||
Ok(Box::new(BoolBox::new(false)))
|
||||
} else {
|
||||
let right_bool = self.is_truthy(&right_val);
|
||||
Ok(Box::new(BoolBox::new(right_bool)))
|
||||
}
|
||||
}
|
||||
|
||||
BinaryOperator::Or => {
|
||||
let left_bool = self.is_truthy(&left_val);
|
||||
if left_bool {
|
||||
Ok(Box::new(BoolBox::new(true)))
|
||||
} else {
|
||||
let right_bool = self.is_truthy(&right_val);
|
||||
Ok(Box::new(BoolBox::new(right_bool)))
|
||||
}
|
||||
}
|
||||
|
||||
BinaryOperator::Subtract => {
|
||||
let sub_box = SubtractBox::new(left_val, right_val);
|
||||
Ok(sub_box.execute())
|
||||
}
|
||||
|
||||
BinaryOperator::Multiply => {
|
||||
let mul_box = MultiplyBox::new(left_val, right_val);
|
||||
Ok(mul_box.execute())
|
||||
}
|
||||
|
||||
BinaryOperator::Divide => {
|
||||
let div_box = DivideBox::new(left_val, right_val);
|
||||
Ok(div_box.execute())
|
||||
}
|
||||
|
||||
BinaryOperator::Less => {
|
||||
let result = CompareBox::less(left_val.as_ref(), right_val.as_ref());
|
||||
Ok(Box::new(result))
|
||||
}
|
||||
|
||||
BinaryOperator::Greater => {
|
||||
let result = CompareBox::greater(left_val.as_ref(), right_val.as_ref());
|
||||
Ok(Box::new(result))
|
||||
}
|
||||
|
||||
BinaryOperator::LessEqual => {
|
||||
let result = CompareBox::less_equal(left_val.as_ref(), right_val.as_ref());
|
||||
Ok(Box::new(result))
|
||||
}
|
||||
|
||||
BinaryOperator::GreaterEqual => {
|
||||
let result = CompareBox::greater_equal(left_val.as_ref(), right_val.as_ref());
|
||||
Ok(Box::new(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 単項演算を実行 - Unary operation processing
|
||||
pub(super) fn execute_unary_op(&mut self, operator: &UnaryOperator, operand: &ASTNode)
|
||||
-> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
let operand_val = self.execute_expression(operand)?;
|
||||
|
||||
match operator {
|
||||
UnaryOperator::Minus => {
|
||||
// 数値の符号反転
|
||||
if let Some(int_box) = operand_val.as_any().downcast_ref::<IntegerBox>() {
|
||||
Ok(Box::new(IntegerBox::new(-int_box.value)))
|
||||
} else if let Some(float_box) = operand_val.as_any().downcast_ref::<FloatBox>() {
|
||||
Ok(Box::new(FloatBox::new(-float_box.value)))
|
||||
} else {
|
||||
Err(RuntimeError::TypeError {
|
||||
message: "Unary minus can only be applied to Integer or Float".to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
UnaryOperator::Not => {
|
||||
// 論理否定
|
||||
if let Some(bool_box) = operand_val.as_any().downcast_ref::<BoolBox>() {
|
||||
Ok(Box::new(BoolBox::new(!bool_box.value)))
|
||||
} else {
|
||||
// どんな値でもtruthyness判定してnot演算を適用
|
||||
let is_truthy = self.is_truthy(&operand_val);
|
||||
Ok(Box::new(BoolBox::new(!is_truthy)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// メソッド呼び出しを実行 - Method call processing
|
||||
pub(super) fn execute_method_call(&mut self, object: &ASTNode, method: &str, arguments: &[ASTNode])
|
||||
-> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
// 🔥 static関数のチェック
|
||||
if let ASTNode::Variable { name, .. } = object {
|
||||
// static関数が存在するかチェック
|
||||
let static_func = {
|
||||
let static_funcs = self.shared.static_functions.read().unwrap();
|
||||
if let Some(box_statics) = static_funcs.get(name) {
|
||||
if let Some(func) = box_statics.get(method) {
|
||||
Some(func.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(static_func) = static_func {
|
||||
// static関数を実行
|
||||
if let ASTNode::FunctionDeclaration { params, body, .. } = static_func {
|
||||
// 引数を評価
|
||||
let mut arg_values = Vec::new();
|
||||
for arg in arguments {
|
||||
arg_values.push(self.execute_expression(arg)?);
|
||||
}
|
||||
|
||||
// パラメータ数チェック
|
||||
if arg_values.len() != params.len() {
|
||||
return Err(RuntimeError::InvalidOperation {
|
||||
message: format!("Static method {}.{} expects {} arguments, got {}",
|
||||
name, method, params.len(), arg_values.len()),
|
||||
});
|
||||
}
|
||||
|
||||
// 🌍 local変数スタックを保存・クリア(static関数呼び出し開始)
|
||||
let saved_locals = self.save_local_vars();
|
||||
self.local_vars.clear();
|
||||
|
||||
// 📤 outbox変数スタックも保存・クリア(static関数専用)
|
||||
let saved_outbox = self.save_outbox_vars();
|
||||
self.outbox_vars.clear();
|
||||
|
||||
// 引数をlocal変数として設定
|
||||
for (param, value) in params.iter().zip(arg_values.iter()) {
|
||||
self.declare_local_variable(param, value.clone_box());
|
||||
}
|
||||
|
||||
// static関数の本体を実行
|
||||
let mut result = Box::new(VoidBox::new()) as Box<dyn NyashBox>;
|
||||
for statement in &body {
|
||||
result = self.execute_statement(statement)?;
|
||||
|
||||
// return文チェック
|
||||
if let super::ControlFlow::Return(return_val) = &self.control_flow {
|
||||
result = return_val.clone_box();
|
||||
self.control_flow = super::ControlFlow::None;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// local変数スタックを復元
|
||||
self.restore_local_vars(saved_locals);
|
||||
|
||||
// outbox変数スタックを復元
|
||||
self.restore_outbox_vars(saved_outbox);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// オブジェクトを評価(通常のメソッド呼び出し)
|
||||
let obj_value = self.execute_expression(object)?;
|
||||
|
||||
// StringBox method calls
|
||||
if let Some(string_box) = obj_value.as_any().downcast_ref::<StringBox>() {
|
||||
return self.execute_string_method(string_box, method, arguments);
|
||||
}
|
||||
|
||||
// ArrayBox method calls
|
||||
if let Some(array_box) = obj_value.as_any().downcast_ref::<ArrayBox>() {
|
||||
return self.execute_array_method(array_box, method, arguments);
|
||||
}
|
||||
|
||||
// FileBox method calls
|
||||
if let Some(file_box) = obj_value.as_any().downcast_ref::<FileBox>() {
|
||||
return self.execute_file_method(file_box, method, arguments);
|
||||
}
|
||||
|
||||
// ResultBox method calls
|
||||
if let Some(result_box) = obj_value.as_any().downcast_ref::<ResultBox>() {
|
||||
return self.execute_result_method(result_box, method, arguments);
|
||||
}
|
||||
|
||||
// FutureBox method calls
|
||||
if let Some(future_box) = obj_value.as_any().downcast_ref::<FutureBox>() {
|
||||
return self.execute_future_method(future_box, method, arguments);
|
||||
}
|
||||
|
||||
// ChannelBox method calls
|
||||
if let Some(channel_box) = obj_value.as_any().downcast_ref::<ChannelBox>() {
|
||||
return self.execute_channel_method(channel_box, method, arguments);
|
||||
}
|
||||
|
||||
// MathBox method calls
|
||||
if let Some(math_box) = obj_value.as_any().downcast_ref::<MathBox>() {
|
||||
return self.execute_math_method(math_box, method, arguments);
|
||||
}
|
||||
|
||||
// NullBox method calls
|
||||
if let Some(null_box) = obj_value.as_any().downcast_ref::<crate::boxes::null_box::NullBox>() {
|
||||
return self.execute_null_method(null_box, method, arguments);
|
||||
}
|
||||
|
||||
// TimeBox method calls
|
||||
if let Some(time_box) = obj_value.as_any().downcast_ref::<TimeBox>() {
|
||||
return self.execute_time_method(time_box, method, arguments);
|
||||
}
|
||||
|
||||
// DateTimeBox method calls
|
||||
if let Some(datetime_box) = obj_value.as_any().downcast_ref::<DateTimeBox>() {
|
||||
return self.execute_datetime_method(datetime_box, method, arguments);
|
||||
}
|
||||
|
||||
// TimerBox method calls
|
||||
if let Some(timer_box) = obj_value.as_any().downcast_ref::<TimerBox>() {
|
||||
return self.execute_timer_method(timer_box, method, arguments);
|
||||
}
|
||||
|
||||
// MapBox method calls
|
||||
if let Some(map_box) = obj_value.as_any().downcast_ref::<MapBox>() {
|
||||
return self.execute_map_method(map_box, method, arguments);
|
||||
}
|
||||
|
||||
// RandomBox method calls
|
||||
if let Some(random_box) = obj_value.as_any().downcast_ref::<RandomBox>() {
|
||||
return self.execute_random_method(random_box, method, arguments);
|
||||
}
|
||||
|
||||
// SoundBox method calls
|
||||
if let Some(sound_box) = obj_value.as_any().downcast_ref::<SoundBox>() {
|
||||
return self.execute_sound_method(sound_box, method, arguments);
|
||||
}
|
||||
|
||||
// DebugBox method calls
|
||||
if let Some(debug_box) = obj_value.as_any().downcast_ref::<DebugBox>() {
|
||||
return self.execute_debug_method(debug_box, method, arguments);
|
||||
}
|
||||
|
||||
// ConsoleBox method calls
|
||||
if let Some(console_box) = obj_value.as_any().downcast_ref::<crate::boxes::console_box::ConsoleBox>() {
|
||||
return self.execute_console_method(console_box, method, arguments);
|
||||
}
|
||||
|
||||
// WebDisplayBox method calls (WASM環境のみ)
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
if let Some(web_display_box) = obj_value.as_any().downcast_ref::<crate::boxes::WebDisplayBox>() {
|
||||
return self.execute_web_display_method(web_display_box, method, arguments);
|
||||
}
|
||||
|
||||
// WebConsoleBox method calls (WASM環境のみ)
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
if let Some(web_console_box) = obj_value.as_any().downcast_ref::<crate::boxes::WebConsoleBox>() {
|
||||
return self.execute_web_console_method(web_console_box, method, arguments);
|
||||
}
|
||||
|
||||
// WebCanvasBox method calls (WASM環境のみ)
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
if let Some(web_canvas_box) = obj_value.as_any().downcast_ref::<crate::boxes::WebCanvasBox>() {
|
||||
return self.execute_web_canvas_method(web_canvas_box, method, arguments);
|
||||
}
|
||||
|
||||
// MethodBox method calls
|
||||
if let Some(method_box) = obj_value.as_any().downcast_ref::<crate::method_box::MethodBox>() {
|
||||
return self.execute_method_box_method(method_box, method, arguments);
|
||||
}
|
||||
|
||||
// IntegerBox method calls
|
||||
if let Some(integer_box) = obj_value.as_any().downcast_ref::<IntegerBox>() {
|
||||
return self.execute_integer_method(integer_box, method, arguments);
|
||||
}
|
||||
|
||||
// FloatBox method calls (将来的に追加予定)
|
||||
|
||||
// RangeBox method calls (将来的に追加予定)
|
||||
|
||||
// InstanceBox method calls
|
||||
if let Some(instance) = obj_value.as_any().downcast_ref::<InstanceBox>() {
|
||||
// fini()は特別処理
|
||||
if method == "fini" {
|
||||
// 既に解放済みの場合は何もしない(二重fini()対策)
|
||||
if instance.is_finalized() {
|
||||
return Ok(Box::new(VoidBox::new()));
|
||||
}
|
||||
|
||||
// まず、Box内で定義されたfini()メソッドがあれば実行
|
||||
if let Some(fini_method) = instance.get_method("fini") {
|
||||
if let ASTNode::FunctionDeclaration { body, .. } = fini_method.clone() {
|
||||
// 🌍 革命的メソッド実行:local変数スタックを使用
|
||||
let saved_locals = self.save_local_vars();
|
||||
self.local_vars.clear();
|
||||
|
||||
// thisをlocal変数として設定
|
||||
self.declare_local_variable("me", obj_value.clone_box());
|
||||
|
||||
// fini()メソッドの本体を実行
|
||||
let mut _result = Box::new(VoidBox::new()) as Box<dyn NyashBox>;
|
||||
for statement in &body {
|
||||
_result = self.execute_statement(statement)?;
|
||||
|
||||
// return文チェック
|
||||
if let super::ControlFlow::Return(_) = &self.control_flow {
|
||||
self.control_flow = super::ControlFlow::None;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// local変数スタックを復元
|
||||
self.restore_local_vars(saved_locals);
|
||||
}
|
||||
}
|
||||
|
||||
// インスタンスの内部的な解放処理
|
||||
instance.fini().map_err(|e| RuntimeError::InvalidOperation {
|
||||
message: e,
|
||||
})?;
|
||||
finalization::mark_as_finalized(instance.box_id());
|
||||
return Ok(Box::new(VoidBox::new()));
|
||||
}
|
||||
|
||||
// メソッドを取得
|
||||
let method_ast = instance.get_method(method)
|
||||
.ok_or(RuntimeError::InvalidOperation {
|
||||
message: format!("Method '{}' not found in {}", method, instance.class_name),
|
||||
})?
|
||||
.clone();
|
||||
|
||||
// メソッドが関数宣言の形式であることを確認
|
||||
if let ASTNode::FunctionDeclaration { params, body, .. } = method_ast {
|
||||
// 引数を評価
|
||||
let mut arg_values = Vec::new();
|
||||
for arg in arguments {
|
||||
arg_values.push(self.execute_expression(arg)?);
|
||||
}
|
||||
|
||||
// パラメータ数チェック
|
||||
if arg_values.len() != params.len() {
|
||||
return Err(RuntimeError::InvalidOperation {
|
||||
message: format!("Method {} expects {} arguments, got {}",
|
||||
method, params.len(), arg_values.len()),
|
||||
});
|
||||
}
|
||||
|
||||
// 🌍 革命的メソッド実行:local変数スタックを使用
|
||||
let saved_locals = self.save_local_vars();
|
||||
self.local_vars.clear();
|
||||
|
||||
// thisをlocal変数として設定
|
||||
self.declare_local_variable("me", obj_value.clone_box());
|
||||
|
||||
// パラメータをlocal変数として設定
|
||||
for (param, value) in params.iter().zip(arg_values.iter()) {
|
||||
self.declare_local_variable(param, value.clone_box());
|
||||
}
|
||||
|
||||
// メソッド本体を実行
|
||||
let mut result: Box<dyn NyashBox> = Box::new(VoidBox::new());
|
||||
for statement in &body {
|
||||
result = self.execute_statement(statement)?;
|
||||
|
||||
// return文チェック
|
||||
if let super::ControlFlow::Return(return_val) = &self.control_flow {
|
||||
result = return_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),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Err(RuntimeError::TypeError {
|
||||
message: format!("Cannot call method '{}' on non-instance type", method),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// フィールドアクセスを実行 - Field access processing
|
||||
pub(super) fn execute_field_access(&mut self, object: &ASTNode, field: &str)
|
||||
-> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
// 🔥 Static Boxアクセスチェック
|
||||
if let ASTNode::Variable { name, .. } = object {
|
||||
// Static boxの可能性をチェック
|
||||
if self.is_static_box(name) {
|
||||
return self.execute_static_field_access(name, field);
|
||||
}
|
||||
}
|
||||
|
||||
// オブジェクトを評価(通常のフィールドアクセス)
|
||||
let obj_value = self.execute_expression(object)?;
|
||||
|
||||
// InstanceBoxにキャスト
|
||||
if let Some(instance) = obj_value.as_any().downcast_ref::<InstanceBox>() {
|
||||
// フィールドの値を取得
|
||||
instance.get_field(field)
|
||||
.ok_or(RuntimeError::InvalidOperation {
|
||||
message: format!("Field '{}' not found in {}", field, instance.class_name),
|
||||
})
|
||||
} else {
|
||||
Err(RuntimeError::TypeError {
|
||||
message: format!("Cannot access field '{}' on non-instance type. Type: {}", field, obj_value.type_name()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// 🔥 Static Box名前空間のフィールドアクセス
|
||||
fn execute_static_field_access(&mut self, static_box_name: &str, field: &str)
|
||||
-> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
// 1. Static Boxの初期化を確実に実行
|
||||
self.ensure_static_box_initialized(static_box_name)?;
|
||||
|
||||
// 2. GlobalBox.statics.{static_box_name} からインスタンスを取得
|
||||
let global_box = self.shared.global_box.lock()
|
||||
.map_err(|_| RuntimeError::RuntimeFailure {
|
||||
message: "Failed to acquire global box lock".to_string()
|
||||
})?;
|
||||
|
||||
let statics_box = global_box.get_field("statics")
|
||||
.ok_or(RuntimeError::RuntimeFailure {
|
||||
message: "statics namespace not found in GlobalBox".to_string()
|
||||
})?;
|
||||
|
||||
let statics_instance = statics_box.as_any()
|
||||
.downcast_ref::<InstanceBox>()
|
||||
.ok_or(RuntimeError::TypeError {
|
||||
message: "statics field is not an InstanceBox".to_string()
|
||||
})?;
|
||||
|
||||
let static_box_instance = statics_instance.get_field(static_box_name)
|
||||
.ok_or(RuntimeError::RuntimeFailure {
|
||||
message: format!("Static box '{}' instance not found in statics namespace", static_box_name)
|
||||
})?;
|
||||
|
||||
let instance = static_box_instance.as_any()
|
||||
.downcast_ref::<InstanceBox>()
|
||||
.ok_or(RuntimeError::TypeError {
|
||||
message: format!("Static box '{}' is not an InstanceBox", static_box_name)
|
||||
})?;
|
||||
|
||||
// 3. フィールドアクセス
|
||||
instance.get_field(field)
|
||||
.ok_or(RuntimeError::InvalidOperation {
|
||||
message: format!("Field '{}' not found in static box '{}'", field, static_box_name),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/// await式を実行 - Execute await expression
|
||||
pub(super) fn execute_await(&mut self, expression: &ASTNode) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
let value = self.execute_expression(expression)?;
|
||||
|
||||
// FutureBoxなら待機して結果を取得
|
||||
if let Some(future) = value.as_any().downcast_ref::<FutureBox>() {
|
||||
future.wait_and_get()
|
||||
.map_err(|msg| RuntimeError::InvalidOperation { message: msg })
|
||||
} else {
|
||||
// FutureBoxでなければそのまま返す
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
96
src/interpreter/functions.rs
Normal file
96
src/interpreter/functions.rs
Normal file
@ -0,0 +1,96 @@
|
||||
/*!
|
||||
* Function Processing Module
|
||||
*
|
||||
* Extracted from core.rs - function call and definition handling
|
||||
* Handles function declarations, calls, and function-related operations
|
||||
* Core philosophy: "Everything is Box" with structured function processing
|
||||
*/
|
||||
|
||||
use super::*;
|
||||
|
||||
impl NyashInterpreter {
|
||||
/// 関数呼び出しを実行 - 🌍 革命的実装:GlobalBoxのメソッド呼び出し
|
||||
pub(super) fn execute_function_call(&mut self, name: &str, arguments: &[ASTNode])
|
||||
-> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
// コンストラクタ内での親コンストラクタ呼び出しチェック
|
||||
if let Some(context) = self.current_constructor_context.clone() {
|
||||
if let Some(parent_class) = context.parent_class {
|
||||
if name == parent_class {
|
||||
// 親コンストラクタ呼び出し
|
||||
return self.execute_parent_constructor(&parent_class, arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 🌍 GlobalBoxのメソッドとして実行
|
||||
let global_box = self.shared.global_box.lock().unwrap();
|
||||
let method_ast = global_box.get_method(name)
|
||||
.ok_or(RuntimeError::UndefinedFunction { name: name.to_string() })?
|
||||
.clone();
|
||||
drop(global_box);
|
||||
|
||||
// メソッド呼び出しとして実行(GlobalBoxインスタンス上で)
|
||||
if let ASTNode::FunctionDeclaration { params, body, .. } = method_ast {
|
||||
// 引数を評価
|
||||
let mut arg_values = Vec::new();
|
||||
for arg in arguments {
|
||||
arg_values.push(self.execute_expression(arg)?);
|
||||
}
|
||||
|
||||
// パラメータ数チェック
|
||||
if arg_values.len() != params.len() {
|
||||
return Err(RuntimeError::InvalidOperation {
|
||||
message: format!("Function {} expects {} arguments, got {}",
|
||||
name, 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());
|
||||
}
|
||||
|
||||
// 関数本体を実行
|
||||
let mut result: Box<dyn NyashBox> = Box::new(VoidBox::new());
|
||||
for statement in &body {
|
||||
result = self.execute_statement(statement)?;
|
||||
|
||||
// return文チェック
|
||||
if let super::ControlFlow::Return(return_val) = &self.control_flow {
|
||||
result = return_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!("Function '{}' is not a valid function declaration", name),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// 関数宣言を登録 - 🌍 革命的実装:GlobalBoxのメソッドとして登録
|
||||
pub(super) fn register_function_declaration(&mut self, name: String, params: Vec<String>, body: Vec<ASTNode>) {
|
||||
// 🌍 GlobalBoxのメソッドとして登録
|
||||
let func_ast = ASTNode::FunctionDeclaration {
|
||||
name: name.clone(),
|
||||
params,
|
||||
body,
|
||||
is_static: false, // 通常の関数は静的でない
|
||||
span: crate::ast::Span::unknown(), // デフォルトspan
|
||||
};
|
||||
|
||||
self.register_global_function(name, func_ast).unwrap_or_else(|err| {
|
||||
eprintln!("Warning: Failed to register global function: {}", err);
|
||||
});
|
||||
}
|
||||
}
|
||||
114
src/interpreter/io.rs
Normal file
114
src/interpreter/io.rs
Normal file
@ -0,0 +1,114 @@
|
||||
/*!
|
||||
* I/O Processing Module
|
||||
*
|
||||
* Extracted from core.rs - file operations and communication
|
||||
* Handles include system, arrow operators, and I/O-related operations
|
||||
* Core philosophy: "Everything is Box" with secure I/O processing
|
||||
*/
|
||||
|
||||
use super::*;
|
||||
use crate::parser::NyashParser;
|
||||
|
||||
impl NyashInterpreter {
|
||||
/// include文を実行:ファイル読み込み・パース・実行 - File inclusion system
|
||||
pub(super) fn execute_include(&mut self, filename: &str) -> Result<(), RuntimeError> {
|
||||
// パス正規化(簡易版)
|
||||
let canonical_path = if filename.starts_with("./") || filename.starts_with("../") {
|
||||
filename.to_string()
|
||||
} else {
|
||||
format!("./{}", filename)
|
||||
};
|
||||
|
||||
// 重複読み込みチェック
|
||||
if self.shared.included_files.lock().unwrap().contains(&canonical_path) {
|
||||
return Ok(()); // 既に読み込み済み
|
||||
}
|
||||
|
||||
// ファイル読み込み
|
||||
let content = std::fs::read_to_string(&canonical_path)
|
||||
.map_err(|e| RuntimeError::InvalidOperation {
|
||||
message: format!("Failed to read file '{}': {}", filename, e),
|
||||
})?;
|
||||
|
||||
// パース
|
||||
let ast = NyashParser::parse_from_string(&content)
|
||||
.map_err(|e| RuntimeError::InvalidOperation {
|
||||
message: format!("Parse error in '{}': {:?}", filename, e),
|
||||
})?;
|
||||
|
||||
// 重複防止リストに追加
|
||||
self.shared.included_files.lock().unwrap().insert(canonical_path);
|
||||
|
||||
// 現在の環境で実行
|
||||
self.execute(ast)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Arrow演算子を実行: sender >> receiver - Channel communication
|
||||
pub(super) fn execute_arrow(&mut self, sender: &ASTNode, receiver: &ASTNode)
|
||||
-> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
// 送信者を評価
|
||||
let sender_value = self.execute_expression(sender)?;
|
||||
|
||||
// 受信者を評価
|
||||
let receiver_str = match receiver {
|
||||
ASTNode::Variable { name, .. } => name.clone(),
|
||||
ASTNode::Literal { value, .. } => {
|
||||
// "*" のようなリテラルの場合
|
||||
value.to_string()
|
||||
}
|
||||
_ => {
|
||||
// その他の式の場合は評価して文字列化
|
||||
let receiver_value = self.execute_expression(receiver)?;
|
||||
receiver_value.to_string_box().value
|
||||
}
|
||||
};
|
||||
|
||||
// 送信者の名前を取得
|
||||
let sender_name = sender_value.to_string_box().value;
|
||||
|
||||
// ChannelBoxを作成して返す
|
||||
let channel_box = Box::new(ChannelBox::new(&sender_name, &receiver_str)) as Box<dyn NyashBox>;
|
||||
// 🌍 革命的実装:Environment tracking廃止
|
||||
Ok(channel_box)
|
||||
}
|
||||
|
||||
/// nowait文を実行 - 非同期実行(真の非同期実装) - Async execution
|
||||
pub(super) fn execute_nowait(&mut self, variable: &str, expression: &ASTNode) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
use crate::box_trait::FutureBox;
|
||||
use std::thread;
|
||||
|
||||
// FutureBoxを作成
|
||||
let future_box = FutureBox::new();
|
||||
let future_box_clone = future_box.clone();
|
||||
|
||||
// 式をクローンして別スレッドで実行
|
||||
let expr_clone = expression.clone();
|
||||
let shared_state = self.shared.clone();
|
||||
|
||||
// 別スレッドで非同期実行
|
||||
thread::spawn(move || {
|
||||
// 新しいインタープリタインスタンスを作成(SharedStateを使用)
|
||||
let mut async_interpreter = NyashInterpreter::with_shared(shared_state);
|
||||
|
||||
// 式を評価
|
||||
match async_interpreter.execute_expression(&expr_clone) {
|
||||
Ok(result) => {
|
||||
future_box_clone.set_result(result);
|
||||
}
|
||||
Err(e) => {
|
||||
// エラーをErrorBoxとして設定
|
||||
let error_box = Box::new(ErrorBox::new("RuntimeError", &format!("{:?}", e)));
|
||||
future_box_clone.set_result(error_box);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// FutureBoxを変数に保存
|
||||
let future_box_instance = Box::new(future_box) as Box<dyn NyashBox>;
|
||||
self.set_variable(variable, future_box_instance)?;
|
||||
|
||||
Ok(Box::new(VoidBox::new()))
|
||||
}
|
||||
}
|
||||
98
src/interpreter/mod.rs
Normal file
98
src/interpreter/mod.rs
Normal file
@ -0,0 +1,98 @@
|
||||
/*!
|
||||
* Nyash Interpreter - Modular Rust Implementation
|
||||
*
|
||||
* Refactored from massive 2,633-line interpreter.rs into logical modules
|
||||
* Everything is Box philosophy with clean separation of concerns
|
||||
*/
|
||||
|
||||
// Import all necessary dependencies
|
||||
use crate::ast::{ASTNode, BinaryOperator, CatchClause};
|
||||
use crate::box_trait::{NyashBox, StringBox, IntegerBox, BoolBox, VoidBox, AddBox, SubtractBox, MultiplyBox, DivideBox, CompareBox, ArrayBox, FileBox, ResultBox, ErrorBox, FutureBox};
|
||||
use crate::instance::InstanceBox;
|
||||
use crate::channel_box::{ChannelBox, MessageBox};
|
||||
use crate::boxes::math_box::{MathBox, FloatBox, RangeBox};
|
||||
use crate::boxes::time_box::{TimeBox, DateTimeBox, TimerBox};
|
||||
use crate::boxes::map_box::MapBox;
|
||||
use crate::boxes::random_box::RandomBox;
|
||||
use crate::boxes::sound_box::SoundBox;
|
||||
use crate::boxes::debug_box::DebugBox;
|
||||
use crate::method_box::MethodBox;
|
||||
use crate::finalization;
|
||||
use crate::exception_box;
|
||||
use std::collections::HashMap;
|
||||
|
||||
// Module declarations
|
||||
mod box_methods;
|
||||
mod core;
|
||||
mod expressions;
|
||||
mod statements;
|
||||
mod functions;
|
||||
mod objects;
|
||||
mod io;
|
||||
|
||||
// Main interpreter implementation - will be moved from interpreter.rs
|
||||
|
||||
|
||||
/// 実行制御フロー
|
||||
#[derive(Debug)]
|
||||
pub enum ControlFlow {
|
||||
None,
|
||||
Break,
|
||||
Return(Box<dyn NyashBox>),
|
||||
Throw(Box<dyn NyashBox>),
|
||||
}
|
||||
|
||||
/// コンストラクタ実行コンテキスト
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ConstructorContext {
|
||||
pub class_name: String,
|
||||
pub parent_class: Option<String>,
|
||||
}
|
||||
|
||||
/// Box宣言を保持する構造体
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BoxDeclaration {
|
||||
pub name: String,
|
||||
pub fields: Vec<String>,
|
||||
pub methods: HashMap<String, ASTNode>,
|
||||
pub constructors: HashMap<String, ASTNode>,
|
||||
pub init_fields: Vec<String>,
|
||||
pub is_interface: bool,
|
||||
pub extends: Option<String>,
|
||||
pub implements: Vec<String>,
|
||||
pub type_parameters: Vec<String>, // 🔥 ジェネリクス型パラメータ
|
||||
}
|
||||
|
||||
/// 🔥 Static Box定義を保持する構造体
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StaticBoxDefinition {
|
||||
pub name: String,
|
||||
pub fields: Vec<String>,
|
||||
pub methods: HashMap<String, ASTNode>,
|
||||
pub init_fields: Vec<String>,
|
||||
pub static_init: Option<Vec<ASTNode>>, // static { } ブロック
|
||||
pub extends: Option<String>,
|
||||
pub implements: Vec<String>,
|
||||
pub type_parameters: Vec<String>,
|
||||
/// 初期化状態
|
||||
pub initialization_state: StaticBoxState,
|
||||
}
|
||||
|
||||
/// 🔥 Static Box初期化状態
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum StaticBoxState {
|
||||
NotInitialized, // 未初期化
|
||||
Initializing, // 初期化中(循環参照検出用)
|
||||
Initialized, // 初期化完了
|
||||
}
|
||||
|
||||
/// 関数宣言を保持する構造体
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FunctionDeclaration {
|
||||
pub name: String,
|
||||
pub params: Vec<String>,
|
||||
pub body: Vec<ASTNode>,
|
||||
}
|
||||
|
||||
// Re-export core interpreter types
|
||||
pub use core::*;
|
||||
746
src/interpreter/objects.rs
Normal file
746
src/interpreter/objects.rs
Normal file
@ -0,0 +1,746 @@
|
||||
/*!
|
||||
* 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::*;
|
||||
use crate::boxes::null_box::NullBox;
|
||||
use crate::boxes::console_box::ConsoleBox;
|
||||
|
||||
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 {
|
||||
"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);
|
||||
}
|
||||
#[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);
|
||||
}
|
||||
"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)?;
|
||||
|
||||
// インスタンスを作成
|
||||
let instance = InstanceBox::new(
|
||||
actual_class_name.clone(),
|
||||
all_fields,
|
||||
all_methods
|
||||
);
|
||||
|
||||
let instance_box = Box::new(instance) as Box<dyn NyashBox>;
|
||||
|
||||
// 現在のスコープでBoxを追跡(自動解放のため)
|
||||
// 🌍 革命的実装:Environment tracking廃止
|
||||
|
||||
// コンストラクタを呼び出す
|
||||
let constructor_key = format!("{}/{}", actual_class_name, arguments.len());
|
||||
if let Some(constructor) = final_box_decl.constructors.get(&constructor_key) {
|
||||
// コンストラクタを実行
|
||||
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(),
|
||||
parent_class: box_decl.extends.clone(),
|
||||
});
|
||||
|
||||
// コンストラクタを実行
|
||||
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(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Box宣言を登録 - Box declaration registration
|
||||
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>,
|
||||
is_interface: bool,
|
||||
extends: Option<String>,
|
||||
implements: Vec<String>,
|
||||
type_parameters: Vec<String> // 🔥 ジェネリクス型パラメータ追加
|
||||
) {
|
||||
let box_decl = super::BoxDeclaration {
|
||||
name: name.clone(),
|
||||
fields,
|
||||
methods,
|
||||
constructors,
|
||||
init_fields,
|
||||
is_interface,
|
||||
extends,
|
||||
implements,
|
||||
type_parameters, // 🔥 ジェネリクス型パラメータを正しく使用
|
||||
};
|
||||
|
||||
{
|
||||
let mut box_decls = self.shared.box_declarations.write().unwrap();
|
||||
box_decls.insert(name, box_decl);
|
||||
}
|
||||
}
|
||||
|
||||
/// 🔥 ジェネリクス型引数の検証
|
||||
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" |
|
||||
"DebugBox" | "MethodBox" | "NullBox" | "ConsoleBox" | "FloatBox"
|
||||
);
|
||||
|
||||
// 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;
|
||||
|
||||
is_builtin || is_web_box ||
|
||||
// または登録済みのユーザー定義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()
|
||||
};
|
||||
|
||||
// 親コンストラクタを探す
|
||||
let constructor_key = format!("{}/{}", parent_class, arguments.len());
|
||||
if let Some(parent_constructor) = parent_decl.constructors.get(&constructor_key) {
|
||||
// 現在の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();
|
||||
|
||||
// 親クラスの継承チェーンを再帰的に解決
|
||||
if let Some(parent_name) = &box_decl.extends {
|
||||
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);
|
||||
}
|
||||
|
||||
// 現在のクラスのフィールドとメソッドを追加(オーバーライド可能)
|
||||
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()
|
||||
}
|
||||
}
|
||||
427
src/interpreter/statements.rs
Normal file
427
src/interpreter/statements.rs
Normal file
@ -0,0 +1,427 @@
|
||||
/*!
|
||||
* Statement Processing Module
|
||||
*
|
||||
* Extracted from core.rs - statement execution engine
|
||||
* Handles all statement types: assignments, if/else, loops, control flow
|
||||
* Core philosophy: "Everything is Box" with structured statement processing
|
||||
*/
|
||||
|
||||
use super::*;
|
||||
|
||||
impl NyashInterpreter {
|
||||
/// 文を実行 - Core statement execution engine
|
||||
pub(super) fn execute_statement(&mut self, statement: &ASTNode) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
match statement {
|
||||
ASTNode::Assignment { target, value, .. } => {
|
||||
self.execute_assignment(target, value)
|
||||
}
|
||||
|
||||
ASTNode::Print { expression, .. } => {
|
||||
let value = self.execute_expression(expression)?;
|
||||
println!("{}", value.to_string_box());
|
||||
Ok(Box::new(VoidBox::new()))
|
||||
}
|
||||
|
||||
ASTNode::If { condition, then_body, else_body, .. } => {
|
||||
self.execute_if(condition, then_body, else_body)
|
||||
}
|
||||
|
||||
ASTNode::Loop { condition, body, .. } => {
|
||||
self.execute_loop(condition, body)
|
||||
}
|
||||
|
||||
ASTNode::Return { value, .. } => {
|
||||
let return_value = if let Some(val) = value {
|
||||
self.execute_expression(val)?
|
||||
} else {
|
||||
Box::new(VoidBox::new())
|
||||
};
|
||||
self.control_flow = super::ControlFlow::Return(return_value);
|
||||
Ok(Box::new(VoidBox::new()))
|
||||
}
|
||||
|
||||
ASTNode::Break { .. } => {
|
||||
self.control_flow = super::ControlFlow::Break;
|
||||
Ok(Box::new(VoidBox::new()))
|
||||
}
|
||||
|
||||
ASTNode::Nowait { variable, expression, .. } => {
|
||||
self.execute_nowait(variable, expression)
|
||||
}
|
||||
|
||||
ASTNode::BoxDeclaration { name, fields, methods, constructors, init_fields, is_interface, extends, implements, type_parameters, is_static, static_init, .. } => {
|
||||
if *is_static {
|
||||
// 🔥 Static Box宣言の処理
|
||||
self.register_static_box_declaration(
|
||||
name.clone(),
|
||||
fields.clone(),
|
||||
methods.clone(),
|
||||
init_fields.clone(),
|
||||
static_init.clone(),
|
||||
extends.clone(),
|
||||
implements.clone(),
|
||||
type_parameters.clone()
|
||||
)?;
|
||||
} else {
|
||||
// 通常のBox宣言の処理
|
||||
self.register_box_declaration(
|
||||
name.clone(),
|
||||
fields.clone(),
|
||||
methods.clone(),
|
||||
constructors.clone(),
|
||||
init_fields.clone(),
|
||||
*is_interface,
|
||||
extends.clone(),
|
||||
implements.clone(),
|
||||
type_parameters.clone() // 🔥 ジェネリクス型パラメータ追加
|
||||
);
|
||||
}
|
||||
Ok(Box::new(VoidBox::new()))
|
||||
}
|
||||
|
||||
ASTNode::FunctionDeclaration { name, params, body, is_static, .. } => {
|
||||
if *is_static {
|
||||
// 🔥 静的関数:box名.関数名の形式で解析
|
||||
if let Some(dot_pos) = name.find('.') {
|
||||
let box_name = name[..dot_pos].to_string();
|
||||
let func_name = name[dot_pos + 1..].to_string();
|
||||
|
||||
// boxのstaticメソッドとして登録
|
||||
let func_ast = ASTNode::FunctionDeclaration {
|
||||
name: func_name.clone(),
|
||||
params: params.clone(),
|
||||
body: body.clone(),
|
||||
is_static: true,
|
||||
span: crate::ast::Span::unknown(),
|
||||
};
|
||||
|
||||
{
|
||||
let mut static_funcs = self.shared.static_functions.write().unwrap();
|
||||
static_funcs
|
||||
.entry(box_name.clone())
|
||||
.or_insert_with(HashMap::new)
|
||||
.insert(func_name.clone(), func_ast);
|
||||
}
|
||||
|
||||
eprintln!("🔥 Static function '{}.{}' registered", box_name, func_name);
|
||||
} else {
|
||||
// box名なしのstatic関数(将来的にはエラーにする)
|
||||
eprintln!("⚠️ Static function '{}' needs box prefix (e.g., Math.min)", name);
|
||||
}
|
||||
} else {
|
||||
// 通常の関数:従来通りGlobalBoxメソッドとして登録
|
||||
self.register_function_declaration(name.clone(), params.clone(), body.clone());
|
||||
}
|
||||
Ok(Box::new(VoidBox::new()))
|
||||
}
|
||||
|
||||
ASTNode::GlobalVar { name, value, .. } => {
|
||||
let val = self.execute_expression(value)?;
|
||||
// 🌍 革命的グローバル変数:GlobalBoxのフィールドとして設定
|
||||
self.set_variable(name, val.clone_box())?;
|
||||
Ok(Box::new(VoidBox::new()))
|
||||
}
|
||||
|
||||
ASTNode::TryCatch { try_body, catch_clauses, finally_body, .. } => {
|
||||
self.execute_try_catch(try_body, catch_clauses, finally_body)
|
||||
}
|
||||
|
||||
ASTNode::Throw { expression, .. } => {
|
||||
self.execute_throw(expression)
|
||||
}
|
||||
|
||||
ASTNode::Local { variables, initial_values, .. } => {
|
||||
// 🌍 革命的local変数宣言:local変数スタックに追加(初期化対応)
|
||||
for (i, var_name) in variables.iter().enumerate() {
|
||||
if let Some(Some(init_expr)) = initial_values.get(i) {
|
||||
// 🚀 初期化付きlocal宣言: local x = value
|
||||
let init_value = self.execute_expression(init_expr)?;
|
||||
self.declare_local_variable(var_name, init_value);
|
||||
} else {
|
||||
// 従来のlocal宣言: local x
|
||||
self.declare_local_variable(var_name, Box::new(VoidBox::new()));
|
||||
}
|
||||
}
|
||||
Ok(Box::new(VoidBox::new()))
|
||||
}
|
||||
|
||||
ASTNode::Outbox { variables, initial_values, .. } => {
|
||||
// 📤 革命的outbox変数宣言:static関数内で所有権移転(初期化対応)
|
||||
for (i, var_name) in variables.iter().enumerate() {
|
||||
if let Some(Some(init_expr)) = initial_values.get(i) {
|
||||
// 🚀 初期化付きoutbox宣言: outbox x = value
|
||||
let init_value = self.execute_expression(init_expr)?;
|
||||
self.declare_outbox_variable(var_name, init_value);
|
||||
} else {
|
||||
// 従来のoutbox宣言: outbox x
|
||||
self.declare_outbox_variable(var_name, Box::new(VoidBox::new()));
|
||||
}
|
||||
}
|
||||
Ok(Box::new(VoidBox::new()))
|
||||
}
|
||||
|
||||
// 式文
|
||||
_ => self.execute_expression(statement),
|
||||
}
|
||||
}
|
||||
|
||||
/// 条件分岐を実行 - If/else statement processing
|
||||
pub(super) fn execute_if(&mut self, condition: &ASTNode, then_body: &[ASTNode], else_body: &Option<Vec<ASTNode>>)
|
||||
-> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
let condition_value = self.execute_expression(condition)?;
|
||||
|
||||
// 条件を真偉値として評価
|
||||
let is_true = self.is_truthy(&condition_value);
|
||||
|
||||
if is_true {
|
||||
for statement in then_body {
|
||||
self.execute_statement(statement)?;
|
||||
if !matches!(self.control_flow, super::ControlFlow::None) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if let Some(else_statements) = else_body {
|
||||
for statement in else_statements {
|
||||
self.execute_statement(statement)?;
|
||||
if !matches!(self.control_flow, super::ControlFlow::None) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Box::new(VoidBox::new()))
|
||||
}
|
||||
|
||||
/// ループを実行 - Loop processing: loop(condition) { body } のみ
|
||||
pub(super) fn execute_loop(&mut self, condition: &Box<ASTNode>, body: &[ASTNode]) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
loop {
|
||||
// 常に条件をチェック
|
||||
let condition_result = self.execute_expression(condition)?;
|
||||
if let Some(bool_box) = condition_result.as_any().downcast_ref::<BoolBox>() {
|
||||
if !bool_box.value {
|
||||
break; // 条件がfalseの場合はループ終了
|
||||
}
|
||||
} else {
|
||||
// 条件が真偉値でない場合は、Interpreter::is_truthy()を使用
|
||||
if !self.is_truthy(&condition_result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ループ本体を実行
|
||||
for statement in body {
|
||||
self.execute_statement(statement)?;
|
||||
|
||||
match &self.control_flow {
|
||||
super::ControlFlow::Break => {
|
||||
self.control_flow = super::ControlFlow::None;
|
||||
return Ok(Box::new(VoidBox::new()));
|
||||
}
|
||||
super::ControlFlow::Return(_) => {
|
||||
// returnはループを抜けるが、上位に伝播
|
||||
return Ok(Box::new(VoidBox::new()));
|
||||
}
|
||||
super::ControlFlow::Throw(_) => {
|
||||
// 例外はループを抜けて上位に伝播
|
||||
return Ok(Box::new(VoidBox::new()));
|
||||
}
|
||||
super::ControlFlow::None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Box::new(VoidBox::new()))
|
||||
}
|
||||
|
||||
/// 代入処理を実行 - Assignment processing
|
||||
pub(super) fn execute_assignment(&mut self, target: &ASTNode, value: &ASTNode) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
let val = self.execute_expression(value)?;
|
||||
|
||||
match target {
|
||||
ASTNode::Variable { name, .. } => {
|
||||
// 🌍 革命的代入:local変数 → GlobalBoxフィールド
|
||||
self.set_variable(name, val.clone_box())?;
|
||||
Ok(val)
|
||||
}
|
||||
|
||||
ASTNode::FieldAccess { object, field, .. } => {
|
||||
// フィールドへの代入
|
||||
let obj_value = self.execute_expression(object)?;
|
||||
|
||||
if let Some(instance) = obj_value.as_any().downcast_ref::<InstanceBox>() {
|
||||
// 既存のフィールド値があればfini()を呼ぶ
|
||||
if let Some(old_field_value) = instance.get_field(field) {
|
||||
if let Some(old_instance) = old_field_value.as_any().downcast_ref::<InstanceBox>() {
|
||||
let _ = old_instance.fini();
|
||||
finalization::mark_as_finalized(old_instance.box_id());
|
||||
}
|
||||
}
|
||||
|
||||
instance.set_field(field, val.clone_box())
|
||||
.map_err(|e| RuntimeError::InvalidOperation { message: e })?;
|
||||
Ok(val)
|
||||
} else {
|
||||
Err(RuntimeError::TypeError {
|
||||
message: format!("Cannot set field '{}' on non-instance type", field),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
ASTNode::ThisField { field, .. } => {
|
||||
// 🌍 革命的this.field代入:local変数から取得
|
||||
let this_value = self.resolve_variable("me")
|
||||
.map_err(|_| RuntimeError::InvalidOperation {
|
||||
message: "'this' is not bound in the current context".to_string(),
|
||||
})?;
|
||||
|
||||
if let Some(instance) = this_value.as_any().downcast_ref::<InstanceBox>() {
|
||||
// 既存のthis.field値があればfini()を呼ぶ
|
||||
if let Some(old_field_value) = instance.get_field(field) {
|
||||
if let Some(old_instance) = old_field_value.as_any().downcast_ref::<InstanceBox>() {
|
||||
let _ = old_instance.fini();
|
||||
finalization::mark_as_finalized(old_instance.box_id());
|
||||
}
|
||||
}
|
||||
|
||||
instance.set_field(field, val.clone_box())
|
||||
.map_err(|e| RuntimeError::InvalidOperation { message: e })?;
|
||||
Ok(val)
|
||||
} else {
|
||||
Err(RuntimeError::TypeError {
|
||||
message: "'this' is not an instance".to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
ASTNode::MeField { field, .. } => {
|
||||
// 🌍 革命的me.field代入:local変数から取得
|
||||
let me_value = self.resolve_variable("me")
|
||||
.map_err(|_| RuntimeError::InvalidOperation {
|
||||
message: "'this' is not bound in the current context".to_string(),
|
||||
})?;
|
||||
|
||||
if let Some(instance) = me_value.as_any().downcast_ref::<InstanceBox>() {
|
||||
// 既存のme.field値があればfini()を呼ぶ
|
||||
if let Some(old_field_value) = instance.get_field(field) {
|
||||
if let Some(old_instance) = old_field_value.as_any().downcast_ref::<InstanceBox>() {
|
||||
let _ = old_instance.fini();
|
||||
finalization::mark_as_finalized(old_instance.box_id());
|
||||
}
|
||||
}
|
||||
|
||||
instance.set_field(field, val.clone_box())
|
||||
.map_err(|e| RuntimeError::InvalidOperation { message: e })?;
|
||||
Ok(val)
|
||||
} else {
|
||||
Err(RuntimeError::TypeError {
|
||||
message: "'this' is not an instance".to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
_ => Err(RuntimeError::InvalidOperation {
|
||||
message: "Invalid assignment target".to_string(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// try/catch/finally文を実行 - Exception handling
|
||||
pub(super) fn execute_try_catch(&mut self, try_body: &[ASTNode], catch_clauses: &[super::CatchClause], finally_body: &Option<Vec<ASTNode>>)
|
||||
-> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
let mut thrown_exception: Option<Box<dyn NyashBox>> = None;
|
||||
|
||||
// Try block execution
|
||||
let mut try_result = Ok(Box::new(VoidBox::new()));
|
||||
for statement in try_body {
|
||||
match self.execute_statement(statement) {
|
||||
Ok(_) => {
|
||||
// 制御フローをチェック
|
||||
if !matches!(self.control_flow, super::ControlFlow::None) {
|
||||
if let super::ControlFlow::Throw(exception) = &self.control_flow {
|
||||
thrown_exception = Some(exception.clone_box());
|
||||
self.control_flow = super::ControlFlow::None;
|
||||
break;
|
||||
} else {
|
||||
break; // Return/Break等は上位に伝播
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
// RuntimeErrorを例外として扱う
|
||||
thrown_exception = Some(Box::new(exception_box::ErrorBox::new(&format!("{:?}", e))));
|
||||
try_result = Err(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Catch clause processing
|
||||
if let Some(exception) = &thrown_exception {
|
||||
for catch_clause in catch_clauses {
|
||||
// 型チェック
|
||||
if let Some(exception_type) = &catch_clause.exception_type {
|
||||
if !exception_box::is_exception_type(exception.as_ref(), exception_type) {
|
||||
continue; // 型が合わない場合は次のcatch句へ
|
||||
}
|
||||
}
|
||||
|
||||
// 🌍 革命的例外変数束縛:local変数として設定
|
||||
if let Some(var_name) = &catch_clause.variable_name {
|
||||
self.declare_local_variable(var_name, exception.clone_box());
|
||||
}
|
||||
|
||||
// Catch body execution
|
||||
for statement in &catch_clause.body {
|
||||
self.execute_statement(statement)?;
|
||||
if !matches!(self.control_flow, super::ControlFlow::None) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 🌍 革命的例外変数クリーンアップ:local変数から削除
|
||||
if let Some(var_name) = &catch_clause.variable_name {
|
||||
self.local_vars.remove(var_name);
|
||||
}
|
||||
|
||||
thrown_exception = None; // 例外が処理された
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally block execution (always executed)
|
||||
if let Some(ref finally_statements) = finally_body {
|
||||
for statement in finally_statements {
|
||||
self.execute_statement(statement)?;
|
||||
if !matches!(self.control_flow, super::ControlFlow::None) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 未処理の例外があれば再スロー
|
||||
if let Some(exception) = thrown_exception {
|
||||
self.control_flow = super::ControlFlow::Throw(exception);
|
||||
}
|
||||
|
||||
match try_result {
|
||||
Ok(result) => Ok(result),
|
||||
Err(_) => Ok(Box::new(VoidBox::new()) as Box<dyn NyashBox>),
|
||||
}
|
||||
}
|
||||
|
||||
/// throw文を実行 - Throw exception
|
||||
pub(super) fn execute_throw(&mut self, expression: &ASTNode) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||
let value = self.execute_expression(expression)?;
|
||||
|
||||
// 値を例外として扱う
|
||||
let exception = if let Some(error_box) = value.as_any().downcast_ref::<exception_box::ErrorBox>() {
|
||||
Box::new(error_box.clone()) as Box<dyn NyashBox>
|
||||
} else {
|
||||
// 文字列や他の値はErrorBoxに変換
|
||||
Box::new(exception_box::ErrorBox::new(&value.to_string_box().value))
|
||||
};
|
||||
|
||||
self.control_flow = super::ControlFlow::Throw(exception);
|
||||
Ok(Box::new(VoidBox::new()))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user