# 機能設計書 57-マクロ展開

## 概要

本ドキュメントは、Julia の `macroexpand` / `@macroexpand` / `@macroexpand1` によるマクロ展開結果の確認機能の設計を記述する。

### 本機能の処理概要

本機能は、マクロが含まれる式を展開し、マクロ呼び出しが除去された等価な式を取得する機能を提供する。マクロのデバッグ、動作理解、生成コードの確認に使用される。再帰的展開（全てのネストしたマクロを展開）と非再帰的展開（最外側のマクロのみ展開）の両方をサポートする。

**業務上の目的・背景**: マクロは強力なコード生成機構だが、展開結果が不透明になりがちである。マクロの動作をデバッグしたり、生成されるコードを理解したりするために、展開結果を確認する手段が必要不可欠。特に複雑なマクロや複数のマクロがネストしている場合に有用。

**機能の利用シーン**: マクロ開発時のデバッグ、マクロの動作理解、生成コードの最適化確認、教育・ドキュメント目的でのマクロ展開結果の表示。

**主要な処理内容**:
1. `macroexpand(m::Module, x; recursive=true)` による式のマクロ展開
2. `macroexpand!(m::Module, x; recursive=true)` による式のin-placeマクロ展開
3. `@macroexpand ex` による再帰的マクロ展開（呼び出し元モジュールで展開）
4. `@macroexpand1 ex` による非再帰的マクロ展開（最外側のみ）
5. `@macroexpand mod, ex` による指定モジュールでの展開

**関連システム・外部連携**: C ランタイムの `jl_macroexpand` 関数、lowering フェーズのマクロ展開処理。

**権限による制御**: 特に権限制御は行われない。

## 関連画面

本機能は GUI 画面を持たないライブラリ機能であり、直接的に関連する画面はない。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | REPL から @macroexpand を呼び出してマクロ展開結果を確認 |

## 機能種別

デバッグ支援（コード解析）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| m | Module | Yes (macroexpand) | マクロを展開するモジュールコンテキスト | 有効な Module |
| x | Any | Yes | マクロ展開対象の式 | 任意（Expr でなくてもよい） |
| recursive | Bool | No | 再帰的に全マクロを展開するか。デフォルト true | Bool |
| legacyscope | Bool | No | レガシーマクロスコープ展開を行うか | Bool |

### 入力データソース

ユーザーが提供する Julia の式（Expr）。`@macroexpand` の場合は引数がパース済み AST として渡される。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 展開後の式 | Any | 全てのマクロが展開された後の式 |

### 出力先

関数/マクロの戻り値として呼び出し元に返却。

## 処理フロー

### 処理シーケンス

```
1. マクロ展開の開始
   └─ macroexpand(m, x) または @macroexpand ex
2. C ランタイム呼び出し
   └─ ccall(:jl_macroexpand, Any, (Any, Any, Cint, Cint, Cint), x, m, recursive, inplace, legacyscope)
3. マクロ関数の検索と呼び出し
   └─ Expr(:macrocall, ...) ノードを検出
   └─ 対応するマクロ関数をモジュール m で解決
   └─ マクロ関数を呼び出し、結果の式で置換
4. ハイジーン処理
   └─ マクロ内の変数名にスコープ情報を付与
5. 再帰展開（recursive=true の場合）
   └─ 展開結果に含まれるマクロ呼び出しを再度展開
   └─ 全てのマクロが除去されるまで繰り返し
6. 結果返却
   └─ 展開後の式を返却
```

### フローチャート

