From 6abcf94d6f20976646999b85842a841aad9f653c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 12 Aug 2025 08:29:25 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=80=20MAJOR:=20Multi-Delegation=20Synt?= =?UTF-8?q?ax=20Implementation=20Complete!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: moe-charm <217100418+moe-charm@users.noreply.github.com> --- src/ast.rs | 10 ++-- src/interpreter/core.rs | 2 +- src/interpreter/expressions.rs | 4 +- src/interpreter/mod.rs | 4 +- src/interpreter/objects.rs | 8 ++-- src/parser/mod.rs | 85 ++++++++++++++++++++++------------ test_multi_delegation.nyash | 28 +++++++++++ 7 files changed, 97 insertions(+), 44 deletions(-) create mode 100644 test_multi_delegation.nyash diff --git a/src/ast.rs b/src/ast.rs index 923104c7..c8450389 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -105,7 +105,7 @@ pub enum StructureNode { constructors: Vec, init_fields: Vec, is_interface: bool, - extends: Option, + extends: Vec, // 🚀 Multi-delegation: Changed from Option to Vec implements: Vec, /// 🔥 ジェネリクス型パラメータ (例: ["T", "U"]) type_parameters: Vec, @@ -450,7 +450,7 @@ pub enum ASTNode { constructors: HashMap, // constructor_key -> FunctionDeclaration init_fields: Vec, // initブロック内のフィールド定義 is_interface: bool, // interface box かどうか - extends: Option, // 継承元のBox名 + extends: Vec, // 🚀 Multi-delegation: Changed from Option to Vec implements: Vec, // 実装するinterface名のリスト type_parameters: Vec, // 🔥 ジェネリクス型パラメータ (例: ["T", "U"]) /// 🔥 Static boxかどうかのフラグ @@ -714,8 +714,8 @@ impl ASTNode { format!("BoxDeclaration({}, {} fields, {} methods, {} constructors", name, fields.len(), methods.len(), constructors.len()) }; - if let Some(parent) = extends { - desc.push_str(&format!(", extends {}", parent)); + if !extends.is_empty() { + desc.push_str(&format!(", extends [{}]", extends.join(", "))); } if !implements.is_empty() { @@ -936,7 +936,7 @@ mod tests { constructors: HashMap::new(), init_fields: vec![], is_interface: false, - extends: None, + extends: vec![], // 🚀 Multi-delegation: Changed from None to vec![] implements: vec![], span: Span::unknown(), }; diff --git a/src/interpreter/core.rs b/src/interpreter/core.rs index 6e1a2f7f..e8119db9 100644 --- a/src/interpreter/core.rs +++ b/src/interpreter/core.rs @@ -565,7 +565,7 @@ impl NyashInterpreter { methods: HashMap, init_fields: Vec, static_init: Option>, - extends: Option, + extends: Vec, // 🚀 Multi-delegation: Changed from Option to Vec implements: Vec, type_parameters: Vec ) -> Result<(), RuntimeError> { diff --git a/src/interpreter/expressions.rs b/src/interpreter/expressions.rs index a5bda4fb..b3632c52 100644 --- a/src/interpreter/expressions.rs +++ b/src/interpreter/expressions.rs @@ -745,8 +745,8 @@ impl NyashInterpreter { name: current_class.clone() })?; - // extendsまたはimplementsでparentが指定されているか確認 - let is_valid_delegation = current_box_decl.extends.as_ref().map(|s| s.as_str()) == Some(parent) || + // extendsまたはimplementsでparentが指定されているか確認 (Multi-delegation) 🚀 + let is_valid_delegation = current_box_decl.extends.contains(&parent.to_string()) || current_box_decl.implements.contains(&parent.to_string()); if !is_valid_delegation { diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index b0edc451..6838059e 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -68,7 +68,7 @@ pub struct BoxDeclaration { pub constructors: HashMap, pub init_fields: Vec, pub is_interface: bool, - pub extends: Option, + pub extends: Vec, // 🚀 Multi-delegation: Changed from Option to Vec pub implements: Vec, pub type_parameters: Vec, // 🔥 ジェネリクス型パラメータ } @@ -81,7 +81,7 @@ pub struct StaticBoxDefinition { pub methods: HashMap, pub init_fields: Vec, pub static_init: Option>, // static { } ブロック - pub extends: Option, + pub extends: Vec, // 🚀 Multi-delegation: Changed from Option to Vec pub implements: Vec, pub type_parameters: Vec, /// 初期化状態 diff --git a/src/interpreter/objects.rs b/src/interpreter/objects.rs index 1588f58f..238e9b94 100644 --- a/src/interpreter/objects.rs +++ b/src/interpreter/objects.rs @@ -720,7 +720,7 @@ impl NyashInterpreter { 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(), + parent_class: box_decl.extends.first().cloned(), // Use first parent for context }); // コンストラクタを実行 @@ -753,7 +753,7 @@ impl NyashInterpreter { constructors: HashMap, init_fields: Vec, is_interface: bool, - extends: Option, + extends: Vec, // 🚀 Multi-delegation: Changed from Option to Vec implements: Vec, type_parameters: Vec // 🔥 ジェネリクス型パラメータ追加 ) -> Result<(), RuntimeError> { @@ -905,8 +905,8 @@ impl NyashInterpreter { let mut all_fields = Vec::new(); let mut all_methods = HashMap::new(); - // 親クラスの継承チェーンを再帰的に解決 - if let Some(parent_name) = &box_decl.extends { + // 親クラスの継承チェーンを再帰的に解決 (Multi-delegation) 🚀 + for parent_name in &box_decl.extends { // 🔥 ビルトインBoxかチェック let is_builtin = matches!(parent_name.as_str(), "IntegerBox" | "StringBox" | "BoolBox" | "ArrayBox" | "MapBox" | diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 0041a404..db9aec23 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -205,24 +205,35 @@ impl NyashParser { Vec::new() }; - // from句のパース(デリゲーション) + // from句のパース(Multi-delegation)🚀 let extends = if self.match_token(&TokenType::FROM) { self.advance(); // consume 'from' - if let TokenType::IDENTIFIER(parent_name) = &self.current_token().token_type { - let parent_name = parent_name.clone(); - self.advance(); - Some(parent_name) - } else { - let line = self.current_token().line; - return Err(ParseError::UnexpectedToken { - found: self.current_token().token_type.clone(), - expected: "parent class name".to_string(), - line, - }); + let mut parent_list = Vec::new(); + + loop { + if let TokenType::IDENTIFIER(parent_name) = &self.current_token().token_type { + parent_list.push(parent_name.clone()); + self.advance(); + + if self.match_token(&TokenType::COMMA) { + self.advance(); // consume ',' + } else { + break; + } + } else { + let line = self.current_token().line; + return Err(ParseError::UnexpectedToken { + found: self.current_token().token_type.clone(), + expected: "parent class name".to_string(), + line, + }); + } } + + parent_list } else { - None + Vec::new() }; // interface句のパース(インターフェース実装) @@ -564,8 +575,11 @@ impl NyashParser { self.consume(TokenType::RBRACE)?; // 🔍 デリゲーションメソッドチェック:親Boxに存在しないメソッドのoverride検出 - if let Some(ref parent_name) = extends { - self.validate_override_methods(&name, parent_name, &methods)?; + if !extends.is_empty() { + // For multi-delegation, validate against all parents + for parent_name in &extends { + self.validate_override_methods(&name, parent_name, &methods)?; + } } Ok(ASTNode::BoxDeclaration { @@ -672,7 +686,7 @@ impl NyashParser { constructors: HashMap::new(), // インターフェースにコンストラクタなし init_fields: vec![], // インターフェースにinitブロックなし is_interface: true, // インターフェースフラグ - extends: None, + extends: vec![], // 🚀 Multi-delegation: Changed from None to vec![] implements: vec![], type_parameters: Vec::new(), // 🔥 インターフェースではジェネリクス未対応 is_static: false, // インターフェースは非static @@ -926,27 +940,38 @@ impl NyashParser { Vec::new() }; - // from句のパース(デリゲーション)- static boxでもデリゲーション可能 + // from句のパース(Multi-delegation)- static boxでもデリゲーション可能 🚀 let extends = if self.match_token(&TokenType::FROM) { self.advance(); // consume 'from' - if let TokenType::IDENTIFIER(parent_name) = &self.current_token().token_type { - let parent_name = parent_name.clone(); - self.advance(); - Some(parent_name) - } else { - let line = self.current_token().line; - return Err(ParseError::UnexpectedToken { - found: self.current_token().token_type.clone(), - expected: "parent class name".to_string(), - line, - }); + let mut parent_list = Vec::new(); + + loop { + if let TokenType::IDENTIFIER(parent_name) = &self.current_token().token_type { + parent_list.push(parent_name.clone()); + self.advance(); + + if self.match_token(&TokenType::COMMA) { + self.advance(); // consume ',' + } else { + break; + } + } else { + let line = self.current_token().line; + return Err(ParseError::UnexpectedToken { + found: self.current_token().token_type.clone(), + expected: "parent class name".to_string(), + line, + }); + } } + + parent_list } else { - None + Vec::new() }; - // interface句のパース(インターフェース実装) + // interface句のパース(インターフェース実装)- static boxでもinterface実装可能 let implements = if self.match_token(&TokenType::INTERFACE) { self.advance(); // consume 'interface' diff --git a/test_multi_delegation.nyash b/test_multi_delegation.nyash new file mode 100644 index 00000000..db47fa72 --- /dev/null +++ b/test_multi_delegation.nyash @@ -0,0 +1,28 @@ +// Test Multi-Delegation Syntax (Phase 2 Implementation) +// This should test the new `box Child from ParentA, ParentB` syntax + +local console = new ConsoleBox() +console.log("=== Testing Multi-Delegation Syntax ===") + +// Test 1: Simple multi-delegation syntax parsing +console.log("Testing multi-delegation syntax...") +box MultiChild from StringBox, IntegerBox { + init { textValue, numValue } + + pack(text, num) { + me.textValue = text + me.numValue = num + } + + getCombined() { + return me.textValue + ": " + me.numValue + } +} + +console.log("Multi-delegation box declared successfully!") + +// Test if the parser accepted the syntax +local multi = new MultiChild("Count", 123) +console.log("Multi delegation instance: " + multi.getCombined()) + +console.log("=== Multi-Delegation Test Complete ===") \ No newline at end of file