# 通知設計書 25-unexpected semicolon

## 概要

本ドキュメントは、CoffeeScriptコンパイラにおける予期しないセミコロンエラー（unexpected semicolon）の通知仕様を記述する。

### 本通知の処理概要

本通知は、CoffeeScriptソースコードにおいて、セミコロン（`;`）が構文的に不正な位置に出現した場合に発生するエラーメッセージである。

**業務上の目的・背景**：CoffeeScriptは文末にセミコロンを必要としない言語設計となっている。しかし、JavaScriptからの移行者がセミコロンを使用することがあり、また特定の文脈（代入の直後や未完了の式の後）でセミコロンが出現すると、構文上の問題を引き起こす。このエラーを検出することで、開発者に正しいCoffeeScriptの構文を促し、予期しないコンパイル結果を防止する。

**通知の送信タイミング**：コンパイル時、Lexerがセミコロントークンを処理する際に、直前のトークンを検証するタイミングで発生する。具体的には、`literalToken`関数内または`suppressSemicolons`関数内で検出される。

**通知の受信者**：CoffeeScriptコンパイラを実行している開発者。コンソール出力またはエラーオブジェクトとして通知される。

**通知内容の概要**：エラーメッセージ「unexpected ;」とともに、セミコロンの位置情報が提供される。

**期待されるアクション**：開発者は、不正な位置にあるセミコロンを削除するか、構文を修正して正しいCoffeeScriptコードにする必要がある。

## 通知種別

コンソールエラー出力 / SyntaxError例外

## 送信仕様

### 基本情報

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

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

コンパイラを実行しているプロセスの標準エラー出力、またはAPIとして呼び出された場合はSyntaxError例外として呼び出し元に返される。

## 通知テンプレート

### コンソール出力の場合

| 項目 | 内容 |
|-----|------|
| 出力先 | stderr |
| 形式 | テキスト |

### 本文テンプレート

```
[ファイル名]:[行番号]:[列番号]: error: unexpected ;
[該当行のソースコード]
[エラー位置を示すキャレット]
```

### 添付ファイル

なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| filename | ソースファイル名 | コンパイルオプション | Yes |
| line | エラー発生行番号 | Lexer位置情報 | Yes |
| column | エラー発生列番号 | Lexer位置情報 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| コンパイル処理 | セミコロンのトークン化 | prev?[0] in ['=', UNFINISHED...] | 直前のトークンが代入演算子または未完了式トークンの場合 |
| コンパイル処理 | suppressSemicolons処理 | @prev()?[0] in ['=', UNFINISHED...] | セミコロン抑制処理中に不正なセミコロンを検出 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 正常なコンテキスト | 直前のトークンが完了した式の場合 |
| TERMINATOR変換 | セミコロンがTERMINATORとして正常に変換される場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[セミコロン検出] --> B{literalToken or suppressSemicolons}
    B --> C[直前のトークンを取得]
    C --> D{prev[0]をチェック}
    D -->|'=' or UNFINISHED| E[error関数呼び出し]
    D -->|それ以外| F[TERMINATORに変換]
    E --> G[SyntaxError生成]
    G --> H[エラーメッセージ出力]
    H --> I[コンパイル中断]
    F --> J[正常処理継続]
```

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

### 参照テーブル一覧

該当なし（ファイルベースのコンパイル処理）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| SyntaxError | 代入や未完了式の後のセミコロン | セミコロンを削除、または構文を修正 |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 制限 | なし（コンパイル時エラー） |

### 配信時間帯

制限なし（コンパイル実行時に即時通知）

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

- エラーメッセージには特に機密情報は含まれない
- セミコロン1文字のみがエラー対象として示される

## 備考

- CoffeeScriptでは文末のセミコロンは基本的に不要
- ただし、1行に複数の文を書く場合はセミコロンで区切ることが可能（このケースではエラーにならない）
- `UNFINISHED`定数には、未完了の構文を示す各種トークンタイプが含まれる

---

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

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

### 推奨読解順序

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

UNFINISHED定数に含まれるトークンタイプを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | lexer.coffee | `src/lexer.coffee` | UNFINISHED定数の定義（ファイル末尾付近） |

**読解のコツ**: UNFINISHEDは、構文的に未完了を示すトークンタイプの配列である。

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

セミコロン検出の2つのポイントを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | lexer.coffee | `src/lexer.coffee` | literalToken関数（796-799行目） |
| 2-2 | lexer.coffee | `src/lexer.coffee` | suppressSemicolons関数（1171-1174行目） |

**主要処理フロー（literalToken）**:
1. **796行目**: `value is ';'`でセミコロンを検出
2. **797行目**: `prev?[0] in ['=', UNFINISHED...]`で直前トークンをチェック
3. **797行目**: 条件に該当すれば`@error 'unexpected ;'`を呼び出し
4. **798-799行目**: 正常な場合はTERMINATORに変換

**主要処理フロー（suppressSemicolons）**:
1. **1171行目**: 関数定義
2. **1172行目**: セミコロントークンをpop
3. **1174行目**: 同様のチェックでエラーを発生

#### Step 3: エラー生成処理を理解する

error関数の動作を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | lexer.coffee | `src/lexer.coffee` | 1178行目以降 - errorメソッド定義 |

**主要処理フロー**:
- エラーメッセージ`'unexpected ;'`でthrowSyntaxErrorを呼び出し

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

```
CoffeeScript.compile()
    │
    ├─ Lexer.tokenize()
    │      ├─ literalToken()
    │      │      ├─ value === ';'
    │      │      ├─ prev?[0] in ['=', UNFINISHED...]
    │      │      │      └─ true → @error('unexpected ;')
    │      │      └─ false → tag = 'TERMINATOR'
    │      │
    │      └─ suppressSemicolons()
    │             ├─ @value() === ';'
    │             ├─ @tokens.pop()
    │             └─ @prev()?[0] in ['=', UNFINISHED...]
    │                    └─ true → @error('unexpected ;')
    │
    └─ エラー時: SyntaxError例外をスロー
```

### データフロー図

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

x = ;                literalToken()               エラーメッセージ
  │                       │                       "unexpected ;"
  ▼                       ▼
トークン:           prev[0] = '='
  IDENTIFIER x      '=' in ['=', UNFINISHED...]
  CALL_START =            │
  ; (セミコロン)           ▼
                    条件 === true
                          │
                          ▼
                    @error('unexpected ;')
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| lexer.coffee | `src/lexer.coffee` | ソース | セミコロントークン処理、エラー検出 |
| helpers.coffee | `src/helpers.coffee` | ソース | throwSyntaxError関数 |
| error_messages.coffee | `test/error_messages.coffee` | テスト | エラーメッセージのテストケース（1874行目） |
