freeze: macro platform complete; default ON with profiles; env consolidation; docs + smokes\n\n- Profiles: --profile {lite|dev|ci|strict} (dev-like default for macros)\n- Macro paths: prefer NYASH_MACRO_PATHS (legacy envs deprecated with warnings)\n- Selfhost pre-expand: auto mode, PyVM-only, add smokes (array/map)\n- Docs: user-macros updated; new macro-profiles guide; AGENTS freeze note; CURRENT_TASK freeze\n- Compat: non-breaking; legacy envs print deprecation notices\n
This commit is contained in:
@ -1,32 +1,75 @@
|
||||
# Phase 10.7 - True Python Native via Plugin Boxes
|
||||
# Phase 10.7 - Python→Nyash革命(Phase 16マクロ統合版)
|
||||
|
||||
## 🎯 概要
|
||||
## 🚀 **Phase 16マクロ革命による劇的変化**
|
||||
|
||||
PythonコードをNyashで**本当にネイティブ実行**する。CPythonへの依存なしに、Pythonコードが完全にNyash MIR/JIT経由で機械語として実行される。
|
||||
**Before Phase 16**: 手動transpiler(2-3ヶ月)
|
||||
**After Phase 16**: マクロボックス自動変換(1-2週間)⚡
|
||||
|
||||
### 現状 vs 理想
|
||||
|
||||
**現状(Phase 10.6)**: PyRuntimeBox → libpython呼び出し
|
||||
**理想(Phase 10.7)**: Python → Nyashスクリプト → MIR → ネイティブ
|
||||
|
||||
## 🏗️ アーキテクチャ:トランスパイル方式
|
||||
### 🎯 新戦略:MacroBox-Driven Python Transpilation
|
||||
|
||||
```
|
||||
Python AST → CorePy IR → Nyash AST → Nyashスクリプト
|
||||
Python AST → MacroBox Pattern Match → Nyash AST (自動生成)
|
||||
```
|
||||
|
||||
### なぜトランスパイル?
|
||||
**革命的変化**:
|
||||
- ❌ **旧**: 手動コード変換地獄(2000行実装)
|
||||
- ✅ **新**: マクロパターンで自動変換(200行実装)
|
||||
|
||||
1. **透明性**: 生成コードが見える・デバッグできる・手を加えられる
|
||||
2. **既存資産活用**: Nyashコンパイラの最適化を自動享受
|
||||
3. **教育的価値**: PythonとNyashの対応が学習価値を持つ
|
||||
4. **段階的改善**: 生成コードの品質を徐々に向上
|
||||
## 🧠 **核心アイデア:Everything is Box + Macro = 言語統合**
|
||||
|
||||
### プラグインBox群
|
||||
### **マクロボックス群(新設計)**
|
||||
|
||||
- **PythonParserBox**: Python → AST変換
|
||||
- **PythonCompilerBox**: AST → Nyashスクリプト生成
|
||||
- **py_runtime.ny**: Pythonセマンティクス保持ライブラリ
|
||||
```rust
|
||||
// src/macro/python_transpiler.rs(新規)
|
||||
@macro_box("python_dataclass")
|
||||
@macro_box("python_property")
|
||||
@macro_box("python_listcomp")
|
||||
@macro_box("python_contextmgr")
|
||||
@macro_box("python_decorator")
|
||||
```
|
||||
|
||||
### **実装例:Python @dataclass**
|
||||
|
||||
#### **Before(手動地獄)**:
|
||||
```python
|
||||
@dataclass
|
||||
class User:
|
||||
name: str
|
||||
age: int
|
||||
```
|
||||
→ 手動変換(数時間) → Nyashコード
|
||||
|
||||
#### **After(マクロ天国)**:
|
||||
```nyash
|
||||
// @python_dataclass マクロが自動処理!
|
||||
@python_dataclass
|
||||
box UserBox {
|
||||
name: StringBox
|
||||
age: IntegerBox
|
||||
}
|
||||
// ↓ 自動展開 ↓
|
||||
@derive(Equals, ToString, Clone)
|
||||
box UserBox {
|
||||
name: StringBox
|
||||
age: IntegerBox
|
||||
}
|
||||
```
|
||||
|
||||
### **実装例:Python List Comprehension**
|
||||
|
||||
#### **Python**:
|
||||
```python
|
||||
result = [x * 2 for x in numbers if x > 0]
|
||||
```
|
||||
|
||||
#### **マクロ展開Nyash**:
|
||||
```nyash
|
||||
// @python_listcomp マクロが自動生成
|
||||
local result = numbers
|
||||
.filter(|x| x > 0)
|
||||
.map(|x| x * 2)
|
||||
.toArray()
|
||||
```
|
||||
|
||||
## ⚠️ All or Nothing設計(フォールバックなし)
|
||||
|
||||
@ -48,27 +91,35 @@ if result.isOk() {
|
||||
|
||||
理由:開発時と本番時で挙動が変わるのは最悪の設計
|
||||
|
||||
## 📋 実装フェーズ
|
||||
## 📋 **新実装フェーズ(Phase 16統合版)**
|
||||
|
||||
### Phase 10.7a - Parser Plugin(1週間)
|
||||
- PythonParserBoxの実装
|
||||
- Python AST → ASTBox変換
|
||||
- テレメトリー基盤
|
||||
### **Phase 10.7-A: MacroBox基盤(3日)**
|
||||
```rust
|
||||
// src/macro/python_transpiler.rs 作成
|
||||
pub fn register_python_macros() {
|
||||
register_macro_box("python_dataclass", PythonDataclassTranspiler);
|
||||
register_macro_box("python_property", PythonPropertyTranspiler);
|
||||
register_macro_box("python_listcomp", PythonListCompTranspiler);
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 10.7b - Compiler Core(2週間)
|
||||
**Phase 1機能(必須)**
|
||||
- 関数定義、条件分岐、ループ
|
||||
- 演算子、関数呼び出し
|
||||
- Python固有:LEGB、デフォルト引数、for/else
|
||||
### **Phase 10.7-B: コア変換パターン(1週間)**
|
||||
**必須マクロ(Phase 1)**:
|
||||
- `@python_dataclass` → `@derive(Equals,ToString)`
|
||||
- `@python_property` → `computed property`
|
||||
- `@python_listcomp` → `.filter().map()`
|
||||
- `@python_function` → Nyash関数+LEGB
|
||||
|
||||
### Phase 10.7c - Validation & Testing(1週間)
|
||||
- コンパイル可能性の事前検証
|
||||
- Differential testing(CPythonと比較)
|
||||
- 明確なエラーメッセージ
|
||||
### **Phase 10.7-C: テスト・検証(3日)**
|
||||
- マクロ展開結果の差分テスト
|
||||
- `nyash --expand` でPython→Nyash変換可視化
|
||||
- エラー時の明確な診断メッセージ
|
||||
|
||||
### Phase 10.7d - Coverage拡大(3-4週間)
|
||||
**Phase 2**: 例外処理、with文、comprehensions
|
||||
**Phase 3**: async/await、デコレータ、ジェネレータ
|
||||
### **Phase 10.7-D: 高度パターン(1週間)**
|
||||
**拡張マクロ(Phase 2)**:
|
||||
- `@python_contextmgr` → try/finally自動展開
|
||||
- `@python_decorator` → マクロ適用チェーン
|
||||
- `@python_async` → async/await変換
|
||||
|
||||
## 🧪 py_runtime設計
|
||||
|
||||
@ -93,56 +144,143 @@ box PyRuntime {
|
||||
}
|
||||
```
|
||||
|
||||
## 📊 成功指標
|
||||
## 📊 **新成功指標(マクロ革命版)**
|
||||
|
||||
### Phase 1完了時
|
||||
### **Phase 1完了時(2週間後)**
|
||||
```
|
||||
Compilable files: 15/100 (15%)
|
||||
Performance (numeric): 10x faster than CPython
|
||||
Correctness: 100% (differential testing)
|
||||
実装コスト: 2000行 → 200行 (90%削減)
|
||||
開発時間: 2-3ヶ月 → 1-2週間 (85%短縮)
|
||||
マクロパターン: 5個実装完了
|
||||
Python→Nyash変換率: 80%+ (基本構文)
|
||||
```
|
||||
|
||||
### 最終目標(Phase 3)
|
||||
### **最終目標(1ヶ月後)**
|
||||
```
|
||||
Coverage: 95%+ of common patterns
|
||||
Performance: 5-20x faster
|
||||
Distribution: Single binary, no CPython
|
||||
マクロパターン: 15個+ (全主要Python構文)
|
||||
変換精度: 95%+ (property/dataclass/listcomp)
|
||||
パフォーマンス: 10-50x faster (LLVM最適化)
|
||||
統合性: Property System完全対応
|
||||
```
|
||||
|
||||
## 🚀 クイックスタート
|
||||
## 🚀 **クイックスタート(マクロ版)**
|
||||
|
||||
```bash
|
||||
# プラグイン作成
|
||||
cd plugins/
|
||||
cargo new nyash-python-parser-plugin --lib
|
||||
# Phase 16マクロ基盤活用
|
||||
cd src/macro/
|
||||
touch python_transpiler.rs
|
||||
|
||||
# 最小実装
|
||||
# 最小マクロボックス実装
|
||||
[dependencies]
|
||||
pyo3 = { version = "0.22", features = ["auto-initialize"] }
|
||||
nyash-plugin-sdk = { path = "../../crates/plugin-sdk" }
|
||||
nyash-rust = { path = "../../" }
|
||||
serde_json = "1.0"
|
||||
|
||||
# テスト実行
|
||||
cargo build --release
|
||||
../../target/release/nyash test_parser.nyash
|
||||
# テスト実行(マクロ展開確認)
|
||||
NYASH_MACRO_ENABLE=1 ./target/release/nyash --expand python_test.ny
|
||||
```
|
||||
|
||||
## 💡 創造的可能性
|
||||
## 🎯 **Property System統合戦略**
|
||||
|
||||
### ハイブリッドプログラミング
|
||||
### **Python @property → Nyash computed**
|
||||
```python
|
||||
@nyash.vectorize # PythonデコレータがNyashのSIMD生成!
|
||||
def matrix_multiply(a, b):
|
||||
return a @ b
|
||||
class Circle:
|
||||
@property
|
||||
def area(self):
|
||||
return 3.14 * self.radius ** 2
|
||||
```
|
||||
|
||||
### 言語の共進化
|
||||
- Nyashが「Pythonで最も使われるイディオム」から学習
|
||||
- Pythonに「Nyash-aware」コーディングスタイル誕生
|
||||
**マクロ自動変換**:
|
||||
```nyash
|
||||
@python_property // マクロが自動処理
|
||||
box CircleBox {
|
||||
radius: FloatBox
|
||||
|
||||
// computed property自動生成
|
||||
area: FloatBox { 3.14 * me.radius * me.radius }
|
||||
}
|
||||
```
|
||||
|
||||
### 教育的インパクト
|
||||
左にPython、右にリアルタイムNyash変換のPlayground
|
||||
### **Python @cached_property → Nyash once**
|
||||
```python
|
||||
@cached_property
|
||||
def expensive_calculation(self):
|
||||
return heavy_computation()
|
||||
```
|
||||
|
||||
## 📚 参考資料
|
||||
**マクロ自動変換**:
|
||||
```nyash
|
||||
// once property自動生成
|
||||
once expensive_calculation: ResultBox {
|
||||
heavyComputation()
|
||||
}
|
||||
```
|
||||
|
||||
## 💡 **創造的可能性(マクロ革命版)**
|
||||
|
||||
### **🎪 ハイブリッドプログラミング**
|
||||
```python
|
||||
@nyash.vectorize # PythonデコレータがNyashマクロ展開!
|
||||
@nyash.config_schema # 環境変数自動読み込み
|
||||
@nyash.api_client("https://api.example.com/swagger.json")
|
||||
class DataProcessor:
|
||||
def process(self, data):
|
||||
return self.api.process_batch(data)
|
||||
```
|
||||
|
||||
**マクロ展開後**:
|
||||
```nyash
|
||||
@vectorize @config_schema @api_client("...")
|
||||
box DataProcessorBox {
|
||||
// 全てマクロで自動生成!
|
||||
api_client: HttpBox { /* 自動生成 */ }
|
||||
config: ConfigBox { /* 環境変数から自動読み込み */ }
|
||||
|
||||
method process(data: ArrayBox) -> ResultBox {
|
||||
me.api.processBatch(data) // SIMD最適化済み
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **🌍 言語統合プラットフォーム**
|
||||
**Phase 16マクロシステムにより実現**:
|
||||
- 🐍 **Python** → 🦀 **Nyash**: 自動変換
|
||||
- ☕ **Java** → 🦀 **Nyash**: `@java_class`マクロで
|
||||
- 🟦 **TypeScript** → 🦀 **Nyash**: `@ts_interface`マクロで
|
||||
- 🔷 **C#** → 🦀 **Nyash**: `@csharp_property`マクロで
|
||||
|
||||
### **🎓 教育革命**
|
||||
**リアルタイム変換Playground**:
|
||||
```
|
||||
┌─ Python Input ─────┐ ┌─ Nyash Output ────┐
|
||||
│ @dataclass │ → │ @derive(...) │
|
||||
│ class User: │ │ box UserBox { │
|
||||
│ name: str │ │ name: StringBox │
|
||||
│ age: int │ │ age: IntegerBox │
|
||||
└────────────────────┘ └────────────────────┘
|
||||
```
|
||||
|
||||
**学習効果**:
|
||||
- プログラミング学習時間: **10分の1**
|
||||
- 言語間移植理解: **瞬時**
|
||||
- 最適化理解: **可視化**
|
||||
|
||||
## 📚 **参考資料(更新版)**
|
||||
|
||||
### **Phase 16統合ドキュメント**
|
||||
- **[Phase 16 Macro Revolution](../phase-16-macro-revolution/README.md)** - マクロシステム全体
|
||||
- **[docs/guides/macro-system.md](../../../../guides/macro-system.md)** - マクロ使用方法
|
||||
- **[Macro Examples](../phase-16-macro-revolution/macro-examples.md)** - 実装例集
|
||||
|
||||
### **従来資料**
|
||||
- **archive/gemini-analysis-transpile-beauty.md** - 創造性分析
|
||||
- **archive/codex-analysis-technical-implementation.md** - 技術分析
|
||||
- **archive/codex-analysis-technical-implementation.md** - 技術分析
|
||||
|
||||
---
|
||||
|
||||
## 🏆 **結論:Phase 10.7の革命的変化**
|
||||
|
||||
**Before Phase 16**: Python実装 = 地獄の手動transpiler
|
||||
**After Phase 16**: Python実装 = 楽しいマクロパターン作成
|
||||
|
||||
**Phase 16マクロシステムにより、Phase 10.7は「Python実装」から「言語統合革命」へと進化した!**
|
||||
|
||||
**実装コスト90%削減、開発時間85%短縮で、10倍の表現力を実現する新時代の到来!** 🚀✨
|
||||
@ -131,6 +131,44 @@ Imports/Namespace plan(15.3‑late)
|
||||
|
||||
---
|
||||
|
||||
## ♻ 再計画(Macro駆動リファクタ)
|
||||
|
||||
強化されたマクロ基盤(AST JSON v0 / PyVMサンドボックス / strict / timeout / golden)を前提に、Phase‑15 のセルフホスティング工程を **「前段AST正規化 → 正式MIR生成」** の二段型にリフレームする。
|
||||
|
||||
### ポイント(運用)
|
||||
- すべてのフロント側変換(構文糖衣・derive相当・軽微なリライト・静的検証)は **MacroBoxSpec**(Nyash/PyVM)で実行(1パス固定点)。
|
||||
- Rust側は **最小のコア**(パース/AST JSON生成、MIRビルド、バックエンド)に収束。
|
||||
- 決定性担保: strict=1(既定)、capabilitiesは全OFF(io/net/env=false)の純粋展開。
|
||||
- 観測: `--dump-expanded-ast-json` と golden 比較で安定性を担保。
|
||||
|
||||
### 実行順序(改定)
|
||||
1) Parse → AST
|
||||
2) Macro expand(1パス固定点: Built‑in(Rust)→User (Nyash/PyVM))
|
||||
3) Using/解決 → MIR → Backend(VM/LLVM/AOT)
|
||||
|
||||
### 直近タスクリスト(Phase‑15用)
|
||||
1. Macro 前段の正式導入(完了/PoC→実運用)
|
||||
- `NYASH_MACRO_BOX_NY=1` → PyVMランナー経由(既定推奨)
|
||||
- strict=1/timeout=2000ms(既定)
|
||||
- `--dump-expanded-ast-json` を golden として活用
|
||||
2. Self‑host フロントの簡素化
|
||||
- Nyash 製パーサは **最小構文**のみサポート(Stage‑2サブセット)
|
||||
- 糖衣や軽いリライトは **MacroBox** に寄せる
|
||||
3. Golden セットの拡充
|
||||
- `apps/tests/*` → `tools/test/golden/*` で展開後JSONの一致
|
||||
- timeout/strict/失敗cap の負例テストを追加
|
||||
4. nyash.toml 設計の雛形(capabilities)
|
||||
- `[macros] paths=[…]` + `[macro_caps."path"] io/net/env=false` をドキュメント化
|
||||
|
||||
### 受け入れ基準(Phase‑15)
|
||||
- `--dump-expanded-ast-json` の golden が緑(MacroON/OFF差分は無い/または期待通り)
|
||||
- PyVM ランナー経由で `MacroBoxSpec.expand(json)` を呼べる(strict/timeout遵守)
|
||||
- MIR/LLVM/VM の後段は、Macro展開済み入力で恒常緑
|
||||
|
||||
関連: [planning/macro_driven_replan.md](planning/macro_driven_replan.md)
|
||||
|
||||
---
|
||||
|
||||
補足: JSON v0 の扱い(互換)
|
||||
- Phase‑15: Bridge で PHI を生成(現行継続)。
|
||||
- MIR18(LoopForm)以降: PHI 自動化後、JSON 側の PHI は非必須(将来は除外方向)。
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
# Phase‑15 Macro‑Driven Replan
|
||||
|
||||
Status: Adopted (2025‑09). This plan reframes Phase‑15 self‑hosting to leverage the new macro system (AST JSON v0 / PyVM sandbox / strict / timeout / golden).
|
||||
|
||||
## Goals
|
||||
- Consolidate all front‑end, sugar, and light rewrites into user macros (Nyash/PyVM)
|
||||
- Keep Rust core minimal: parse/AST emit/MIR build/backend only
|
||||
- Deterministic expansion with strict failure and timeouts; golden testing as acceptance
|
||||
|
||||
## Execution Pipeline
|
||||
1) Parse (Rust) → AST
|
||||
2) Macro Expansion (fixed‑point, 1 pass): Built‑in (Rust) → User Macros (Nyash/PyVM)
|
||||
3) Using/resolve → MIR → Backend (VM/LLVM/WASM/AOT)
|
||||
|
||||
## Guardrails
|
||||
- strict=1 (default): child error/timeout aborts the build
|
||||
- timeout: `NYASH_NY_COMPILER_TIMEOUT_MS=2000` (default)
|
||||
- capabilities: all OFF (io/net/env=false) for Phase‑15
|
||||
- observability: `--dump-expanded-ast-json` + JSONL trace (`NYASH_MACRO_TRACE_JSONL`)
|
||||
|
||||
## Work Items
|
||||
1) Enable PyVM runner route for macros (done)
|
||||
- `NYASH_MACRO_BOX_CHILD_RUNNER=1` → runner includes macro + calls `MacroBoxSpec.expand(json)`
|
||||
2) Identity + upper_string templates (done)
|
||||
- Examples under `apps/macros/examples/`
|
||||
3) Golden tests
|
||||
- identity/upper cases (done)
|
||||
- add 1–2 more (array/map literal touch) [next]
|
||||
4) Selfhost compiler refactor (front)
|
||||
- Limit Ny parser to Stage‑2 subset; sugar via macros
|
||||
- Keep resolver in runner (Phase‑15 policy)
|
||||
5) nyash.toml sketch for macro registration and caps
|
||||
- `[macros]` + `[macro_caps."path"]` io/net/env=false (docs only in Phase‑15)
|
||||
|
||||
## Acceptance
|
||||
- Expanded AST JSON matches goldens for sample programs
|
||||
- Macro runner path green under strict=1, timeout=2000ms
|
||||
- MIR/LLVM/VM paths stable with expanded inputs
|
||||
|
||||
@ -0,0 +1,742 @@
|
||||
# Phase 16 Implementation Guide: Box-Based Macro System
|
||||
|
||||
Date: 2025-09-19
|
||||
Version: 0.1.0
|
||||
Status: **READY** - 実装開始準備完了
|
||||
|
||||
## 🚀 **実装開始チェックリスト**
|
||||
|
||||
### **前提条件確認**
|
||||
- [x] CLI統合完了(--expand, --run-tests既に実装済み)
|
||||
- [x] 環境変数対応(NYASH_MACRO_ENABLE等)
|
||||
- [x] AST基盤(既存のASTNode構造体)
|
||||
- [x] パーサー基盤(NyashParser実装済み)
|
||||
- [ ] **開始準備**: Phase 1実装開始
|
||||
|
||||
## 🎯 **Phase 1: AST Pattern Matching 実装**
|
||||
|
||||
### **Step 1.1: AST構造体拡張**
|
||||
|
||||
#### **ファイル**: `src/ast.rs`
|
||||
```rust
|
||||
// 既存のASTNodeに追加
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ASTNode {
|
||||
// ... 既存のVariant ...
|
||||
|
||||
// 新規追加: パターンマッチング
|
||||
Match {
|
||||
target: Box<ASTNode>,
|
||||
arms: Vec<MatchArm>,
|
||||
span: Span,
|
||||
},
|
||||
|
||||
// パターン表現
|
||||
Pattern(PatternAst),
|
||||
}
|
||||
|
||||
// 新規追加: パターンAST
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PatternAst {
|
||||
// 基本パターン
|
||||
Wildcard { span: Span },
|
||||
Identifier { name: String, span: Span },
|
||||
Literal { value: LiteralValue, span: Span },
|
||||
|
||||
// 構造パターン
|
||||
BoxPattern {
|
||||
name: String,
|
||||
fields: Vec<FieldPattern>,
|
||||
rest: Option<String>, // ..rest
|
||||
span: Span,
|
||||
},
|
||||
|
||||
// 配列パターン
|
||||
ArrayPattern {
|
||||
elements: Vec<PatternAst>,
|
||||
rest: Option<String>, // ...rest
|
||||
span: Span,
|
||||
},
|
||||
|
||||
// OR パターン
|
||||
OrPattern {
|
||||
patterns: Vec<PatternAst>,
|
||||
span: Span,
|
||||
},
|
||||
|
||||
// バインドパターン
|
||||
BindPattern {
|
||||
name: String, // @variable
|
||||
pattern: Box<PatternAst>,
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MatchArm {
|
||||
pub pattern: PatternAst,
|
||||
pub guard: Option<Box<ASTNode>>,
|
||||
pub body: Vec<ASTNode>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FieldPattern {
|
||||
pub name: String,
|
||||
pub pattern: PatternAst,
|
||||
pub span: Span,
|
||||
}
|
||||
```
|
||||
|
||||
**実装タスク**:
|
||||
```bash
|
||||
# 1. ast.rsに上記の定義を追加
|
||||
# 2. 既存のコンパイルエラーを修正
|
||||
# 3. 基本的なDebug traitの動作確認
|
||||
```
|
||||
|
||||
### **Step 1.2: Tokenizer拡張**
|
||||
|
||||
#### **ファイル**: `src/tokenizer.rs`
|
||||
```rust
|
||||
// TokenTypeに追加
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum TokenType {
|
||||
// ... 既存のToken ...
|
||||
|
||||
// パターンマッチング用
|
||||
MATCH, // match
|
||||
PIPE, // |
|
||||
AT, // @
|
||||
DOTDOT, // ..
|
||||
DOTDOTDOT, // ...
|
||||
}
|
||||
|
||||
// Tokenizerに追加
|
||||
impl Tokenizer {
|
||||
fn read_word(&mut self) -> TokenType {
|
||||
match word.as_str() {
|
||||
// ... 既存のキーワード ...
|
||||
"match" => TokenType::MATCH,
|
||||
_ => TokenType::IDENTIFIER(word),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_symbol(&mut self) -> TokenType {
|
||||
match self.current_char() {
|
||||
// ... 既存のシンボル ...
|
||||
'|' => TokenType::PIPE,
|
||||
'@' => TokenType::AT,
|
||||
'.' => {
|
||||
if self.peek_char() == Some('.') {
|
||||
self.advance(); // consume second '.'
|
||||
if self.peek_char() == Some('.') {
|
||||
self.advance(); // consume third '.'
|
||||
TokenType::DOTDOTDOT
|
||||
} else {
|
||||
TokenType::DOTDOT
|
||||
}
|
||||
} else {
|
||||
TokenType::DOT
|
||||
}
|
||||
}
|
||||
_ => // ... 既存の処理 ...
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**実装タスク**:
|
||||
```bash
|
||||
# 1. TokenTypeに新しいトークンを追加
|
||||
# 2. Tokenizerの辞書登録
|
||||
# 3. 基本的なトークン化テスト
|
||||
```
|
||||
|
||||
### **Step 1.3: Parser拡張(match式)**
|
||||
|
||||
#### **ファイル**: `src/parser/expressions.rs` (新規作成)
|
||||
```rust
|
||||
use crate::ast::{ASTNode, PatternAst, MatchArm, FieldPattern};
|
||||
use crate::parser::{NyashParser, ParseError};
|
||||
use crate::tokenizer::TokenType;
|
||||
|
||||
impl NyashParser {
|
||||
/// match式のパース
|
||||
pub fn parse_match_expression(&mut self) -> Result<ASTNode, ParseError> {
|
||||
let start_line = self.current_token().line;
|
||||
self.consume(TokenType::MATCH)?;
|
||||
|
||||
// match対象の式
|
||||
let target = Box::new(self.parse_expression()?);
|
||||
|
||||
self.consume(TokenType::LBRACE)?;
|
||||
self.skip_newlines();
|
||||
|
||||
// match arms
|
||||
let mut arms = Vec::new();
|
||||
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
|
||||
arms.push(self.parse_match_arm()?);
|
||||
self.skip_newlines();
|
||||
}
|
||||
|
||||
if arms.is_empty() {
|
||||
return Err(ParseError::UnexpectedToken {
|
||||
expected: "at least one match arm".to_string(),
|
||||
found: self.current_token().token_type.clone(),
|
||||
line: start_line,
|
||||
});
|
||||
}
|
||||
|
||||
self.consume(TokenType::RBRACE)?;
|
||||
|
||||
Ok(ASTNode::Match {
|
||||
target,
|
||||
arms,
|
||||
span: crate::ast::Span::unknown(),
|
||||
})
|
||||
}
|
||||
|
||||
/// マッチアームのパース
|
||||
fn parse_match_arm(&mut self) -> Result<MatchArm, ParseError> {
|
||||
// パターン
|
||||
let pattern = self.parse_pattern()?;
|
||||
|
||||
// ガード(if condition)
|
||||
let guard = if self.match_token(&TokenType::IF) {
|
||||
self.advance(); // consume 'if'
|
||||
Some(Box::new(self.parse_expression()?))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
self.consume(TokenType::ARROW)?; // =>
|
||||
|
||||
// ボディ
|
||||
let body = if self.match_token(&TokenType::LBRACE) {
|
||||
self.parse_block_statements()?
|
||||
} else {
|
||||
vec![self.parse_statement()?]
|
||||
};
|
||||
|
||||
Ok(MatchArm {
|
||||
pattern,
|
||||
guard,
|
||||
body,
|
||||
span: crate::ast::Span::unknown(),
|
||||
})
|
||||
}
|
||||
|
||||
/// パターンのパース
|
||||
pub fn parse_pattern(&mut self) -> Result<PatternAst, ParseError> {
|
||||
self.parse_or_pattern()
|
||||
}
|
||||
|
||||
/// ORパターン(最低優先度)
|
||||
fn parse_or_pattern(&mut self) -> Result<PatternAst, ParseError> {
|
||||
let mut pattern = self.parse_bind_pattern()?;
|
||||
|
||||
if self.match_token(&TokenType::PIPE) {
|
||||
let mut patterns = vec![pattern];
|
||||
|
||||
while self.match_token(&TokenType::PIPE) {
|
||||
self.advance(); // consume '|'
|
||||
patterns.push(self.parse_bind_pattern()?);
|
||||
}
|
||||
|
||||
pattern = PatternAst::OrPattern {
|
||||
patterns,
|
||||
span: crate::ast::Span::unknown(),
|
||||
};
|
||||
}
|
||||
|
||||
Ok(pattern)
|
||||
}
|
||||
|
||||
/// バインドパターン(@variable pattern)
|
||||
fn parse_bind_pattern(&mut self) -> Result<PatternAst, ParseError> {
|
||||
if self.match_token(&TokenType::AT) {
|
||||
self.advance(); // consume '@'
|
||||
|
||||
let name = if let TokenType::IDENTIFIER(name) = &self.current_token().token_type {
|
||||
let name = name.clone();
|
||||
self.advance();
|
||||
name
|
||||
} else {
|
||||
return Err(ParseError::UnexpectedToken {
|
||||
expected: "identifier after '@'".to_string(),
|
||||
found: self.current_token().token_type.clone(),
|
||||
line: self.current_token().line,
|
||||
});
|
||||
};
|
||||
|
||||
let pattern = Box::new(self.parse_primary_pattern()?);
|
||||
|
||||
Ok(PatternAst::BindPattern {
|
||||
name,
|
||||
pattern,
|
||||
span: crate::ast::Span::unknown(),
|
||||
})
|
||||
} else {
|
||||
self.parse_primary_pattern()
|
||||
}
|
||||
}
|
||||
|
||||
/// 基本パターン
|
||||
fn parse_primary_pattern(&mut self) -> Result<PatternAst, ParseError> {
|
||||
match &self.current_token().token_type {
|
||||
// ワイルドカード
|
||||
TokenType::UNDERSCORE => {
|
||||
self.advance();
|
||||
Ok(PatternAst::Wildcard {
|
||||
span: crate::ast::Span::unknown(),
|
||||
})
|
||||
}
|
||||
|
||||
// 識別子(変数バインドまたは構造体パターン)
|
||||
TokenType::IDENTIFIER(name) => {
|
||||
let name = name.clone();
|
||||
self.advance();
|
||||
|
||||
if self.match_token(&TokenType::LBRACE) {
|
||||
// 構造パターン: TypeName { field1, field2, .. }
|
||||
self.parse_box_pattern(name)
|
||||
} else {
|
||||
// 変数バインド
|
||||
Ok(PatternAst::Identifier {
|
||||
name,
|
||||
span: crate::ast::Span::unknown(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// リテラル
|
||||
TokenType::INTEGER(value) => {
|
||||
let value = *value;
|
||||
self.advance();
|
||||
Ok(PatternAst::Literal {
|
||||
value: crate::ast::LiteralValue::Integer(value),
|
||||
span: crate::ast::Span::unknown(),
|
||||
})
|
||||
}
|
||||
|
||||
TokenType::STRING(value) => {
|
||||
let value = value.clone();
|
||||
self.advance();
|
||||
Ok(PatternAst::Literal {
|
||||
value: crate::ast::LiteralValue::String(value),
|
||||
span: crate::ast::Span::unknown(),
|
||||
})
|
||||
}
|
||||
|
||||
// 配列パターン
|
||||
TokenType::LBRACKET => self.parse_array_pattern(),
|
||||
|
||||
_ => Err(ParseError::UnexpectedToken {
|
||||
expected: "pattern".to_string(),
|
||||
found: self.current_token().token_type.clone(),
|
||||
line: self.current_token().line,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Box構造パターン: TypeName { field1, field2, .. }
|
||||
fn parse_box_pattern(&mut self, type_name: String) -> Result<PatternAst, ParseError> {
|
||||
self.consume(TokenType::LBRACE)?;
|
||||
self.skip_newlines();
|
||||
|
||||
let mut fields = Vec::new();
|
||||
let mut rest = None;
|
||||
|
||||
while !self.match_token(&TokenType::RBRACE) && !self.is_at_end() {
|
||||
// rest pattern: ..rest
|
||||
if self.match_token(&TokenType::DOTDOT) {
|
||||
self.advance(); // consume '..'
|
||||
|
||||
if let TokenType::IDENTIFIER(name) = &self.current_token().token_type {
|
||||
rest = Some(name.clone());
|
||||
self.advance();
|
||||
} else {
|
||||
return Err(ParseError::UnexpectedToken {
|
||||
expected: "identifier after '..'".to_string(),
|
||||
found: self.current_token().token_type.clone(),
|
||||
line: self.current_token().line,
|
||||
});
|
||||
}
|
||||
break; // rest patternは最後でなければならない
|
||||
}
|
||||
|
||||
// フィールドパターン
|
||||
let field_name = if let TokenType::IDENTIFIER(name) = &self.current_token().token_type {
|
||||
let name = name.clone();
|
||||
self.advance();
|
||||
name
|
||||
} else {
|
||||
return Err(ParseError::UnexpectedToken {
|
||||
expected: "field name".to_string(),
|
||||
found: self.current_token().token_type.clone(),
|
||||
line: self.current_token().line,
|
||||
});
|
||||
};
|
||||
|
||||
let pattern = if self.match_token(&TokenType::COLON) {
|
||||
self.advance(); // consume ':'
|
||||
self.parse_pattern()?
|
||||
} else {
|
||||
// 短縮形: field は field: field と同じ
|
||||
PatternAst::Identifier {
|
||||
name: field_name.clone(),
|
||||
span: crate::ast::Span::unknown(),
|
||||
}
|
||||
};
|
||||
|
||||
fields.push(FieldPattern {
|
||||
name: field_name,
|
||||
pattern,
|
||||
span: crate::ast::Span::unknown(),
|
||||
});
|
||||
|
||||
if self.match_token(&TokenType::COMMA) {
|
||||
self.advance();
|
||||
self.skip_newlines();
|
||||
} else if !self.match_token(&TokenType::RBRACE) {
|
||||
return Err(ParseError::UnexpectedToken {
|
||||
expected: "',' or '}'".to_string(),
|
||||
found: self.current_token().token_type.clone(),
|
||||
line: self.current_token().line,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
self.consume(TokenType::RBRACE)?;
|
||||
|
||||
Ok(PatternAst::BoxPattern {
|
||||
name: type_name,
|
||||
fields,
|
||||
rest,
|
||||
span: crate::ast::Span::unknown(),
|
||||
})
|
||||
}
|
||||
|
||||
/// 配列パターン: [first, second, ...rest]
|
||||
fn parse_array_pattern(&mut self) -> Result<PatternAst, ParseError> {
|
||||
self.consume(TokenType::LBRACKET)?;
|
||||
self.skip_newlines();
|
||||
|
||||
let mut elements = Vec::new();
|
||||
let mut rest = None;
|
||||
|
||||
while !self.match_token(&TokenType::RBRACKET) && !self.is_at_end() {
|
||||
// rest pattern: ...rest
|
||||
if self.match_token(&TokenType::DOTDOTDOT) {
|
||||
self.advance(); // consume '...'
|
||||
|
||||
if let TokenType::IDENTIFIER(name) = &self.current_token().token_type {
|
||||
rest = Some(name.clone());
|
||||
self.advance();
|
||||
} else {
|
||||
return Err(ParseError::UnexpectedToken {
|
||||
expected: "identifier after '...'".to_string(),
|
||||
found: self.current_token().token_type.clone(),
|
||||
line: self.current_token().line,
|
||||
});
|
||||
}
|
||||
break; // rest patternは最後でなければならない
|
||||
}
|
||||
|
||||
elements.push(self.parse_pattern()?);
|
||||
|
||||
if self.match_token(&TokenType::COMMA) {
|
||||
self.advance();
|
||||
self.skip_newlines();
|
||||
} else if !self.match_token(&TokenType::RBRACKET) {
|
||||
return Err(ParseError::UnexpectedToken {
|
||||
expected: "',' or ']'".to_string(),
|
||||
found: self.current_token().token_type.clone(),
|
||||
line: self.current_token().line,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
self.consume(TokenType::RBRACKET)?;
|
||||
|
||||
Ok(PatternAst::ArrayPattern {
|
||||
elements,
|
||||
rest,
|
||||
span: crate::ast::Span::unknown(),
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**実装タスク**:
|
||||
```bash
|
||||
# 1. src/parser/expressions.rs を作成
|
||||
# 2. src/parser/mod.rs に追加
|
||||
# 3. 基本的なmatch式のパーステスト
|
||||
```
|
||||
|
||||
### **Step 1.4: パターンマッチング実行エンジン**
|
||||
|
||||
#### **ファイル**: `src/macro_system/pattern_matcher.rs` (新規作成)
|
||||
```rust
|
||||
use crate::ast::{ASTNode, PatternAst, FieldPattern, LiteralValue};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PatternMatcher {
|
||||
bindings: HashMap<String, ASTNode>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MatchResult {
|
||||
Success,
|
||||
Failure,
|
||||
}
|
||||
|
||||
impl PatternMatcher {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
bindings: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// パターンマッチング実行
|
||||
pub fn match_pattern(&mut self, pattern: &PatternAst, value: &ASTNode) -> MatchResult {
|
||||
match (pattern, value) {
|
||||
// ワイルドカード: 常に成功
|
||||
(PatternAst::Wildcard { .. }, _) => MatchResult::Success,
|
||||
|
||||
// 識別子: 変数バインド
|
||||
(PatternAst::Identifier { name, .. }, _) => {
|
||||
self.bindings.insert(name.clone(), value.clone());
|
||||
MatchResult::Success
|
||||
}
|
||||
|
||||
// リテラル: 値比較
|
||||
(PatternAst::Literal { value: pattern_val, .. },
|
||||
ASTNode::Literal { value: node_val, .. }) => {
|
||||
if self.literal_equals(pattern_val, node_val) {
|
||||
MatchResult::Success
|
||||
} else {
|
||||
MatchResult::Failure
|
||||
}
|
||||
}
|
||||
|
||||
// Box構造パターン
|
||||
(PatternAst::BoxPattern { name: pattern_name, fields: pattern_fields, rest, .. },
|
||||
ASTNode::BoxDeclaration { name: box_name, fields: box_fields, .. }) => {
|
||||
if pattern_name == box_name {
|
||||
self.match_box_fields(pattern_fields, box_fields, rest)
|
||||
} else {
|
||||
MatchResult::Failure
|
||||
}
|
||||
}
|
||||
|
||||
// 配列パターン
|
||||
(PatternAst::ArrayPattern { elements, rest, .. },
|
||||
ASTNode::Array { elements: array_elements, .. }) => {
|
||||
self.match_array_elements(elements, array_elements, rest)
|
||||
}
|
||||
|
||||
// ORパターン: いずれかが成功すれば成功
|
||||
(PatternAst::OrPattern { patterns, .. }, value) => {
|
||||
for pattern in patterns {
|
||||
let mut temp_matcher = PatternMatcher::new();
|
||||
if let MatchResult::Success = temp_matcher.match_pattern(pattern, value) {
|
||||
// 成功したバインディングをマージ
|
||||
self.bindings.extend(temp_matcher.bindings);
|
||||
return MatchResult::Success;
|
||||
}
|
||||
}
|
||||
MatchResult::Failure
|
||||
}
|
||||
|
||||
// バインドパターン: 内部パターンマッチ + 変数バインド
|
||||
(PatternAst::BindPattern { name, pattern, .. }, value) => {
|
||||
if let MatchResult::Success = self.match_pattern(pattern, value) {
|
||||
self.bindings.insert(name.clone(), value.clone());
|
||||
MatchResult::Success
|
||||
} else {
|
||||
MatchResult::Failure
|
||||
}
|
||||
}
|
||||
|
||||
// その他: 失敗
|
||||
_ => MatchResult::Failure,
|
||||
}
|
||||
}
|
||||
|
||||
/// リテラル値の比較
|
||||
fn literal_equals(&self, a: &LiteralValue, b: &LiteralValue) -> bool {
|
||||
match (a, b) {
|
||||
(LiteralValue::Integer(a), LiteralValue::Integer(b)) => a == b,
|
||||
(LiteralValue::String(a), LiteralValue::String(b)) => a == b,
|
||||
(LiteralValue::Bool(a), LiteralValue::Bool(b)) => a == b,
|
||||
(LiteralValue::Null, LiteralValue::Null) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Boxフィールドのマッチング
|
||||
fn match_box_fields(
|
||||
&mut self,
|
||||
pattern_fields: &[FieldPattern],
|
||||
box_fields: &[String],
|
||||
rest: &Option<String>,
|
||||
) -> MatchResult {
|
||||
// TODO: 実装
|
||||
// 現在は簡単のため、フィールド名のマッチングのみ
|
||||
if pattern_fields.len() <= box_fields.len() {
|
||||
MatchResult::Success
|
||||
} else {
|
||||
MatchResult::Failure
|
||||
}
|
||||
}
|
||||
|
||||
/// 配列要素のマッチング
|
||||
fn match_array_elements(
|
||||
&mut self,
|
||||
pattern_elements: &[PatternAst],
|
||||
array_elements: &[ASTNode],
|
||||
rest: &Option<String>,
|
||||
) -> MatchResult {
|
||||
// TODO: 実装
|
||||
// 現在は簡単のため、要素数のチェックのみ
|
||||
if pattern_elements.len() <= array_elements.len() {
|
||||
MatchResult::Success
|
||||
} else {
|
||||
MatchResult::Failure
|
||||
}
|
||||
}
|
||||
|
||||
/// バインディング取得
|
||||
pub fn get_binding(&self, name: &str) -> Option<&ASTNode> {
|
||||
self.bindings.get(name)
|
||||
}
|
||||
|
||||
/// すべてのバインディング取得
|
||||
pub fn bindings(&self) -> &HashMap<String, ASTNode> {
|
||||
&self.bindings
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**実装タスク**:
|
||||
```bash
|
||||
# 1. src/macro_system ディレクトリ作成
|
||||
# 2. pattern_matcher.rs 作成
|
||||
# 3. src/lib.rs にmacro_systemモジュール追加
|
||||
# 4. 基本的なパターンマッチテスト
|
||||
```
|
||||
|
||||
### **Step 1.5: 基本テスト**
|
||||
|
||||
#### **ファイル**: `src/tests/pattern_matching_tests.rs` (新規作成)
|
||||
```rust
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::ast::{ASTNode, PatternAst, LiteralValue};
|
||||
use crate::macro_system::pattern_matcher::{PatternMatcher, MatchResult};
|
||||
|
||||
#[test]
|
||||
fn test_wildcard_pattern() {
|
||||
let mut matcher = PatternMatcher::new();
|
||||
let pattern = PatternAst::Wildcard { span: crate::ast::Span::unknown() };
|
||||
let value = ASTNode::Literal {
|
||||
value: LiteralValue::Integer(42),
|
||||
span: crate::ast::Span::unknown(),
|
||||
};
|
||||
|
||||
let result = matcher.match_pattern(&pattern, &value);
|
||||
assert!(matches!(result, MatchResult::Success));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_identifier_pattern() {
|
||||
let mut matcher = PatternMatcher::new();
|
||||
let pattern = PatternAst::Identifier {
|
||||
name: "x".to_string(),
|
||||
span: crate::ast::Span::unknown(),
|
||||
};
|
||||
let value = ASTNode::Literal {
|
||||
value: LiteralValue::Integer(42),
|
||||
span: crate::ast::Span::unknown(),
|
||||
};
|
||||
|
||||
let result = matcher.match_pattern(&pattern, &value);
|
||||
assert!(matches!(result, MatchResult::Success));
|
||||
|
||||
// バインディング確認
|
||||
let binding = matcher.get_binding("x");
|
||||
assert!(binding.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_literal_pattern_success() {
|
||||
let mut matcher = PatternMatcher::new();
|
||||
let pattern = PatternAst::Literal {
|
||||
value: LiteralValue::Integer(42),
|
||||
span: crate::ast::Span::unknown(),
|
||||
};
|
||||
let value = ASTNode::Literal {
|
||||
value: LiteralValue::Integer(42),
|
||||
span: crate::ast::Span::unknown(),
|
||||
};
|
||||
|
||||
let result = matcher.match_pattern(&pattern, &value);
|
||||
assert!(matches!(result, MatchResult::Success));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_literal_pattern_failure() {
|
||||
let mut matcher = PatternMatcher::new();
|
||||
let pattern = PatternAst::Literal {
|
||||
value: LiteralValue::Integer(42),
|
||||
span: crate::ast::Span::unknown(),
|
||||
};
|
||||
let value = ASTNode::Literal {
|
||||
value: LiteralValue::Integer(99),
|
||||
span: crate::ast::Span::unknown(),
|
||||
};
|
||||
|
||||
let result = matcher.match_pattern(&pattern, &value);
|
||||
assert!(matches!(result, MatchResult::Failure));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**実装タスク**:
|
||||
```bash
|
||||
# 1. テストファイル作成
|
||||
# 2. cargo test で動作確認
|
||||
# 3. CI通過確認
|
||||
```
|
||||
|
||||
## 🎯 **Phase 1 完成目標**
|
||||
|
||||
### **動作する最小例**
|
||||
```nyash
|
||||
// パース可能なmatch式
|
||||
match some_value {
|
||||
42 => print("Found answer")
|
||||
x => print("Found: " + x.toString())
|
||||
_ => print("Unknown")
|
||||
}
|
||||
|
||||
// パース可能なパターン
|
||||
BoxDeclaration { name: "Person", fields: [first, ...rest] }
|
||||
```
|
||||
|
||||
### **Phase 1 完了条件**
|
||||
- [ ] すべてのパターン構文がパース可能
|
||||
- [ ] 基本的なパターンマッチングが動作
|
||||
- [ ] テストが緑色(通過)
|
||||
- [ ] 既存機能に影響なし(回帰テスト通過)
|
||||
|
||||
---
|
||||
|
||||
**Phase 1が完了したら、Phase 2(Quote/Unquote)の実装に進む!** 🚀
|
||||
|
||||
**Next**: [Phase 2実装ガイド](./PHASE2_IMPLEMENTATION.md) | [テスト戦略](./TESTING_STRATEGY.md)
|
||||
@ -114,10 +114,10 @@ method __generated_equals_1234(other: UserBox) -> BoolBox {
|
||||
```
|
||||
|
||||
#### 完了条件
|
||||
- [ ] @derive(Equals)の動作確認
|
||||
- [ ] @derive(ToString)の動作確認
|
||||
- [ ] HIRパッチエンジンの安定動作
|
||||
- [ ] 4つの必須テストケース通過
|
||||
- [x] @derive(Equals)の動作確認(AST展開→MIRで実行)
|
||||
- [x] @derive(ToString)の動作確認
|
||||
- [x] HIRパッチエンジンの安定動作(MVP: no‑op/derive注入)
|
||||
- [x] 初期スモークにてgreen(追加テスト拡充中)
|
||||
|
||||
## 🛡️ Phase 16.4: @validate統合(1週間)
|
||||
|
||||
@ -187,11 +187,11 @@ static method load() -> Result<AppConfig, ConfigError> {
|
||||
|
||||
### 品質保証とデモンストレーション
|
||||
|
||||
#### ChatGPT推奨の必須テスト
|
||||
1. **derive等価性**: `UserBox("a",1) == UserBox("a",1)` → 真
|
||||
2. **validation**: `age=200` → `ValidationError`
|
||||
3. **config**: `DATABASE_URL`未設定 → `Err`
|
||||
4. **hygiene**: 手書き`equals`と生成コードが衝突しない
|
||||
#### ChatGPT推奨の必須テスト(進捗: 部分達成)
|
||||
1. **derive等価性**: `UserBox("a",1) == UserBox("a",1)` → 真(達成)
|
||||
2. **validation**: `age=200` → `ValidationError`(未)
|
||||
3. **config**: `DATABASE_URL`未設定 → `Err`(未)
|
||||
4. **hygiene**: 手書き`equals`と生成コードが衝突しない(MVPでは上書き回避で担保)
|
||||
|
||||
#### デバッグツール
|
||||
- `nyash --expand`: マクロ展開結果の可視化
|
||||
@ -297,22 +297,22 @@ local request = HttpRequestBox.builder()
|
||||
- **学習コスト**: 充実したドキュメントとサンプル
|
||||
- **既存影響**: MIR14不変でリスク最小化
|
||||
|
||||
## 🎯 次のアクション
|
||||
## 🎯 次のアクション(進捗反映)
|
||||
|
||||
### 即座着手(今週)
|
||||
1. **Pattern Matching最小実装**開始
|
||||
2. **AST操作基盤API設計**確定
|
||||
3. **HIRパッチエンジン設計**詳細化
|
||||
4. **@derive(Equals)実装計画**策定
|
||||
1. **Pattern/Quote最小実装**($name / $...name / OrPattern)完了
|
||||
2. **AST操作基盤API設計**(MVP)完了
|
||||
3. **HIRパッチエンジン**(MVP)完了
|
||||
4. **@derive(Equals/ToString)** 実装済み(MVP)
|
||||
|
||||
### 2週間後
|
||||
1. **Pattern Matching完成**
|
||||
2. **@derive(Equals)スモーク動作**
|
||||
3. **マクロ展開デバッグツール**完成
|
||||
4. **実用アプリ適用**開始
|
||||
1. **Test Runner拡張**(Box内/entry policy/args JSON)
|
||||
2. **Pattern強化**(配列/マップ/中間可変)
|
||||
3. **Macro debug CLI**(展開ステップの可視化の拡張)
|
||||
4. **実用アプリ適用**(derive/test導入)
|
||||
|
||||
---
|
||||
|
||||
**Phase 16 Macro Revolution**により、Nyashは世界最強のマクロ言語への道を確実に歩む。
|
||||
|
||||
*全AI賢者の叡智を統合した、実現可能かつ革新的な実装戦略。*
|
||||
*全AI賢者の叡智を統合した、実現可能かつ革新的な実装戦略。*
|
||||
|
||||
@ -1,132 +1,255 @@
|
||||
# Phase 16: Macro Revolution - 世界最強マクロ言語への道
|
||||
# Phase 16: Macro Revolution - 世界最強マクロシステムの構築
|
||||
|
||||
**開始日**: 2025-09-18
|
||||
**ステータス**: 計画中
|
||||
**目標**: Box-Based Macro Systemにより、Lisp/Rust/C++/Nim/Juliaを超越する
|
||||
Date: 2025-09-19
|
||||
Status: **ACTIVE** - AST Pattern Matching実装中
|
||||
Target: 2025年12月完了
|
||||
|
||||
## 🔥 革命の発端
|
||||
## 🎯 **革命の概要**
|
||||
|
||||
2025年9月18日、Nyashの調査中に**マクロ機能が存在しない**ことが判明。これを「第4の革命」の機会と捉え、世界最強のマクロ言語を目指すPhase 16が誕生。
|
||||
**Everything is Box** 設計の究極進化形として、世界初の **Box-Based Macro System** を実装。
|
||||
Lisp、Rust、C++、Nim、Juliaを超越する次世代マクロ言語を目指す。
|
||||
|
||||
### 🌟 これまでの革命
|
||||
1. **Property System革命**: stored/computed/once/birth_once統一構文
|
||||
2. **Python統合革命**: @property/@cached_property完全マッピング
|
||||
3. **Pattern Matching革命**: ChatGPT提案(実装予定)
|
||||
4. **🆕 Macro System革命**: 今回のPhase 16
|
||||
## 🔥 **なぜ革命的か**
|
||||
|
||||
## 🎯 目標:5つの最強言語を超越
|
||||
### **従来のマクロシステム**
|
||||
```rust
|
||||
// Rust: 型ごとに別実装が必要
|
||||
#[derive(Debug)] struct A {} // struct用実装
|
||||
#[derive(Debug)] enum B {} // enum用実装
|
||||
#[derive(Debug)] union C {} // union用実装
|
||||
```
|
||||
|
||||
| 言語 | 強み | Nyashでの超越方法 |
|
||||
|------|------|-------------------|
|
||||
| **Lisp** | homoiconicity | BoxがAST表現 → コード=Box |
|
||||
| **Rust** | 型安全derive | Property System + 型情報 |
|
||||
| **C++** | 零オーバーヘッド | LLVM最適化 + Box統一 |
|
||||
| **Nim** | 読みやすさ | Box記法 → より直感的 |
|
||||
| **Julia** | 科学計算特化 | Python統合 → ライブラリ活用 |
|
||||
|
||||
## 🌟 Box-Based Macro の革新性
|
||||
|
||||
### 世界初の特徴
|
||||
### **Nyash: Box-Based Macro**
|
||||
```nyash
|
||||
// 🚀 マクロが一等市民のBox
|
||||
box CustomMacroBox {
|
||||
template: StringBox
|
||||
|
||||
// computed: Property SystemとMacro Systemの融合!
|
||||
expanded_code: StringBox { expand(me.template) }
|
||||
|
||||
// once: 重いコンパイル処理をキャッシュ
|
||||
once compiled_ast: ASTBox { compile(me.expanded_code) }
|
||||
|
||||
// birth_once: マクロライブラリの事前読み込み
|
||||
birth_once macro_lib: MacroLibBox { load_stdlib() }
|
||||
// すべてがBoxなので、1つの実装で全対応!
|
||||
@derive(Debug) box A {} // 同じ実装
|
||||
@derive(Debug) box B {} // 同じ実装
|
||||
@derive(Debug) box C {} // 同じ実装
|
||||
```
|
||||
|
||||
**複雑度**: `O(型の種類 × マクロの種類)` → `O(マクロの種類)`
|
||||
|
||||
## 🏗️ **アーキテクチャ設計**
|
||||
|
||||
### **Phase 1: AST Pattern Matching基盤**
|
||||
```nyash
|
||||
// 安全なASTパターンマッチング
|
||||
match ast_node {
|
||||
BoxDeclaration { name, fields, methods, .. } => {
|
||||
// 型安全な変換処理
|
||||
}
|
||||
FunctionDeclaration { name: @fname, params: [first, ...rest] } => {
|
||||
// 束縛とワイルドカード対応
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 独自の革新要素
|
||||
- **Everything is Box**: マクロもBoxとして統一
|
||||
- **Property System統合**: リアルタイム展開 + キャッシュ
|
||||
- **型安全性**: `MacroBox<InputAst, OutputAst>`
|
||||
- **Visual debugging**: 展開ステップの可視化
|
||||
- **Live macro**: ファイル変更でリアルタイム更新
|
||||
|
||||
## 📋 実装ロードマップ
|
||||
|
||||
### **Phase A: AST基盤構築**(1週間)
|
||||
- AST Pattern/Unifier(変数/ワイルドカード)
|
||||
- Quasi-quote/unquote、AST Builder
|
||||
- Rewriter(停止条件/置換)
|
||||
|
||||
### **Phase B: 最小マクロシステム**(1-2週間)
|
||||
- マクロ定義/登録/解決(関数風)
|
||||
- 簡易衛生(gensym)+ 再帰上限
|
||||
- エラー設計(Span指向)
|
||||
|
||||
### **Phase C: Box-Based Macro完成**(1-2週間)
|
||||
- 属性マクロ(宣言/プロパティ)
|
||||
- MacroBox(型付きAPI)
|
||||
- デシュガ(pattern matching等)
|
||||
|
||||
### **Phase D: 高機能化**(以降)
|
||||
- 本格衛生(SyntaxContext)
|
||||
- 外部手続きマクロ(JSON AST)
|
||||
- AI支援マクロ生成
|
||||
|
||||
## 🤖 AI協働の成果
|
||||
|
||||
### Gemini洞察(言語設計)
|
||||
- Property×Macro統合の合理性確認
|
||||
- MacroBox一等市民化の革新性評価
|
||||
- Pattern Matching優先実装の推奨
|
||||
|
||||
### Codex洞察(実装戦略)
|
||||
- 技術的実現可能性の確認
|
||||
- 段階的実装ロードマップ
|
||||
- 工数見積もり(最小2-3週間、充実4-6週間)
|
||||
|
||||
## 🎯 成功指標
|
||||
|
||||
### Phase A完了時
|
||||
- AST操作ツールのユニットテスト通過
|
||||
- Span一貫性の確保
|
||||
|
||||
### Phase B完了時
|
||||
- マクロ→通常構文→MIR14が既存スモークと一致
|
||||
- PyVM/LLVM両方で差分なし
|
||||
|
||||
### Phase C完了時
|
||||
- 属性マクロでProperty宣言の糖衣実装
|
||||
- MacroBoxで実例1つ動作
|
||||
|
||||
### 最終目標
|
||||
### **Phase 2: Quote/Unquote システム**
|
||||
```nyash
|
||||
// 🎯 世界最強マクロの証明
|
||||
@live_derive(Equals, ToString, Clone)
|
||||
@python_bridge(numpy, pandas)
|
||||
@visual_debug(expand_steps=true)
|
||||
box RevolutionaryBox {
|
||||
// Property System + Macro System完全融合
|
||||
once ai_methods: MethodBox { AI.generate(me.type()) }
|
||||
computed quality: QualityBox { analyze(me.generated_code) }
|
||||
// 安全なコード生成
|
||||
let template = quote! {
|
||||
$(method_name)(other) {
|
||||
return $(field_comparison_logic)
|
||||
}
|
||||
}
|
||||
|
||||
// 型安全な展開
|
||||
let generated = unquote! {
|
||||
template with {
|
||||
method_name: "equals",
|
||||
field_comparison_logic: generate_field_comparisons(box_fields)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📚 関連ドキュメント
|
||||
### **Phase 3: HIRパッチ式マクロエンジン**
|
||||
```nyash
|
||||
// MIR命令は増やさない!HIRレベルで変換
|
||||
box MacroEngineBox {
|
||||
expand_derive(input_box: BoxAst) -> Vec<MethodAst> {
|
||||
// HIRレベルでパッチ適用
|
||||
// 既存MIR14命令セットで実行
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 🎯 実装計画
|
||||
- **[統合実装ロードマップ](IMPLEMENTATION_ROADMAP.md)** - 全AI相談結果を統合した実装戦略
|
||||
- **[Pattern Matching基盤計画](PATTERN_MATCHING_FOUNDATION.md)** - マクロ実装の必須前提条件
|
||||
## 🎯 **実装する実マクロ**
|
||||
|
||||
### 🤖 AI相談結果
|
||||
- **[ChatGPT最強思考モード分析](CHATGPT_CONSULTATION.md)** - 6つのマクロタイプ評価と実装優先度
|
||||
- **[Gemini哲学的検討](GEMINI_CONSULTATION.md)** - Property×Macro統合の合理性検証
|
||||
- **[Codex技術分析](CODEX_CONSULTATION.md)** - 実装可能性と技術的制約
|
||||
### **@derive マクロファミリー**
|
||||
```nyash
|
||||
@derive(Equals, ToString, Clone, Debug)
|
||||
box Person {
|
||||
name: StringBox
|
||||
age: IntegerBox
|
||||
address: AddressBox // ネストしたBoxも自動対応
|
||||
}
|
||||
|
||||
### 🌟 設計ドキュメント
|
||||
- **[マクロ実例集](macro-examples.md)** - 6つの革命的マクロタイプの具体例
|
||||
// 自動生成される:
|
||||
// - equals(other) メソッド
|
||||
// - toString() メソッド
|
||||
// - clone() メソッド
|
||||
// - debug() メソッド
|
||||
```
|
||||
|
||||
### **@test マクロ + ランナー**
|
||||
```nyash
|
||||
@test
|
||||
test_person_creation() {
|
||||
local person = new Person("Alice", 25, new AddressBox("Tokyo"))
|
||||
assert_equals(person.name, "Alice")
|
||||
assert_equals(person.age, 25)
|
||||
}
|
||||
|
||||
@test
|
||||
test_person_equals() {
|
||||
local p1 = new Person("Bob", 30, new AddressBox("Osaka"))
|
||||
local p2 = new Person("Bob", 30, new AddressBox("Osaka"))
|
||||
assert_equals(p1.equals(p2), true)
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
# テスト実行
|
||||
nyash --run-tests my_program.nyash
|
||||
# [TEST] test_person_creation ... OK
|
||||
# [TEST] test_person_equals ... OK
|
||||
# Tests: 2 passed, 0 failed
|
||||
```
|
||||
|
||||
## 🛡️ **ガードレール(安全性保証)**
|
||||
|
||||
### **1. Hygiene(名前衝突回避)**
|
||||
```nyash
|
||||
macro generate_counter() {
|
||||
local temp = gensym("counter_temp") // 自動でユニーク名生成
|
||||
quote! {
|
||||
local $(temp) = 0
|
||||
$(temp).increment()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **2. 循環検出・再帰制限**
|
||||
```nyash
|
||||
// マクロ展開時に自動チェック
|
||||
macro recursive_macro(depth) {
|
||||
if macro_depth() > 100 {
|
||||
compile_error!("Macro recursion limit exceeded")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **3. 決定性・副作用なし**
|
||||
```nyash
|
||||
// ✅ 決定的なマクロ(推奨)
|
||||
macro pure_derive(box_name, trait_name) {
|
||||
// 同じ入力なら常に同じ出力
|
||||
return generate_method(box_name, trait_name)
|
||||
}
|
||||
|
||||
// ❌ 副作用のあるマクロ(禁止)
|
||||
macro bad_macro() {
|
||||
println!("This is forbidden!") // コンパイル時IO禁止
|
||||
}
|
||||
```
|
||||
|
||||
## 🎨 **開発者体験**
|
||||
|
||||
### **マクロ展開の可視化**
|
||||
```bash
|
||||
# マクロ展開結果を表示
|
||||
nyash --expand my_program.nyash
|
||||
|
||||
# 詳細トレース
|
||||
NYASH_MACRO_TRACE=1 nyash my_program.nyash
|
||||
# [MACRO] @derive(Equals) -> generating equals() method for Person
|
||||
# [MACRO] @test -> collecting test_person_creation()
|
||||
# [MACRO] Expansion complete: 2 macros processed, 0 errors
|
||||
```
|
||||
|
||||
### **エラーメッセージの親切さ**
|
||||
```nyash
|
||||
@derive(UnknownTrait)
|
||||
box Person {}
|
||||
|
||||
// エラー例:
|
||||
// error: Unknown derive trait 'UnknownTrait'
|
||||
// --> person.nyash:1:9
|
||||
// |
|
||||
// 1 | @derive(UnknownTrait)
|
||||
// | ^^^^^^^^^^^^
|
||||
// |
|
||||
// = help: Available traits: Equals, ToString, Clone, Debug
|
||||
// = note: Did you mean 'ToString'?
|
||||
```
|
||||
|
||||
## 📊 **他言語との比較優位性**
|
||||
|
||||
| 言語 | 型安全性 | 学習コスト | デバッグ性 | 実行性能 | 表現力 |
|
||||
|------|----------|------------|------------|----------|--------|
|
||||
| **Nyash** | ✅ | 🟢 Low | 🟢 High | 🟢 High | 🟢 High |
|
||||
| Rust | ✅ | 🔴 High | 🔴 Low | 🟢 High | 🟡 Medium |
|
||||
| Lisp | ❌ | 🔴 High | 🔴 Low | 🟡 Medium | 🟢 High |
|
||||
| C++ | ❌ | 🔴 Very High | 🔴 Very Low | 🟢 High | 🟢 High |
|
||||
| Nim | 🟡 | 🟡 Medium | 🟡 Medium | 🟢 High | 🟢 High |
|
||||
|
||||
## 🚀 **実装スケジュール**
|
||||
|
||||
### **Week 1-2: AST Pattern Matching基盤**
|
||||
- [x] AST定義の拡張(パターン用)
|
||||
- [ ] パターンマッチング構文の実装
|
||||
- [ ] 束縛・ワイルドカードサポート
|
||||
- [ ] 基本テストケース
|
||||
|
||||
### **Week 3-4: Quote/Unquote システム**
|
||||
- [ ] Quote構文の実装
|
||||
- [ ] Unquote展開エンジン
|
||||
- [ ] スパン情報伝播
|
||||
- [ ] エラー処理強化
|
||||
|
||||
### **Week 5-6: HIRパッチ式エンジン**
|
||||
- [ ] マクロエンジンコア実装
|
||||
- [ ] HIRレベル変換処理
|
||||
- [ ] MIR14命令互換性確保
|
||||
- [ ] パフォーマンス最適化
|
||||
|
||||
### **Week 7-8: 実マクロ実装**
|
||||
- [ ] @derive(Equals, ToString)
|
||||
- [ ] @test マクロ + ランナー
|
||||
- [ ] CLI統合(--expand, --run-tests)
|
||||
- [ ] ドキュメント・例示
|
||||
|
||||
### **Week 9-12: 安定化・拡張**
|
||||
- [ ] ガードレール強化
|
||||
- [ ] エラーメッセージ改善
|
||||
- [ ] 性能最適化・メモリ効率
|
||||
- [ ] 実用アプリでの検証
|
||||
|
||||
## 🎯 **成功指標**
|
||||
|
||||
### **技術指標**
|
||||
- [ ] @derive マクロで100行→5行の圧縮達成
|
||||
- [ ] マクロ展開時間 < 100ms(中規模プロジェクト)
|
||||
- [ ] 型エラー100%コンパイル時検出
|
||||
- [ ] メモリ使用量増加 < 20%
|
||||
|
||||
### **開発者体験指標**
|
||||
- [ ] 学習コスト: 30分でマクロ作成可能
|
||||
- [ ] デバッグ時間: --expand で即座に問題特定
|
||||
- [ ] エラー理解率: 初学者でも90%理解
|
||||
|
||||
## 🏆 **世界制覇への道**
|
||||
|
||||
この実装完了により、Nyashは:
|
||||
|
||||
1. **Lisp超越**: 型安全性と構造化でパワーアップ
|
||||
2. **Rust超越**: 学習コストとデバッグ性で圧勝
|
||||
3. **C++超越**: 安全性と開発効率で完全勝利
|
||||
4. **Nim超越**: Box統一でさらに直感的
|
||||
5. **Julia超越**: Python統合で科学計算も制覇
|
||||
|
||||
**世界最強マクロ言語**の地位を確立する!🌟
|
||||
|
||||
---
|
||||
|
||||
**🚀 Nyash Macro Revolution - Everything is Box, Everything is Macro!**
|
||||
|
||||
*目標:3週間で世界最強のマクロ言語を実現する*
|
||||
**Next**: [実装詳細](./IMPLEMENTATION.md) | [技術仕様](./TECHNICAL_SPEC.md)
|
||||
@ -0,0 +1,606 @@
|
||||
# Phase 16 Technical Specification: Box-Based Macro System
|
||||
|
||||
Date: 2025-09-19
|
||||
Version: 0.1.0
|
||||
Status: **DRAFT** - 実装前仕様
|
||||
|
||||
## 🏗️ **アーキテクチャ概要**
|
||||
|
||||
### **システム構成**
|
||||
```
|
||||
Nyash Source Code
|
||||
↓
|
||||
Lexer/Parser
|
||||
↓
|
||||
Raw AST
|
||||
↓
|
||||
┌─────────────────────┐
|
||||
│ Macro Expansion │ ← 新規実装部分
|
||||
│ ┌───────────────┐ │
|
||||
│ │ AST Pattern │ │ ← Phase 1
|
||||
│ │ Matching │ │
|
||||
│ └───────────────┘ │
|
||||
│ ┌───────────────┐ │
|
||||
│ │ Quote/Unquote │ │ ← Phase 2
|
||||
│ │ System │ │
|
||||
│ └───────────────┘ │
|
||||
│ ┌───────────────┐ │
|
||||
│ │ HIR Patch │ │ ← Phase 3
|
||||
│ │ Engine │ │
|
||||
│ └───────────────┘ │
|
||||
└─────────────────────┘
|
||||
↓
|
||||
Expanded AST
|
||||
↓
|
||||
MIR Lowering ← 既存システム(無変更)
|
||||
↓
|
||||
MIR14 Instructions
|
||||
↓
|
||||
VM/JIT/AOT Execution
|
||||
```
|
||||
|
||||
## 🎯 **Phase 1: AST Pattern Matching**
|
||||
|
||||
### **新規AST構造体**
|
||||
|
||||
#### **PatternAst**
|
||||
```rust
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PatternAst {
|
||||
// 基本パターン
|
||||
Wildcard { span: Span }, // _
|
||||
Identifier { name: String, span: Span }, // variable
|
||||
Literal { value: LiteralValue, span: Span }, // 42, "hello"
|
||||
|
||||
// 構造パターン
|
||||
BoxPattern {
|
||||
name: String, // BoxDeclaration
|
||||
fields: Vec<FieldPattern>, // { field1, field2, .. }
|
||||
span: Span,
|
||||
},
|
||||
|
||||
// 配列パターン
|
||||
ArrayPattern {
|
||||
elements: Vec<PatternAst>, // [first, second, ...]
|
||||
rest: Option<String>, // ...rest
|
||||
span: Span,
|
||||
},
|
||||
|
||||
// OR パターン
|
||||
OrPattern {
|
||||
patterns: Vec<PatternAst>, // pattern1 | pattern2
|
||||
span: Span,
|
||||
},
|
||||
|
||||
// バインドパターン
|
||||
BindPattern {
|
||||
name: String, // @variable
|
||||
pattern: Box<PatternAst>, // @var pattern
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FieldPattern {
|
||||
pub name: String,
|
||||
pub pattern: PatternAst,
|
||||
pub span: Span,
|
||||
}
|
||||
```
|
||||
|
||||
#### **MatchExpression**
|
||||
```rust
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MatchExpression {
|
||||
pub target: Box<ASTNode>, // match対象
|
||||
pub arms: Vec<MatchArm>, // マッチアーム
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MatchArm {
|
||||
pub pattern: PatternAst, // パターン
|
||||
pub guard: Option<Box<ASTNode>>, // if guard
|
||||
pub body: Vec<ASTNode>, // 実行文
|
||||
pub span: Span,
|
||||
}
|
||||
```
|
||||
|
||||
### **パターンマッチング構文**
|
||||
|
||||
#### **基本構文**
|
||||
```nyash
|
||||
match ast_node {
|
||||
BoxDeclaration { name, fields, .. } => {
|
||||
// Box宣言の処理
|
||||
}
|
||||
FunctionDeclaration { name: "main", .. } => {
|
||||
// main関数の特別処理
|
||||
}
|
||||
_ => {
|
||||
// その他
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **高度なパターン**
|
||||
```nyash
|
||||
match ast_node {
|
||||
// 束縛パターン
|
||||
BoxDeclaration { name: @box_name, fields: [first, ...rest] } => {
|
||||
// box_nameにnameをバインド
|
||||
// firstに最初のフィールド、restに残り
|
||||
}
|
||||
|
||||
// ORパターン
|
||||
Literal { value: IntegerValue | StringValue } => {
|
||||
// 整数または文字列リテラル
|
||||
}
|
||||
|
||||
// ガード
|
||||
BoxDeclaration { fields } if fields.length > 5 => {
|
||||
// フィールドが5個より多いBox
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **実装詳細**
|
||||
|
||||
#### **Parser拡張**
|
||||
```rust
|
||||
impl NyashParser {
|
||||
/// match式のパース
|
||||
pub fn parse_match_expression(&mut self) -> Result<MatchExpression, ParseError> {
|
||||
self.consume(TokenType::MATCH)?;
|
||||
let target = self.parse_expression()?;
|
||||
self.consume(TokenType::LBRACE)?;
|
||||
|
||||
let mut arms = Vec::new();
|
||||
while !self.match_token(&TokenType::RBRACE) {
|
||||
arms.push(self.parse_match_arm()?);
|
||||
}
|
||||
|
||||
self.consume(TokenType::RBRACE)?;
|
||||
Ok(MatchExpression { target: Box::new(target), arms, span: Span::unknown() })
|
||||
}
|
||||
|
||||
/// パターンのパース
|
||||
pub fn parse_pattern(&mut self) -> Result<PatternAst, ParseError> {
|
||||
// パターン実装...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **PatternMatcher**
|
||||
```rust
|
||||
pub struct PatternMatcher {
|
||||
bindings: HashMap<String, ASTNode>,
|
||||
}
|
||||
|
||||
impl PatternMatcher {
|
||||
/// パターンマッチング実行
|
||||
pub fn match_pattern(&mut self, pattern: &PatternAst, value: &ASTNode) -> bool {
|
||||
match (pattern, value) {
|
||||
(PatternAst::Wildcard { .. }, _) => true,
|
||||
|
||||
(PatternAst::Identifier { name, .. }, value) => {
|
||||
self.bindings.insert(name.clone(), value.clone());
|
||||
true
|
||||
}
|
||||
|
||||
(PatternAst::BoxPattern { name, fields, .. },
|
||||
ASTNode::BoxDeclaration { name: box_name, fields: box_fields, .. }) => {
|
||||
if name == box_name {
|
||||
self.match_fields(fields, box_fields)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// その他のパターン...
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🎯 **Phase 2: Quote/Unquote System**
|
||||
|
||||
### **新規AST構造体**
|
||||
|
||||
#### **QuoteExpression**
|
||||
```rust
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct QuoteExpression {
|
||||
pub template: Vec<ASTNode>, // テンプレート
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UnquoteExpression {
|
||||
pub template: Box<QuoteExpression>, // 展開するテンプレート
|
||||
pub substitutions: HashMap<String, ASTNode>, // 置換マップ
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
// テンプレート内の変数展開
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TemplateVariable {
|
||||
pub name: String, // $(variable_name)
|
||||
pub span: Span,
|
||||
}
|
||||
```
|
||||
|
||||
### **Quote/Unquote構文**
|
||||
|
||||
#### **基本構文**
|
||||
```nyash
|
||||
// コードテンプレート作成
|
||||
let template = quote! {
|
||||
$(method_name)(other) {
|
||||
return me.$(field_name).equals(other.$(field_name))
|
||||
}
|
||||
}
|
||||
|
||||
// テンプレート展開
|
||||
let generated = unquote! {
|
||||
template with {
|
||||
method_name: "equals",
|
||||
field_name: "name"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **高度な展開**
|
||||
```nyash
|
||||
// リスト展開
|
||||
let field_comparisons = quote! {
|
||||
$(for field in fields) {
|
||||
me.$(field.name).equals(other.$(field.name))
|
||||
}
|
||||
}
|
||||
|
||||
// 条件展開
|
||||
let method_body = quote! {
|
||||
$(if has_fields) {
|
||||
return $(field_comparisons)
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **実装詳細**
|
||||
|
||||
#### **TemplateEngine**
|
||||
```rust
|
||||
pub struct TemplateEngine {
|
||||
substitutions: HashMap<String, ASTNode>,
|
||||
}
|
||||
|
||||
impl TemplateEngine {
|
||||
/// テンプレート展開
|
||||
pub fn expand_template(&self, template: &QuoteExpression) -> Result<Vec<ASTNode>, MacroError> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
for node in &template.template {
|
||||
match self.expand_node(node)? {
|
||||
ExpandResult::Single(n) => result.push(n),
|
||||
ExpandResult::Multiple(nodes) => result.extend(nodes),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// 単一ノード展開
|
||||
fn expand_node(&self, node: &ASTNode) -> Result<ExpandResult, MacroError> {
|
||||
match node {
|
||||
ASTNode::TemplateVariable { name, .. } => {
|
||||
if let Some(substitution) = self.substitutions.get(name) {
|
||||
Ok(ExpandResult::Single(substitution.clone()))
|
||||
} else {
|
||||
Err(MacroError::UnboundVariable(name.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
// 再帰的展開
|
||||
_ => self.expand_node_recursive(node),
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🎯 **Phase 3: HIRパッチ式マクロエンジン**
|
||||
|
||||
### **MacroEngine Core**
|
||||
|
||||
#### **MacroRegistry**
|
||||
```rust
|
||||
pub struct MacroRegistry {
|
||||
derive_macros: HashMap<String, Box<dyn DeriveMacro>>,
|
||||
attribute_macros: HashMap<String, Box<dyn AttributeMacro>>,
|
||||
function_macros: HashMap<String, Box<dyn FunctionMacro>>,
|
||||
}
|
||||
|
||||
impl MacroRegistry {
|
||||
pub fn register_derive<T: DeriveMacro + 'static>(&mut self, name: &str, macro_impl: T) {
|
||||
self.derive_macros.insert(name.to_string(), Box::new(macro_impl));
|
||||
}
|
||||
|
||||
pub fn expand_derive(&self, name: &str, input: &BoxDeclaration) -> Result<Vec<ASTNode>, MacroError> {
|
||||
if let Some(macro_impl) = self.derive_macros.get(name) {
|
||||
macro_impl.expand(input)
|
||||
} else {
|
||||
Err(MacroError::UnknownDeriveMacro(name.to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **DeriveMacro Trait**
|
||||
```rust
|
||||
pub trait DeriveMacro {
|
||||
/// derive マクロ展開
|
||||
fn expand(&self, input: &BoxDeclaration) -> Result<Vec<ASTNode>, MacroError>;
|
||||
|
||||
/// サポートする型チェック
|
||||
fn supports_box(&self, box_decl: &BoxDeclaration) -> bool {
|
||||
true // デフォルト:すべてのBoxをサポート
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **@derive実装例**
|
||||
|
||||
#### **EqualsDeriveMacro**
|
||||
```rust
|
||||
pub struct EqualsDeriveMacro;
|
||||
|
||||
impl DeriveMacro for EqualsDeriveMacro {
|
||||
fn expand(&self, input: &BoxDeclaration) -> Result<Vec<ASTNode>, MacroError> {
|
||||
let method_name = "equals";
|
||||
let param_name = "other";
|
||||
|
||||
// フィールド比較の生成
|
||||
let field_comparisons = self.generate_field_comparisons(&input.fields)?;
|
||||
|
||||
// equals メソッドの生成
|
||||
let equals_method = ASTNode::FunctionDeclaration {
|
||||
name: method_name.to_string(),
|
||||
params: vec![param_name.to_string()],
|
||||
body: vec![
|
||||
ASTNode::Return {
|
||||
value: Some(Box::new(field_comparisons)),
|
||||
span: Span::unknown(),
|
||||
}
|
||||
],
|
||||
is_static: false,
|
||||
is_override: false,
|
||||
span: Span::unknown(),
|
||||
};
|
||||
|
||||
Ok(vec![equals_method])
|
||||
}
|
||||
|
||||
fn generate_field_comparisons(&self, fields: &[String]) -> Result<ASTNode, MacroError> {
|
||||
if fields.is_empty() {
|
||||
// フィールドなし:常にtrue
|
||||
return Ok(ASTNode::Literal {
|
||||
value: LiteralValue::Bool(true),
|
||||
span: Span::unknown(),
|
||||
});
|
||||
}
|
||||
|
||||
// フィールド比較の連鎖
|
||||
let mut comparison = self.generate_single_field_comparison(&fields[0])?;
|
||||
|
||||
for field in &fields[1..] {
|
||||
let field_comp = self.generate_single_field_comparison(field)?;
|
||||
comparison = ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::And,
|
||||
left: Box::new(comparison),
|
||||
right: Box::new(field_comp),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
}
|
||||
|
||||
Ok(comparison)
|
||||
}
|
||||
|
||||
fn generate_single_field_comparison(&self, field: &str) -> Result<ASTNode, MacroError> {
|
||||
// me.field.equals(other.field)
|
||||
Ok(ASTNode::MethodCall {
|
||||
object: Box::new(ASTNode::FieldAccess {
|
||||
object: Box::new(ASTNode::Me { span: Span::unknown() }),
|
||||
field: field.to_string(),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
method: "equals".to_string(),
|
||||
arguments: vec![
|
||||
ASTNode::FieldAccess {
|
||||
object: Box::new(ASTNode::Variable {
|
||||
name: "other".to_string(),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
field: field.to_string(),
|
||||
span: Span::unknown(),
|
||||
}
|
||||
],
|
||||
span: Span::unknown(),
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **TestMacro**
|
||||
```rust
|
||||
pub struct TestMacro;
|
||||
|
||||
impl AttributeMacro for TestMacro {
|
||||
fn expand(&self, input: &FunctionDeclaration) -> Result<Vec<ASTNode>, MacroError> {
|
||||
// テスト関数をテストレジストリに登録
|
||||
let register_call = ASTNode::MethodCall {
|
||||
object: Box::new(ASTNode::Variable {
|
||||
name: "TestRegistry".to_string(),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
method: "register".to_string(),
|
||||
arguments: vec![
|
||||
ASTNode::Literal {
|
||||
value: LiteralValue::String(input.name.clone()),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
ASTNode::Variable {
|
||||
name: input.name.clone(),
|
||||
span: Span::unknown(),
|
||||
}
|
||||
],
|
||||
span: Span::unknown(),
|
||||
};
|
||||
|
||||
Ok(vec![
|
||||
register_call,
|
||||
ASTNode::FunctionDeclaration {
|
||||
name: input.name.clone(),
|
||||
params: input.params.clone(),
|
||||
body: input.body.clone(),
|
||||
is_static: input.is_static,
|
||||
is_override: input.is_override,
|
||||
span: input.span.clone(),
|
||||
}
|
||||
])
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🛡️ **エラーハンドリング**
|
||||
|
||||
### **MacroError定義**
|
||||
```rust
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum MacroError {
|
||||
// パターンマッチングエラー
|
||||
PatternMismatch { expected: String, found: String },
|
||||
UnboundVariable(String),
|
||||
|
||||
// Quote/Unquoteエラー
|
||||
TemplateExpansionFailed(String),
|
||||
InvalidSubstitution { variable: String, reason: String },
|
||||
|
||||
// Deriveマクロエラー
|
||||
UnknownDeriveMacro(String),
|
||||
UnsupportedBoxType { derive_name: String, box_name: String },
|
||||
|
||||
// 一般エラー
|
||||
RecursionLimitExceeded,
|
||||
CircularDependency(Vec<String>),
|
||||
}
|
||||
```
|
||||
|
||||
### **エラーメッセージ**
|
||||
```rust
|
||||
impl MacroError {
|
||||
pub fn user_message(&self) -> String {
|
||||
match self {
|
||||
MacroError::UnknownDeriveMacro(name) => {
|
||||
format!("Unknown derive trait '{}'
|
||||
Available traits: Equals, ToString, Clone, Debug
|
||||
Did you mean 'ToString'?", name)
|
||||
}
|
||||
|
||||
MacroError::PatternMismatch { expected, found } => {
|
||||
format!("Pattern mismatch: expected {}, found {}", expected, found)
|
||||
}
|
||||
|
||||
_ => format!("Macro error: {:?}", self),
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🎨 **CLI統合**
|
||||
|
||||
### **新規コマンドオプション**
|
||||
|
||||
既に実装済み:
|
||||
```rust
|
||||
// src/cli.rs で確認済み
|
||||
.arg(
|
||||
Arg::new("expand")
|
||||
.long("expand")
|
||||
.help("Macro: enable macro engine and dump expansion traces")
|
||||
.action(clap::ArgAction::SetTrue)
|
||||
)
|
||||
.arg(
|
||||
Arg::new("run-tests")
|
||||
.long("run-tests")
|
||||
.help("Run tests: enable macro engine and inject test harness")
|
||||
.action(clap::ArgAction::SetTrue)
|
||||
)
|
||||
.arg(
|
||||
Arg::new("test-filter")
|
||||
.long("test-filter")
|
||||
.value_name("SUBSTR")
|
||||
.help("Only run tests whose name contains SUBSTR")
|
||||
)
|
||||
```
|
||||
|
||||
### **環境変数**
|
||||
```rust
|
||||
// マクロエンジン有効化
|
||||
NYASH_MACRO_ENABLE=1
|
||||
|
||||
// マクロ展開トレース
|
||||
NYASH_MACRO_TRACE=1
|
||||
|
||||
// テスト実行
|
||||
NYASH_TEST_RUN=1
|
||||
|
||||
// テストフィルタ
|
||||
NYASH_TEST_FILTER="substring"
|
||||
```
|
||||
|
||||
## 📊 **パフォーマンス要件**
|
||||
|
||||
### **目標指標**
|
||||
- **展開時間**: < 100ms(中規模プロジェクト)
|
||||
- **メモリ使用量**: < 20% 増加(ベースコンパイラ比)
|
||||
- **型チェック**: 100% コンパイル時
|
||||
- **エラー検出**: 100% コンパイル時
|
||||
|
||||
### **最適化戦略**
|
||||
1. **遅延展開**: 必要な時のみマクロ展開
|
||||
2. **キャッシュ**: 同一パターンの結果をキャッシュ
|
||||
3. **並列処理**: 独立なマクロの並列展開
|
||||
4. **メモリプール**: AST ノードの効率的割り当て
|
||||
|
||||
## 🚀 **実装順序**
|
||||
|
||||
### **Week 1-2: AST Pattern Matching**
|
||||
1. PatternAst構造体定義
|
||||
2. Parser拡張(match式)
|
||||
3. PatternMatcher実装
|
||||
4. 基本テストケース
|
||||
|
||||
### **Week 3-4: Quote/Unquote**
|
||||
1. QuoteExpression定義
|
||||
2. TemplateEngine実装
|
||||
3. 変数置換システム
|
||||
4. エラーハンドリング
|
||||
|
||||
### **Week 5-6: HIRパッチエンジン**
|
||||
1. MacroRegistry実装
|
||||
2. DeriveMacro trait定義
|
||||
3. EqualsDeriveMacro実装
|
||||
4. TestMacro実装
|
||||
|
||||
### **Week 7-8: 統合・最適化**
|
||||
1. CLI統合
|
||||
2. エラーメッセージ改善
|
||||
3. パフォーマンス最適化
|
||||
4. ドキュメント作成
|
||||
|
||||
---
|
||||
|
||||
**この仕様に基づいて、世界最強のBox-Basedマクロシステムを実装する!** 🌟
|
||||
Reference in New Issue
Block a user