# 機能設計書 18-Procクラス

## 概要

本ドキュメントは、mrubyにおけるProcクラスの機能設計を記述する。Procクラスは手続きオブジェクト（ブロック・ラムダ）の生成・呼び出し・環境キャプチャを提供する組み込み型クラスである。

### 本機能の処理概要

Procクラスは、コードブロックをオブジェクトとして扱う機能を提供する。ISO 15.2.17に準拠し、ブロック（Proc）とラムダの2種類の手続きオブジェクトをサポートする。Procオブジェクトは、生成時のローカル変数のバインディング（クロージャ環境）をキャプチャし、後から呼び出し可能にする。RProc構造体はirep（コンパイル済みバイトコード）またはC関数ポインタのいずれかを本体として持ち、REnv構造体で環境（スタック）を管理する。

**業務上の目的・背景**：手続きオブジェクトは、コールバック、イテレータのブロック引数、遅延評価、関数型プログラミングスタイルの実装基盤として不可欠な機能である。ブロック構文（`{ |x| ... }`や`do...end`）はRubyの最も特徴的な言語機能であり、Enumerableの各メソッドもProcオブジェクトを通じてブロックを受け取る。

**機能の利用シーン**：ブロック引数の受け渡し（`&block`）、Proc.new/lambdaによる手続きオブジェクト生成、コールバック関数の登録、イテレータのブロック、C関数のラッピング等。

**主要な処理内容**：
1. Procオブジェクトの生成（ブロックからの生成、Proc.new、lambda）
2. Procの呼び出し（call、[]）
3. クロージャ環境のキャプチャ（REnv構造体によるスタックの保存）
4. C関数のProcラッピング（mrb_proc_new_cfunc）
5. 環境の共有解除（mrb_env_unshare）
6. upper（親Proc）チェーンによるスコープ管理
7. ターゲットクラスの管理
8. メソッドテーブルへのProcの登録

**関連システム・外部連携**：VMのメソッドディスパッチ、コールスタック管理、irep（コンパイル済みバイトコード）、Enumerableの各メソッド、Kernel#lambda等。

**権限による制御**：Procのアロケータは未定義化されている（MRB_UNDEF_ALLOCATOR）。Proc.newはブロック引数からのみ生成可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | CLIベースのランタイム機能のため関連画面なし |

## 機能種別

データ操作 / 制御フロー / クロージャ管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| block | Block | Yes（Proc.new） | キャプチャするブロック | ブロックなしでArgumentError |
| irep | mrb_irep* | Yes（C API） | コンパイル済みバイトコード | NULL可 |
| func | mrb_func_t | Yes（cfunc） | C関数ポインタ | NULL不可 |
| args | Object | No（call） | Proc呼び出し時の引数 | なし |

### 入力データソース

ブロック構文、Proc.new、lambda式、C APIからの生成。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Proc | Proc | 生成された手続きオブジェクト |
| 戻り値 | Object | call/[] によるProc呼び出しの結果 |

### 出力先

呼び出し元への戻り値として返却。

## 処理フロー

### 処理シーケンス

```
1. Procオブジェクトの生成
   └─ RProc構造体の割り当て
   └─ bodyの設定（irep or cfunc）
   └─ upper（親Proc）の設定
   └─ ターゲットクラスの設定
   └─ クロージャ環境の設定（必要時）
       └─ closure_setup: REnv構造体の生成/参照
2. Procの呼び出し（call/[]）
   └─ OP_CALL オペコードの実行
   └─ コールスタックにフレーム追加
   └─ 本体の実行（irep or cfunc）
   └─ 結果の返却
3. 環境管理
   └─ REnv: スタックの参照を保持
   └─ mrb_env_unshare: コールフレームとの共有解除
   └─ MRB_ENV_CLOSE: コンテキスト参照をNULLに
```

### フローチャート

