# 機能設計書 64-正規表現

## 概要

本ドキュメントは、CoffeeScriptの正規表現（Regular Expression）機能の設計を記述する。正規表現リテラルとヒアドキュメント正規表現（`///`）を提供し、複雑なパターンを可読性高く記述できる言語機能である。

### 本機能の処理概要

CoffeeScriptの正規表現は、JavaScriptの正規表現リテラル（`/pattern/flags`）に加え、ヒアドキュメント正規表現（`///...///`）を提供する。ヒアドキュメント正規表現では、複数行に渡るパターンの記述、空白の自由な挿入、コメントの追加、さらには式の補間が可能である。これにより、複雑な正規表現を構造化して記述でき、保守性が向上する。

**業務上の目的・背景**：
複雑な正規表現は一行で記述すると可読性が低下し、保守が困難になる。CoffeeScriptのヒアドキュメント正規表現により、パターンを論理的なセクションに分割し、各部分にコメントを付けることができる。また、変数やサブパターンを補間することで、正規表現の再利用性も向上する。

**機能の利用シーン**：
- 単純なパターンマッチング（例：`/^\d+$/`）
- 複数行にわたる複雑なパターン（例：URLパーサー、メールアドレスバリデーション）
- パターンの一部を変数化（例：`///#{prefix}.*#{suffix}///`）
- コメント付きの自己文書化されたパターン
- フラグ（`g`, `i`, `m`, `u`, `y`）の指定

**主要な処理内容**：
1. `/pattern/`形式の通常の正規表現リテラルの解析
2. `///pattern///`形式のヒアドキュメント正規表現の解析
3. ヒアドキュメント内の空白・改行・コメントの処理
4. `#{...}`による式の補間（ヒアドキュメント時）
5. フラグの解析と検証
6. RegexLiteralまたはRegexWithInterpolationsノードの生成

**関連システム・外部連携**：
正規表現はLexer（lexer.coffee）の`regexToken`メソッドで解析され、補間がない場合はRegexLiteralノード、補間がある場合はRegexWithInterpolationsノードとしてASTに組み込まれる。補間付きの場合は`RegExp()`コンストラクタ呼び出しに変換される。

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

## 関連画面

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

## 機能種別

言語構文変換 / パターンマッチング

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| value | String | Yes | 正規表現パターン | 有効な正規表現パターン |
| delimiter | String | Yes | 区切り文字（`/` または `///`） | - |
| flags | String | No | 正規表現フラグ（`g`, `i`, `m`, `s`, `u`, `y`） | VALID_FLAGS正規表現で検証 |
| heregexCommentTokens | Array | No | ヒアドキュメント内のコメントトークン | - |

### 入力データソース

CoffeeScriptソースコード内の正規表現リテラル

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| JavaScript（通常） | String | JavaScriptの正規表現リテラル（`/pattern/flags`） |
| JavaScript（補間あり） | String | `RegExp()`コンストラクタ呼び出し |
| AST | Object | RegexLiteralまたはInterpolatedRegExpLiteralノード |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. 正規表現トークンの解析
   └─ Lexer.regexToken()で`/`または`///`を検出
2. パターンタイプの判定
   └─ 2.1 `/pattern/`：通常の正規表現
   └─ 2.2 `///...///`：ヒアドキュメント正規表現
3. ヒアドキュメントの場合の処理
   └─ 3.1 matchWithInterpolations()で補間を検出
   └─ 3.2 コメントを抽出・保存
   └─ 3.3 空白・改行を除去
4. フラグの解析と検証
   └─ VALID_FLAGS（gimsuyvd）で検証
5. ノード生成
   └─ 5.1 補間なし：RegexLiteral
   └─ 5.2 補間あり：RegexWithInterpolations（RegExp呼び出し）
```

### フローチャート

```mermaid
flowchart TD
    A[正規表現開始検出] --> B{区切り文字}
    B -->|/| C[通常の正規表現]
    B -->|///| D[ヒアドキュメント正規表現]
    C --> E[パターン解析]
    D --> F[matchWithInterpolations]
    F --> G[コメント抽出]
    G --> H[空白除去]
    H --> I{補間あり?}
    E --> J[フラグ解析]
    I -->|Yes| K[RegexWithInterpolations生成]
    I -->|No| L[RegexLiteral生成]
    J --> M{フラグ有効?}
    M -->|Yes| L
    M -->|No| N[エラー: invalid flags]
    K --> O[RegExp呼び出しとして出力]
    L --> P[正規表現リテラルとして出力]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-64-1 | ヒアドキュメントの空白処理 | `///`内の空白と改行はパターンに含まれない | 区切り文字が`///`の場合 |
