🎁 feat: pack構文革命完全達成 - Box哲学の具現化
【実装内容】 - packキーワード追加: TokenType::PACK, "pack" mapping - パーサー対応: init同様の特別扱い + from Parent.pack() - インタープリター対応: pack > init > Box名順優先選択 - デリゲーション統合: from Parent.pack()で親packを呼び出し - テスト完備: test_pack_syntax.nyash包括テスト 【革命的効果】 - Box哲学具現化: 「箱に詰める」でコードを書くたび哲学体験 - 他言語差別化: new/init超越のNyash独自アイデンティティ - 直感的UX: Gemini・ChatGPT両先生一致推薦の最適命名 - メンタルモデル統一: 全Boxで1つのpack動詞に収束 - 拡張基盤: try_pack, from_*パターンへの発展準備完了 🎉 Everything is Box - Now Everything is Packed\! 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
47
CLAUDE.md
47
CLAUDE.md
@ -60,6 +60,20 @@ cd projects/nyash-wasm
|
|||||||
- すべての値がBox(StringBox, IntegerBox, BoolBox等)
|
- すべての値がBox(StringBox, IntegerBox, BoolBox等)
|
||||||
- ユーザー定義Box: `box ClassName { init { field1, field2 } }`
|
- ユーザー定義Box: `box ClassName { init { field1, field2 } }`
|
||||||
|
|
||||||
|
### 🌟 完全明示デリゲーション(2025-08-11革命)
|
||||||
|
```nyash
|
||||||
|
// デリゲーション構文
|
||||||
|
box Child from Parent { // from構文でデリゲーション
|
||||||
|
init(args) { // コンストラクタは「init」に統一
|
||||||
|
from Parent.init(args) // 親の初期化
|
||||||
|
}
|
||||||
|
|
||||||
|
override method() { // 明示的オーバーライド必須
|
||||||
|
from Parent.method() // 親メソッド呼び出し
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### 🔄 統一ループ構文
|
### 🔄 統一ループ構文
|
||||||
```nyash
|
```nyash
|
||||||
// ✅ 唯一の正しい形式
|
// ✅ 唯一の正しい形式
|
||||||
@ -70,6 +84,32 @@ while condition { } // 使用不可
|
|||||||
loop() { } // 使用不可
|
loop() { } // 使用不可
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 🎁 pack構文 - Box哲学の具現化(2025-08-11実装)
|
||||||
|
```nyash
|
||||||
|
// 🎁 「箱に詰める」直感的コンストラクタ
|
||||||
|
box User {
|
||||||
|
init { name, email }
|
||||||
|
|
||||||
|
pack(userName, userEmail) { // ← Box哲学を体現!
|
||||||
|
me.name = userName
|
||||||
|
me.email = userEmail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🔄 デリゲーションでのpack
|
||||||
|
box AdminUser from User {
|
||||||
|
init { permissions }
|
||||||
|
|
||||||
|
pack(adminName, adminEmail, perms) {
|
||||||
|
from User.pack(adminName, adminEmail) // 親のpackを呼び出し
|
||||||
|
me.permissions = perms
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ 優先順位: pack > init > Box名形式
|
||||||
|
local user = new User("Alice", "alice@example.com") // packが使われる
|
||||||
|
```
|
||||||
|
|
||||||
### 🎯 正統派Nyashスタイル(2025-08-09実装)
|
### 🎯 正統派Nyashスタイル(2025-08-09実装)
|
||||||
```nyash
|
```nyash
|
||||||
// 🚀 Static Box Main パターン - エントリーポイントの統一スタイル
|
// 🚀 Static Box Main パターン - エントリーポイントの統一スタイル
|
||||||
@ -238,4 +278,9 @@ docs/
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
最終更新: 2025年8月9日 - **🔥 パーサー無限ループ完全制圧!`--debug-fuel`引数でユーザー制御可能+must_advance!マクロによる早期検出システム完成。予約語問題も安全にエラー表示。静的Box Mainパターン+変数宣言厳密化と合わせて本格言語レベル到達!**
|
最終更新: 2025年8月11日 - **🎁 `pack`構文革命完全達成!**
|
||||||
|
- **Everything is Packed**: Gemini・ChatGPT両先生一致推薦の`pack`コンストラクタ採用
|
||||||
|
- **Box哲学具現化**: 「箱に詰める」直感的メタファーでコードを書くたび哲学体験
|
||||||
|
- **完全実装**: `pack()`、`from Parent.pack()`、`pack`>`init`>Box名順優先選択
|
||||||
|
- **革命的UX**: 他言語の`new`/`init`を超越、Nyash独自アイデンティティ確立
|
||||||
|
- **デリゲーション完成**: `box Child from Parent`+`pack`+`override`+`from`統合完了
|
||||||
@ -748,8 +748,8 @@ impl NyashInterpreter {
|
|||||||
|
|
||||||
drop(box_declarations); // ロック早期解放
|
drop(box_declarations); // ロック早期解放
|
||||||
|
|
||||||
// 4. constructorの場合の特別処理
|
// 4. constructorまたはinitまたはpackの場合の特別処理
|
||||||
if method == "constructor" {
|
if method == "constructor" || method == "init" || method == "pack" || method == parent {
|
||||||
return self.execute_from_parent_constructor(parent, &parent_box_decl, current_instance_val.clone_box(), arguments);
|
return self.execute_from_parent_constructor(parent, &parent_box_decl, current_instance_val.clone_box(), arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -820,16 +820,17 @@ impl NyashInterpreter {
|
|||||||
current_instance: Box<dyn NyashBox>, arguments: &[ASTNode])
|
current_instance: Box<dyn NyashBox>, arguments: &[ASTNode])
|
||||||
-> Result<Box<dyn NyashBox>, RuntimeError> {
|
-> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||||
|
|
||||||
// 1. 親クラスのコンストラクタを取得(デフォルトコンストラクタまたは指定されたもの)
|
// 1. 親クラスのコンストラクタを取得(引数の数でキーを作成)
|
||||||
let constructor_name = if arguments.is_empty() {
|
// "pack/引数数"、"init/引数数"、"Box名/引数数" の順で試す
|
||||||
"constructor"
|
let pack_key = format!("pack/{}", arguments.len());
|
||||||
} else {
|
let init_key = format!("init/{}", arguments.len());
|
||||||
"constructor" // TODO: 将来的に名前付きコンストラクタ対応
|
let box_name_key = format!("{}/{}", parent, arguments.len());
|
||||||
};
|
|
||||||
|
|
||||||
let parent_constructor = parent_box_decl.constructors.get(constructor_name)
|
let parent_constructor = parent_box_decl.constructors.get(&pack_key)
|
||||||
|
.or_else(|| parent_box_decl.constructors.get(&init_key))
|
||||||
|
.or_else(|| parent_box_decl.constructors.get(&box_name_key))
|
||||||
.ok_or(RuntimeError::InvalidOperation {
|
.ok_or(RuntimeError::InvalidOperation {
|
||||||
message: format!("Constructor '{}' not found in parent class '{}'", constructor_name, parent),
|
message: format!("No constructor found for parent class '{}' with {} arguments", parent, arguments.len()),
|
||||||
})?
|
})?
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
@ -844,8 +845,8 @@ impl NyashInterpreter {
|
|||||||
// パラメータ数チェック
|
// パラメータ数チェック
|
||||||
if arg_values.len() != params.len() {
|
if arg_values.len() != params.len() {
|
||||||
return Err(RuntimeError::InvalidOperation {
|
return Err(RuntimeError::InvalidOperation {
|
||||||
message: format!("Parent constructor {}.{} expects {} arguments, got {}",
|
message: format!("Parent constructor {} expects {} arguments, got {}",
|
||||||
parent, constructor_name, params.len(), arg_values.len()),
|
parent, params.len(), arg_values.len()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -881,7 +882,7 @@ impl NyashInterpreter {
|
|||||||
Ok(current_instance)
|
Ok(current_instance)
|
||||||
} else {
|
} else {
|
||||||
Err(RuntimeError::InvalidOperation {
|
Err(RuntimeError::InvalidOperation {
|
||||||
message: format!("Parent constructor '{}' is not a valid function declaration", constructor_name),
|
message: format!("Parent constructor is not a valid function declaration"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -592,8 +592,14 @@ impl NyashInterpreter {
|
|||||||
// 🌍 革命的実装:Environment tracking廃止
|
// 🌍 革命的実装:Environment tracking廃止
|
||||||
|
|
||||||
// コンストラクタを呼び出す
|
// コンストラクタを呼び出す
|
||||||
let constructor_key = format!("{}/{}", actual_class_name, arguments.len());
|
// "pack/引数数"、"init/引数数"、"Box名/引数数" の順で試す
|
||||||
if let Some(constructor) = final_box_decl.constructors.get(&constructor_key) {
|
let pack_key = format!("pack/{}", arguments.len());
|
||||||
|
let init_key = format!("init/{}", arguments.len());
|
||||||
|
let box_name_key = format!("{}/{}", actual_class_name, arguments.len());
|
||||||
|
|
||||||
|
if let Some(constructor) = final_box_decl.constructors.get(&pack_key)
|
||||||
|
.or_else(|| final_box_decl.constructors.get(&init_key))
|
||||||
|
.or_else(|| final_box_decl.constructors.get(&box_name_key)) {
|
||||||
// コンストラクタを実行
|
// コンストラクタを実行
|
||||||
self.execute_constructor(&instance_box, constructor, arguments, &final_box_decl)?;
|
self.execute_constructor(&instance_box, constructor, arguments, &final_box_decl)?;
|
||||||
} else if !arguments.is_empty() {
|
} else if !arguments.is_empty() {
|
||||||
@ -797,8 +803,12 @@ impl NyashInterpreter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 親コンストラクタを探す
|
// 親コンストラクタを探す
|
||||||
let constructor_key = format!("{}/{}", parent_class, arguments.len());
|
// まず "init/引数数" を試し、なければ "Box名/引数数" を試す
|
||||||
if let Some(parent_constructor) = parent_decl.constructors.get(&constructor_key) {
|
let init_key = format!("init/{}", arguments.len());
|
||||||
|
let box_name_key = format!("{}/{}", parent_class, arguments.len());
|
||||||
|
|
||||||
|
if let Some(parent_constructor) = parent_decl.constructors.get(&init_key)
|
||||||
|
.or_else(|| parent_decl.constructors.get(&box_name_key)) {
|
||||||
// 現在のthis参照を取得
|
// 現在のthis参照を取得
|
||||||
// 🌍 革命的this取得:local変数から
|
// 🌍 革命的this取得:local変数から
|
||||||
let this_instance = self.resolve_variable("me")
|
let this_instance = self.resolve_variable("me")
|
||||||
|
|||||||
@ -480,18 +480,29 @@ impl NyashParser {
|
|||||||
// DOTを確認
|
// DOTを確認
|
||||||
self.consume(TokenType::DOT)?;
|
self.consume(TokenType::DOT)?;
|
||||||
|
|
||||||
// method名を取得
|
// method名を取得 (IDENTIFIERまたはINITを受け入れ)
|
||||||
let method = if let TokenType::IDENTIFIER(name) = &self.current_token().token_type {
|
let method = match &self.current_token().token_type {
|
||||||
let name = name.clone();
|
TokenType::IDENTIFIER(name) => {
|
||||||
self.advance();
|
let name = name.clone();
|
||||||
name
|
self.advance();
|
||||||
} else {
|
name
|
||||||
let line = self.current_token().line;
|
}
|
||||||
return Err(ParseError::UnexpectedToken {
|
TokenType::INIT => {
|
||||||
found: self.current_token().token_type.clone(),
|
self.advance();
|
||||||
expected: "method name".to_string(),
|
"init".to_string()
|
||||||
line,
|
}
|
||||||
});
|
TokenType::PACK => {
|
||||||
|
self.advance();
|
||||||
|
"pack".to_string()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let line = self.current_token().line;
|
||||||
|
return Err(ParseError::UnexpectedToken {
|
||||||
|
found: self.current_token().token_type.clone(),
|
||||||
|
expected: "method name".to_string(),
|
||||||
|
line,
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 引数リストをパース
|
// 引数リストをパース
|
||||||
|
|||||||
@ -205,8 +205,8 @@ impl NyashParser {
|
|||||||
Vec::new()
|
Vec::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
// from句のパース(継承)
|
// from句のパース(デリゲーション)
|
||||||
let extends = if self.match_token(&TokenType::COLON) {
|
let extends = if self.match_token(&TokenType::FROM) {
|
||||||
self.advance(); // consume 'from'
|
self.advance(); // consume 'from'
|
||||||
|
|
||||||
if let TokenType::IDENTIFIER(parent_name) = &self.current_token().token_type {
|
if let TokenType::IDENTIFIER(parent_name) = &self.current_token().token_type {
|
||||||
@ -272,8 +272,8 @@ impl NyashParser {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// initブロックの処理
|
// initブロックの処理(initメソッドではない場合のみ)
|
||||||
if self.match_token(&TokenType::INIT) {
|
if self.match_token(&TokenType::INIT) && self.peek_token() != &TokenType::LPAREN {
|
||||||
self.advance(); // consume 'init'
|
self.advance(); // consume 'init'
|
||||||
self.consume(TokenType::LBRACE)?;
|
self.consume(TokenType::LBRACE)?;
|
||||||
|
|
||||||
@ -307,14 +307,147 @@ impl NyashParser {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let TokenType::IDENTIFIER(field_or_method) = &self.current_token().token_type {
|
// overrideキーワードをチェック
|
||||||
|
let mut is_override = false;
|
||||||
|
if self.match_token(&TokenType::OVERRIDE) {
|
||||||
|
is_override = true;
|
||||||
|
self.advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
// initトークンをメソッド名として特別処理
|
||||||
|
if self.match_token(&TokenType::INIT) && self.peek_token() == &TokenType::LPAREN {
|
||||||
|
let field_or_method = "init".to_string();
|
||||||
|
self.advance(); // consume 'init'
|
||||||
|
|
||||||
|
// コンストラクタとして処理
|
||||||
|
if self.match_token(&TokenType::LPAREN) {
|
||||||
|
// initは常にコンストラクタ
|
||||||
|
if is_override {
|
||||||
|
return Err(ParseError::UnexpectedToken {
|
||||||
|
expected: "method definition, not constructor after override keyword".to_string(),
|
||||||
|
found: TokenType::INIT,
|
||||||
|
line: self.current_token().line,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// コンストラクタの処理
|
||||||
|
self.advance(); // consume '('
|
||||||
|
|
||||||
|
let mut params = Vec::new();
|
||||||
|
while !self.match_token(&TokenType::RPAREN) && !self.is_at_end() {
|
||||||
|
must_advance!(self, _unused, "constructor parameter parsing");
|
||||||
|
|
||||||
|
if let TokenType::IDENTIFIER(param) = &self.current_token().token_type {
|
||||||
|
params.push(param.clone());
|
||||||
|
self.advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.match_token(&TokenType::COMMA) {
|
||||||
|
self.advance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.consume(TokenType::RPAREN)?;
|
||||||
|
self.consume(TokenType::LBRACE)?;
|
||||||
|
|
||||||
|
let mut body = Vec::new();
|
||||||
|
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
|
||||||
|
self.skip_newlines();
|
||||||
|
if !self.match_token(&TokenType::RBRACE) {
|
||||||
|
body.push(self.parse_statement()?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.consume(TokenType::RBRACE)?;
|
||||||
|
|
||||||
|
let constructor = ASTNode::FunctionDeclaration {
|
||||||
|
name: field_or_method.clone(),
|
||||||
|
params: params.clone(),
|
||||||
|
body,
|
||||||
|
is_static: false,
|
||||||
|
is_override: false,
|
||||||
|
span: Span::unknown(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// パラメータの数でコンストラクタを区別
|
||||||
|
let constructor_key = format!("{}/{}", field_or_method, params.len());
|
||||||
|
constructors.insert(constructor_key, constructor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// packトークンをメソッド名として特別処理
|
||||||
|
else if self.match_token(&TokenType::PACK) && self.peek_token() == &TokenType::LPAREN {
|
||||||
|
let field_or_method = "pack".to_string();
|
||||||
|
self.advance(); // consume 'pack'
|
||||||
|
|
||||||
|
// コンストラクタとして処理
|
||||||
|
if self.match_token(&TokenType::LPAREN) {
|
||||||
|
// packは常にコンストラクタ
|
||||||
|
if is_override {
|
||||||
|
return Err(ParseError::UnexpectedToken {
|
||||||
|
expected: "method definition, not constructor after override keyword".to_string(),
|
||||||
|
found: TokenType::PACK,
|
||||||
|
line: self.current_token().line,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// コンストラクタの処理
|
||||||
|
self.advance(); // consume '('
|
||||||
|
|
||||||
|
let mut params = Vec::new();
|
||||||
|
while !self.match_token(&TokenType::RPAREN) && !self.is_at_end() {
|
||||||
|
must_advance!(self, _unused, "constructor parameter parsing");
|
||||||
|
|
||||||
|
if let TokenType::IDENTIFIER(param) = &self.current_token().token_type {
|
||||||
|
params.push(param.clone());
|
||||||
|
self.advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.match_token(&TokenType::COMMA) {
|
||||||
|
self.advance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.consume(TokenType::RPAREN)?;
|
||||||
|
self.consume(TokenType::LBRACE)?;
|
||||||
|
|
||||||
|
let mut body = Vec::new();
|
||||||
|
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
|
||||||
|
self.skip_newlines();
|
||||||
|
if !self.match_token(&TokenType::RBRACE) {
|
||||||
|
body.push(self.parse_statement()?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.consume(TokenType::RBRACE)?;
|
||||||
|
|
||||||
|
let constructor = ASTNode::FunctionDeclaration {
|
||||||
|
name: field_or_method.clone(),
|
||||||
|
params: params.clone(),
|
||||||
|
body,
|
||||||
|
is_static: false,
|
||||||
|
is_override: false,
|
||||||
|
span: Span::unknown(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// パラメータの数でコンストラクタを区別
|
||||||
|
let constructor_key = format!("{}/{}", field_or_method, params.len());
|
||||||
|
constructors.insert(constructor_key, constructor);
|
||||||
|
}
|
||||||
|
} else if let TokenType::IDENTIFIER(field_or_method) = &self.current_token().token_type {
|
||||||
let field_or_method = field_or_method.clone();
|
let field_or_method = field_or_method.clone();
|
||||||
self.advance();
|
self.advance();
|
||||||
|
|
||||||
// メソッド定義またはコンストラクタか?
|
// メソッド定義またはコンストラクタか?
|
||||||
if self.match_token(&TokenType::LPAREN) {
|
if self.match_token(&TokenType::LPAREN) {
|
||||||
// Box名と同じ場合はコンストラクタ
|
// Box名と同じまたは"init"または"pack"の場合はコンストラクタ
|
||||||
if field_or_method == name {
|
if field_or_method == name || field_or_method == "init" || field_or_method == "pack" {
|
||||||
|
// コンストラクタはoverrideできない
|
||||||
|
if is_override {
|
||||||
|
return Err(ParseError::UnexpectedToken {
|
||||||
|
expected: "method definition, not constructor after override keyword".to_string(),
|
||||||
|
found: TokenType::IDENTIFIER(field_or_method.clone()),
|
||||||
|
line: self.current_token().line,
|
||||||
|
});
|
||||||
|
}
|
||||||
// コンストラクタの処理
|
// コンストラクタの処理
|
||||||
self.advance(); // consume '('
|
self.advance(); // consume '('
|
||||||
|
|
||||||
@ -402,7 +535,7 @@ impl NyashParser {
|
|||||||
params,
|
params,
|
||||||
body,
|
body,
|
||||||
is_static: false, // メソッドは通常静的でない
|
is_static: false, // メソッドは通常静的でない
|
||||||
is_override: false, // デフォルトは非オーバーライド
|
is_override, // overrideキーワードの有無を反映
|
||||||
span: Span::unknown(),
|
span: Span::unknown(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -410,6 +543,13 @@ impl NyashParser {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// フィールド定義
|
// フィールド定義
|
||||||
|
if is_override {
|
||||||
|
return Err(ParseError::UnexpectedToken {
|
||||||
|
expected: "method definition after override keyword".to_string(),
|
||||||
|
found: self.current_token().token_type.clone(),
|
||||||
|
line: self.current_token().line,
|
||||||
|
});
|
||||||
|
}
|
||||||
fields.push(field_or_method);
|
fields.push(field_or_method);
|
||||||
}
|
}
|
||||||
self.skip_newlines(); // フィールド/メソッド定義後の改行をスキップ
|
self.skip_newlines(); // フィールド/メソッド定義後の改行をスキップ
|
||||||
@ -781,8 +921,8 @@ impl NyashParser {
|
|||||||
Vec::new()
|
Vec::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
// from句のパース(継承)- static boxでも継承可能
|
// from句のパース(デリゲーション)- static boxでもデリゲーション可能
|
||||||
let extends = if self.match_token(&TokenType::COLON) {
|
let extends = if self.match_token(&TokenType::FROM) {
|
||||||
self.advance(); // consume 'from'
|
self.advance(); // consume 'from'
|
||||||
|
|
||||||
if let TokenType::IDENTIFIER(parent_name) = &self.current_token().token_type {
|
if let TokenType::IDENTIFIER(parent_name) = &self.current_token().token_type {
|
||||||
@ -1030,6 +1170,15 @@ impl NyashParser {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 次のトークンを先読み(位置を進めない)
|
||||||
|
fn peek_token(&self) -> &TokenType {
|
||||||
|
if self.current + 1 < self.tokens.len() {
|
||||||
|
&self.tokens[self.current + 1].token_type
|
||||||
|
} else {
|
||||||
|
&TokenType::EOF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 位置を1つ進める
|
/// 位置を1つ進める
|
||||||
fn advance(&mut self) {
|
fn advance(&mut self) {
|
||||||
if !self.is_at_end() {
|
if !self.is_at_end() {
|
||||||
|
|||||||
@ -32,6 +32,7 @@ pub enum TokenType {
|
|||||||
THIS,
|
THIS,
|
||||||
ME,
|
ME,
|
||||||
INIT, // init (初期化ブロック)
|
INIT, // init (初期化ブロック)
|
||||||
|
PACK, // pack (コンストラクタ)
|
||||||
NOWAIT, // nowait
|
NOWAIT, // nowait
|
||||||
AWAIT, // await
|
AWAIT, // await
|
||||||
INTERFACE, // interface
|
INTERFACE, // interface
|
||||||
@ -390,6 +391,7 @@ impl NyashTokenizer {
|
|||||||
"this" => TokenType::THIS,
|
"this" => TokenType::THIS,
|
||||||
"me" => TokenType::ME,
|
"me" => TokenType::ME,
|
||||||
"init" => TokenType::INIT,
|
"init" => TokenType::INIT,
|
||||||
|
"pack" => TokenType::PACK,
|
||||||
"nowait" => TokenType::NOWAIT,
|
"nowait" => TokenType::NOWAIT,
|
||||||
"await" => TokenType::AWAIT,
|
"await" => TokenType::AWAIT,
|
||||||
"interface" => TokenType::INTERFACE,
|
"interface" => TokenType::INTERFACE,
|
||||||
|
|||||||
108
test_pack_syntax.nyash
Normal file
108
test_pack_syntax.nyash
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
// 🎁 pack構文の包括的テスト
|
||||||
|
|
||||||
|
// 1. 基本的なpack構文
|
||||||
|
box Animal {
|
||||||
|
init { name, age }
|
||||||
|
|
||||||
|
pack(animalName, animalAge) {
|
||||||
|
me.name = animalName
|
||||||
|
me.age = animalAge
|
||||||
|
}
|
||||||
|
|
||||||
|
speak() {
|
||||||
|
return me.name + " (age " + me.age + ") makes a sound"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. fromデリゲーションでのpack
|
||||||
|
box Dog from Animal {
|
||||||
|
init { breed }
|
||||||
|
|
||||||
|
pack(dogName, dogAge, dogBreed) {
|
||||||
|
from Animal.pack(dogName, dogAge) // 親のpackを呼び出し
|
||||||
|
me.breed = dogBreed
|
||||||
|
}
|
||||||
|
|
||||||
|
override speak() {
|
||||||
|
return me.name + " (age " + me.age + ", " + me.breed + ") barks: Woof!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 混在形式(packと従来形式の共存)
|
||||||
|
box Cat from Animal {
|
||||||
|
init { color }
|
||||||
|
|
||||||
|
Cat(catName, catAge, catColor) { // 従来形式
|
||||||
|
from Animal.pack(catName, catAge) // 親はpack使用
|
||||||
|
me.color = catColor
|
||||||
|
}
|
||||||
|
|
||||||
|
override speak() {
|
||||||
|
return me.name + " (age " + me.age + ", " + me.color + ") meows: Meow!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. pack単独使用テスト
|
||||||
|
box Bird {
|
||||||
|
init { species, canFly }
|
||||||
|
|
||||||
|
// pack単独 - Box哲学に最適!
|
||||||
|
pack(birdSpecies, flying) {
|
||||||
|
me.species = birdSpecies + " (pack使用)"
|
||||||
|
me.canFly = flying
|
||||||
|
}
|
||||||
|
|
||||||
|
describe() {
|
||||||
|
local flyText
|
||||||
|
if me.canFly {
|
||||||
|
flyText = "can fly"
|
||||||
|
} else {
|
||||||
|
flyText = "cannot fly"
|
||||||
|
}
|
||||||
|
return me.species + " - " + flyText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// テスト実行
|
||||||
|
print("=== 🎁 pack構文テスト ===")
|
||||||
|
|
||||||
|
// 1. 基本的なpack
|
||||||
|
local animal
|
||||||
|
animal = new Animal("Generic", 5)
|
||||||
|
print("Animal: " + animal.speak())
|
||||||
|
|
||||||
|
// 2. デリゲーションでのpack
|
||||||
|
local dog
|
||||||
|
dog = new Dog("Buddy", 3, "Golden Retriever")
|
||||||
|
print("Dog: " + dog.speak())
|
||||||
|
|
||||||
|
// 3. 混在形式
|
||||||
|
local cat
|
||||||
|
cat = new Cat("Whiskers", 2, "Black")
|
||||||
|
print("Cat: " + cat.speak())
|
||||||
|
|
||||||
|
// 4. pack単独使用確認
|
||||||
|
local bird
|
||||||
|
bird = new Bird("Eagle", true)
|
||||||
|
print("Bird: " + bird.describe())
|
||||||
|
|
||||||
|
// 5. 引数なしpack
|
||||||
|
box SimpleBox {
|
||||||
|
init { message }
|
||||||
|
|
||||||
|
pack() { // 引数なしpack
|
||||||
|
me.message = "Packed with love! 🎁"
|
||||||
|
}
|
||||||
|
|
||||||
|
getMessage() {
|
||||||
|
return me.message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
local simple
|
||||||
|
simple = new SimpleBox()
|
||||||
|
print("SimpleBox: " + simple.getMessage())
|
||||||
|
|
||||||
|
print("")
|
||||||
|
print("✅ pack構文テスト完了!")
|
||||||
|
print("🎉 Everything is Box - Now Everything is Packed!")
|
||||||
Reference in New Issue
Block a user