# 機能設計書 60-スプレッド演算子

## 概要

本ドキュメントは、CoffeeScriptのスプレッド演算子（...）機能の設計を記述する。配列・オブジェクトのスプレッド展開をサポートする。

### 本機能の処理概要

スプレッド演算子機能は、配列やオブジェクトの要素を展開するための構文を提供する。関数呼び出し時の引数展開、配列リテラル内での展開、オブジェクトリテラル内でのプロパティ展開など、様々なコンテキストで使用できる。

**業務上の目的・背景**：可変長引数の処理、配列の結合、オブジェクトのマージなどは、従来のJavaScriptではapplyメソッドやObject.assignなどの複雑な記法が必要であった。スプレッド演算子を使用することで、これらの操作をより直感的かつ簡潔に記述でき、コードの可読性が大幅に向上する。

**機能の利用シーン**：
- 関数呼び出し時の配列展開（apply相当）
- 配列の結合・コピー
- オブジェクトのマージ・コピー
- 可変長引数（レストパラメータ）
- 配列の分割代入でのレスト要素

**主要な処理内容**：
1. スプレッド構文の解析（prefix/postfix両対応）
2. 配列スプレッドの処理
3. オブジェクトスプレッドの処理
4. 関数呼び出し時のスプレッド展開
5. ES6スプレッド構文へのコード生成

**関連システム・外部連携**：
- Grammar（文法定義）
- Nodes（コード生成）
- Call（関数呼び出し処理）

**権限による制御**：該当なし

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 専用の画面なし（言語機能として全般的に使用） |

## 機能種別

言語機能 / コード生成

## 入力仕様

### 入力パラメータ

#### Splatノード
| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | Expression | Yes | スプレッド対象の式 | - |
| lhs | Boolean | No | 左辺値（代入先）かどうか | - |
| postfix | Boolean | No | 後置形式（expr...）かどうか（デフォルト: true） | - |

### 入力データソース

- CoffeeScriptソースコード内のスプレッド式

### 構文例

```coffeescript
# 配列スプレッド（関数呼び出し）
console.log ...args

# 配列リテラル内
combined = [first, ...middle, last]

# 配列コピー
copy = [...original]

# オブジェクトスプレッド
merged = {defaults..., custom...}

# オブジェクトマージ
newObj = {...obj, key: value}

# 関数パラメータ（レストパラメータ）
sum = (numbers...) ->
  total = 0
  total += n for n in numbers
  total

# 前置形式
[...rest, last] = array

# 後置形式
[first, rest...] = array
```

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| compiledCode | String | ES6スプレッド構文のJavaScriptコード |

### 出力先

- コンパイル済みJavaScriptファイル

### 出力例

```javascript
// 関数呼び出しでのスプレッド
console.log(...args);

// 配列リテラル内
var combined = [first, ...middle, last];

// オブジェクトスプレッド
var merged = {...defaults, ...custom};

// レストパラメータ
var sum = function(...numbers) {
  var n, total;
  total = 0;
  for (n of numbers) {
    total += n;
  }
  return total;
};
```

## 処理フロー

### 処理シーケンス

```
1. スプレッド構文の検出
   └─ Expression ... （後置形式）
   └─ ... Expression （前置形式）

2. Splatノードの生成
   └─ new Splat(name, {postfix, lhs})
   └─ nameが文字列の場合はLiteralでラップ

3. コンテキスト判定
   └─ 配列リテラル内
   └─ オブジェクトリテラル内
   └─ 関数呼び出し引数
   └─ 関数パラメータ（レストパラメータ）
   └─ 分割代入パターン

4. コード生成
   └─ compileNode で ... + name をコンパイル
   └─ JSXの場合は {} でラップ

5. isAssignable判定
   └─ 左辺値の場合は代入可能かチェック
   └─ 複雑なスプレッドはallowComplexSplatで制御
```

### フローチャート

