# Nim コンパイラ コードリーディングガイドライン

## はじめに

このガイドラインは、Nimコンパイラのコードベースを効率的に理解するための手引きです。
Nim言語に精通していないエンジニアでも、段階的に学習できるよう構成されています。

**対象読者:**
- プロジェクトに新規参画するエンジニア
- 他言語からの経験者
- コードレビューを行う担当者

**プロジェクト概要:**
- **リポジトリ名**: Nim-devel（Nimコンパイラ開発版）
- **主要言語**: Nim
- **ライセンス**: MIT
- **作者**: Andreas Rumpf

---

## 1. 言語基礎

> このセクションでは、Nim言語の基本構文と概念を解説します。

### 1.1 プログラム構造

Nimはインデントベースの構文を持つコンパイル型言語です。各ファイルはモジュールとして扱われます。

```nim
# compiler/nim.nim:1-14
#
#
#           The Nim Compiler
#        (c) Copyright 2015 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

import std/[os, strutils, parseopt]

when defined(nimPreviewSlimSystem):
  import std/assertions
```

**解説:**
- `#` でコメントを記述
- `import` でモジュールをインポート
- `when` は条件付きコンパイル（C言語の`#if`に相当）
- `defined()` はコンパイル時シンボルの存在をチェック

### 1.2 データ型と変数

Nimは静的型付け言語で、`var`（変数）、`let`（不変変数）、`const`（コンパイル時定数）を使用します。

```nim
# compiler/lexer.nim:27-33
const
  numChars*: set[char] = {'0'..'9', 'a'..'z', 'A'..'Z'}
  SymChars*: set[char] = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
  SymStartChars*: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
  OpChars*: set[char] = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.',
    '|', '=', '%', '&', '$', '@', '~', ':'}
```

**解説:**
- `*` はエクスポートマーカー（外部モジュールからアクセス可能）
- `set[char]` は文字の集合型
- `'a'..'z'` は範囲指定

### 1.3 制御構造

Nimの制御構造は読みやすさを重視した設計です。

```nim
# compiler/nim.nim:57-77
while true:
  parseopt.next(p)
  case p.kind
  of cmdEnd: break
  of cmdLongOption, cmdShortOption:
    config.commandLine.add " "
    config.commandLine.addCmdPrefix p.kind
    if p.key == "":
      p.key = "-"
      if processArgument(pass, p, argsCount, config): break
    else:
      processSwitch(pass, p, config)
  of cmdArgument:
    config.commandLine.add " "
    config.commandLine.add p.key.quoteShell
    if processArgument(pass, p, argsCount, config): break
```

**解説:**
- `while true` は無限ループ
- `case ... of` はパターンマッチ（switch文の強化版）
- `break` でループを抜ける
- `if ... else` は標準的な条件分岐

### 1.4 関数/メソッド定義

Nimでは`proc`（プロシージャ）で関数を定義します。

```nim
# compiler/nim.nim:41-48
proc nimbleLockExists(config: ConfigRef): bool =
  const nimbleLock = "nimble.lock"
  let pd = if not config.projectPath.isEmpty: config.projectPath else: AbsoluteDir(getCurrentDir())
  if optSkipParentConfigFiles notin config.globalOptions:
    for dir in parentDirs(pd.string, fromRoot=true, inclusive=false):
      if fileExists(dir / nimbleLock):
        return true
  return fileExists(pd.string / nimbleLock)
```

**解説:**
- `proc 名前(引数: 型): 戻り値型 =` の形式
- `result` は暗黙の戻り値変数（または明示的に`return`を使用）
- `notin` は「含まれない」演算子

### 1.5 モジュール/インポート

Nimのモジュールシステムは明示的なインポートを採用しています。

```nim
# compiler/nim.nim:27-32
import
  commands, options, msgs, extccomp, main, idents, lineinfos, cmdlinehelper,
  pathutils, modulegraphs

from std/browsers import openDefaultBrowser
from nodejs import findNodeJs
```

