# 通知設計書 6-unmatched_token

## 概要

本ドキュメントは、CoffeeScriptコンパイラが対応するペアのない閉じ括弧等を検出した際に発生する構文エラー「unmatched token」の通知仕様を定義する。

### 本通知の処理概要

CoffeeScriptコンパイラのレキサー（字句解析器）において、閉じ括弧（)、]、}）が検出されたが、対応する開き括弧が存在しない場合に、構文エラーとして通知を行う処理である。これはペアリングの不整合を示しており、ソースコードの構造的な問題を検出する。

**業務上の目的・背景**：括弧類はプログラムの構造を定義する重要な要素であり、ペアが正しくない場合はプログラムが意図通りに動作しない。この通知により、開発者は括弧の不整合を早期に発見し、バグを未然に防止できる。

**通知の送信タイミング**：レキサーのpair()メソッドにおいて、閉じタグが検出されたが、@ends配列のトップにある開始タグと一致しない場合に発生する。ただし、OUTDENTの場合は自動クローズを試みる。

**通知の受信者**：CoffeeScriptソースコードをコンパイルしている開発者。

**通知内容の概要**：エラーメッセージとして「unmatched {tag}」という形式で、不整合となったタグを特定できるようにしている。

**期待されるアクション**：開発者は括弧のペアを確認し、不足している開き括弧を追加するか、余分な閉じ括弧を削除する。

## 通知種別

コンパイラ出力（標準エラー出力 / SyntaxError例外）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（コンパイル処理中に即座に発生） |
| 優先度 | 高（コンパイルを中断） |
| リトライ | 無（即時エラーとして処理） |

### 送信先決定ロジック

CoffeeScriptコンパイラを呼び出しているコンテキストに依存する。

## 通知テンプレート

### エラーメッセージ形式

| 項目 | 内容 |
|-----|------|
| 形式 | テキスト |

### 本文テンプレート

```
[filename]:[line]:[column]: error: unmatched {tag}
[source_code_line]
[marker]
```

### 添付ファイル

なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| tag | 不整合となった閉じタグ（)、]、}等） | pair()メソッドの引数 | Yes |
| filename | ソースファイル名 | コンパイルオプション | No |
| line | エラー発生行番号 | locationData.first_line | Yes |
| column | エラー発生列番号 | locationData.first_column | Yes |
| source_code_line | エラーが発生した行のソースコード | 入力ソースコード | Yes |
| marker | エラー位置を示すマーカー | 計算により生成 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| コンパイル処理 | pair()メソッド実行中 | @ends配列のトップと閉じタグが一致しない場合（OUTDENTを除く） | 閉じタグ検出時にペアチェック |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| OUTDENT | OUTDENTの場合はoutdentToken()を呼び出して自動クローズを試みる |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[閉じタグ検出] --> B[pair呼び出し]
    B --> C{@ends配列のトップと一致?}
    C -->|Yes| D[@ends.pop]
    D --> E[正常継続]
    C -->|No| F{期待されるタグはOUTDENT?}
    F -->|Yes| G[outdentToken呼び出し]
    G --> H[pair再帰呼び出し]
    H --> B
    F -->|No| I[error: unmatched tag]
    I --> J[throwSyntaxError実行]
    J --> K[SyntaxError例外発生]
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし

### 内部データ構造

| 構造名 | 用途 | 備考 |
|--------|------|------|
| @ends配列 | 開始タグのスタック | lexer.coffee 45行目で初期化 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| SyntaxError | 閉じタグに対応する開始タグがない | 開発者が括弧のペアを修正 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし

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

- エラーメッセージにはソースコードの一部が含まれる

## 備考

- OUTDENTの場合は特別な処理（自動クローズ）が行われる
- 補間内での不整合（例：`"#{5) + (4}_"`）もこのエラーで検出される

---

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

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

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | lexer.coffee | `src/lexer.coffee` | @ends配列の初期化と管理 |

**読解のコツ**: @ends配列は開始タグをスタックとして管理し、対応する終了タグが見つかるとpair()でポップされる。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | lexer.coffee | `src/lexer.coffee` | pair()メソッド（1022-1036行目） |

**主要処理フロー**:
1. **1025-1026行目**: @endsの最後の要素のtagと引数tagを比較
2. **1027行目**: 一致しない場合、OUTDENTでなければ「unmatched {tag}」エラーを発生
3. **1028-1035行目**: OUTDENTの場合はoutdentToken()を呼び出して自動クローズを試みる

#### Step 3: 呼び出し元を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | lexer.coffee | `src/lexer.coffee` | literalToken()メソッド（821行目） |

**主要処理フロー**:
- **821行目**: 閉じ括弧（)、}、]）検出時にpair()を呼び出す

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

```
Lexer.tokenize()
    |
    +-- literalToken()
           |
           +-- 閉じ括弧検出 (821行目)
           |       |
           |       +-- pair()
           |               |
           |               +-- @ends配列トップと比較
           |               |
           |               +-- [一致しない場合]
           |               |       |
           |               |       +-- [OUTDENTの場合] outdentToken() → pair()再帰
           |               |       |
           |               |       +-- [その他] error("unmatched {tag}")
           |               |
           |               +-- [一致する場合] @ends.pop()
           |
           +-- @ends.push() (820行目)
```

### データフロー図

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

ソースコード  -----> literalToken()     -----> トークンストリーム
    |                     |
    |                     v
    |               閉じ括弧検出
    |                     |
    |                     v
    |               pair()
    |                     |
    |                     v
    |               @ends.トップと比較
    |                     |
    |              [一致しない場合（非OUTDENT）]
    |                     |
    |                     v
    +------------> error() + throwSyntaxError()
                          |
                          v
                   SyntaxError例外
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| lexer.coffee | `src/lexer.coffee` | ソース | pair()メソッドでunmatchedチェック |
| helpers.coffee | `src/helpers.coffee` | ソース | throwSyntaxError関数 |
| error_messages.coffee | `test/error_messages.coffee` | テスト | unmatchedエラーテスト（17-26行目、275-280行目） |
