From bf0229c24a98a2509f7c8423af3e3fc7985a34f5 Mon Sep 17 00:00:00 2001 From: Moe Charm Date: Thu, 21 Aug 2025 12:28:47 +0900 Subject: [PATCH] refactor: Extract basic type constructors from execute_new function - Create objects_basic_constructors.rs with create_basic_box() method - Handle StringBox, IntegerBox, BoolBox, ArrayBox, NullBox, FloatBox, MapBox - Reduce execute_new function complexity by delegating basic types - Start decomposing 875-line function into manageable modules - All tests pass successfully --- src/interpreter/mod.rs | 1 + src/interpreter/objects.rs | 26 +-- src/interpreter/objects_basic_constructors.rs | 157 ++++++++++++++++++ .../objects_non_basic_constructors.rs | 83 +++++++++ 4 files changed, 254 insertions(+), 13 deletions(-) create mode 100644 src/interpreter/objects_basic_constructors.rs create mode 100644 src/interpreter/objects_non_basic_constructors.rs diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 43eb98e5..c05af308 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -34,6 +34,7 @@ mod expressions; mod statements; mod functions; mod objects; +mod objects_basic_constructors; mod io; mod methods; mod math_methods; diff --git a/src/interpreter/objects.rs b/src/interpreter/objects.rs index 415ae7d5..a8ce64f0 100644 --- a/src/interpreter/objects.rs +++ b/src/interpreter/objects.rs @@ -88,22 +88,22 @@ impl NyashInterpreter { // 🚧 Legacy implementation (will be removed in Phase 9.78e) eprintln!("🔍 Falling back to legacy match statement for: {}", class); - // 組み込みBox型のチェック + // Try basic type constructors first + if let Ok(basic_box) = self.create_basic_box(class, arguments) { + return Ok(basic_box); + } + + // 組み込みBox型のチェック (基本型以外) eprintln!("🔍 Starting built-in Box type checks..."); match class { - // Basic Box constructors (CRITICAL - these were missing!) - "StringBox" => { - // StringBoxは引数1個(文字列値)で作成 - if arguments.len() != 1 { - return Err(RuntimeError::InvalidOperation { - message: format!("StringBox constructor expects 1 argument, got {}", arguments.len()), - }); - } - let value = self.execute_expression(&arguments[0])?; - let string_value = value.to_string_box().value; - let string_box = Box::new(StringBox::new(string_value)) as Box; - return Ok(string_box); + // Basic types are handled by create_basic_box() above + "StringBox" | "IntegerBox" | "BoolBox" | "ArrayBox" | "ResultBox" | + "ErrorBox" | "NullBox" | "FloatBox" | "MapBox" => { + // These are handled by create_basic_box(), should not reach here + unreachable!("Basic type {} should have been handled by create_basic_box()", class); } + + /* Basic types are now handled by create_basic_box() - keeping for reference "IntegerBox" => { // IntegerBoxは引数1個(整数値)で作成 if arguments.len() != 1 { diff --git a/src/interpreter/objects_basic_constructors.rs b/src/interpreter/objects_basic_constructors.rs new file mode 100644 index 00000000..79fe7d8e --- /dev/null +++ b/src/interpreter/objects_basic_constructors.rs @@ -0,0 +1,157 @@ +//! Basic type constructors for execute_new +//! Handles StringBox, IntegerBox, BoolBox, ArrayBox, etc. + +use crate::ast::ASTNode; +use crate::box_trait::*; +use crate::interpreter::core::{NyashInterpreter as Interpreter, RuntimeError}; +use crate::boxes::FloatBox; +use crate::NullBox; +use crate::MapBox; + +impl Interpreter { + /// Create basic type boxes (StringBox, IntegerBox, BoolBox, etc.) + pub(super) fn create_basic_box( + &mut self, + class: &str, + arguments: &[ASTNode] + ) -> Result, RuntimeError> { + match class { + "StringBox" => { + // StringBoxは引数1個(文字列値)で作成 + if arguments.len() != 1 { + return Err(RuntimeError::InvalidOperation { + message: format!("StringBox constructor expects 1 argument, got {}", arguments.len()), + }); + } + + let value = self.execute_expression(&arguments[0])?; + if let Some(s) = value.as_any().downcast_ref::() { + return Ok(Box::new(StringBox::new(s.value.clone()))); + } else if let Some(i) = value.as_any().downcast_ref::() { + return Ok(Box::new(StringBox::new(i.value.to_string()))); + } else if let Some(b) = value.as_any().downcast_ref::() { + return Ok(Box::new(StringBox::new(b.value.to_string()))); + } else { + return Ok(Box::new(StringBox::new(value.to_string_box().value))); + } + } + + "IntegerBox" => { + // IntegerBoxは引数1個(整数値)で作成 + if arguments.len() != 1 { + return Err(RuntimeError::InvalidOperation { + message: format!("IntegerBox constructor expects 1 argument, got {}", arguments.len()), + }); + } + + let value = self.execute_expression(&arguments[0])?; + if let Some(i) = value.as_any().downcast_ref::() { + return Ok(Box::new(IntegerBox::new(i.value))); + } else if let Some(s) = value.as_any().downcast_ref::() { + match s.value.parse::() { + Ok(n) => return Ok(Box::new(IntegerBox::new(n))), + Err(_) => return Err(RuntimeError::TypeError { + message: format!("Cannot convert '{}' to integer", s.value), + }), + } + } else { + return Err(RuntimeError::TypeError { + message: "IntegerBox constructor requires integer or string argument".to_string(), + }); + } + } + + "BoolBox" => { + // BoolBoxは引数1個(ブール値)で作成 + if arguments.len() != 1 { + return Err(RuntimeError::InvalidOperation { + message: format!("BoolBox constructor expects 1 argument, got {}", arguments.len()), + }); + } + + let value = self.execute_expression(&arguments[0])?; + if let Some(b) = value.as_any().downcast_ref::() { + return Ok(Box::new(BoolBox::new(b.value))); + } else if let Some(s) = value.as_any().downcast_ref::() { + let val = match s.value.as_str() { + "true" => true, + "false" => false, + _ => return Err(RuntimeError::TypeError { + message: format!("Cannot convert '{}' to boolean", s.value), + }), + }; + return Ok(Box::new(BoolBox::new(val))); + } else { + return Err(RuntimeError::TypeError { + message: "BoolBox constructor requires boolean or string argument".to_string(), + }); + } + } + + "ArrayBox" => { + // ArrayBoxは引数なしで作成 + if !arguments.is_empty() { + return Err(RuntimeError::InvalidOperation { + message: format!("ArrayBox constructor expects 0 arguments, got {}", arguments.len()), + }); + } + return Ok(Box::new(ArrayBox::new())); + } + + "NullBox" => { + // NullBoxは引数なしで作成 + if !arguments.is_empty() { + return Err(RuntimeError::InvalidOperation { + message: format!("NullBox constructor expects 0 arguments, got {}", arguments.len()), + }); + } + return Ok(Box::new(NullBox::new())); + } + + "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; + return Ok(map_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(f) = value.as_any().downcast_ref::() { + return Ok(Box::new(FloatBox::new(f.value))); + } else if let Some(i) = value.as_any().downcast_ref::() { + return Ok(Box::new(FloatBox::new(i.value as f64))); + } else if let Some(s) = value.as_any().downcast_ref::() { + match s.value.parse::() { + Ok(n) => return Ok(Box::new(FloatBox::new(n))), + Err(_) => return Err(RuntimeError::TypeError { + message: format!("Cannot convert '{}' to float", s.value), + }), + } + } else { + return Err(RuntimeError::TypeError { + message: "FloatBox constructor requires float, integer, or string argument".to_string(), + }); + } + } + + _ => { + // Not a basic type + Err(RuntimeError::TypeError { + message: format!("Not a basic type: {}", class), + }) + } + } + } +} \ No newline at end of file diff --git a/src/interpreter/objects_non_basic_constructors.rs b/src/interpreter/objects_non_basic_constructors.rs new file mode 100644 index 00000000..c112433a --- /dev/null +++ b/src/interpreter/objects_non_basic_constructors.rs @@ -0,0 +1,83 @@ +//! Non-basic type constructors for execute_new +//! Handles MathBox, ConsoleBox, GUI boxes, Network boxes, etc. + +use crate::ast::ASTNode; +use crate::box_trait::*; +use crate::interpreter::core::{NyashInterpreter as Interpreter, RuntimeError}; +use crate::boxes::math_box::MathBox; +use crate::boxes::random_box::RandomBox; +use crate::boxes::sound_box::SoundBox; +use crate::boxes::debug_box::DebugBox; + +impl Interpreter { + /// Create non-basic type boxes (MathBox, ConsoleBox, GUI/Network boxes, etc.) + pub(super) fn create_non_basic_box( + &mut self, + class: &str, + arguments: &[ASTNode] + ) -> Result, RuntimeError> { + match class { + "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; + return Ok(math_box); + } + + "ConsoleBox" => { + // ConsoleBoxは引数なしで作成 + if !arguments.is_empty() { + return Err(RuntimeError::InvalidOperation { + message: format!("ConsoleBox constructor expects 0 arguments, got {}", arguments.len()), + }); + } + let console_box = Box::new(crate::box_trait::ConsoleBox::new()) as Box; + return Ok(console_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; + 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; + 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; + return Ok(debug_box); + } + + _ => { + // Not a non-basic type handled here + Err(RuntimeError::TypeError { + message: format!("Not a non-basic type handled in this method: {}", class), + }) + } + } + } +} \ No newline at end of file