**解説:**
- `import` は全シンボルをインポート
- `from X import Y` は特定シンボルのみインポート
- `std/` プレフィックスは標準ライブラリ

---

## 2. プロジェクト固有の概念

> このセクションでは、Nimコンパイラ特有の概念を解説します。

### 2.1 コンパイラパイプライン

Nimコンパイラは複数のパス（フェーズ）で構成されています。

```nim
# compiler/pipelines.nim:22-62
proc setPipeLinePass*(graph: ModuleGraph; pass: PipelinePass) =
  graph.pipelinePass = pass

proc processPipeline(graph: ModuleGraph; semNode: PNode; bModule: PPassContext): PNode =
  case graph.pipelinePass
  of CgenPass:
    result = semNode
    if bModule != nil:
      genTopLevelStmt(BModule(bModule), result)
  of NifgenPass:
    result = semNode
    if bModule != nil:
      genTopLevelNif(bModule, result)
  of JSgenPass:
    when not defined(leanCompiler):
      result = processJSCodeGen(bModule, semNode)
```

**主要なパイプラインパス:**
| パス | 説明 |
|------|------|
| `SemPass` | 意味解析（セマンティック解析） |
| `CgenPass` | Cコード生成 |
| `JSgenPass` | JavaScriptコード生成 |
| `NifgenPass` | NIF（Nim Intermediate Format）生成 |
| `Docgen2Pass` | ドキュメント生成 |
| `EvalPass` | コンパイル時評価 |

### 2.2 AST（抽象構文木）

コンパイラの中核はASTの処理です。

```nim
# compiler/ast.nim:73-93
proc owner*(s: PSym): PSym {.inline.} =
  if s.state == Partial: loadSym(s)
  result = s.ownerFieldImpl

proc kind*(s: PSym): TSymKind {.inline.} =
  if s.state == Partial: loadSym(s)
  result = s.kindImpl
```

**主要な型:**
| 型 | 説明 |
|-----|------|
| `PNode` | ASTノードのポインタ |
| `PSym` | シンボル（変数、関数など）のポインタ |
| `PType` | 型情報のポインタ |
| `TNodeKind` | ノードの種類を表す列挙型 |
| `TSymKind` | シンボルの種類を表す列挙型 |

### 2.3 コンパイル時評価（VM）

Nimにはコンパイル時にコードを実行するVMが組み込まれています。

```nim
# compiler/vm.nim:10-11
## This file implements the new evaluation engine for Nim code.
## An instruction is 1-3 int32s in memory, it is a register based VM.
```

**VMの用途:**
- マクロの実行
- `static`式の評価
- コンパイル時FFI

---

## 3. 命名規則

> このセクションでは、プロジェクト全体で使用される命名規則を解説します。

### 3.1 ファイル・ディレクトリ命名

| パターン | 意味 | 例 |
|---------|------|-----|
| `小文字.nim` | 一般的なモジュール | `ast.nim`, `lexer.nim`, `parser.nim` |
| `sem*.nim` | セマンティック解析関連 | `sem.nim`, `semexprs.nim`, `semstmts.nim` |
| `ccg*.nim` | Cコード生成関連 | `ccgexprs.nim`, `ccgstmts.nim`, `ccgtypes.nim` |
| `vm*.nim` | 仮想マシン関連 | `vm.nim`, `vmdef.nim`, `vmgen.nim` |

### 3.2 型・関数・変数命名

| プレフィックス/サフィックス | 意味 | 例 |
|---------------------------|------|-----|
| `P` | ポインタ型（ref/ptr） | `PNode`, `PSym`, `PType` |
| `T` | 列挙型・レコード型 | `TNodeKind`, `TSymKind`, `TSymFlag` |
| `sf` | シンボルフラグ | `sfExported`, `sfUsed`, `sfGlobal` |
| `nk` | ノードカインド | `nkIdent`, `nkProcDef`, `nkCall` |
| `*` | エクスポートされたシンボル | `proc foo*()`, `type Bar* = object` |

### 3.3 プログラム分類一覧

