# 機能設計書 12-暗黙の関数呼び出し

## 概要

本ドキュメントは、CoffeeScriptコンパイラにおける「暗黙の関数呼び出し」機能の設計を記述する。この機能はRewriterの一部として実装され、括弧なしで記述された関数呼び出しに暗黙の括弧（CALL_START/CALL_END）を追加する処理を担当する。

### 本機能の処理概要

暗黙の関数呼び出し機能は、CoffeeScriptの特徴的な構文である括弧省略をサポートするための中核的な機能である。

**業務上の目的・背景**：CoffeeScriptでは、関数呼び出し時の括弧を省略できる構文が許可されている。例えば、`console.log "hello"` は `console.log("hello")` と同等である。この簡潔な構文はCoffeeScriptの可読性を高める重要な特徴であるが、パーサーで直接処理するには文法が複雑になりすぎる。そのため、Rewriterでトークン列を前処理し、暗黙の括弧を明示的なCALL_START/CALL_ENDトークンとして挿入することで、パーサーの文法を単純に保っている。

**機能の利用シーン**：以下のような括弧省略パターンで使用される。
- 標準的な関数呼び出し: `func arg1, arg2`
- メソッドチェーン: `obj.method1 arg1 .method2 arg2`
- 条件演算子付き呼び出し: `func? arg`
- スプレッド演算子付き呼び出し: `func ...args`
- インデント付きオブジェクト引数: `func\n  a: 1\n  b: 2`

**主要な処理内容**：
1. IMPLICIT_FUNCトークン（関数として呼び出し可能なトークン）の検出
2. 次のトークンがIMPLICIT_CALLトークン（引数として有効なトークン）かどうかの判定
3. 制御フロー内でないことの確認（forループ条件内の関数などは暗黙呼び出しにしない）
4. CALL_STARTトークンの挿入
5. 引数リストの終端検出とCALL_ENDトークンの挿入
6. ネストされた暗黙呼び出しの正しいスタック管理

**関連システム・外部連携**：Rewriter内のaddImplicitBracesAndParensメソッドの一部として実装されている。Lexerからのトークン列を入力とし、変換後のトークン列をパーサーに渡す。

**権限による制御**：特になし。コンパイル処理全体に一律適用される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 13 | Annotated Source - Rewriter | 主画面 | addImplicitBracesAndParensの解説を含む |
| 28 | Annotated Source - Rewriter | 主画面 | addImplicitBracesAndParensの解説を含む（v2） |

## 機能種別

データ変換処理 / トークン列書き換え

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| tokens | Array | Yes | Lexerが生成したトークン配列（Rewriter内部で処理） | 有効なトークン配列 |

### 入力データソース

Rewriterのrewriteメソッドで管理されるトークン配列（@tokens）を直接操作する。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| tokens | Array | CALL_START/CALL_ENDが挿入されたトークン配列 |

### 出力先

Rewriter内部のトークン配列に直接書き込み、後続の処理パスに渡す。

## 処理フロー

### 処理シーケンス

```
1. scanTokensでトークン列をスキャン
   └─ 各トークンに対して以下を判定

2. 暗黙の関数呼び出し条件の判定
   ├─ 現在のトークンがIMPLICIT_FUNCに含まれるか
   ├─ トークンがスペース付きか（token.spaced）
   └─ 次のトークンがIMPLICIT_CALLに含まれるか

3. 制御フロー内かどうかの判定（inControlFlow）
   └─ FOR, WHILE, UNTIL, LOOP内の関数は暗黙呼び出しにしない

4. CALL_STARTトークンの挿入
   └─ startImplicitCall(i + 1)でCALL_STARTを挿入

5. 引数リストの終端検出
   ├─ IMPLICIT_ENDトークンの検出
   ├─ CALL_CLOSERSトークン（., ?., ::等）の検出
   └─ ネストレベルの追跡

6. CALL_ENDトークンの挿入
   └─ endImplicitCall()でCALL_ENDを挿入
```

### フローチャート

