# 機能設計書 66-Bindingクラス

## 概要

本ドキュメントは、mrubyにおけるBindingクラスの設計を記述する。mruby-binding gemとして実装され、実行コンテキスト（ローカル変数のバインディング）をオブジェクトとして取得する機能を提供する。

### 本機能の処理概要

Bindingクラスは、Rubyの実行コンテキスト（ローカル変数、self、proc情報等）をファーストクラスオブジェクトとして捕捉する機能を提供する。Kernel#binding メソッドでBindingオブジェクトを生成し、eval()に渡してそのコンテキストでコードを評価したり、ローカル変数を直接操作したりできる。

**業務上の目的・背景**：テンプレートエンジン（ERB等）やデバッガにおいて、特定の実行コンテキストのスコープ情報を保存し、後から参照・操作する必要がある。Bindingオブジェクトはこの機能を実現する。

**機能の利用シーン**：テンプレートエンジンでの変数展開、デバッガでの式評価、eval()へのコンテキスト渡し、ローカル変数の動的取得・設定等で使用される。

**主要な処理内容**：
1. Bindingオブジェクトの生成（Kernel#binding）
2. ローカル変数の定義確認（local_variable_defined?）
3. ローカル変数の取得（local_variable_get）
4. ローカル変数の設定（local_variable_set）
5. ローカル変数一覧の取得（local_variables）
6. レシーバの取得（receiver）
7. ソース位置情報の取得（source_location）
8. Bindingのコピー（initialize_copy）

**関連システム・外部連携**：mruby-eval（eval機能での利用）に連携。

**権限による制御**：Kernel#bindingはprivateメソッド。new/allocateは使用不可。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | CLIベースのため画面なし |

## 機能種別

リフレクション / コンテキスト管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| symbol | Symbol | Yes (変数操作時) | ローカル変数名 | 小文字/アンダースコアで始まる識別子 |
| value | Object | Yes (set時) | 設定する値 | 型制約なし |

### 入力データソース

mrubyスクリプトからの直接呼び出し

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Binding | Binding | 実行コンテキストを保持するオブジェクト |
| 変数値 | Object | ローカル変数の値 |
| 変数一覧 | Array[Symbol] | ローカル変数名のSymbol配列 |
| ソース位置 | [String, Integer] | [ファイル名, 行番号] |

### 出力先

mruby値スタック上に結果を返却

## 処理フロー

### 処理シーケンス

```
1. Binding生成（Kernel#binding呼び出し）
   └─ mrb_f_binding() → mrb_binding_new()
       a. 呼び出し元のprocとenvを取得
       b. binding_wrap_lvspace()でローカル変数空間を作成
       c. proc/recv/envをインスタンス変数として設定
2. ローカル変数操作
   └─ binding_local_variable_search()でproc/envチェーンを走査
       a. 各irep.lvをチェックして変数名を検索
       b. 対応するenv->stackのスロットを返却
3. 変数の新規追加
   └─ mrb_proc_merge_lvar()でirepとenvに変数を追加
```

### フローチャート

