# 機能設計書 66-Luaソースコード解析

## 概要

本ドキュメントは、Lua Language Serverにおける「Luaソースコード解析」機能の設計を記述する。本機能は、Lua 5.1/5.2/5.3/5.4/5.5およびLuaJITの構文を解析し、後続の処理（型推論、補完、診断等）の基盤となる構文解析機能を提供する。

### 本機能の処理概要

Luaソースコード解析機能は、Luaソースコードテキストを入力として受け取り、トークン化（字句解析）と構文解析を行い、抽象構文木（AST）を生成する。複数のLuaバージョンに対応し、バージョン固有の構文もサポートする。

**業務上の目的・背景**：Lua Language Serverの全ての機能（補完、定義ジャンプ、診断など）は、ソースコードの構造を理解する必要がある。構文解析によりソースコードをAST形式で表現することで、後続の各機能がコード構造に基づいた処理を行えるようになる。

**機能の利用シーン**：
- ファイルを開いた時の初回解析
- ファイル編集時の再解析
- 診断処理前の構文チェック
- 補完候補の計算時
- 定義・参照の検索時

**主要な処理内容**：
1. ソースコードのトークン化（字句解析）
2. トークン列からの構文解析
3. 各種文（ステートメント）の解析
4. 式（エクスプレッション）の解析
5. 関数定義の解析
6. テーブル定義の解析
7. ローカル変数・グローバル変数のスコープ管理
8. goto/labelの解決
9. LuaDocコメントとの統合

**関連システム・外部連携**：
- files.lua：ファイル管理モジュールからの呼び出し
- luadoc.lua：LuaDocアノテーションの解析との統合
- vm/infer.lua：型推論エンジンへのAST提供
- 各種LSP機能：AST情報の利用

**権限による制御**：本機能に権限制御は存在しない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 41 | AST可視化 | 主機能 | Luaコードの構文解析 |
| 42 | PSIビュー | 主機能 | 構文木（PSI）のビュー表示 |
| 43 | PSI選択 | 主機能 | 構文木（PSI）のノード選択 |

## 機能種別

コード解析 / パーサー

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| text | string | Yes | Luaソースコードテキスト | - |
| mode | string | Yes | 解析モード（'Lua', 'String'等） | 有効なモード名 |
| version | string | Yes | Luaバージョン | 'Lua 5.1' - 'Lua 5.5', 'LuaJIT' |
| options | table | No | 解析オプション | - |

### 入力データソース

- LSPプロトコル経由でクライアントから送信されるファイルテキスト
- ファイルシステムから読み込まれたファイル内容

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| state | parser.state | パーサーの状態オブジェクト |
| state.ast | table | 抽象構文木のルートノード |
| state.errs | table | 構文エラーのリスト |
| state.comms | table | コメントのリスト |
| state.lines | table | 行情報のテーブル |

### 出力先

呼び出し元の関数に返却される

## 処理フロー

### 処理シーケンス

```
1. 初期化
   └─ State、トークン配列等の初期化
2. トークン化
   └─ tokens.luaでソースコードをトークンに分割
3. 構文解析開始
   └─ parseActionsで文（statement）を解析
4. 各種文の解析
   ├─ ローカル変数宣言（local）
   ├─ 関数定義（function）
   ├─ 制御構文（if, for, while, repeat）
   ├─ return, break, goto
   └─ 代入文、関数呼び出し
5. 式の解析
   ├─ 算術式、比較式、論理式
   ├─ テーブルコンストラクタ
   ├─ 関数呼び出し
   └─ リテラル（数値、文字列、boolean等）
6. スコープ解決
   └─ ローカル変数のスコープをチャンクに登録
7. goto/label解決
   └─ goto文とlabelの対応付け
8. LuaDoc統合
   └─ luadoc.luaでアノテーションを解析
9. AST完成
   └─ state.astとして返却
```

### フローチャート