```mermaid
flowchart TD
    A["@macroexpand @time f(x)"] --> B["QuoteNode で式をクォート"]
    B --> C["macroexpand(__module__, expr)"]
    C --> D["ccall(:jl_macroexpand, ...)"]
    D --> E{"Expr(:macrocall) を検出?"}
    E -->|Yes| F["マクロ関数を解決・呼び出し"]
    F --> G["ハイジーン処理"]
    G --> H{recursive?}
    H -->|Yes| E
    H -->|No| I["結果返却"]
    E -->|No| I
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-57-1 | モジュールコンテキスト | @macroexpand は呼び出し元モジュールで展開。macroexpand は指定モジュールで展開 | 常時 |
| BR-57-2 | 再帰展開 | @macroexpand はデフォルトで再帰展開。@macroexpand1 は非再帰 | 常時 |
| BR-57-3 | in-place展開 | macroexpand! は入力式を変更（コピーなし）。macroexpand はコピーを作成 | macroexpand! 使用時 |
| BR-57-4 | legacyscope | macroexpand はデフォルト legacyscope=true。macroexpand! はデフォルト false | 各関数のデフォルト |

### 計算ロジック

特別な計算ロジックは存在しない。マクロ関数の呼び出しと式の置換が主要な処理。

## データベース操作仕様

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | LoadError | マクロ展開中にエラーが発生 | マクロ実装のデバッグ |
| - | UndefVarError | マクロが参照するシンボルが未定義 | 適切なモジュールを指定 |
| - | MethodError | マクロ関数のシグネチャ不一致 | マクロ呼び出し構文を修正 |

### リトライ仕様

該当なし。

## トランザクション仕様

該当なし。

## パフォーマンス要件

- マクロ展開は通常高速（式のツリー変換のみ）
- 深くネストしたマクロの再帰展開では呼び出し回数に比例したコスト

## セキュリティ考慮事項

マクロ展開はマクロ本体のコードを実行するため、信頼できないマクロの展開には注意が必要。

## 備考

- `@macroexpand` と `macroexpand` ではモジュールコンテキストの扱いが異なるため注意（M.f() の例を参照）
- Julia 1.11 で @macroexpand の 2 引数形式（モジュール指定）が追加された
- `macroexpand!` は Julia の新しい API で、効率的な in-place 展開を提供

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: 公開 API を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | expr.jl | `base/expr.jl` | macroexpand 関数（206-208行目）: ccall(:jl_macroexpand) を呼び出し。recursive, inplace=false, legacyscope パラメータ |
| 1-2 | expr.jl | `base/expr.jl` | macroexpand! 関数（226-228行目）: ccall(:jl_macroexpand) を inplace=true で呼び出し |
| 1-3 | expr.jl | `base/expr.jl` | @macroexpand マクロ（273-278行目）: QuoteNode で式をクォートし macroexpand を呼び出し。1引数・2引数版 |
| 1-4 | expr.jl | `base/expr.jl` | @macroexpand1 マクロ（285-290行目）: recursive=false で macroexpand を呼び出し |

**読解のコツ**: `@macroexpand` は式を QuoteNode で包んでから macroexpand に渡すため、式自体は評価されない。`$__module__` で呼び出し元のモジュールを取得している点に注目。2 引数版では `esc(mod)` で明示的にモジュールを指定。

#### Step 2: C ランタイム実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ast.c | `src/ast.c` | jl_macroexpand のC実装（本調査では未詳細確認）。recursive フラグに基づく再帰展開ロジック |

**主要処理フロー**:
- **207行目**: `ccall(:jl_macroexpand, Any, (Any, Any, Cint, Cint, Cint), x, m, recursive, false, legacyscope)` - コピー版
- **227行目**: `ccall(:jl_macroexpand, Any, (Any, Any, Cint, Cint, Cint), x, m, recursive, true, legacyscope)` - in-place版
- **274行目**: `macroexpand($__module__, $(QuoteNode(code)); recursive=true, legacyscope=true)` - @macroexpand の展開結果

### プログラム呼び出し階層図

```
@macroexpand ex
    │
    └─ macroexpand(__module__, QuoteNode(ex); recursive=true, legacyscope=true)
           │
           └─ ccall(:jl_macroexpand, Any, ...)
                  │
                  ├─ Expr(:macrocall, ...) ノードを検出
                  ├─ マクロ関数を解決
                  ├─ マクロ関数を呼び出し
                  ├─ ハイジーン処理
                  └─ recursive ? 再帰展開 : 結果返却

@macroexpand1 ex
    └─ macroexpand(__module__, QuoteNode(ex); recursive=false, legacyscope=true)

macroexpand!(m, x)
    └─ ccall(:jl_macroexpand, ..., inplace=true)
```

### データフロー図

```
[入力]                       [処理]                          [出力]

@macroexpand @time f(x)   → QuoteNode(:(@time f(x)))      → 展開後の式
                             macroexpand(Main, ...)           (begin
                             ccall(:jl_macroexpand)              local val = ...
                             マクロ関数呼び出し                    elapsed = ...
                             ハイジーン処理                        val
                                                               end)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| expr.jl | `base/expr.jl` | ソース | macroexpand, macroexpand!, @macroexpand, @macroexpand1 の実装 |
| ast.c | `src/ast.c` | ソース (C) | jl_macroexpand の C ランタイム実装 |
| meta.jl | `base/meta.jl` | ソース | Meta モジュールでの式操作ユーティリティ |