| ファイルパターン | 役割 |
|----------------|------|
| `compiler/*.nim` | コンパイラ本体 |
| `lib/system.nim` | 暗黙的にインポートされるシステムモジュール |
| `lib/pure/*.nim` | 純粋なNimで書かれた標準ライブラリ |
| `lib/std/*.nim` | 新しい標準ライブラリモジュール |
| `lib/impure/*.nim` | 外部依存のある標準ライブラリ |
| `lib/wrappers/*.nim` | 外部ライブラリのラッパー |
| `tests/*/*.nim` | テストケース |

---

## 4. ディレクトリ構造

> このセクションでは、プロジェクトのディレクトリ構造を解説します。

```
Nim-devel/
├── bin/                    # ビルド済みバイナリ（空）
├── build/                  # ビルド中間ファイル（空）
├── compiler/               # コンパイラソースコード
│   ├── ast.nim            # AST定義
│   ├── astdef.nim         # AST基本型定義
│   ├── lexer.nim          # 字句解析器
│   ├── parser.nim         # 構文解析器
│   ├── sem*.nim           # 意味解析
│   ├── cgen.nim           # Cコード生成
│   ├── ccg*.nim           # C生成ヘルパー
│   ├── jsgen.nim          # JS生成
│   ├── vm*.nim            # 仮想マシン
│   ├── nim.nim            # コンパイラエントリーポイント
│   └── plugins/           # コンパイラプラグイン
├── config/                 # 設定ファイル
├── doc/                    # ドキュメント（reStructuredText）
├── lib/                    # 標準ライブラリ
│   ├── system.nim         # システムモジュール
│   ├── pure/              # 純粋なNimモジュール
│   ├── std/               # 新しいstdモジュール
│   ├── core/              # コアモジュール
│   ├── impure/            # 外部依存モジュール
│   └── wrappers/          # FFIラッパー
├── nimsuggest/            # IDE支援ツール
├── nimpretty/             # コードフォーマッタ
├── testament/             # テストフレームワーク
├── tests/                 # テストケース
├── tools/                 # 各種ツール
├── koch.nim               # ビルドツール
└── nim.nimble             # パッケージ定義
```

### 各ディレクトリの役割

| ディレクトリ | 役割 | 主要ファイル |
|-------------|------|-------------|
| `compiler/` | コンパイラ本体 | `nim.nim`, `ast.nim`, `sem.nim`, `cgen.nim` |
| `lib/` | 標準ライブラリ | `system.nim`, `pure/strutils.nim`, `pure/os.nim` |
| `lib/pure/` | 依存なしモジュール | `strutils.nim`, `math.nim`, `json.nim` |
| `lib/std/` | 新APIモジュール | `paths.nim`, `syncio.nim`, `assertions.nim` |
| `tests/` | テストスイート | カテゴリごとにサブディレクトリ |
| `nimsuggest/` | 言語サーバー | IDE補完・解析サポート |
| `testament/` | テスト実行器 | `testament.nim` |

---

## 5. アーキテクチャ

> このセクションでは、プロジェクトのアーキテクチャパターンを解説します。

### 5.1 全体アーキテクチャ

Nimコンパイラはパイプラインアーキテクチャを採用しています。

```mermaid
flowchart LR
    A[Source Code] --> B[Lexer]
    B --> C[Parser]
    C --> D[Semantic Analysis]
    D --> E{Backend}
    E -->|C| F[C Code Generator]
    E -->|JS| G[JS Code Generator]
    E -->|VM| H[Nim VM]
    F --> I[C Compiler]
    I --> J[Native Binary]
    G --> K[JavaScript]
```

### 5.2 レイヤー構成

| レイヤー | 責務 | 代表的なファイル |
|---------|------|-----------------|
| フロントエンド | ソースコード解析 | `lexer.nim`, `parser.nim` |
| 中間処理 | 意味解析・最適化 | `sem.nim`, `transf.nim`, `injectdestructors.nim` |
| バックエンド | コード生成 | `cgen.nim`, `jsgen.nim`, `vm.nim` |
| 共通基盤 | AST・型定義 | `ast.nim`, `astdef.nim`, `types.nim` |