| BR-64-2 | コメント処理 | `///`内の`#`以降はコメントとして除去 | 区切り文字が`///`の場合 |
| BR-64-3 | 補間のエスケープ | 補間式は`RegExp()`に渡す前にエスケープされる | 補間が存在する場合 |
| BR-64-4 | フラグ検証 | 無効なフラグが指定された場合はエラー | フラグがVALID_FLAGSに一致しない場合 |
| BR-64-5 | Unicode エスケープ | `\u{...}`形式のUnicodeエスケープをサポート | - |

### 計算ロジック

- 補間式のエスケープ: 正規表現の特殊文字をエスケープしてから結合
- ヒアドキュメントのフラット化: 複数行を単一行に変換（空白・コメント除去後）

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

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| SyntaxError | 構文エラー | `regular expressions cannot begin with *` | 先頭の`*`を削除またはエスケープ |
| SyntaxError | 構文エラー | `missing / (unclosed regex)` | 正規表現を正しく閉じる |
| SyntaxError | 構文エラー | `invalid regular expression flags` | 有効なフラグのみを使用 |

### リトライ仕様

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

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

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

## パフォーマンス要件

- コンパイル時間: パターンの長さに比例
- 補間付きの場合: `RegExp()`呼び出しのオーバーヘッドあり

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

- ユーザー入力を補間する場合、ReDoS（正規表現サービス拒否）攻撃に注意
- 動的に生成された正規表現は慎重に検証が必要

## 備考

- ヒアドキュメント正規表現は可読性のために推奨
- ES2018のフラグ（`s`）もサポート
- Unicode関連フラグ（`u`）でユニコードパターンをサポート

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | grammar.coffee | `src/grammar.coffee` | Regex規則の定義（231-234行目） |

**読解のコツ**:
- 232行目: `REGEX`で通常の正規表現リテラルを処理
- 233行目: `REGEX_START Invocation REGEX_END`でヒアドキュメント正規表現を処理

**主要処理フロー**:
1. **232行目**: `REGEX` → `RegexLiteral`
2. **233行目**: `REGEX_START Invocation REGEX_END` → `RegexWithInterpolations`

#### Step 2: Lexerの正規表現処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | lexer.coffee | `src/lexer.coffee` | regexTokenメソッド（444-502行目） |

**主要処理フロー**:
- **446-448行目**: `REGEX_ILLEGAL`で不正な開始文字をチェック
- **449-459行目**: `HEREGEX`でヒアドキュメント正規表現を処理
- **460-470行目**: 通常の`REGEX`を処理
- **474-495行目**: フラグの解析と`REGEX_START`/`REGEX_END`トークン生成

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | nodes.coffee | `src/nodes.coffee` | RegexLiteral、RegexWithInterpolationsクラス（1107行目、2199行目） |

**主要処理フロー**:
- **1107行目**: `class RegexLiteral extends Literal` - 通常の正規表現
- **2199行目**: `class RegexWithInterpolations extends Base` - 補間付き正規表現
- **2205-2206行目**: `compileNode`は内部の`call`をコンパイル（RegExp呼び出し）

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

```
CoffeeScript.compile()
    │
    ├─ Lexer.tokenize()
    │      └─ regexToken()
    │             ├─ REGEX マッチ → REGEXトークン
    │             └─ HEREGEX マッチ
    │                    ├─ matchWithInterpolations()
    │                    ├─ commentToken() でコメント抽出
    │                    └─ REGEX_START/END トークン生成
    │
    ├─ parser.parse()
    │      ├─ RegexLiteral ノード生成（補間なし）
    │      └─ RegexWithInterpolations ノード生成（補間あり）
    │             └─ Call(RegExp, [pattern, flags])
    │
    └─ compileNode()
           ├─ RegexLiteral.compileNode() → /pattern/flags
           └─ RegexWithInterpolations.compileNode() → RegExp(...)
```

### データフロー図

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

CoffeeScript           Lexer           Parser              Compiler
正規表現           →  トークン列  →   Regex          →    JavaScript
                                    ノード               正規表現

例1: /\d+/g
    ↓
[REGEX('/\\d+/g')]
    ↓
RegexLiteral { value: '/\\d+/g', delimiter: '/' }
    ↓
/\d+/g

例2: ///#{pattern}///g
    ↓
[REGEX_START, ..., REGEX_END]
    ↓
RegexWithInterpolations { call: Call(RegExp, [...]) }
    ↓
RegExp(pattern, 'g')
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| grammar.coffee | `src/grammar.coffee` | ソース | 正規表現の文法規則定義（231-234行目） |
| nodes.coffee | `src/nodes.coffee` | ソース | RegexLiteral（1107行目）、RegexWithInterpolations（2199行目） |
| lexer.coffee | `src/lexer.coffee` | ソース | regexTokenメソッド（444-502行目） |
| helpers.coffee | `src/helpers.coffee` | ソース | Unicode エスケープ処理 |