```mermaid
flowchart TD
    A[Proc生成要求] --> B{生成方法?}
    B -->|ブロック| C[mrb_proc_new + closure_setup]
    B -->|C関数| D[mrb_proc_new_cfunc]
    B -->|lambda| E[proc_lambda + MRB_PROC_STRICT]
    C --> F[RProc 構造体返却]
    D --> F
    E --> F

    G[Proc.call呼び出し] --> H{本体の種類?}
    H -->|irep| I[VM バイトコード実行]
    H -->|cfunc| J[C 関数呼び出し]
    I --> K[結果返却]
    J --> K
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-18-01 | クロージャ | Procは生成時のローカル変数環境をキャプチャする | Proc生成時 |
| BR-18-02 | ブロック/ラムダ区別 | lambdaは引数チェックが厳密、returnの挙動も異なる | Proc呼び出し時 |
| BR-18-03 | call_irep | call/[]はOP_CALLオペコード1つの静的irepを使用 | call/[]呼び出し時 |
| BR-18-04 | アロケータ未定義 | Proc.allocateは使用不可 | 常時 |
| BR-18-05 | upper チェーン | Proc.upperでスコープチェーンを辿る | スコープ解決時 |
| BR-18-06 | 環境共有 | REnvのstackはコールフレームと共有される場合がある | クロージャ環境管理 |

### 計算ロジック

- **bidx計算**: `bidx = 1 + (n==15 ? 1 : n) + (nk==15 ? 1 : 2*nk)` でブロック引数位置を算出
- **call_irep**: `OP_CALL` 1命令のみの静的irep（コンパイル不要）

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

該当なし（インメモリ操作のみ）。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ArgumentError | Proc.newにブロックなし | ブロックを渡す |
| - | ArgumentError | lambdaで引数の数が不一致 | 正しい引数数で呼び出す |
| - | LocalJumpError | ブロック外のProc内でreturn（非lambda） | lambdaを使用する |

### リトライ仕様

該当なし。

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

該当なし。

## パフォーマンス要件

- call_irepは静的定数（コンパイル不要、GC不要）
- RProc/REnvはGC管理対象
- クロージャ環境の遅延コピー（on-stack → off-stack）

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

- 環境キャプチャによりスコープ外の変数にアクセス可能（設計上の仕様）
- orphanプロック（上位スコープが終了したProc）の安全な処理

## 備考

- ISO 15.2.17に準拠
- MRB_PROC_CFUNC_FL: C関数Procフラグ
- MRB_PROC_STRICT: lambda（厳密モード）フラグ
- MRB_PROC_ORPHAN: 親スコープ終了済みフラグ
- MRB_PROC_ALIAS: メソッドエイリアスフラグ

---

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

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

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | proc.h | `include/mruby/proc.h` | RProc, REnv構造体、各種フラグマクロ |

**読解のコツ**: RProcのbodyは共用体で`irep`（バイトコード）、`func`（C関数）、`mid`（エイリアス用シンボル）の3形態。flags のMRB_PROC_CFUNC_FL（128）でC関数かirepかを判定する。REnvのstackはコールフレームのスタックを直接参照し、`cxt`がNULLでない間はon-stack状態。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | proc.c | `src/proc.c` | `mrb_init_proc()`関数（557行目）でクラス定義 |

**主要処理フロー**:
1. **557-572行目**: Procクラス定義、Proc.new登録、call/[]メソッド登録、Kernel#lambda登録

#### Step 3: Proc生成と環境管理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | proc.c | `src/proc.c` | mrb_proc_new, mrb_env_new, closure_setup |

**主要処理フロー**:
- **17-19行目**: call_iseq - OP_CALL 1命令の静的命令列
- **21-37行目**: call_irep - call用の静的irep定義
- **39-43行目**: call_proc - 静的Procオブジェクト（frozen、GC RED）
- **45-70行目**: mrb_proc_new - irep からのProc生成（upper/target_class設定）
- **72-92行目**: mrb_env_new - 環境オブジェクトの生成（bidx計算あり）
- **94-100行目**: closure_setup - クロージャ環境の設定

#### Step 4: メソッドとProcの関係を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | proc.h | `include/mruby/proc.h` | MRB_METHOD_* マクロ群（117-137行目） |

**主要処理フロー**:
- **117-137行目**: mrb_method_t構造体の操作マクロ群
  - MRB_METHOD_FROM_FUNC: C関数からメソッド生成
  - MRB_METHOD_FROM_PROC: Procからメソッド生成
  - MRB_METHOD_VISIBILITY: 可視性管理

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

```
mrb_init_proc()
    |
    +-- mrb_define_class_id(Proc)
    +-- MRB_UNDEF_ALLOCATOR(Proc)
    +-- mrb_define_class_method_id(new, mrb_proc_s_new)
    +-- MRB_MT_INIT_ROM(proc_rom_entries)
    +-- mrb_define_method_raw(call, call_proc)
    +-- mrb_define_method_raw([], call_proc)
    +-- mrb_define_private_method_id(lambda, proc_lambda)

Proc生成:
    mrb_proc_new(irep)
        |
        +-- MRB_OBJ_ALLOC(MRB_TT_PROC)
        +-- ci->proc (upper設定)
        +-- target_class設定
        +-- mrb_irep_incref (参照カウント増)
        |
        +-- closure_setup
                |
                +-- mrb_env_new (REnv生成)
                +-- MRB_PROC_ENVSET フラグ設定
```

### データフロー図

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

ブロック/irep        mrb_proc_new                       RProc オブジェクト
/C関数        ---->   + closure_setup              ---->  (irep + REnv)
                       |
Proc.call        OP_CALL → VM実行                   呼び出し結果
             ---->   or C関数呼び出し              ---->  mrb_value
                       |
                     REnv: スタック参照管理
                     MRB_ENV_CLOSE: 参照解除
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| proc.c | `src/proc.c` | ソース（C） | Procクラスの主要実装（573行） |
| proc.h | `include/mruby/proc.h` | ヘッダ | RProc/REnv構造体とC API |
| irep.h | `include/mruby/irep.h` | ヘッダ | irep（命令列）構造体定義 |
| vm.c | `src/vm.c` | ソース（C） | OP_CALLの実行処理 |