### 5.3 データフロー

1. **字句解析** (`lexer.nim`): ソースコードをトークン列に変換
2. **構文解析** (`parser.nim`): トークン列をAST（抽象構文木）に変換
3. **意味解析** (`sem.nim`): 型チェック、シンボル解決、マクロ展開
4. **変換** (`transf.nim`): デストラクタ注入、ループ展開など
5. **コード生成** (`cgen.nim`/`jsgen.nim`): ターゲットコード出力

---

## 6. 主要コンポーネント

> このセクションでは、主要なコンポーネントとその連携を解説します。

### 6.1 エントリーポイント

コンパイラの起動は `compiler/nim.nim` から始まります。

```nim
# compiler/nim.nim:167-172
when not defined(selftest):
  let conf = newConfigRef()
  handleCmdLine(newIdentCache(), conf)
  when declared(GC_setMaxPause):
    echo GC_getStatistics()
  msgQuit(int8(conf.errorCounter > 0))
```

**処理の流れ:**
1. 設定オブジェクト（`ConfigRef`）を作成
2. コマンドライン引数を処理
3. `handleCmdLine` でメイン処理を実行

### 6.2 メインコマンド処理

`compiler/main.nim` でコマンドに応じた処理を実行します。

```nim
# compiler/main.nim:254-293
proc mainCommand*(graph: ModuleGraph) =
  let conf = graph.config
  let cache = graph.cache

  conf.lastCmdTime = epochTime()
  conf.searchPaths.add(conf.libpath)

  case conf.cmd
  of cmdBackends:
    compileToBackend()
  of cmdCheck:
    commandCheck(graph)
  of cmdDoc:
    docLikeCmd():
      commandDoc2(graph, HtmlExt)
```

### 6.3 意味解析

`compiler/sem.nim` が意味解析の中心です。

```nim
# compiler/sem.nim:37-56
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode
proc semExprNoType(c: PContext, n: PNode): PNode
proc semProcBody(c: PContext, n: PNode; expectedType: PType = nil): PNode
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType
proc semStmt(c: PContext, n: PNode; flags: TExprFlags): PNode
```

**主要な関数:**
| 関数 | 役割 |
|------|------|
| `semExpr` | 式のセマンティック解析 |
| `semStmt` | 文のセマンティック解析 |
| `semTypeNode` | 型式の解析 |
| `semProcBody` | プロシージャ本体の解析 |

### 6.4 コード生成

Cコード生成は `compiler/cgen.nim` で行われます。

```nim
# compiler/cgen.nim:9-10
## This module implements the C code generator.
```

関連ファイル群:
- `ccgexprs.nim`: 式のCコード生成
- `ccgstmts.nim`: 文のCコード生成
- `ccgtypes.nim`: 型のCコード生成
- `ccgcalls.nim`: 関数呼び出しのコード生成

---

## 7. よく使われるパターン

> このセクションでは、コード内で頻出するパターンを解説します。

### パターン一覧

| パターン | 説明 | 出現頻度 | 代表的なファイル |
|---------|------|---------|-----------------|
| 遅延ロード | オンデマンドでシンボル/型をロード | 高 | `ast.nim` |
| パイプライン | 処理を段階的に実行 | 高 | `pipelines.nim` |
| ビジター | AST走査パターン | 中 | `sem.nim`, `cgen.nim` |
| 設定オブジェクト | 設定を一元管理 | 高 | `options.nim` |

### 各パターンの詳細

#### パターン1: 遅延ロード (Lazy Loading)

**目的:** インクリメンタルコンパイル対応のため、必要になるまでシンボルをロードしない

```nim
# compiler/ast.nim:73-76
proc owner*(s: PSym): PSym {.inline.} =
  if s.state == Partial: loadSym(s)
  result = s.ownerFieldImpl
```

**解説:**
- `state == Partial` は未ロード状態
- アクセス時に `loadSym` で完全な情報をロード
- NIF（Nim Intermediate Format）ファイルからの読み込みに使用

