# 機能設計書 43-セマンティックトークン (textDocument/semanticTokens)

## 概要

本ドキュメントは、Lua Language Serverにおけるセマンティックトークン機能（textDocument/semanticTokens/full）の設計仕様を記述する。この機能は、ソースコード内のトークンにセマンティック情報（型、修飾子）を付与し、エディタの構文ハイライトを拡張する。

### 本機能の処理概要

セマンティックトークン機能は、Luaソースコードを解析し、各識別子や構文要素に対してセマンティック情報（変数、関数、パラメータ、型など）を付与する。これにより、通常の構文ハイライトでは区別できない要素（ローカル変数とグローバル変数、関数と通常変数など）を視覚的に区別できるようになる。

**業務上の目的・背景**：構文ハイライトは開発者がコードを読み解く際の重要な視覚的補助である。標準的な構文ハイライトはキーワードや文字列を色分けするが、セマンティックトークンはより深い解析に基づいて、変数の種類（ローカル/グローバル/パラメータ）、関数定義と参照、型情報、LuaDocアノテーションなどを区別してハイライトする。これにより、コードの可読性と理解度が大幅に向上する。

**機能の利用シーン**：
- コード編集時のリアルタイムハイライト
- グローバル変数と標準ライブラリ関数の視覚的区別
- 関数定義と変数の視覚的区別
- LuaDocアノテーションの構文ハイライト
- constやclose属性を持つ変数の視覚的区別

**主要な処理内容**：
1. クライアントからsemanticTokens/fullリクエストを受信
2. ドキュメントのAST（抽象構文木）を取得
3. AST内の各ソース要素を走査し、トークンタイプと修飾子を決定
4. コメント内のLuaDocアノテーションを処理
5. 複数行トークンとオーバーラップの解決
6. LSP形式のトークンデータ配列を生成して返却

**関連システム・外部連携**：
- パーサー（script/parser）からのAST情報
- 型推論エンジン（script/vm）からの型情報
- LSPクライアントとのJSON-RPC通信

**権限による制御**：設定（Lua.semantic.enable, Lua.semantic.variable, Lua.semantic.annotation, Lua.semantic.keyword）により動作をカスタマイズ可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 17 | セマンティックトークン（全体） | 主機能 | ファイル全体のセマンティックハイライト情報を提供する主処理 |

## 機能種別

構文ハイライト拡張 / コードインテリジェンス

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| textDocument.uri | string | Yes | 対象ドキュメントのURI | 有効なファイルURIであること |

### 入力データソース

- LSPクライアントからのJSON-RPCリクエスト
- ファイルシステム上のLuaソースコード（AST経由）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| data | integer[] | エンコードされたトークン情報の配列 |

トークンデータのエンコード（5つ組の連続）:
- deltaLine: 前のトークンからの行差分
- deltaStartChar: 前のトークンからの文字差分（同一行の場合）または開始位置
- length: トークンの長さ
- tokenType: トークンタイプのインデックス
- tokenModifiers: 修飾子のビットマスク

### 出力先

- LSPクライアントへのJSON-RPCレスポンス

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ textDocument/semanticTokens/fullメッセージを受信

2. 設定確認
   └─ Lua.semantic.enableがfalseなら空配列を返却

3. ドキュメント状態取得
   └─ files.getState(uri)でAST情報を取得

4. AST走査
   └─ guide.eachSourceBetween()で各ソース要素を処理

5. トークン分類
   └─ Careスイッチで各タイプに応じたトークン情報を生成

6. コメント処理
   └─ state.commsからLuaDocアノテーションを処理

7. 複数行・オーバーラップ解決
   └─ solveMultilineAndOverlapping()でトークンを整理

8. エンコード
   └─ buildTokens()で差分エンコードを実行

