# 機能設計書 17-スコープ管理

## 概要

本ドキュメントは、CoffeeScriptコンパイラにおけるスコープ管理機能の設計を記述する。Scopeクラスは、レキシカルスコープを管理し、変数宣言やスコープチェーンを追跡する機能を提供する。

### 本機能の処理概要

スコープ管理機能は、CoffeeScriptコードをJavaScriptに変換する際に、変数のスコープを正しく管理し、適切なvar宣言を生成するための機能である。

**業務上の目的・背景**：JavaScriptでは、var宣言されていない変数はグローバルスコープに属してしまう問題がある。CoffeeScriptは、代入時に自動的にローカル変数として宣言することで、この問題を解決している。Scopeクラスは、どの変数が各スコープで宣言されているかを追跡し、コンパイル時に必要なvar宣言を自動生成する。また、関数パラメータ、一時変数（コンパイラが生成する変数）の管理も行う。レキシカルスコープの階層構造を親への参照で実現し、変数の可視性を正しく判定する。

**機能の利用シーン**：
- 関数定義のコンパイル時：新しいスコープを作成
- 変数への代入時：スコープに変数を登録
- 変数の参照時：スコープチェーンを遡って変数を検索
- コード生成時：var宣言のリストを生成
- 一時変数の生成時：競合しない変数名を生成

**主要な処理内容**：
1. スコープの作成（コンストラクタ）：親スコープ、式ブロック、メソッド参照を設定
2. 変数の追加（add）：変数名と型（var, param, arguments）を登録
3. 変数の検索（find）：存在確認し、なければ追加
4. 変数の存在確認（check）：スコープチェーンを遡って検索
5. パラメータの登録（parameter）：関数パラメータとして登録
6. 一時変数の生成（freeVariable）：競合しない一時変数名を生成
7. 変数宣言の取得（declaredVariables）：var宣言が必要な変数リストを取得
8. 代入の登録（assign）：スコープトップでの代入を登録

**関連システム・外部連携**：
- nodes.coffee：Blockクラスがスコープを使用して変数宣言を生成
- coffeescript.coffee：コンパイルオプションにスコープを設定

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 14 | Annotated Source - Scope | 主画面 | スコープ管理scope.litcoffeeのソースコード解説表示 |
| 29 | Annotated Source - Scope | 主画面 | スコープ管理scope.litcoffeeのソースコード解説表示（v2） |

## 機能種別

スコープ管理 / 変数追跡

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| parent | Scope | No | 親スコープ（nullの場合はルートスコープ） | Scopeインスタンスまたはnull |
| expressions | Block | Yes | このスコープに属する式ブロック | Blockインスタンス |
| method | Object | No | このスコープが属するメソッド | メソッド情報オブジェクト |
| referencedVars | Array | No | ソースで参照されている変数名のリスト | 文字列配列 |

### 入力データソース

nodes.coffeeのBlockクラスやCodeクラスからスコープが作成される。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| declaredVariables | Array | var宣言が必要な変数名の配列 |
| assignedVariables | Array | スコープトップで代入される変数の配列 |

### 出力先

Block.compileWithDeclarationsでvar宣言として出力される。

## 処理フロー

### 処理シーケンス

```
1. スコープの作成
   ├─ 親スコープへの参照を設定
   ├─ variables配列を初期化（argumentsを含む）
   ├─ commentsオブジェクトを初期化
   └─ rootスコープへの参照を設定

2. 変数の追加（add）
   ├─ sharedスコープの場合は親に委譲
   ├─ 既存の場合は型を更新
   └─ 新規の場合はvariables配列に追加

3. 変数の検索（find）
   ├─ checkで存在確認
   ├─ 存在すればtrueを返す
   └─ 存在しなければaddして false を返す

4. 存在確認（check）
   ├─ typeで現在スコープを検索
   ├─ 見つかればtrue
   └─ 親スコープを再帰的に検索

5. 一時変数生成（freeVariable）
   ├─ temporary関数で変数名を生成
   ├─ checkで競合を確認
   ├─ referencedVarsとも競合を確認
   └─ 競合がなくなるまでインデックスをインクリメント
```

### フローチャート