#### パターン2: パイプラインパス

**目的:** コンパイルの各段階を明確に分離し、柔軟な処理を可能に

```nim
# compiler/pipelines.nim:22-24
proc setPipeLinePass*(graph: ModuleGraph; pass: PipelinePass) =
  graph.pipelinePass = pass
```

**解説:**
- `PipelinePass` 列挙型で現在のパスを指定
- パスに応じて異なる処理を実行

#### パターン3: 条件付きコンパイル

**目的:** ビルド条件に応じてコードを有効化/無効化

```nim
# compiler/cgen.nim:36-38
when not defined(leanCompiler):
  import spawn, semparallel
```

**解説:**
- `when defined()` でコンパイル時条件分岐
- `leanCompiler` はメモリ使用量削減のためのフラグ

---

## 8. 業務フロー追跡の実践例

> このセクションでは、実際の業務フローをコードで追跡する方法を解説します。

### 8.1 フロー追跡の基本手順

1. エントリーポイントを特定
2. 処理の流れを追跡（呼び出し関係を追う）
3. データの変換を確認
4. 最終的な出力を確認

### 8.2 フロー追跡の実例

#### 例1: コンパイルコマンドの実行フロー

**概要:** `nim c hello.nim` を実行したときの処理フロー

**処理フロー:**
```
nim.nim → handleCmdLine → mainCommand → compileToBackend → commandCompileToC
```

**詳細な追跡:**

1. **エントリーポイント** (`compiler/nim.nim:167-172`)
   ```nim
   when not defined(selftest):
     let conf = newConfigRef()
     handleCmdLine(newIdentCache(), conf)
   ```

2. **コマンドライン処理** (`compiler/nim.nim:98-112`)
   ```nim
   proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
     let self = NimProg(
       supportsStdinFile: true,
       processCmdLine: processCmdLine
     )
     self.initDefinesProg(conf, "nim_compiler")
     # ...
     mainCommand(graph)
   ```

3. **メインコマンド実行** (`compiler/main.nim:320-322`)
   ```nim
   case conf.cmd
   of cmdBackends:
     compileToBackend()
   ```

4. **Cコード生成** (`compiler/main.nim:146-176`)
   ```nim
   proc commandCompileToC(graph: ModuleGraph) =
     # ...
     setPipeLinePass(graph, CgenPass)
     compilePipelineProject(graph)
     cgenWriteModules(graph.backend, conf)
     extccomp.callCCompiler(conf)
   ```

### 8.3 フロー追跡チェックリスト

- [ ] エントリーポイントを特定したか
- [ ] 呼び出し関係を把握したか
- [ ] データの変換ポイントを確認したか
- [ ] エラーハンドリングを確認したか
- [ ] 最終的な出力を確認したか

---

## 9. 設計書の参照順序

> このセクションでは、プロジェクト理解のための設計書参照順序を案内します。

### 9.1 目的別ロードマップ

#### 全体像を把握したい場合
1. `readme.md` - プロジェクト概要
2. `doc/intern.html` - コンパイラ内部構造
3. `compiler/readme.md` - コンパイラディレクトリの説明

#### 特定機能を理解したい場合
1. 対象機能のソースファイル（ヘッダコメント）
2. 関連する `doc/*.rst` ファイル
3. `tests/` 内の対応するテストケース

#### 改修作業を行う場合
1. 対象機能のソースコード
2. 関連するテストケース（`tests/` 以下）
3. `changelog.md` で過去の変更履歴を確認

### 9.2 ドキュメント一覧

| ドキュメント | 概要 | 参照タイミング |
|-------------|------|---------------|
| `readme.md` | プロジェクト概要 | 最初に読む |
| `doc/koch.md` | ビルドツール説明 | ビルド時 |
| `doc/intern.html` | コンパイラ内部 | 開発時 |
| `doc/grammar.txt` | 文法定義 | パーサー理解時 |
| `changelog.md` | 変更履歴 | 影響調査時 |

