# 機能設計書 65-eval関数

## 概要

本ドキュメントは、mrubyにおけるeval関数の設計を記述する。mruby-eval gemとして実装され、文字列をRubyコードとして動的に評価する機能を提供する。

### 本機能の処理概要

eval関数は、文字列として渡されたRubyソースコードを実行時にコンパイル・評価する機能を提供する。Kernel#eval、BasicObject#instance_eval（文字列版）、Module#class_eval/module_eval（文字列版）、Binding#evalの各メソッドを実装する。mruby-compilerに依存し、パーサとコード生成器を使用してソースコードをバイトコード（irep）に変換し、VMで実行する。

**業務上の目的・背景**：動的なコード生成・実行は、テンプレートエンジン、設定ファイルの評価、REPLの実装等に不可欠である。mrubyでもevalを提供することで、柔軟なスクリプティング環境を実現する。

**機能の利用シーン**：対話型シェル（mirb）でのコード評価、設定ファイルのDSL評価、テストフレームワークでの動的テスト生成、デバッガでの式評価等で使用される。

**主要な処理内容**：
1. 文字列のパース（mrb_parse_nstring）
2. バイトコード生成（mrb_generate_code）
3. スコープ連鎖の設定（upper proc、環境変数の引き継ぎ）
4. バイトコードの実行（mrb_exec_irep）
5. Bindingコンテキストでの評価（ローカル変数空間の拡張）
6. instance_evalでのレシーバコンテキスト切り替え
7. class_eval/module_evalでのクラスコンテキスト切り替え

**関連システム・外部連携**：mruby-compiler（パーサ・コード生成器）、mruby-binding（Bindingオブジェクト）に依存。

**権限による制御**：evalはprivateメソッドとして定義される。instance_evalはレシーバのシングルトンクラスコンテキストで実行。

## 関連画面

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

## 機能種別

動的コード評価

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| string | String | Yes | 評価するRubyソースコード | 構文エラーがないこと |
| binding | Binding | No | 評価コンテキスト | Bindingオブジェクトであること |
| filename | String | No | エラー報告用ファイル名（デフォルト"(eval)"） | UINT16_MAX未満の長さ |
| lineno | Integer | No | エラー報告用行番号（デフォルト1） | 正の整数 |

### 入力データソース

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

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 評価結果 | Object | evalした式の最後の値 |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. 引数の解析
   └─ 文字列、binding、ファイル名、行番号を取得
2. Binding前処理（あれば）
   └─ binding_eval_prepare()でローカル変数空間を拡張
3. Procの生成
   └─ create_proc_from_string()で文字列をコンパイル
       a. mrb_ccontext_new()でコンパイルコンテキスト作成
       b. mrb_parse_nstring()でパース
       c. mrb_generate_code()でバイトコード生成
       d. upper proc / 環境のリンク
4. IRePの実行
   └─ eval_irep()でバイトコードを実行
