# 通知設計書 17-get/set keyword error

## 概要

本ドキュメントは、CoffeeScriptコンパイラにおける「'{keyword}' cannot be used as a keyword, or as a function call without parentheses」（get/setキーワード使用エラー）通知の設計仕様を定義する。

### 本通知の処理概要

この通知は、CoffeeScriptソースコード内で`get`または`set`をJavaScriptスタイルのゲッター/セッターキーワードとして使用しようとした場合に発生する構文エラーを開発者に通知するものである。

**業務上の目的・背景**：CoffeeScriptでは`get`と`set`は予約語ではなく、通常の識別子として扱われる。JavaScriptのオブジェクトリテラルで使用される`get foo() {}`や`set foo(value) {}`のような構文はCoffeeScriptでは直接サポートされていない。この通知により、開発者はCoffeeScriptの正しい構文を使用するよう誘導される。CoffeeScriptでゲッター/セッターを定義するには`Object.defineProperty`を使用するか、クラス構文内で別の方法を用いる必要がある。

**通知の送信タイミング**：字句解析（Lexer）フェーズにおいて、`identifierToken`メソッドが識別子を処理する際に発生する。`get`または`set`の後にプロパティ名が続き、それがキーワードとして使用されていると判断された場合に検出される。

**通知の受信者**：CoffeeScriptコードをコンパイルしている開発者。コマンドラインツール、REPL、またはプログラムからの呼び出し時に、標準エラー出力またはエラーオブジェクトとして通知される。

**通知内容の概要**：エラーメッセージ「'{keyword}' cannot be used as a keyword, or as a function call without parentheses」と、該当するソースコード内の位置情報（行番号・列番号）、および問題のキーワード（`get`または`set`）が含まれる。

**期待されるアクション**：開発者は以下のいずれかの対応を行う必要がある。(1) `get`/`set`を関数呼び出しとして使用する場合は括弧を付ける（例: `get(foo)`）、(2) ゲッター/セッターを定義する場合は`Object.defineProperty`を使用する、(3) CoffeeScript 2のクラス構文でゲッター/セッターを定義する。

## 通知種別

コンパイルエラー（SyntaxError）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（コンパイル時即時） |
| 優先度 | 高（コンパイル停止） |
| リトライ | なし |

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

コンパイラ呼び出し元に対してエラーがスローされる。CLIの場合は標準エラー出力、プログラムAPIの場合は例外としてスローされる。

## 通知テンプレート

### エラーメッセージ

| 項目 | 内容 |
|-----|------|
| メッセージ形式 | `[ファイル名]:行:列: error: '{keyword}' cannot be used as a keyword, or as a function call without parentheses` |
| 形式 | テキスト |

### 本文テンプレート

```
[stdin]:2:3: error: 'get' cannot be used as a keyword, or as a function call without parentheses
  get foo: ->
  ^^^
```

### 添付ファイル

なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| keyword | 問題のキーワード（`get`または`set`） | prev[1] | Yes |
| first_line | エラー発生行番号 | prev[2] | Yes |
| first_column | エラー発生列番号 | prev[2] | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| コンパイル処理 | identifierTokenメソッド実行 | `prev.spaced and prev[0] in CALLABLE and /^[gs]et$/.test(prev[1])` | getまたはsetがスペース後にCALLABLEトークンとして現れた |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| メソッドチェーン | `.get`または`?.get`のようなプロパティアクセスの場合はエラーなし |
| 括弧付き呼び出し | `get(foo)`のように括弧が付いている場合はエラーなし |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ソースコード読み込み] --> B[identifierTokenメソッド呼び出し]
    B --> C[識別子を処理]
    C --> D{tag is 'PROPERTY' and prev?}
    D -->|Yes| E{prev.spaced and prev[0] in CALLABLE?}
    D -->|No| F[通常処理継続]
    E -->|Yes| G{/^[gs]et$/.test prev[1]?}
    E -->|No| F
    G -->|Yes| H{前のトークンが '.', '?.', '@' でない?}
    G -->|No| F
    H -->|Yes| I[error 呼び出し]
    H -->|No| F
    I --> J[throwSyntaxError]
    J --> K[コンパイル停止]