---

## 10. トラブルシューティング

> このセクションでは、コードリーディング時によくある問題と解決法を解説します。

### よくある疑問と回答

#### Q: `P` プレフィックスの型は何ですか？
A: ポインタ型（refまたはptr）を示します。例: `PNode` = `ref TNode`。Nimではガベージコレクションされる参照型には `ref` を使用します。

#### Q: `sf` で始まる定数は何ですか？
A: シンボルフラグ（Symbol Flag）です。`compiler/astdef.nim` で定義され、シンボルの属性を表します。例: `sfExported`（エクスポート済み）、`sfUsed`（使用済み）。

#### Q: `nk` で始まる定数は何ですか？
A: ノードカインド（Node Kind）です。`compiler/nodekinds.nim` で定義され、ASTノードの種類を表します。例: `nkProcDef`（プロシージャ定義）、`nkCall`（関数呼び出し）。

#### Q: `when defined()` の条件はどこで設定されますか？
A: コンパイル時に `-d:シンボル名` で設定するか、`.nim.cfg` ファイルで定義します。主要なシンボル:
- `nimPreviewSlimSystem`: スリムなsystemモジュール
- `leanCompiler`: 軽量コンパイラビルド
- `nimKochBootstrap`: ブートストラップビルド

### デバッグのヒント

1. **コンパイラのデバッグ出力:**
   ```bash
   nim c --verbosity:3 yourfile.nim
   ```

2. **AST出力の確認:**
   ```bash
   nim dump --ast yourfile.nim
   ```

3. **生成Cコードの確認:**
   生成されたCコードは `~/.cache/nim/` 以下に保存されます。

4. **テストの実行:**
   ```bash
   ./koch tests cat async  # 特定カテゴリのみ
   ```

---

## 付録

### A. 用語集

| 用語 | 説明 |
|-----|------|
| AST | 抽象構文木（Abstract Syntax Tree） |
| PSym | シンボルへのポインタ（変数、関数、型などの情報） |
| PNode | ASTノードへのポインタ |
| PType | 型情報へのポインタ |
| NIF | Nim Intermediate Format（中間フォーマット） |
| koch | Nimのビルド・保守ツール |
| testament | Nimのテストフレームワーク |
| nimsuggest | IDE支援ツール（言語サーバー） |
| VM | 仮想マシン（コンパイル時コード実行用） |
| IC | Incremental Compilation（インクリメンタルコンパイル） |

### B. ファイル一覧

| ファイル/ディレクトリ | 説明 | 主な内容 |
|---------------------|------|---------|
| `compiler/nim.nim` | コンパイラエントリーポイント | メイン関数、コマンドライン処理 |
| `compiler/ast.nim` | AST操作 | ノード操作関数、シンボル操作 |
| `compiler/astdef.nim` | AST型定義 | TNodeKind, TSymKind, フラグ定義 |
| `compiler/lexer.nim` | 字句解析器 | トークン定義、字句解析ロジック |
| `compiler/parser.nim` | 構文解析器 | 文法規則に基づくパーサー |
| `compiler/sem.nim` | 意味解析 | 型チェック、シンボル解決 |
| `compiler/cgen.nim` | Cコード生成 | C言語へのトランスパイル |
| `compiler/jsgen.nim` | JSコード生成 | JavaScriptへのトランスパイル |
| `compiler/vm.nim` | 仮想マシン | コンパイル時コード実行 |
| `lib/system.nim` | システムモジュール | 基本型、基本関数 |
| `koch.nim` | ビルドツール | ビルド、テスト、ドキュメント生成 |

### C. 参考資料

- [Nim公式ドキュメント](https://nim-lang.org/documentation.html)
- [Nim言語マニュアル](https://nim-lang.org/docs/manual.html)
- [コンパイラ内部ドキュメント](https://nim-lang.github.io/Nim/intern.html)
- [Nimフォーラム](https://forum.nim-lang.org/)
- [Nim GitHub Wiki](https://github.com/nim-lang/Nim/wiki)