```mermaid
flowchart TD
    A[Kernel#binding] --> B{C呼び出し元?}
    B -->|Yes| C[RuntimeError]
    B -->|No| D[呼び出し元のproc/env取得]
    D --> E[binding_wrap_lvspace]
    E --> F[lvspace proc + env生成]
    F --> G[Bindingオブジェクト生成]
    G --> H[proc/recv/envをIV設定]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-66-01 | Ruby呼び出し元限定 | C関数からの呼び出しではBindingを作成できない | binding呼び出し時 |
| BR-66-02 | 変数名規約 | 小文字またはアンダースコアで始まる識別子のみ | local_variable系メソッド |
| BR-66-03 | upper proc制限 | BINDING_UPPER_MAXを超えるネスト深度でエラー | binding生成時 |
| BR-66-04 | new/allocate不可 | Bindingクラスのnew/allocateは使用不可 | クラスメソッド呼び出し時 |
| BR-66-05 | フリーズ耐性 | local_variable_setはフリーズされたBindingのソースでも変数を変更できる（CRuby互換） | initialize_copy時 |

### 計算ロジック

ローカル変数空間（lvspace）はダミーのirepとenvで構成される。binding.evalやlocal_variable_setで新しい変数が追加されると、mrb_proc_merge_lvar()でirepのnlocalsとenvのstackが拡張される。

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | RuntimeError | C関数から呼ばれた場合 | Ruby関数から呼び出す |
| - | RuntimeError | upper procが多すぎる（BINDING_UPPER_MAX超過） | ネスト深度を減らす |
| - | NameError | 不正な変数名、未定義の変数のget | 変数名を確認 |
| - | TypeError | Bindingでないオブジェクトの操作 | Bindingオブジェクトを使用 |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

BINDING_UPPER_MAX（デフォルト20、最大100）でupper procチェーンの走査深度を制限。

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

Bindingオブジェクトは実行コンテキストの全ローカル変数へのアクセスを提供するため、信頼できないコードに渡してはならない。

## 備考

- BINDING_UPPER_MAXはMRB_BINDING_UPPER_MAXマクロで設定可能（10〜100の範囲）
- Bindingオブジェクトの内部はproc/recv/envの3つのインスタンス変数で管理

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | binding.c | `mrbgems/mruby-binding/src/binding.c` | Bindingオブジェクトの内部構造（proc/recv/env/pcインスタンス変数） |

**読解のコツ**:
- Bindingオブジェクトは通常のRObject（MRB_TT_OBJECT）で、proc/recv/env/pcの4つのインスタンス変数で管理
- **12-26行目**: BINDING_UPPER_MAX定数の設定（デフォルト20）
- **41-47行目**: mrb_binding_extract_proc() - procインスタンス変数の取得
- **49-60行目**: mrb_binding_extract_env() - envインスタンス変数の取得

#### Step 2: lvspace（ローカル変数空間）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | binding.c | `mrbgems/mruby-binding/src/binding.c` | binding_wrap_lvspaceの仕組み |

**主要処理フロー**:
- **62-75行目**: binding_irep_new_lvspace() - ダミーirepの生成（OP_RETURNのみ）
- **77-88行目**: binding_proc_new_lvspace() - ダミーRProcの生成
- **90-105行目**: binding_env_new_lvspace() - ダミーREnvの生成
- **138-149行目**: binding_wrap_lvspace() - proc + envを新しいlvspaceでラップ

#### Step 3: ローカル変数操作を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | binding.c | `mrbgems/mruby-binding/src/binding.c` | 変数検索と設定の仕組み |

**主要処理フロー**:
- **219-243行目**: binding_local_variable_search() - proc/envチェーンを走査してirep.lvから変数を検索
- **266-281行目**: binding_local_variable_defined_p()
- **306-320行目**: binding_local_variable_get()
- **336-357行目**: binding_local_variable_set() - 既存変数は直接更新、新規はmerge_lvar

#### Step 4: Binding生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | binding.c | `mrbgems/mruby-binding/src/binding.c` | mrb_f_binding()とmrb_binding_new() |

**主要処理フロー**:
- **440-456行目**: mrb_binding_new() - Bindingオブジェクトの生成。pcの保存、lvspaceのラップ
- **478-492行目**: mrb_f_binding() - Kernel#bindingのエントリーポイント。C関数からの呼び出しを拒否

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

```
Kernel#binding
    |
    +-- mrb_f_binding()
            +-- mrb_proc_get_caller()  ... 呼び出し元proc/env取得
            +-- mrb_binding_new()
                    +-- binding_wrap_lvspace()
                    |       +-- binding_proc_new_lvspace()
                    |       +-- binding_env_new_lvspace()
                    +-- mrb_obj_iv_set() x4  ... proc/recv/env/pc設定

binding.local_variable_get(:x)
    |
    +-- binding_local_variable_get()
            +-- mrb_binding_extract_proc/env()
            +-- binding_local_variable_search()
                    +-- irep.lv走査 ... 各スコープの変数テーブル検索
```

### データフロー図

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

呼び出し元のスコープ  ──▶ mrb_f_binding()           ──▶ Binding (proc/recv/env)
                              +-- wrap_lvspace

Binding + Symbol     ──▶ local_variable_search()   ──▶ 変数値 or NameError
                              +-- irep.lv走査

Binding + Symbol + val ──▶ local_variable_set()    ──▶ 設定値
                              +-- merge_lvar (新規時)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| binding.c | `mrbgems/mruby-binding/src/binding.c` | ソース | Bindingクラス全実装（519行） |
| mrbgem.rake | `mrbgems/mruby-binding/mrbgem.rake` | 設定 | gem仕様定義 |
| binding.rb | `mrbgems/mruby-binding/test/binding.rb` | テスト | Rubyテストケース |
| binding.c | `mrbgems/mruby-binding/test/binding.c` | テスト | Cテストケース |