```

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

### 参照テーブル一覧

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

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| SyntaxError | オブジェクト内で`get foo: ->`を使用 | 括弧を付けるか、別の構文を使用 |
| SyntaxError | クラス内で`get foo: ->`を使用 | クラスのゲッター/セッター構文を使用 |
| SyntaxError | 関数内で`get foo: ->`を使用 | 括弧を付けるか、別の構文を使用 |

### リトライ仕様

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

## 配信設定

### レート制限

該当なし（即時エラー通知）

### 配信時間帯

制限なし

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

特になし。ソースコードの内容がエラーメッセージに含まれる可能性があるが、開発時のみ表示されるため問題なし。

## 備考

- `get`と`set`はCoffeeScriptの予約語ではない
- CoffeeScript 2ではクラス内でゲッター/セッターを定義する特別な構文がある
- エラーメッセージには「括弧なしの関数呼び出し」という代替解釈も含まれている

---

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

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

### 推奨読解順序

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

識別子トークンの処理と関連定数を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | lexer.coffee | `src/lexer.coffee` | CALLABLE定数（1452行目）を確認 |

**読解のコツ**: CALLABLEには`IDENTIFIER`, `PROPERTY`, `)`, `]`, `?`, `@`, `THIS`, `SUPER`, `DYNAMIC_IMPORT`が含まれる。これらのトークンの後に`get`/`set`が来る場合にチェックが行われる。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | lexer.coffee | `src/lexer.coffee` | identifierTokenメソッドがエントリーポイント |

**主要処理フロー**:
1. **identifierToken**メソッドで識別子を処理
2. **210-229行目**: `get`/`set`キーワードのチェックロジック

#### Step 3: 実際のエラー検出ロジック

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | lexer.coffee | `src/lexer.coffee` (213-229行) | get/setキーワードエラー検出 |

**主要処理フロー**:
- **213-217行目**: 最初のチェック条件
  - `tag is 'PROPERTY' and prev`
  - `prev.spaced and prev[0] in CALLABLE`
  - `/^[gs]et$/.test(prev[1])`
  - `@tokens[@tokens.length - 2][0] not in ['.', '?.', '@']`
- **223-229行目**: 2番目のチェック条件（`@`や`THIS`の後）
  - `prev[0] in ['@', 'THIS']`
  - `prevprev.spaced and /^[gs]et$/.test(prevprev[1])`

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

```
CoffeeScript.compile(source)
    │
    └─ Lexer.tokenize(code)
           │
           ├─ identifierToken()
           │      ├─ 識別子をトークン化
           │      └─ tag is 'PROPERTY' チェック
           │             ├─ prev.spaced チェック
           │             ├─ prev[0] in CALLABLE チェック
           │             ├─ /^[gs]et$/.test(prev[1]) チェック
           │             └─ error("'get' cannot be used...")
           │                    └─ throwSyntaxError()
           │
           └─ 他のトークン処理メソッド
```

### データフロー図

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

obj =                     Lexer.identifierToken()           SyntaxError例外
  get foo: ->   ────▶           │
     │                    prev = 'get' トークン
     │                          ↓
     │                    tag = 'PROPERTY' (foo)
     │                          ↓
     └────────────▶ 条件チェック → エラー
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| lexer.coffee | `src/lexer.coffee` | ソース | 字句解析器本体、identifierTokenメソッド（213-229行目） |
| lexer.coffee | `src/lexer.coffee` | ソース | CALLABLE定数定義（1452行目） |
| helpers.coffee | `src/helpers.coffee` | ソース | throwSyntaxError関数の定義 |
| error_messages.coffee | `test/error_messages.coffee` | テスト | get/set keyword errorのテストケース（1410-1544行目） |
