# 機能設計書 68-mrubyコンパイラ

## 概要

本ドキュメントは、mrubyにおけるコンパイラ（mruby-compiler gem）の設計を記述する。Rubyソースコードをパース（構文解析）してAST（抽象構文木）を生成し、そこからmrubyバイトコード（irep）を生成するコンパイルパイプラインを提供する。

### 本機能の処理概要

mrubyコンパイラは、Rubyソースコードの文字列をmruby VMが実行可能なバイトコード（命令シーケンス：iseq）に変換する2段階のコンパイルパイプラインを実装する。第1段階はパーサ（parse.y / y.tab.c）で、字句解析と構文解析を行いASTを構築する。第2段階はコードジェネレータ（codegen.c）で、ASTを走査してバイトコード命令を生成する。

**業務上の目的・背景**：mrubyで動的なスクリプト実行（eval、load等）を可能にするため、実行時にソースコードをバイトコードに変換する機能が必要である。また、mrbcコマンドによる事前コンパイル（AOT）もこのコンパイラを使用する。

**機能の利用シーン**：eval()での文字列コード評価、mrbcによる事前コンパイル、mirbでの対話的コード実行、プログラム起動時のソースファイルコンパイル等で使用される。

**主要な処理内容**：
1. 字句解析（lexer）：ソースコードをトークン列に変換
2. 構文解析（parser）：トークン列をAST（抽象構文木）に変換
3. コード生成（codegen）：ASTをバイトコード（irep）に変換
4. スコープ管理：ローカル変数、レジスタ割り当て、ネストされたスコープの管理
5. ループ処理：while/until/for/begin-rescueのbreak/next/redo対応
6. 例外ハンドラ：rescue/ensure用のcatch_table生成

**関連システム・外部連携**：mruby-eval（eval機能がコンパイラを使用）、mrbc（コマンドラインコンパイラ）に連携。

**権限による制御**：特になし。コンパイラ自体はmruby内部APIとして使用される。

## 関連画面

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

## 機能種別

コンパイラ / コード変換

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| source | const char* | Yes | Rubyソースコード文字列 | 構文的に正しいRubyコード |
| filename | const char* | No | エラー報告用ファイル名 | 文字列 |
| lineno | int | No | 開始行番号（デフォルト1） | 正の整数 |

### 入力データソース

mruby-eval、mrbc、mirb等からの内部API呼び出し

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| RProc* | struct RProc* | コンパイル結果のプロシージャ（irepを含む） |
| mrb_irep* | mrb_irep* | 命令シーケンス、リテラルプール、シンボルテーブル |

### 出力先

mrubyオブジェクトヒープ上にRProcとして返却

## 処理フロー

### 処理シーケンス

```
1. パース処理
   └─ mrb_parse_nstring() / mrb_parse_string()
       a. mrb_parser_new()でパーサ状態を初期化
       b. mrb_parser_parse()で構文解析
       c. ASTをparser_state->treeに格納
2. コード生成
   └─ mrb_generate_code()
       a. scope_new()でトップレベルスコープ作成
       b. codegen()でAST再帰走査
       c. 各ASTノードに対応するオペコードを生成
       d. scope_finish()でirepを完成
3. RProcの生成
   └─ mrb_proc_new()でirepをラップ
```

### フローチャート