```mermaid
flowchart TD
    A[スプレッド構文検出] --> B{前置/後置?}
    B -->|後置 expr...| C[postfix = true]
    B -->|前置 ...expr| D[postfix = false]
    C --> E[Splatノード生成]
    D --> E
    E --> F{コンテキスト判定}
    F -->|配列リテラル| G[配列スプレッド]
    F -->|オブジェクトリテラル| H[オブジェクトスプレッド]
    F -->|関数呼び出し| I[引数スプレッド]
    F -->|関数パラメータ| J[レストパラメータ]
    F -->|分割代入| K[レスト要素]
    G --> L[compileNode]
    H --> L
    I --> L
    J --> L
    K --> L
    L --> M{JSX?}
    M -->|Yes| N[{}でラップ]
    M -->|No| O[...name出力]
    N --> P[出力]
    O --> P
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-60-01 | 後置形式デフォルト | CoffeeScriptのスプレッドはデフォルトで後置形式（expr...） | スプレッド定義時 |
| BR-60-02 | 前置形式サポート | ...exprも有効な構文として認識 | スプレッド定義時 |
| BR-60-03 | JSXスプレッド | JSX内のスプレッドは{}でラップ | JSXコンテキスト |
| BR-60-04 | 複雑なスプレッド | ObjやParensのスプレッドはallowComplexSplatで制御 | isAssignable判定時 |
| BR-60-05 | 配列内スプレッド | 配列リテラル内では任意の位置で使用可能 | 配列コンテキスト |
| BR-60-06 | レストパラメータ | 関数パラメータでは末尾のみ | 関数パラメータ |
| BR-60-07 | オブジェクトスプレッド | オブジェクトリテラル内では任意の位置で使用可能 | オブジェクトコンテキスト |

### 計算ロジック

該当なし

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

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 構文エラー | レストパラメータが末尾でない | パラメータリストを修正 |
| - | 構文エラー | 代入不可能なスプレッド | スプレッド対象を修正 |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

- スプレッドのコンパイルは同期的に実行
- 大きな配列のスプレッドも効率的に処理

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

該当なし

## 備考

- CoffeeScriptはES6以前からスプレッド構文をサポートしていた
- ES6との構文の違い：CoffeeScriptはexpr...（後置）、ES6は...expr（前置）
- CoffeeScript 2は両形式をサポート

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | grammar.coffee | `src/grammar.coffee` | Splat、ObjRestValue規則（383-386, 287-292行目） |

**主要処理フロー**:
- **383-386行目**: Splat
  - `Expression ...` → new Splat $1（後置形式）
  - `... Expression` → new Splat $2, {postfix: no}（前置形式）
- **287-292行目**: ObjRestValue（オブジェクトスプレッド）
  - `SimpleObjAssignable ...` → new Splat new Value $1
  - `... SimpleObjAssignable` → new Splat new Value($2), postfix: no
  - `ObjSpreadExpr ...` → new Splat $1
  - `... ObjSpreadExpr` → new Splat $2, postfix: no

**読解のコツ**: 後置形式と前置形式の両方が文法で定義されている。

#### Step 2: Splatノードクラスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | nodes.coffee | `src/nodes.coffee` | Splatクラス（4454-4485行目） |

**主要処理フロー**:
- **4454-4457行目**: constructor
  - name: 式またはLiteral
  - lhs: 左辺値フラグ
  - postfix: 後置形式フラグ（デフォルトtrue）
- **4461-4465行目**: isAssignable
  - Obj/Parensの場合はallowComplexSplat
  - それ以外はname.isAssignable()
- **4470-4473行目**: compileNode
  - `...` + name.compileToFragments
  - JSXの場合は`{}`でラップ
- **4477-4480行目**: propagateLhs
  - lhsフラグの伝播

#### Step 3: 関数パラメータでのスプレッド処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | grammar.coffee | `src/grammar.coffee` | Param規則（366-372行目） |

**主要処理フロー**:
- **367行目**: `ParamVar` → new Param $1
- **368行目**: `ParamVar ...` → new Param $1, null, on（スプラットパラメータ）
- **369行目**: `... ParamVar` → new Param $2, null, postfix: no
- **371行目**: `...` → new Expansion（純粋なExpansion）

#### Step 4: 配列/オブジェクト内でのスプレッド使用を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | grammar.coffee | `src/grammar.coffee` | Arg規則（630-635行目） |

**主要処理フロー**:
- **631行目**: Expression
- **632行目**: ExpressionLine
- **633行目**: Splat
- **634行目**: `...` → new Expansion

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

```
Grammar: Splat規則
    │
    ├─ Expression ...
    │      └─ new Splat($1)                    # 後置形式
    │
    └─ ... Expression
           └─ new Splat($2, {postfix: no})     # 前置形式
                  │
                  ├─ constructor(name, options)
                  │      ├─ @name = name or Literal
                  │      ├─ @lhs = options.lhs
                  │      └─ @postfix = options.postfix
                  │
                  ├─ isAssignable({allowComplexSplat})
                  │      ├─ Obj/Parens → allowComplexSplat
                  │      └─ other → name.isAssignable()
                  │
                  ├─ compileNode(o)
                  │      ├─ compiledSplat = [..., name.compile...]
                  │      └─ JSX → [{, compiledSplat, }]
                  │
                  └─ propagateLhs(setLhs)
                         └─ name.propagateLhs(yes)
```

### データフロー図

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

[...args]               ───▶  Grammar解析  ───▶  Splatノード
                               │
                               ▼
                         compileNode
                               │
                               ▼
                         [...args]（ES6構文）

func(args...)           ───▶  Grammar解析  ───▶  Call + Splat
                               │
                               ▼
                         compileNode
                               │
                               ▼
                         func(...args)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| grammar.coffee | `src/grammar.coffee` | ソース | Splat、ObjRestValue、Param文法規則 |
| nodes.coffee | `src/nodes.coffee` | ソース | Splatノードクラスの実装 |
| lexer.coffee | `src/lexer.coffee` | ソース | ...トークンの生成 |