5. 結果の返却
```

### フローチャート

```mermaid
flowchart TD
    A[eval呼び出し] --> B{Binding引数あり?}
    B -->|Yes| C[binding_eval_prepare]
    B -->|No| D[呼び出し元のスコープを使用]
    C --> E[create_proc_from_string]
    D --> E
    E --> F[mrb_parse_nstring]
    F --> G{パースエラー?}
    G -->|Yes| H[SyntaxError]
    G -->|No| I[mrb_generate_code]
    I --> J{コード生成エラー?}
    J -->|Yes| K[ScriptError]
    J -->|No| L[upper proc / 環境リンク]
    L --> M[eval_irep]
    M --> N[結果返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-65-01 | スコープ継承 | evalコードは呼び出し元のスコープ（ローカル変数）を継承する | 全eval系メソッド |
| BR-65-02 | Binding拡張 | Binding経由のevalでは新しいローカル変数を追加可能 | binding.eval時 |
| BR-65-03 | instance_evalコンテキスト | instance_evalではselfがレシーバに切り替わる | instance_eval時 |
| BR-65-04 | class_evalコンテキスト | class_evalではメソッド定義がそのクラスに追加される | class_eval/module_eval時 |

### 計算ロジック

create_proc_from_string()内でcompiler contextのno_optimizeをTRUEに設定し、最適化を無効にしてデバッグ性を確保する。

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | SyntaxError | 構文エラーのあるコード | コードの構文を修正 |
| - | ScriptError | コード生成エラー | コードの内容を確認 |
| - | TypeError | Binding以外がbinding引数に渡された | Bindingオブジェクトを使用 |
| - | RuntimeError | パーサ状態の生成失敗（メモリ不足） | メモリを確保 |
| - | ArgumentError | ファイル名が長すぎる（UINT16_MAX以上） | 短いファイル名を使用 |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

evalは実行時コンパイルを伴うため、頻繁な呼び出しはパフォーマンスに影響する。可能な場合はProcやメソッドの使用を推奨。

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

evalは任意のコードを実行できるため、信頼できない入力を直接evalしてはならない。

## 備考

- mruby-compilerに依存するため、コンパイラが利用可能な環境でのみ使用可能
- ブロック付きのinstance_eval/class_evalは、evalなしの既存VM実装（mrb_obj_instance_eval/mrb_mod_module_eval）に委譲

---

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

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

### 推奨読解順序

#### Step 1: コア関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | eval.c | `mrbgems/mruby-eval/src/eval.c` | create_proc_from_string()の処理フロー |

**主要処理フロー**:
- **22-140行目**: create_proc_from_string() - 文字列からProcを生成する中核関数
- **34-52行目**: Binding処理 - scopeとenvの取得
- **63-68行目**: コンパイルコンテキストの設定（no_optimize=TRUE）
- **71行目**: mrb_parse_nstring()でパース
- **103行目**: mrb_generate_code()でバイトコード生成
- **116-133行目**: 環境チェーンの設定（upper proc、env、target_class）

#### Step 2: eval_irepを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | eval.c | `mrbgems/mruby-eval/src/eval.c` | eval_irep()によるバイトコード実行 |

**主要処理フロー**:
- **142-155行目**: eval_irep() - callinfo設定後にmrb_exec_irep()を呼び出し
- **148-153行目**: n=0, nk=0でブロック引数なし、可視性ブレーク設定

#### Step 3: Binding連携を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | eval.c | `mrbgems/mruby-eval/src/eval.c` | binding_eval_prepare()とf_eval() |

**主要処理フロー**:
- **242-260行目**: binding_eval_prepare() - ローカル変数空間の拡張
- **280-300行目**: f_eval() - Kernel#evalのエントリーポイント
- **406-420行目**: mrb_binding_eval() - Binding#eval

#### Step 4: gem初期化を理解する

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

**主要処理フロー**:
- **422-432行目**: gem初期化 - eval, instance_eval, module_eval, class_eval, Binding#evalの登録

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

```
Kernel#eval(string, binding, file, line)
    |
    +-- binding_eval_prepare()  [Bindingあり時]
    |       +-- mrb_parse_nstring()
    |       +-- expand_lvspace()  ... ローカル変数拡張
    |
    +-- create_proc_from_string()
    |       +-- mrb_ccontext_new()
    |       +-- mrb_parse_nstring()
    |       +-- mrb_generate_code()
    |       +-- env/upper設定
    |
    +-- eval_irep()
            +-- mrb_exec_irep()  ... VM実行
```

### データフロー図

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

String (Ruby code)   ──▶ mrb_parse_nstring()    ──▶ AST
                              |
AST                  ──▶ mrb_generate_code()    ──▶ irep (バイトコード)
                              |
Binding (optional)   ──▶ env/scope設定          ──▶ RProc
                              |
RProc                ──▶ mrb_exec_irep()        ──▶ 評価結果 (mrb_value)
```

### 関連ファイル一覧

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