diff --git a/CLAUDE.md b/CLAUDE.md index ab6612f0..214171a5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -122,30 +122,56 @@ while condition { } // 使用不可 loop() { } // 使用不可 ``` -### 🎁 pack構文 - Box哲学の具現化(2025-08-11実装) +### 🌟 birth構文 - 生命をBoxに与える(2025-08-15実装) ```nyash -// 🎁 「箱に詰める」直感的コンストラクタ -box User { - init { name, email } +// 🌟 「Boxに生命を与える」直感的コンストラクタ +box Life { + init { name, energy } - pack(userName, userEmail) { // ← Box哲学を体現! - me.name = userName - me.email = userEmail + birth(lifeName) { // ← Everything is Box哲学を体現! + me.name = lifeName + me.energy = 100 + print("🌟 " + lifeName + " が誕生しました!") } } -// 🔄 デリゲーションでのpack -box AdminUser from User { - init { permissions } +// 🔄 デリゲーションでのbirth +box Human from Life { + init { intelligence } - pack(adminName, adminEmail, perms) { - from User.pack(adminName, adminEmail) // 親のpackを呼び出し - me.permissions = perms + birth(humanName) { + from Life.birth(humanName) // 親のbirthを呼び出し + me.intelligence = 50 } } -// ✅ 優先順位: pack > init > Box名形式 -local user = new User("Alice", "alice@example.com") // packが使われる +// ✅ 優先順位: birth > pack > init > Box名形式 +local alice = new Human("Alice") // birthが使われる +``` + +### 🚨 pack構文 - ビルトインBox継承専用 +```nyash +// ⚠️ pack構文はビルトインBox継承専用!ユーザー定義Boxでは使わない +box EnhancedP2P from P2PBox { + init { features } + + pack(nodeId, transport) { + from P2PBox.pack(nodeId, transport) // ビルトイン初期化 + me.features = new ArrayBox() + } + + override send(intent, data, target) { + me.features.push("send:" + intent) + return from P2PBox.send(intent, data, target) + } +} + +// ❌ 間違い: ユーザー定義Boxでpack使用 +box RegularUser { + pack(name) { // これは間違い!birth()を使う + me.name = name + } +} ``` ### 🎯 正統派Nyashスタイル(2025-08-09実装) diff --git a/docs/CURRENT_TASK.md b/docs/CURRENT_TASK.md index 3ef609d2..d1c8e4f1 100644 --- a/docs/CURRENT_TASK.md +++ b/docs/CURRENT_TASK.md @@ -7,6 +7,70 @@ - **Arc::ptr_eq()検出**: 真のゼロコピー判定実現 ✅ - **新API978行追加**: すべて正常ビルド・実行成功 ✅ +## 🚨 **コンストラクタ構文統一の緊急実装 (2025-08-15)** + +### **🌟 birth()実装完了 → pack透明化設計** ✅ + +**birth()統一構文実装完了**!次は**pack透明化システム**の実装が必要 + +### **🎯 pack透明化設計 - ユーザー完全不可視システム** + +**核心方針**: ユーザーは`pack`を一切書かない・意識しない + +### **📋 ユーザー側の理想的な書き方** +```nyash +# ✅ ユーザーはこう書く(packを一切意識しない) +box EnhancedString from StringBox { + init { prefix } + + birth(content, prefixStr) { + from StringBox(content) # ← シンプルな呼び出し + me.prefix = prefixStr + } + + override toString() { + return me.prefix + from StringBox.toString() + } +} +``` + +### **🔧 実装側の内部動作** +```rust +// from StringBox(content) の解決優先度 +fn resolve_builtin_delegation(builtin: &str, args: Vec<_>) -> String { + if is_builtin_box(builtin) { + // 1. ビルトインBoxの場合、内部的にpackを呼ぶ + builtin_pack_registry.call_pack(builtin, args) + } else { + // 2. ユーザー定義Boxの場合、birth優先 + resolve_user_constructor(builtin, args) // birth > init > Box名 + } +} +``` + +### **🎯 実装すべきこと** + +**1. ビルトインBox自動判定** +- `is_builtin_box()` 関数実装 +- StringBox, P2PBox, MathBox等をビルトイン登録 + +**2. pack透明化システム** +- `from BuiltinBox()` → 内部的に `BuiltinBox.pack()` 呼び出し +- ユーザーは`pack`という単語を見ない・書かない + +**3. デリゲーション解決統一** +- ビルトインBox: 自動pack呼び出し +- ユーザー定義Box: birth > init > Box名 優先順位 + +**4. エラーメッセージ改善** +- ユーザーには「birth()がありません」と表示 +- packエラーは内部ログのみ + +### **🎉 期待される効果** +- **完全透明化**: ユーザーはpackを一切意識しない +- **統一体験**: `from Parent()` で全て解決 +- **設計分離**: ビルトインBox内部実装とユーザーAPI完全分離 + ## 🔄 **次期優先タスク** **GitHub Issue**: https://github.com/moe-charm/nyash/issues/98 **移植計画**: 3つの実用Cアプリケーション同時移植プロジェクト @@ -36,6 +100,61 @@ - **実行性能**: WASM 13.5倍、VM 20.4倍高速化達成 - **Everything is Box哲学**: 全11個のBox型でRwLock統一完了 +## 🔥 **実装優先度** + +### **🚨 Critical (即時実装)** +1. **ビルトインBox判定システム** - is_builtin_box()実装(15分) +2. **pack透明化解決** - from BuiltinBox()自動変換(30分) +3. **統合テスト作成** - 透明化動作確認(10分) + +### **⚡ High (今週中)** +4. **エラーメッセージ改善** - pack隠蔽、birth中心メッセージ +5. **ドキュメント更新** - CLAUDE.md透明化設計反映 +6. **パフォーマンス最適化** - ビルトイン判定高速化 + +### **📝 Medium (来週)** +7. **既存テスト見直し** - pack直接呼び出し削除 +8. **delegation-system.md更新** - 透明化設計反映 + +### **🔮 Future (今後の予定)** +9. **FFI/ABI統合** - ExternBox経由外部API(Phase 11予定) +10. **動的ライブラリ読み込み** - 外部ライブラリBox化(Phase 12予定) +11. **BID自動生成** - YAML→実装自動化(Phase 13予定) + +## 🚀 **Phase 8.8: pack透明化システム実装準備完了** + +### **✅ 完了事項 (2025-08-15)** +1. **birth()実装完了** - コンストラクタ統一構文実装 ✅ +2. **ドキュメント矛盾修正完了** - pack機能正しい定義確立 ✅ +3. **pack透明化イシュー作成完了** - Copilot実装仕様書完成 ✅ + +### **📋 ドキュメント修正完了リスト** +- ✅ `delegation-system.md` - pack→birth統一、pack専用セクション追加 +- ✅ `box-design/README.md` - pack専用セクション追加 +- ✅ `LANGUAGE_GUIDE.md` - birth統一、pack専用明記 +- ✅ `CLAUDE.md` - birth哲学、pack専用システム分離 + +### **🎯 次のアクション (Copilot実装待ち)** +**イシュー**: `phase_8_8_pack_transparency_system.md` + +#### **実装内容** +1. **ビルトインBox判定システム** - `is_builtin_box()` 関数 +2. **pack透明化解決** - `from BuiltinBox()` 自動変換 +3. **エラーメッセージ改善** - pack隠蔽、ユーザーフレンドリー化 + +#### **必須テストケース (5種類)** +- ユーザー定義Box基本動作 +- ビルトインBox継承 +- **透明化システム動作** (最重要) +- 混在テスト +- エラーケーステスト + +#### **完了条件** +- 全テストケース PASS +- 既存機能継続動作 +- パフォーマンス維持 +- ユーザーはpackを一切意識しない + --- -**現在状況**: Phase 9.75完了 → Phase 9.5 HTTPサーバー実用テスト準備中 -**最終更新**: 2025-08-15 \ No newline at end of file +**現在状況**: pack透明化システム実装準備完了✅ → Copilot実装開始待ち🤖 +**最終更新**: 2025-08-15 17:00 \ No newline at end of file diff --git a/docs/design-decisions/constructor-name-decision.md b/docs/design-decisions/constructor-name-decision.md new file mode 100644 index 00000000..08278dbb --- /dev/null +++ b/docs/design-decisions/constructor-name-decision.md @@ -0,0 +1,115 @@ +# 🌟 Nyash コンストラクタ名決定: birth() 採用 + +**決定日**: 2025-08-15 +**決定者**: Nyashプロジェクトチーム +**ステータス**: 正式決定 + +## 🎯 **最終決定** + +**`birth()` を唯一のコンストラクタ名として採用** + +## 📋 **検討経過** + +### 候補と評価 + +1. **constructor()** - 業界標準だが長い、Box哲学との親和性低い +2. **pack()** - Box哲学完璧だが独自性強すぎ、混乱の元 +3. **init()** - initフィールドとの混乱、廃止済み +4. **make()** - Go言語実績あり、短い、実用的 +5. **birth()** - 🌟 **採用決定** 🌟 + +### birth() 選定理由 + +**1. 哲学的完璧性** +- 「Everything is Box」哲学との完璧な親和性 +- 「Boxに魂が宿る」生命感のある言語思想を体現 +- 「生命を誕生させる」直感的イメージ + +**2. 強力なブランディング効果** +- 圧倒的独自性で一度見たら忘れない +- Nyashらしさを言語の核心で表現 +- 学習者がコンストラクタを使うたびに世界観を体感 + +**3. 実用性** +- 短い(5文字)で覚えやすい +- 学習コストは低い(初見で一瞬考えるだけ) +- 明確で曖昧性がない + +## 💡 **Geminiの専門的評価** + +> 「`birth()` を採用することは、単なる名前選び以上の意味を持つ。それは、**Nyashの哲学を言語の根幹に据えるという宣言**である。学習者はコンストラクタを使うたびに、無意識にその世界観に触れることになる。これは非常に強力なブランディングです。」 + +**Gemini最終推奨**: `birth()` 採用 + +## 🌟 **構文例** + +```nyash +// 基本的な使用法 +box Life { + init { name, energy } + + birth(lifeName) { // 生命を誕生させる + me.name = lifeName + me.energy = 100 + print("🌟 " + lifeName + " が誕生しました!") + } +} + +// デリゲーション +box Human from Life { + init { intelligence } + + birth(humanName) { + from Life.birth(humanName) // 親から生命を受け継ぐ + me.intelligence = 50 + } +} + +// 使用例 +local alice = new Human("Alice") // birth()が自動呼び出し +``` + +## 🔧 **実装要件** + +### 1. トークナイザー修正 +```rust +BIRTH, // birth (コンストラクタ) + +"birth" => TokenType::BIRTH, +``` + +### 2. パーサー修正 +- `birth()` 構文パース対応 +- `init/pack/constructor` と同様の処理システム統合 + +### 3. インタープリター修正 +- `birth/引数数` キーでの検索対応 +- デリゲーション時の `from Parent.birth()` サポート + +### 4. 優先順位システム +```rust +// 検索順序 +1. "birth/引数数" // 最優先 +2. "init/引数数" // 互換性 +3. "pack/引数数" // 互換性 +4. "Box名/引数数" // 互換性 +``` + +## 🎉 **期待される効果** + +- **哲学的一貫性**: Everything is Box思想の完璧な体現 +- **ブランド確立**: Nyash独自の世界観を言語レベルで表現 +- **学習体験向上**: コンストラクタ使用のたびに世界観を体感 +- **混乱解消**: initフィールドとの完全な区別 +- **統一性**: 全てのBoxで同一のbirth()構文 + +## 📝 **移行計画** + +1. **Phase 1**: birth()実装(トークナイザー・パーサー・インタープリター) +2. **Phase 2**: テスト作成・動作確認 +3. **Phase 3**: 既存コード段階的移行(互換性維持) +4. **Phase 4**: ドキュメント更新(CLAUDE.md等) + +--- + +**🌟 Nyashは `birth()` でBoxに生命を与える言語として、新たな進化を遂げる 🌟** \ No newline at end of file diff --git a/docs/予定/native-plan/issues/phase_8_8_pack_transparency_system.md b/docs/予定/native-plan/issues/phase_8_8_pack_transparency_system.md new file mode 100644 index 00000000..521947e8 --- /dev/null +++ b/docs/予定/native-plan/issues/phase_8_8_pack_transparency_system.md @@ -0,0 +1,226 @@ +# Phase 8.8: pack透明化システム実装 + +**Priority**: Critical +**Estimated Effort**: 2-3日 +**Assignee**: Copilot (Claude監修) +**Status**: Ready for Implementation + +## 🎯 概要 + +**pack構文のユーザー完全透明化システム**を実装する。ユーザーは`pack`を一切意識せず、`from BuiltinBox()`で自動的に内部のpack機能が呼ばれるシステム。 + +### 🚨 背景問題 +- **Copilotがpack機能を誤解**:一般コンストラクタとして実装 +- **ドキュメント矛盾**:packの定義が混乱していた ✅ 修正済み +- **ユーザー体験悪化**:packを意識する必要があった + +## 📋 実装要件 + +### 1. **ビルトインBox判定システム** +```rust +// 実装必要な関数 +fn is_builtin_box(box_name: &str) -> bool { + // StringBox, P2PBox, MathBox, ConsoleBox等を判定 +} + +// 登録リスト (最低限) +const BUILTIN_BOXES: &[&str] = &[ + "StringBox", "IntegerBox", "BoolBox", "NullBox", + "P2PBox", "MathBox", "ConsoleBox", "DebugBox", + "TimeBox", "RandomBox", "SoundBox", "MapBox" +]; +``` + +### 2. **pack透明化解決システム** +```rust +// from BuiltinBox() の自動解決 +fn resolve_builtin_delegation(builtin: &str, args: Vec<_>) -> Result<(), String> { + if is_builtin_box(builtin) { + // 内部的に BuiltinBox.pack() を呼ぶ + call_builtin_pack(builtin, args) + } else { + // ユーザー定義Box: birth > init > Box名 の順 + resolve_user_constructor(builtin, args) + } +} +``` + +### 3. **エラーメッセージ改善** +- ユーザーには「birth()がありません」表示 +- pack関連エラーは内部ログのみ +- 混乱を避ける明確なメッセージ + +## 🧪 テスト要件 + +### **必須テストケース** (全て PASS 必須) + +#### **A. ユーザー定義Box基本動作** +```nyash +# test_user_box_basic.nyash +box Life { + init { name, energy } + + birth(lifeName) { + me.name = lifeName + me.energy = 100 + } +} + +local alice = new Life("Alice") +assert(alice.name == "Alice") +assert(alice.energy == 100) +``` + +#### **B. ビルトインBox継承** +```nyash +# test_builtin_inheritance.nyash +box EnhancedP2P from P2PBox { + init { features } + + pack(nodeId, transport) { + from P2PBox.pack(nodeId, transport) # 明示的pack + me.features = new ArrayBox() + } +} + +local node = new EnhancedP2P("node1", "tcp") +assert(node.features != null) +``` + +#### **C. 透明化システム動作** +```nyash +# test_transparency.nyash +box SimpleString from StringBox { + init { prefix } + + birth(content, prefixStr) { + from StringBox(content) # ← 透明化!内部的にpack呼び出し + me.prefix = prefixStr + } + + override toString() { + return me.prefix + from StringBox.toString() + } +} + +local str = new SimpleString("Hello", ">>> ") +assert(str.toString() == ">>> Hello") +``` + +#### **D. 混在テスト** +```nyash +# test_mixed_inheritance.nyash +box AdvancedCalc from MathBox { + init { history } + + birth() { + from MathBox() # 透明化 + me.history = new ArrayBox() + } +} + +box Calculator { + init { result } + + birth() { + me.result = 0 + } +} + +local calc1 = new AdvancedCalc() # ビルトイン継承 +local calc2 = new Calculator() # ユーザー定義 +assert(calc1.history != null) +assert(calc2.result == 0) +``` + +#### **E. エラーケーステスト** +```nyash +# test_error_cases.nyash + +# 1. 存在しないmethodを呼び出し +box BadBox from StringBox { + birth(content) { + from StringBox.nonexistent() # エラー:適切なメッセージ + } +} + +# 2. 引数不一致 +box ArgMismatch from P2PBox { + birth() { + from P2PBox("too", "many", "args") # エラー:引数不一致 + } +} +``` + +### **パフォーマンステスト** +```nyash +# test_performance.nyash +local startTime = getCurrentTime() + +loop(i < 1000) { + local str = new SimpleString("test" + i, "prefix") + local result = str.toString() +} + +local endTime = getCurrentTime() +local elapsed = endTime - startTime +assert(elapsed < 1000) # 1秒以内で完了 +``` + +## ✅ チェックリスト + +### **実装前チェック** +- [ ] 既存のbirth()実装が正常動作している +- [ ] ドキュメント修正が完了している +- [ ] テストファイルが準備されている + +### **実装中チェック** +- [ ] `is_builtin_box()` 関数実装完了 +- [ ] pack透明化解決システム実装完了 +- [ ] エラーメッセージ改善完了 +- [ ] 全テストケース PASS + +### **実装後チェック** +- [ ] 既存テストファイルが継続動作 +- [ ] パフォーマンス劣化なし(<5%) +- [ ] birth()優先順位システム正常動作 +- [ ] エラーメッセージがユーザーフレンドリー + +### **統合テスト** +- [ ] `test_birth_simple.nyash` 継続動作 ✅ +- [ ] Chip-8エミュレーター修正版動作 +- [ ] 全ビルトインBox継承パターン動作 +- [ ] デリゲーションチェーン正常動作 + +## 📂 実装場所 + +### **主要ファイル** +- `src/interpreter/expressions.rs` - from解決ロジック +- `src/interpreter/objects.rs` - コンストラクタ優先順位 +- `src/interpreter/core.rs` - ビルトインBox判定 +- `src/box_trait.rs` - BUILTIN_BOXES定数 + +### **テストファイル** +- `test_pack_transparency.nyash` - 統合テスト +- `test_builtin_inheritance.nyash` - ビルトイン継承 +- `test_user_box_birth.nyash` - ユーザー定義Box +- `test_error_cases.nyash` - エラーケース + +## 🎉 完了条件 + +1. **全テストケース PASS** ✅ +2. **既存機能の継続動作** ✅ +3. **パフォーマンス維持** ✅ +4. **エラーメッセージ改善** ✅ +5. **ドキュメント整合性** ✅ + +## 🚨 注意事項 + +- **既存のbirth()実装は変更しない** +- **pack機能自体は残す**(ビルトイン継承で必要) +- **ユーザーAPIからpackを完全隠蔽** +- **パフォーマンス劣化は避ける** + +--- + +**実装時は必ずテストファースト開発で進める!** 🧪 \ No newline at end of file diff --git a/docs/説明書/LANGUAGE_GUIDE.md b/docs/説明書/LANGUAGE_GUIDE.md index 437c08f5..e930c5df 100644 --- a/docs/説明書/LANGUAGE_GUIDE.md +++ b/docs/説明書/LANGUAGE_GUIDE.md @@ -65,9 +65,10 @@ not condition, a and b, a or b box User { init { name, email } // フィールド宣言 - pack(userName, userEmail) { // 🎁 Box哲学の具現化! + birth(userName, userEmail) { // 🌟 生命をBoxに与える! me.name = userName - me.email = userEmail + me.email = userEmail + print("🌟 " + userName + " が誕生しました!") } greet() { @@ -81,8 +82,8 @@ box User { box AdminUser from User { // 🔥 from構文でデリゲーション init { permissions } - pack(adminName, adminEmail, perms) { - from User.pack(adminName, adminEmail) // 親のpack呼び出し + birth(adminName, adminEmail, perms) { + from User.birth(adminName, adminEmail) // 親のbirth呼び出し me.permissions = perms } @@ -93,6 +94,25 @@ box AdminUser from User { // 🔥 from構文でデリゲーション } ``` +#### ビルトインBox継承(pack専用) +```nyash +// ⚠️ pack構文はビルトインBox継承専用 +box EnhancedP2P from P2PBox { + init { features } + + pack(nodeId, transport) { + from P2PBox.pack(nodeId, transport) // ビルトイン初期化 + me.features = new ArrayBox() + print("🌐 Enhanced P2P Node created: " + nodeId) + } + + override send(intent, data, target) { + me.features.push("send:" + intent) + return from P2PBox.send(intent, data, target) + } +} +``` + #### Static Box Main パターン ```nyash static box Main { diff --git a/docs/説明書/reference/box-design/README.md b/docs/説明書/reference/box-design/README.md index 65d69063..d758fb43 100644 --- a/docs/説明書/reference/box-design/README.md +++ b/docs/説明書/reference/box-design/README.md @@ -63,9 +63,10 @@ local num = new IntegerBox(42) box User { init { name, email } - pack(userName, userEmail) { + birth(userName, userEmail) { me.name = userName me.email = userEmail + print("🌟 User " + userName + " が誕生しました!") } } ``` @@ -75,8 +76,8 @@ box User { box AdminUser from User { init { permissions } - pack(adminName, adminEmail, perms) { - from User.pack(adminName, adminEmail) + birth(adminName, adminEmail, perms) { + from User.birth(adminName, adminEmail) me.permissions = perms } @@ -86,6 +87,24 @@ box AdminUser from User { } ``` +### ビルトインBox継承(pack専用) +```nyash +// ビルトインBoxを継承する場合のみpackを使用 +box EnhancedP2P from P2PBox { + init { features } + + pack(nodeId, transport) { + from P2PBox.pack(nodeId, transport) // ビルトイン初期化 + me.features = new ArrayBox() + } + + override send(intent, data, target) { + me.features.push("send:" + intent) + return from P2PBox.send(intent, data, target) + } +} +``` + ### 外部ライブラリ統合(FFI/ABI) ```nyash // ExternBoxで外部APIを統一的に利用 diff --git a/docs/説明書/reference/box-design/delegation-system.md b/docs/説明書/reference/box-design/delegation-system.md index 1216bb46..5e3e8990 100644 --- a/docs/説明書/reference/box-design/delegation-system.md +++ b/docs/説明書/reference/box-design/delegation-system.md @@ -134,21 +134,22 @@ box MultiChild from ParentA, ParentB { } ``` -## 🎁 pack構文 - Box哲学の具現化 +## 🌟 birth構文 - Box哲学の具現化 -### packの優先順位 +### コンストラクタの優先順位 ```nyash box User { init { name, email } - // 優先度1: pack(推奨) - pack(userName, userEmail) { + // 優先度1: birth(推奨) + birth(userName, userEmail) { me.name = userName me.email = userEmail + print("🌟 " + userName + " が誕生しました!") } - // 優先度2: init(packがない場合) + // 優先度2: init(birthがない場合) init(name, email) { me.name = name me.email = email @@ -161,28 +162,29 @@ box User { } } -// packが優先的に使用される +// birthが優先的に使用される local user = new User("Alice", "alice@example.com") ``` -### packとデリゲーション +### birth構文とデリゲーション ```nyash box Product { init { name, price } - pack(productName, productPrice) { + birth(productName, productPrice) { me.name = productName me.price = productPrice + print("📦 Product created: " + productName) } } box DiscountedProduct from Product { init { discount } - pack(name, originalPrice, discountPercent) { + birth(name, originalPrice, discountPercent) { local discountedPrice = originalPrice * (1 - discountPercent / 100) - from Product.pack(name, discountedPrice) + from Product.birth(name, discountedPrice) # 親のbirthを呼ぶ me.discount = discountPercent } @@ -192,6 +194,38 @@ box DiscountedProduct from Product { } ``` +### 🚨 pack構文 - ビルトインBox継承専用 + +**重要**: `pack`構文は**ビルトインBox継承専用**です。ユーザー定義Boxでは使用しません。 + +```nyash +# ✅ 正しい使い方(ビルトインBox継承のみ) +box EnhancedP2P from P2PBox { + init { extraFeatures } + + pack(nodeId, transport) { + from P2PBox.pack(nodeId, transport) # ビルトインBoxの初期化 + me.extraFeatures = new ArrayBox() + } +} + +box CustomMath from MathBox { + init { history } + + pack() { + from MathBox.pack() # ビルトインBoxの初期化 + me.history = new ArrayBox() + } +} + +# ❌ 間違い(ユーザー定義Boxでpack使用) +box RegularUser { + pack(name) { # これは間違い!birth()を使う + me.name = name + } +} +``` + ## 🔍 from構文の詳細 ### メソッド内でのfrom使用 diff --git a/src/interpreter/core.rs b/src/interpreter/core.rs index 198f807a..56d3469c 100644 --- a/src/interpreter/core.rs +++ b/src/interpreter/core.rs @@ -362,7 +362,38 @@ impl NyashInterpreter { return Ok(field_value); } - // 4. エラー:見つからない + // 4. statics名前空間内のstatic boxをチェック + eprintln!("🔍 DEBUG: Checking statics namespace for '{}'...", name); + if let Some(statics_namespace) = global_box.get_field("statics") { + eprintln!("🔍 DEBUG: statics namespace type: {}", statics_namespace.type_name()); + + // MapBoxとして試す + if let Some(map_box) = statics_namespace.as_any().downcast_ref::() { + eprintln!("🔍 DEBUG: statics is a MapBox, looking for '{}'", name); + let key_box: Box = Box::new(StringBox::new(name)); + let static_box_result = map_box.get(key_box); + + // NullBoxでないかチェック(MapBoxは見つからない場合NullBoxを返す) + if static_box_result.type_name() != "NullBox" { + eprintln!("🔍 DEBUG: Found '{}' in statics namespace", name); + return Ok(Arc::from(static_box_result)); + } else { + eprintln!("🔍 DEBUG: '{}' not found in statics MapBox", name); + } + } else if let Some(instance) = statics_namespace.as_any().downcast_ref::() { + eprintln!("🔍 DEBUG: statics is an InstanceBox, looking for '{}'", name); + if let Some(static_box) = instance.get_field(name) { + eprintln!("🔍 DEBUG: Found '{}' in statics namespace", name); + return Ok(static_box); + } else { + eprintln!("🔍 DEBUG: '{}' not found in statics InstanceBox", name); + } + } else { + eprintln!("🔍 DEBUG: statics namespace is neither MapBox nor InstanceBox"); + } + } + + // 5. エラー:見つからない eprintln!("🔍 DEBUG: '{}' not found anywhere!", name); Err(RuntimeError::UndefinedVariable { name: name.to_string(), diff --git a/src/interpreter/expressions.rs b/src/interpreter/expressions.rs index 29b7639f..e800a97b 100644 --- a/src/interpreter/expressions.rs +++ b/src/interpreter/expressions.rs @@ -1104,8 +1104,8 @@ impl NyashInterpreter { drop(box_declarations); // ロック早期解放 - // 4. constructorまたはinitまたはpackの場合の特別処理 - if method == "constructor" || method == "init" || method == "pack" || method == parent { + // 4. constructorまたはinitまたはpackまたはbirthの場合の特別処理 + if method == "constructor" || method == "init" || method == "pack" || method == "birth" || method == parent { return self.execute_from_parent_constructor(parent, &parent_box_decl, current_instance_val.clone_box(), arguments); } @@ -1177,12 +1177,14 @@ impl NyashInterpreter { -> Result, RuntimeError> { // 1. 親クラスのコンストラクタを取得(引数の数でキーを作成) - // "pack/引数数"、"init/引数数"、"Box名/引数数" の順で試す + // "birth/引数数"、"pack/引数数"、"init/引数数"、"Box名/引数数" の順で試す + let birth_key = format!("birth/{}", arguments.len()); let pack_key = format!("pack/{}", arguments.len()); let init_key = format!("init/{}", arguments.len()); let box_name_key = format!("{}/{}", parent, arguments.len()); - let parent_constructor = parent_box_decl.constructors.get(&pack_key) + let parent_constructor = parent_box_decl.constructors.get(&birth_key) + .or_else(|| 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 { diff --git a/src/interpreter/objects.rs b/src/interpreter/objects.rs index 4a82d7b9..1fb85e33 100644 --- a/src/interpreter/objects.rs +++ b/src/interpreter/objects.rs @@ -713,12 +713,14 @@ impl NyashInterpreter { let instance_arc = Arc::from(instance_box); // コンストラクタを呼び出す - // "pack/引数数"、"init/引数数"、"Box名/引数数" の順で試す + // "birth/引数数"、"pack/引数数"、"init/引数数"、"Box名/引数数" の順で試す + let birth_key = format!("birth/{}", arguments.len()); 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) + if let Some(constructor) = final_box_decl.constructors.get(&birth_key) + .or_else(|| 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)) { // コンストラクタを実行 diff --git a/src/parser/mod.rs b/src/parser/mod.rs index aae2df5d..158da1f7 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -451,6 +451,66 @@ impl NyashParser { span: Span::unknown(), }; + // パラメータの数でコンストラクタを区別 + let constructor_key = format!("{}/{}", field_or_method, params.len()); + constructors.insert(constructor_key, constructor); + } + } + + // birthトークンをメソッド名として特別処理 + else if self.match_token(&TokenType::BIRTH) && self.peek_token() == &TokenType::LPAREN { + let field_or_method = "birth".to_string(); + self.advance(); // consume 'birth' + + // コンストラクタとして処理 + if self.match_token(&TokenType::LPAREN) { + // birthは常にコンストラクタ + if is_override { + return Err(ParseError::UnexpectedToken { + expected: "method definition, not constructor after override keyword".to_string(), + found: TokenType::BIRTH, + 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); @@ -461,8 +521,8 @@ impl NyashParser { // メソッド定義またはコンストラクタか? if self.match_token(&TokenType::LPAREN) { - // Box名と同じまたは"init"または"pack"の場合はコンストラクタ - if field_or_method == name || field_or_method == "init" || field_or_method == "pack" { + // Box名と同じまたは"init"または"pack"または"birth"の場合はコンストラクタ + if field_or_method == name || field_or_method == "init" || field_or_method == "pack" || field_or_method == "birth" { // コンストラクタはoverrideできない if is_override { return Err(ParseError::UnexpectedToken { diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 06b96100..37e5a353 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -33,7 +33,8 @@ pub enum TokenType { THIS, ME, INIT, // init (初期化ブロック) - PACK, // pack (コンストラクタ) + PACK, // pack (コンストラクタ - 互換性) + BIRTH, // birth (コンストラクタ) NOWAIT, // nowait AWAIT, // await INTERFACE, // interface @@ -399,6 +400,7 @@ impl NyashTokenizer { "me" => TokenType::ME, "init" => TokenType::INIT, "pack" => TokenType::PACK, + "birth" => TokenType::BIRTH, "nowait" => TokenType::NOWAIT, "await" => TokenType::AWAIT, "interface" => TokenType::INTERFACE, diff --git a/test_birth_simple.nyash b/test_birth_simple.nyash new file mode 100644 index 00000000..fd55a371 --- /dev/null +++ b/test_birth_simple.nyash @@ -0,0 +1,27 @@ +# 🌟 birth() テスト - 生命をBoxに与える! + +box Life { + init { name, energy } + + birth(lifeName) { # 生命を誕生させる + me.name = lifeName + me.energy = 100 + print("🌟 " + lifeName + " が誕生しました!") + } + + introduce() { + print("私の名前は " + me.name + " です。エネルギーは " + me.energy + " です。") + return me.name + } +} + +print("=== birth() 構文テスト開始 ===") + +# birth()コンストラクタでLife作成 +local alice = new Life("Alice") +alice.introduce() + +local bob = new Life("Bob") +bob.introduce() + +print("=== birth() テスト完了 ===") \ No newline at end of file