9. レスポンス返却
   └─ { data: integer[] }を返却
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B{Lua.semantic.enable?}
    B -->|false| C[空配列返却]
    B -->|true| D{ドキュメント状態取得}
    D -->|失敗| C
    D -->|成功| E[オプション設定取得]
    E --> F[guide.eachSourceBetween]
    F --> G[Care スイッチ処理]
    G --> H{仮想ソース?}
    H -->|Yes| I[スキップ]
    H -->|No| J[トークン情報生成]
    I --> K{次のソース}
    J --> K
    K -->|あり| H
    K -->|なし| L[コメント処理]
    L --> M[solveMultilineAndOverlapping]
    M --> N[buildTokens]
    N --> O[レスポンス返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-43-01 | セマンティック無効化 | Lua.semantic.enable=falseで機能無効 | 設定値 |
| BR-43-02 | 変数無効化 | Lua.semantic.variable=falseで変数トークン無効 | 設定値 |
| BR-43-03 | アノテーション無効化 | Lua.semantic.annotation=falseでLuaDoc無効 | 設定値 |
| BR-43-04 | キーワード無効化 | Lua.semantic.keyword=falseでキーワードトークン無効 | 設定値 |
| BR-43-05 | 仮想ソーススキップ | source.virtual=trueのソースはスキップ | 常時 |
| BR-43-06 | defaultLibrary修飾子 | メタファイル定義のグローバルにdefaultLibraryを付与 | グローバル変数 |
| BR-43-07 | declaration修飾子 | 宣言位置にdeclarationを付与 | 宣言時 |
| BR-43-08 | readonly修飾子 | const属性、_ENVに付与 | const/close変数 |

### 計算ロジック

トークンエンコード:
```lua
-- 5つ組でエンコード
tokens[len + 1] = deltaLine
tokens[len + 2] = deltaStartChar
tokens[len + 3] = finishPos.character - startPos.character
tokens[len + 4] = source.type
tokens[len + 5] = source.modifieres or 0
```

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

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 空配列返却 | Lua.semantic.enable=false | 空のdata配列を返却 |
| - | 空配列返却 | ドキュメント状態が取得できない | 空のdata配列を返却 |

### リトライ仕様

リトライは行わない。

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

該当なし（メモリ内処理のみ）

## パフォーマンス要件

- 100要素ごとにawait.delay()で他の処理に譲る
- abortByFileUpdate=trueにより、ファイル更新時は処理をキャンセル
- クライアントのuseSemanticByRangeオプションにより範囲指定に切り替え可能

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

- 特になし

## 備考

- TokenTypesとTokenModifiersはproto/define.luaで定義
- マルチライントークンはクライアントの対応状況に応じて分割

---

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

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

### 推奨読解順序

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

トークンタイプと修飾子の定義を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | define.lua | `script/proto/define.lua` | TokenTypes（142-166行目）とTokenModifiers（128-140行目）を理解 |

**読解のコツ**: TokenModifiersはビットマスクで複数の修飾子を組み合わせ可能。

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

LSPリクエストハンドラを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | provider.lua | `script/provider/provider.lua` | semanticTokens/fullの登録を理解（1079-1109行目） |

**主要処理フロー**:
1. **1082-1091行目**: capability定義（legend設定）
2. **1094-1098行目**: ワークスペース準備とsleep
3. **1100-1101行目**: core/semantic-tokens.lua呼び出し
4. **1102-1104行目**: レスポンス生成

#### Step 3: コアロジックを理解する

セマンティックトークン生成のロジックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | semantic-tokens.lua | `script/core/semantic-tokens.lua` | Careスイッチの各ケースを理解 |

**主要処理フロー**:
- **12-54行目**: getglobal/setglobal処理（グローバル変数）
- **55-70行目**: getmethod/setmethod処理（メソッド）
- **71-116行目**: field処理（フィールド）
- **117-255行目**: local/self/getlocal/setlocal処理（ローカル変数）
- **256-280行目**: function/ifblock等のキーワード処理
- **421-471行目**: doc.type.name処理（型名）
- **731-764行目**: buildTokens()でエンコード

#### Step 4: 複数行処理を理解する

マルチラインとオーバーラップの解決処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | semantic-tokens.lua | `script/core/semantic-tokens.lua` | solveMultilineAndOverlapping関数（767-870行目）を理解 |

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

```
provider.lua (m.register 'textDocument/semanticTokens/full')
    │
    ├─ workspace.awaitReady(uri)
    │      └─ workspace.lua: ワークスペース準備完了を待機
    │
    └─ core/semantic-tokens.lua
           │
           ├─ config.get(uri, 'Lua.semantic.enable')
           │      └─ 有効/無効チェック
           │
           ├─ files.getState(uri)
           │      └─ AST取得
           │
           ├─ guide.eachSourceBetween(state.ast, start, finish, callback)
           │      │
           │      └─ Care(source.type, source, options, results)
           │             ├─ getglobal/setglobal → variable/function
           │             ├─ getmethod/setmethod → method
           │             ├─ field → property/method
           │             ├─ local/getlocal/setlocal → variable/function/parameter
           │             ├─ function/if/do... → keyword
           │             └─ doc.* → type/parameter/class
           │
           ├─ state.comms処理
           │      └─ コメント/LuaDocのトークン生成
           │
           ├─ solveMultilineAndOverlapping(state, results)
           │      └─ トークンの整理
           │
           └─ buildTokens(results)
                  └─ 差分エンコード
```

### データフロー図

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

LSPリクエスト             provider.lua
  └─ uri          ───▶    └─ workspace.awaitReady()
                                    │
                                    ▼
                          semantic-tokens.lua
                          ├─ config.get() → options
                          ├─ files.getState() → AST
                          │
                          ▼
                    guide.eachSourceBetween()
                          │
                    ┌─────┴─────┐
                    ▼           ▼
              Care(type)   comms処理
                    │           │
                    └─────┬─────┘
                          ▼
              solveMultilineAndOverlapping()
                          │
                          ▼
                    buildTokens()
                          │
                          ▼                      { data: integer[] }
                    LSPレスポンス ────────────▶   [deltaLine, deltaChar,
                                                   length, type, modifiers, ...]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| provider.lua | `script/provider/provider.lua` | ソース | LSPリクエストハンドラの登録・実行 |
| semantic-tokens.lua | `script/core/semantic-tokens.lua` | ソース | セマンティックトークン生成のコアロジック |
| define.lua | `script/proto/define.lua` | ソース | TokenTypes/TokenModifiersの定義 |
| converter.lua | `script/proto/converter.lua` | ソース | 位置変換 |
| files.lua | `script/files.lua` | ソース | ファイル管理・状態取得 |
| guide.lua | `script/parser/guide.lua` | ソース | AST走査ユーティリティ |
| vm/infer.lua | `script/vm/infer.lua` | ソース | 型推論（hasFunction判定） |
| linked-table.lua | `script/linked-table.lua` | ソース | オーバーラップ解決用データ構造 |