```mermaid
flowchart TD
    A[スコープ作成] --> B[変数への代入]
    B --> C{find: 存在する?}
    C -->|Yes| D[既存変数として使用]
    C -->|No| E[add: 新規変数として追加]
    E --> F[var宣言リストに追加]
    D --> G[コード生成]
    F --> G
    G --> H[declaredVariablesでvar宣言を生成]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-17-01 | 自動var宣言 | 初めて代入される変数は自動的にvar宣言される | 変数への代入時 |
| BR-17-02 | レキシカルスコープ | 親スコープの変数は子スコープから参照可能 | 変数参照時 |
| BR-17-03 | パラメータはvar不要 | 関数パラメータはvar宣言が不要 | parameterメソッド使用時 |
| BR-17-04 | arguments予約 | argumentsは最初から存在する変数として扱う | スコープ作成時 |
| BR-17-05 | 一時変数の一意性 | freeVariableは既存変数と競合しない名前を生成 | 一時変数生成時 |
| BR-17-06 | シェアードスコープ | closureでラップされた式は親スコープを共有 | compileClosure時 |

### 計算ロジック

一時変数名の生成（temporary関数）:
```coffeescript
temporary: (name, index, single=false) ->
  if single
    startCode = name.charCodeAt(0)
    endCode = 'z'.charCodeAt(0)
    diff = endCode - startCode
    newCode = startCode + index % (diff + 1)
    letter = String.fromCharCode(newCode)
    num = index // (diff + 1)
    "#{letter}#{num or ''}"
  else
    "#{name}#{index or ''}"
```

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

### 操作別データベース影響一覧

データベースは使用しない。

### テーブル別操作詳細

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | - | スコープ管理自体はエラーを発生させない | - |

### リトライ仕様

該当なし。

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

トランザクションは使用しない。

## パフォーマンス要件

特に定められていない。

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

特になし。

## 備考

- scope.litcoffeeはLiterate CoffeeScript形式（Markdownとコードの混合）
- 変数の型は'var', 'param', 'arguments', または代入情報オブジェクト

---

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

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

### 推奨読解順序

#### Step 1: Scopeクラスの構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | scope.litcoffee | `src/scope.litcoffee` | 1-26行目のクラス定義とコンストラクタを理解する |

**読解のコツ**: Literate CoffeeScriptは、Markdownドキュメントにコードブロックが埋め込まれた形式。4スペースインデントのブロックがコードとして扱われる。

**主要処理フロー**:
- **8行目**: `exports.Scope = class Scope` でクラスをエクスポート
- **17-21行目**: コンストラクタでparent, expressions, method, referencedVarsを受け取る
- **18行目**: `@variables = [{name: 'arguments', type: 'arguments'}]` でargumentsを初期登録
- **25行目**: `@root = @parent?.root ? this` でルートスコープへの参照を設定

#### Step 2: 変数の追加・検索を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | scope.litcoffee | `src/scope.litcoffee` | 29-52行目のadd, find, parameterメソッドを理解する |

**主要処理フロー**:
- **29-34行目**: addで変数を追加（sharedの場合は親に委譲）
- **49-52行目**: findで変数を検索し、なければ追加
- **57-59行目**: parameterでパラメータを登録

#### Step 3: 変数の存在確認を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | scope.litcoffee | `src/scope.litcoffee` | 64-85行目のcheck, type, freeVariableメソッドを理解する |

**主要処理フロー**:
- **64-65行目**: checkでスコープチェーンを遡って存在確認
- **83-85行目**: typeで変数の型を取得
- **90-97行目**: freeVariableで競合しない一時変数名を生成

#### Step 4: 変数宣言の生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | scope.litcoffee | `src/scope.litcoffee` | 108-121行目のdeclaredVariables, assignedVariablesメソッドを理解する |

**主要処理フロー**:
- **113-114行目**: declaredVariablesでvar型の変数名をソートして返す
- **119-120行目**: assignedVariablesで代入式を生成

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

```
Block.compileWithDeclarations() (nodes.coffee:687)
    │
    ├─ scope.hasDeclarations() (scope.litcoffee:108)
    │      └─ declaredVariables().length を確認
    │
    ├─ scope.declaredVariables() (scope.litcoffee:113)
    │      └─ var型の変数名をソートして返す
    │
    └─ scope.assignedVariables() (scope.litcoffee:119)
           └─ 代入式を生成

Code.compileNode() (nodes.coffee)
    │
    └─ new Scope(parent, @body, @, referencedVars)
           │
           ├─ scope.parameter() - パラメータ登録
           │
           └─ scope.find() / scope.add() - 変数登録
```

### データフロー図

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

変数への代入             Scope処理                       var宣言
    │                        │                              │
x = 1               ├─ find('x')                      var x;
y = 2      ───▶    │      └─ add('x', 'var')   ───▶  var y;
                    ├─ find('y')
                    │      └─ add('y', 'var')
                    └─ declaredVariables()
                           └─ ['x', 'y'].sort()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| scope.litcoffee | `src/scope.litcoffee` | ソース | Scopeクラスの実装 |
| nodes.coffee | `src/nodes.coffee` | ソース | スコープを使用してコード生成 |
| coffeescript.coffee | `src/coffeescript.coffee` | ソース | コンパイルオプションにスコープを設定 |