```mermaid
flowchart TD
    A[トークンをスキャン] --> B{IMPLICIT_FUNCか?}
    B -->|No| A
    B -->|Yes| C{token.spacedか?}
    C -->|No| D{token[0] is '?'かつ前トークンがspaced無し?}
    D -->|No| A
    C -->|Yes| E{次トークンがIMPLICIT_CALLか?}
    D -->|Yes| E
    E -->|No| F{次トークンが'...'でその次がIMPLICIT_CALLか?}
    F -->|No| A
    E -->|Yes| G{制御フロー内か?}
    F -->|Yes| G
    G -->|Yes| A
    G -->|No| H[CALL_STARTを挿入]
    H --> I[引数リスト終端を検出]
    I --> J[CALL_ENDを挿入]
    J --> A
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-12-01 | スペース区切り呼び出し | スペースで区切られたIMPLICIT_FUNCの後にIMPLICIT_CALLが続く場合、暗黙の括弧を追加 | `func arg` パターン |
| BR-12-02 | 存在演算子呼び出し | `?`の後にIMPLICIT_CALLが続く場合、FUNC_EXISTに変換し暗黙の括弧を追加 | `func? arg` パターン |
| BR-12-03 | スプレッド呼び出し | `...`の後にIMPLICIT_CALLが続く場合、暗黙の括弧を追加 | `func ...args` パターン |
| BR-12-04 | インデントオブジェクト | 次の行にインデントされたオブジェクト形式がある場合、暗黙の括弧を追加 | `func\n  a: 1` パターン |
| BR-12-05 | 制御フロー除外 | FOR/WHILE/UNTIL/LOOP内の関数は暗黙呼び出しにしない | `while func arg` は除外 |
| BR-12-06 | メソッドチェーン終端 | `.`, `?.`, `::`, `?::`が改行後に現れたら暗黙呼び出しを終了 | `func arg\n.method` パターン |

### 計算ロジック

IMPLICIT_FUNCトークンリスト:
```
['IDENTIFIER', 'PROPERTY', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS']
```

IMPLICIT_CALLトークンリスト:
```
['IDENTIFIER', 'JSX_TAG', 'PROPERTY', 'NUMBER', 'INFINITY', 'NAN',
 'STRING', 'STRING_START', 'REGEX', 'REGEX_START', 'JS',
 'NEW', 'PARAM_START', 'CLASS', 'IF', 'TRY', 'SWITCH', 'THIS',
 'DYNAMIC_IMPORT', 'IMPORT_META', 'NEW_TARGET',
 'UNDEFINED', 'NULL', 'BOOL',
 'UNARY', 'DO', 'DO_IIFE', 'YIELD', 'AWAIT', 'UNARY_MATH', 'SUPER', 'THROW',
 '@', '->', '=>', '[', '(', '{', '--', '++']
```

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

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

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

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | - | 暗黙の関数呼び出し処理自体はエラーを発生させない | - |

### リトライ仕様

該当なし。

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

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

## パフォーマンス要件

特に定められていない。トークン列のシングルパススキャンで処理される。

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

特になし。

## 備考

- IMPLICIT_UNSPACED_CALL (`['+', '-']`) は、スペースなしでも暗黙呼び出しを許可するトークン
- 暗黙の関数呼び出しと暗黙のオブジェクトリテラルは同じメソッド内で処理され、相互に影響する

---

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

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

### 推奨読解順序

#### Step 1: 定数定義を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | rewriter.coffee | `src/rewriter.coffee` | 817-831行目のIMPLICIT_FUNC、IMPLICIT_CALL、IMPLICIT_UNSPACED_CALL定数を理解する |

**読解のコツ**: IMPLICIT_FUNCは「関数として呼び出される可能性があるトークン」、IMPLICIT_CALLは「引数として渡される可能性があるトークン」を表す。

#### Step 2: スタック管理とヘルパー関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | rewriter.coffee | `src/rewriter.coffee` | 178-210行目のスタック管理とstartImplicitCall、endImplicitCall関数を理解する |

**主要処理フロー**:
- **178行目**: `stack = []` でネストレベル追跡用スタックを初期化
- **203-205行目**: `startImplicitCall` でCALL_STARTトークンを挿入
- **207-210行目**: `endImplicitCall` でCALL_ENDトークンを挿入

#### Step 3: 暗黙の関数呼び出し検出ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | rewriter.coffee | `src/rewriter.coffee` | 287-328行目の暗黙の関数呼び出し検出条件を理解する |

**主要処理フロー**:
- **290-296行目**: 標準的な暗黙呼び出しの検出条件
- **297-298行目**: `?`演算子をFUNC_EXISTに変換
- **319-328行目**: インデント付きオブジェクト引数の検出

#### Step 4: 暗黙呼び出しの終了条件を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | rewriter.coffee | `src/rewriter.coffee` | 389-413行目の暗黙呼び出し終了条件を理解する |

**主要処理フロー**:
- **389-391行目**: IMPLICIT_ENDまたはCALL_CLOSERSで終了判定
- **394-397行目**: カンマ以外のトークンで暗黙呼び出しを終了

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

```
Rewriter.rewrite() (rewriter.coffee:43)
    │
    └─ addImplicitBracesAndParens() (rewriter.coffee:176)
           │
           ├─ scanTokens() (rewriter.coffee:71)
           │      │
           │      └─ 各トークンに対して判定処理を実行
           │
           ├─ startImplicitCall() (rewriter.coffee:203)
           │      └─ generate('CALL_START', ...) でトークン生成
           │
           ├─ endImplicitCall() (rewriter.coffee:207)
           │      └─ generate('CALL_END', ...) でトークン生成
           │
           └─ inControlFlow() (rewriter.coffee:273)
                  └─ findTagsBackwards() で制御フロー内かを判定
```

### データフロー図

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

トークン列              暗黙の関数呼び出し処理           変換後トークン列

[IDENTIFIER,            ├─ IMPLICIT_FUNC検出            [IDENTIFIER,
 'func']                ├─ IMPLICIT_CALL検出              'func']
[IDENTIFIER,            ├─ CALL_START挿入               [CALL_START,
 'arg']        ───▶    └─ CALL_END挿入          ───▶    '(']
                                                        [IDENTIFIER,
                                                          'arg']
                                                        [CALL_END,
                                                          ')']
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| rewriter.coffee | `src/rewriter.coffee` | ソース | addImplicitBracesAndParensメソッドの実装 |
| lexer.coffee | `src/lexer.coffee` | ソース | IMPLICIT_FUNCトークンを生成するLexer |
| grammar.coffee | `src/grammar.coffee` | ソース | CALL_START/CALL_ENDを処理する文法定義 |
| helpers.coffee | `src/helpers.coffee` | ソース | ヘルパー関数 |
