# 機能設計書 63-文字列補間

## 概要

本ドキュメントは、CoffeeScriptの文字列補間（String Interpolation）機能の設計を記述する。文字列補間は、ダブルクォート文字列内で`#{...}`構文を使用して式を展開する言語機能である。

### 本機能の処理概要

CoffeeScriptの文字列補間は、ダブルクォート（`"`）またはヒアドキュメント（`"""`）で囲まれた文字列内に`#{expression}`形式で式を埋め込み、実行時にその式の値を文字列に展開する機能である。ES2015のテンプレートリテラル（`` `${...}` ``）と同様の機能を、より早い時期から提供している。

**業務上の目的・背景**：
従来のJavaScriptでは文字列連結（`"Hello, " + name + "!"`）が必要で、複雑な文字列構築は可読性が低下する。CoffeeScriptの文字列補間により、変数や式を文字列内に直接埋め込むことができ、より自然で読みやすいコードを記述できる。国際化（i18n）メッセージやテンプレート生成、ログ出力などで特に有用である。

**機能の利用シーン**：
- 変数を含むメッセージの生成（例：`"Hello, #{name}!"`）
- 複数行のテンプレート生成（ヒアドキュメントと組み合わせ）
- 式の結果を文字列に含める（例：`"Total: #{price * quantity}"`）
- 関数呼び出し結果の埋め込み（例：`"Today is #{formatDate(new Date())}"`）
- オブジェクトプロパティの展開（例：`"User: #{user.name}"`）

**主要な処理内容**：
1. ダブルクォート文字列内の`#{`開始タグの検出
2. 補間式の解析と終了タグ`}`の検出
3. 複数の補間式がある場合の分割処理
4. 通常の文字列リテラル部分とInterpolationノードの分離
5. ES2015テンプレートリテラル（`` ` ``）へのコンパイル
6. JSX属性内での特殊処理

**関連システム・外部連携**：
文字列補間はLexer（lexer.coffee）の`matchWithInterpolations`メソッドで解析され、StringWithInterpolationsノード（nodes.coffee）としてASTに組み込まれる。コンパイル時にはES2015のテンプレートリテラルに変換される。

**権限による制御**：
本機能はコンパイル時の言語機能であり、権限による制御は適用されない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面関連なし（言語機能） |

## 機能種別

言語構文変換 / テンプレート処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| body | Block | Yes | 補間要素（StringLiteralとInterpolationの配列）を含むブロック | - |
| quote | String | Yes | 引用符の種類（`"` または `"""`） | - |
| startQuote | Literal | No | 開始引用符のトークン（位置情報用） | - |
| jsxAttribute | Boolean | No | JSX属性内かどうか | - |

### 入力データソース

CoffeeScriptソースコード内のダブルクォート文字列

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| JavaScript | String | ES2015テンプレートリテラル（`` `...${...}...` ``） |
| value | String | 補間後の文字列値（実行時） |

### 出力先

JavaScriptコード（標準出力またはファイル）

## 処理フロー

### 処理シーケンス

```
1. 文字列トークンの解析
   └─ Lexer.stringToken()で`"`または`"""`を検出
2. 補間のマッチング
   └─ matchWithInterpolations()で`#{`と`}`のペアを検出
3. トークンのマージ
   └─ mergeInterpolationTokens()でSTRING_START〜STRING_ENDトークン列を生成
4. パーサーでのノード生成
   └─ StringWithInterpolationsノードを生成
5. コンパイル処理（compileNode）
   └─ 5.1 extractElements()で要素を抽出
   └─ 5.2 StringLiteralはそのまま、Interpolationは式として展開
   └─ 5.3 テンプレートリテラル形式（`...${...}...`）で出力