```mermaid
flowchart TD
    A[ソースコード文字列] --> B[mrb_parse_nstring]
    B --> C[字句解析 lexer]
    C --> D[構文解析 parser]
    D --> E{パースエラー?}
    E -->|Yes| F[SyntaxError]
    E -->|No| G[AST tree]
    G --> H[mrb_generate_code]
    H --> I[scope_new]
    I --> J[codegen AST走査]
    J --> K{再帰深度超過?}
    K -->|Yes| L[codegen_error]
    K -->|No| M[オペコード生成]
    M --> N[scope_finish]
    N --> O[mrb_irep]
    O --> P[mrb_proc_new]
    P --> Q[RProc*]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-68-01 | 再帰深度制限 | MRB_CODEGEN_LEVEL_MAX（デフォルト256）を超える再帰でエラー | codegen再帰呼び出し時 |
| BR-68-02 | オペランド拡張 | 0xFFを超えるオペランドはOP_EXT1/2/3で拡張 | genop_1/genop_2呼び出し時 |
| BR-68-03 | no_ext_ops制限 | no_ext_opsオプション時は拡張オペコード使用不可 | コンパイルオプション設定時 |
| BR-68-04 | MAXARG_S制限 | 一部のオペコードでオペランドが(1<<16)を超えるとエラー | OP_SUPER等 |

### 計算ロジック

コード生成はcodegen_scope構造体でスコープ状態を管理する。各スコープにはiseq（命令バッファ）、pool（リテラルプール）、syms（シンボルテーブル）、reps（子irep）が含まれ、動的に拡張される。レジスタはsp（スタックポインタ）で管理し、nregsで最大使用数を追跡する。

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | SyntaxError | 構文エラー（パーサ段階） | ソースコードの構文を修正 |
| - | codegen_error | コード生成中のエラー（再帰深度超過等） | コードのネストを減らす |
| - | codegen_error | メモリ割り当て失敗 | メモリを確保 |
| - | codegen_error | OP_EXTs禁止時のオペランド超過 | no_ext_opsを無効にするかコードを簡素化 |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

- パーサはyacc/bisonで生成されたLALRパーサを使用し、線形時間でパース
- コードジェネレータのiseqバッファは倍増戦略で動的拡張（初期8、上限UINT32_MAX）
- メモリプール（mempool）を使用してスコープごとの割り当てを効率化

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

コンパイラ自体はコード実行を行わないが、生成されたバイトコードが任意のコードを実行可能にするため、evalと同様に信頼できない入力への適用は注意が必要。

## 備考

- パーサはparse.yからyaccで生成されたy.tab.cを使用
- 字句解析にはgperfで生成されたlex.defを使用
- ビルド時にyaccとgperfが必要
- codegen.cは7316行の大規模ファイル

---

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

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

### 推奨読解順序

#### Step 1: ASTノード定義を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | node.h | `mrbgems/mruby-compiler/core/node.h` | enum node_typeのノード種別一覧 |

**読解のコツ**:
- **10-97行目**: enum node_type - 約90種類のASTノード種別を定義
- NODE_SCOPE, NODE_BLOCK等の制御構造ノード
- NODE_CALL, NODE_SUPER等のメソッド呼び出しノード
- NODE_LVAR, NODE_IVAR等の変数ノード
- NODE_CASE_MATCH, NODE_PAT_*等のパターンマッチノード（84-96行目）

#### Step 2: コードジェネレータの構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | codegen.c | `mrbgems/mruby-compiler/core/codegen.c` | codegen_scope構造体とスコープ管理 |

**主要処理フロー**:
- **63-66行目**: MRB_CODEGEN_LEVEL_MAX定数（デフォルト256）
- **80-87行目**: enum looptype - ループ種別（NORMAL, BLOCK, FOR, BEGIN, RESCUE）
- **89-97行目**: struct loopinfo - ループ情報（break/next/redo用ジャンプ先）
- **99-139行目**: codegen_scope構造体 - スコープ状態管理の中核データ構造

#### Step 3: オペコード生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | codegen.c | `mrbgems/mruby-compiler/core/codegen.c` | genop系関数群 |

**主要処理フロー**:
- **291-316行目**: emit_B() - 1バイト命令の出力とiseqバッファの動的拡張
- **372-377行目**: genop_0() - オペランドなしオペコード生成
- **389-403行目**: genop_1() - 1オペランドオペコード生成（OP_EXT1対応）
- **416-444行目**: genop_2() - 2オペランドオペコード生成（OP_EXT1/2/3対応）

#### Step 4: メイン処理フローを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | codegen.c | `mrbgems/mruby-compiler/core/codegen.c` | generate_code()とmrb_generate_code() |

**主要処理フロー**:
- **7274-7309行目**: generate_code() - コード生成のエントリーポイント
- **7277行目**: scope_new()でトップレベルスコープ作成
- **7291行目**: codegen()でAST走査開始
- **7292行目**: mrb_proc_new()でRProc生成
- **7312-7315行目**: mrb_generate_code() - 公開API

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

```
mrb_generate_code(mrb, parser_state)
    |
    +-- generate_code()
            +-- scope_new()              ... スコープ初期化
            +-- codegen(scope, tree, val)  ... AST再帰走査
            |       +-- codegen_while()     ... whileノード処理
            |       +-- codegen_call()      ... メソッド呼び出し処理
            |       +-- genop_1/2/3()       ... オペコード生成
            |       |       +-- emit_B()    ... バイト出力
            |       +-- scope_new()         ... ネストスコープ
            |       +-- scope_finish()      ... スコープ完了
            +-- mrb_proc_new()           ... RProc生成
            +-- mempool_close()          ... メモリプール解放

mrb_parse_nstring(mrb, source, len, cxt)
    |
    +-- mrb_parser_new()              ... パーサ状態初期化
    +-- mrb_parser_parse()            ... 字句・構文解析
            +-- yyparse()              ... yacc生成パーサ
            +-- yylex()                ... 字句解析器
```

### データフロー図

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

String (Ruby code)   ──▶ mrb_parse_nstring()    ──▶ AST (parser_state->tree)
                              |
                              +-- yylex()       ──▶ token列
                              +-- yyparse()     ──▶ ASTノード

AST                  ──▶ generate_code()        ──▶ mrb_irep*
                              |
                              +-- codegen()     ──▶ iseq (命令列)
                              +-- pool          ──▶ リテラルプール
                              +-- syms          ──▶ シンボルテーブル
                              +-- reps          ──▶ 子irep (ネスト)

mrb_irep*            ──▶ mrb_proc_new()         ──▶ struct RProc*
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| codegen.c | `mrbgems/mruby-compiler/core/codegen.c` | ソース | コードジェネレータ（7316行） |
| node.h | `mrbgems/mruby-compiler/core/node.h` | ヘッダ | ASTノード種別定義（785行） |
| parse.y | `mrbgems/mruby-compiler/core/parse.y` | ソース | yacc文法定義（パーサ） |
| y.tab.c | `mrbgems/mruby-compiler/core/y.tab.c` | 生成物 | パーサ（yaccから自動生成） |
| lex.def | `mrbgems/mruby-compiler/core/lex.def` | 生成物 | 字句解析テーブル（gperfから自動生成） |
| keywords | `mrbgems/mruby-compiler/core/keywords` | 入力 | gperf入力のキーワード定義 |
| mrbgem.rake | `mrbgems/mruby-compiler/mrbgem.rake` | 設定 | ビルド設定（yacc/gperf実行定義） |