```mermaid
flowchart TD
    A[ソースコード入力] --> B[トークン化]
    B --> C[parseActions開始]
    C --> D{トークンあり?}
    D -->|Yes| E[文の種類を判定]
    E --> F{文の種類}
    F -->|local| G[ローカル変数解析]
    F -->|function| H[関数定義解析]
    F -->|if/for/while| I[制御構文解析]
    F -->|return/break| J[ジャンプ文解析]
    F -->|式| K[式解析]
    G --> L[スコープ登録]
    H --> L
    I --> L
    J --> L
    K --> L
    L --> D
    D -->|No| M[goto/label解決]
    M --> N[LuaDoc統合]
    N --> O[AST返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | バージョン互換 | 指定されたLuaバージョンの構文をサポート | 常時 |
| BR-02 | エラー回復 | 構文エラー時も可能な限り解析を継続 | 構文エラー発生時 |
| BR-03 | スコープ管理 | ローカル変数のスコープを正確に追跡 | 変数宣言時 |
| BR-04 | goto解決 | gotoとlabelの対応を解決 | Lua 5.2以降 |
| BR-05 | 特殊関数追跡 | require, pcall等の特殊関数を追跡 | 関数呼び出し時 |

### 計算ロジック

特になし

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

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

本機能はデータベースを使用しない（メモリ上でAST操作を行う）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| MISS_SYMBOL | Warning | 期待するシンボルがない | シンボルを追加 |
| MISS_NAME | Warning | 名前が期待される位置にない | 名前を追加 |
| MISS_EXP | Warning | 式が期待される位置にない | 式を追加 |
| MISS_END | Warning | endキーワードがない | endを追加 |
| UNKNOWN_SYMBOL | Warning | 認識できないシンボル | シンボルを修正 |
| KEYWORD | Warning | キーワードが識別子として使用 | 別の名前を使用 |

### リトライ仕様

リトライは不要（エラー回復しながら解析を継続）

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

トランザクション管理は不要（メモリ上の解析処理）

## パフォーマンス要件

- 10KB以下のファイルは100ms以内に解析完了
- 100KB以下のファイルは500ms以内に解析完了
- 1MB以下のファイルは5秒以内に解析完了

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

- 極端に大きなファイルの処理制限
- 深くネストされた構文の再帰制限

## 備考

- compile.luaはLuaの全構文要素に対応した包括的なパーサー
- エラー回復機能により、不完全なコードでも部分的なAST生成が可能
- LuaDocとの統合により、型アノテーションも同時に解析

---

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

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

### 推奨読解順序

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

まず、パーサーの状態オブジェクトとASTノードの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | compile.lua | `script/parser/compile.lua` | State変数の構造、parser.state型の定義 |
| 1-2 | guide.lua | `script/parser/guide.lua` | ASTノードの操作関数 |

**読解のコツ**: `State`変数は以下のフィールドを持つ：
- `ast`: 抽象構文木のルート
- `errs`: 構文エラーのリスト
- `comms`: コメントのリスト
- `lines`: 行情報
- `version`: Luaバージョン
- `options`: 解析オプション

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

ソースコード解析の起点を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | compile.lua | `script/parser/compile.lua` | `compile`関数（ファイル末尾付近） |

**主要処理フロー**:
1. State初期化
2. トークン化（tokens.lua）
3. parseActions呼び出し
4. luadoc.luaでアノテーション解析
5. AST返却

#### Step 3: 文（Statement）の解析を理解する

各種文の解析処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | compile.lua | `script/parser/compile.lua` | `parseAction`関数 |
| 3-2 | compile.lua | `script/parser/compile.lua` | `parseLocal`関数 |
| 3-3 | compile.lua | `script/parser/compile.lua` | `parseFunction`関数 |
| 3-4 | compile.lua | `script/parser/compile.lua` | `parseIf`, `parseFor`, `parseWhile`関数 |

**主要処理フロー**:
- トークンを先読みして文の種類を判定
- 対応する解析関数を呼び出し
- ASTノードを生成してチャンクに追加

#### Step 4: 式（Expression）の解析を理解する

式の解析処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | compile.lua | `script/parser/compile.lua` | `parseExp`関数 |
| 4-2 | compile.lua | `script/parser/compile.lua` | `parseSimple`関数 |
| 4-3 | compile.lua | `script/parser/compile.lua` | `parseTable`関数 |

**主要処理フロー**:
- 演算子の優先順位に基づく式解析
- 関数呼び出し、メソッド呼び出しの解析
- テーブルコンストラクタの解析

#### Step 5: スコープ管理を理解する

ローカル変数のスコープ管理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | compile.lua | `script/parser/compile.lua` | `createLocal`関数（729-757行目） |
| 5-2 | compile.lua | `script/parser/compile.lua` | `getLocal`関数（759-781行目） |
| 5-3 | compile.lua | `script/parser/compile.lua` | `pushChunk`, `popChunk`関数 |

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

```
compile (エントリーポイント)
    │
    ├─ tokens.tokenize (トークン化)
    │
    ├─ parseActions (文の解析ループ)
    │      ├─ parseAction
    │      │      ├─ parseLocal
    │      │      │      └─ createLocal
    │      │      ├─ parseFunction
    │      │      │      └─ parseFuncBody
    │      │      ├─ parseIf / parseFor / parseWhile
    │      │      │      └─ pushChunk / popChunk
    │      │      └─ parseExp (式として)
    │      │             └─ parseSimple
    │      │                    └─ parseTable
    │      └─ skipSpace / skipNL
    │
    ├─ resolveGoTo (goto解決)
    │
    └─ luadoc.luadoc (アノテーション解析)
```

### データフロー図

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

local x = 1 + 2
function foo() end
        │
        ▼
  トークン化           ───▶  トークン配列
        │                    [local, x, =, 1, +, 2, ...]
        ▼
  parseActions         ───▶  文の解析
        │
        ├─ parseLocal  ───▶  {type: 'local', [1]: 'x', value: {...}}
        │
        └─ parseFunction ──▶  {type: 'function', name: 'foo', ...}
        │
        ▼
  スコープ登録         ───▶  Chunk.locals に追加
        │
        ▼
  state.ast            ───▶  完成したAST
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| compile.lua | `script/parser/compile.lua` | ソース | メインのパーサー実装 |
| tokens.lua | `script/parser/tokens.lua` | ソース | 字句解析（トークナイザー） |
| guide.lua | `script/parser/guide.lua` | ソース | AST操作ユーティリティ |
| luadoc.lua | `script/parser/luadoc.lua` | ソース | LuaDocアノテーション解析 |
| files.lua | `script/files.lua` | ソース | ファイル管理（パーサー呼び出し元） |
| parser.lua | `script/parser.lua` | ソース | パーサーモジュールのエントリー |