```

### フローチャート

```mermaid
flowchart TD
    A[文字列開始トークン検出] --> B{引用符の種類}
    B -->|"| C[単一行文字列]
    B -->|"""| D[ヒアドキュメント]
    C --> E{補間あり?}
    D --> E
    E -->|No| F[通常のStringLiteralを生成]
    E -->|Yes| G[matchWithInterpolations呼び出し]
    G --> H[STRING_STARTトークン生成]
    H --> I[各補間要素を解析]
    I --> J[STRING_ENDトークン生成]
    J --> K[StringWithInterpolationsノード生成]
    K --> L[compileNode呼び出し]
    L --> M[テンプレートリテラル出力]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-63-1 | ダブルクォート限定 | シングルクォート文字列では補間が行われない | 引用符が`'`または`'''`の場合 |
| BR-63-2 | ネスト補間 | 補間式内に別の補間文字列を含めることが可能 | - |
| BR-63-3 | 空の補間 | `#{}`は空文字列に展開される | - |
| BR-63-4 | エスケープ | `\#{`は補間として解釈されず、文字列`#{`となる | バックスラッシュでエスケープ |
| BR-63-5 | ヒアドキュメントのインデント | ヒアドキュメント内の最小インデントは削除される | 引用符が`"""`の場合 |
| BR-63-6 | JSX属性 | JSX属性内の補間文字列は`{...}`でラップされる | jsxAttributeがtrueの場合 |

### 計算ロジック

- 補間式の評価: 補間内の式は通常のJavaScript式として評価され、その結果が文字列に変換される
- 複数補間の結合: テンプレートリテラルとして出力され、実行時に結合される

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

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

本機能はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| SyntaxError | 構文エラー | 補間の`{`と`}`の対応が取れない | 括弧を正しく閉じる |
| SyntaxError | 構文エラー | 補間内の式が無効 | 有効なCoffeeScript式を記述する |

### リトライ仕様

コンパイル時エラーのため、リトライは適用されない。

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

本機能はデータベーストランザクションを使用しない。

## パフォーマンス要件

- コンパイル時間: 補間の数に比例
- 生成コードの実行時間: テンプレートリテラルと同等

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

- 補間式はサニタイズされないため、ユーザー入力を含む場合はXSSなどの攻撃に注意
- SQLクエリやHTMLテンプレートでの使用時は適切なエスケープが必要

## 備考

- CoffeeScriptはES2015テンプレートリテラル以前から文字列補間をサポート
- コンパイル結果はバッククォート形式のテンプレートリテラルになる
- Rubyの文字列補間（`"Hello, #{name}!"`）と同じ構文

---

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

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

### 推奨読解順序

#### Step 1: 文法定義を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | grammar.coffee | `src/grammar.coffee` | String、Interpolations、InterpolationChunkの定義（203-227行目） |

**読解のコツ**:
- 214行目: `STRING_START Interpolations STRING_END`でStringWithInterpolationsを生成
- 217-227行目: Interpolations、InterpolationChunkで補間要素を解析

**主要処理フロー**:
1. **214行目**: `STRING_START Interpolations STRING_END` → `StringWithInterpolations`
2. **223行目**: `INTERPOLATION_START Body INTERPOLATION_END` → `Interpolation`
3. **225行目**: `INTERPOLATION_START INTERPOLATION_END` → 空のInterpolation

#### Step 2: Lexerの補間処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | lexer.coffee | `src/lexer.coffee` | stringToken、matchWithInterpolations、mergeInterpolationTokensメソッド |

**主要処理フロー**:
- **291-325行目**: `stringToken`メソッドで文字列を解析
- **307行目**: `matchWithInterpolations`で補間を検出
- **319行目**: `mergeInterpolationTokens`でトークンをマージ

#### Step 3: StringWithInterpolationsノードを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | nodes.coffee | `src/nodes.coffee` | StringWithInterpolationsクラスの定義（5170-5307行目） |

**主要処理フロー**:
- **5172行目**: `class StringWithInterpolations extends Base`
- **5191-5236行目**: `extractElements`メソッドでStringLiteralとInterpolationを抽出
- **5238-5270行目**: `compileNode`メソッドでテンプレートリテラルを生成
- **5249行目**: バッククォート（`` ` ``）で囲む
- **5255行目**: 補間部分は`$`と波括弧でラップ

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

```
CoffeeScript.compile()
    │
    ├─ Lexer.tokenize()
    │      ├─ stringToken()
    │      │      └─ matchWithInterpolations()
    │      │             └─ INTERPOLATION_START/END トークン生成
    │      └─ mergeInterpolationTokens()
    │             └─ STRING_START/END トークン生成
    │
    ├─ parser.parse()
    │      └─ StringWithInterpolationsノード生成
    │             ├─ Block.wrap()
    │             └─ Interpolationノード生成
    │
    └─ StringWithInterpolations.compileNode()
           ├─ extractElements()
           │      ├─ StringLiteral → そのまま出力
           │      └─ Interpolation → 式を展開
           └─ テンプレートリテラル形式で出力
```

### データフロー図

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

CoffeeScript           Lexer           Parser              Compiler
補間文字列         →  トークン列  →   StringWith      →    テンプレート
                                    Interpolations        リテラル

例: "Hello, #{name}!"
    ↓
[STRING_START, NEOSTRING("Hello, "), INTERPOLATION_START, IDENTIFIER("name"), INTERPOLATION_END, NEOSTRING("!"), STRING_END]
    ↓
StringWithInterpolations {
  body: Block([
    StringLiteral("Hello, "),
    Interpolation(IdentifierLiteral("name")),
    StringLiteral("!")
  ])
}
    ↓
`Hello, ${name}!`
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| grammar.coffee | `src/grammar.coffee` | ソース | 文字列補間の文法規則定義（203-227行目） |
| nodes.coffee | `src/nodes.coffee` | ソース | StringWithInterpolations、Interpolationクラス（5170-5319行目） |
| lexer.coffee | `src/lexer.coffee` | ソース | stringToken、matchWithInterpolations、mergeInterpolationTokensメソッド |
| helpers.coffee | `src/helpers.coffee` | ソース | replaceUnicodeCodePointEscapes等のヘルパー関数 |
