# 機能設計書：97-with（withマクロ）

## 1. 概要

### 本機能の処理概要
withモジュールは、関数チェーンを簡潔に記述するための`with`マクロを提供する。このマクロは、指定されたオブジェクトに対して複数の操作を連続して適用する際に、オブジェクト名の繰り返し記述を省略できるようにする。RFC-192およびRFC-193に基づいて設計され、Nim 1.2以降で利用可能である。

### 関連画面
本機能は標準ライブラリのユーティリティマクロであり、特定の画面には関連しない。

### 機能種別
ライブラリ機能（マクロ・DSL）

## 2. 入力仕様

### マクロシグネチャ
```nim
macro with*(arg: typed; calls: varargs[untyped]): untyped
```

### 入力パラメータ

| パラメータ | 型 | 説明 |
|----------|-----|------|
| arg | typed | チェーンの対象となるオブジェクト |
| calls | varargs[untyped] | argに対して適用される呼び出しのリスト |

### 使用パターン

```nim
# パターン1: 基本的なメソッド呼び出し
with x:
  add "abc"
  add "efg"

# パターン2: 演算子の適用
with a:
  += 4
  -= 5

# パターン3: ネストしたwith
with foo:
  bar = 2
  with qux:
    baz = 3
```

## 3. 出力仕様

### マクロ展開結果
マクロは入力された呼び出しリストを変換し、各呼び出しの第一引数に`arg`を挿入したステートメントリストを生成する。

### 展開例

入力:
```nim
var x = "yay"
with x:
  add "abc"
  add "efg"
```

展開後:
```nim
var x = "yay"
x.add("abc")
x.add("efg")
```

## 4. 処理フロー

### 4.1 マクロ展開フロー

```
[with(arg, calls)呼び出し]
    |
    v
[nnkStmtList結果ノード作成]
    |
    v
[underscoredCalls(result, calls, arg)]
    |
    v
[各call要素を処理]
    |
    +-- [nnkCallKinds] --> [underscoredCall]
    |       |
    |       +-- [with呼び出し検出] --> [ネスト処理]
    |       |
    |       +-- [_位置検出] --> [arg挿入]
    |       |
    |       +-- [その他] --> [第一引数としてarg追加]
    |
    +-- [nnkAsgn/nnkExprEqExpr] --> [ドット代入に変換]
    |
    +-- [その他] --> [関数呼び出しとしてarg追加]
    |
    v
[変換済みステートメントリストを返却]
```

### 4.2 アンダースコア位置検出

```
[underscorePos(n)呼び出し]
    |
    v
[n[1..n.len-1]を走査]
    |
    +-- ["_"と一致] --> [位置iを返却]
    |
    +-- [一致なし] --> [0を返却（先頭に挿入）]
```

## 5. ビジネスルール

### BR-01: 引数の複数評価
`arg`は各呼び出しで個別に評価される。副作用を持つ式を`arg`として渡す場合、複数回実行される可能性があるため注意が必要。

### BR-02: アンダースコアによる位置指定
呼び出し内で`_`を使用することで、`arg`の挿入位置を明示的に指定できる（dupマクロと同様の機能）。

### BR-03: ネストサポート
`with`ブロック内で別の`with`を使用することで、ネストしたオブジェクトへのアクセスが可能。この場合、内部の`with`は外部の`arg`にドットアクセスした結果を新たな`arg`として使用する。

### BR-04: 代入演算子のサポート
`=`や`+=`などの代入演算子は、`arg.field = value`形式に変換される。

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

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

## 7. エラー処理

### コンパイル時エラー

| 条件 | エラー |
|-----|--------|
| ネストwithで第一引数がIdent/Symでない | expectKindによるコンパイルエラー |

### 注意事項
- 実行時エラーは発生しない（すべてコンパイル時に解決）
- 型チェックは`arg`が`typed`であることで保証

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

本機能はトランザクション処理を行わない。

## 9. パフォーマンス要件

### コンパイル時間
- マクロ展開はコンパイル時に完了
- 展開後のコードは直接記述と同等の効率

### 実行時オーバーヘッド
- なし（マクロは完全にコンパイル時に解決）
- 生成されるコードは手書きと等価

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

### 安全性
- 型安全性はコンパイラが保証
- マクロ展開は予測可能で透過的

### 注意点
- `arg`の複数評価による副作用に注意

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

### 11.1 推奨される読み解き順序

1. **モジュールドキュメント**（10-15行目）
   - RFC参照とバージョン情報
   - 設計背景の理解

2. **withマクロ本体**（19-48行目）
   - `arg: typed`と`calls: varargs[untyped]`の役割
   - `underscoredCalls`への委譲

3. **underscored_calls.nim**（lib/std/private/underscored_calls.nim）
   - `underscoredCalls`プロシージャ（49-56行目）
   - `underscoredCall`プロシージャ（17-47行目）
   - `underscorePos`内部関数（18-21行目）

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

```
with*(arg: typed, calls: varargs[untyped]): untyped
└── underscoredCalls(result, calls, arg0: NimNode)
    ├── [StmtList/StmtListExprの場合] 再帰呼び出し
    └── underscoredCall(n, arg0: NimNode): NimNode
        ├── [nnkCallKinds]
        │   ├── [with呼び出し] underscoredCalls (再帰)
        │   └── [その他] underscorePos → arg0挿入
        ├── [nnkAsgn/nnkExprEqExpr] newDotExpr + newAssignment
        └── [その他] nnkCall作成
```

### 11.3 データフロー図

```
入力AST:
  with x:          ──┐
    add "abc"        ├──> [withマクロ]
    add "efg"      ──┘
                          |
                          v
                   [underscoredCalls]
                          |
           ┌──────────────┼──────────────┐
           v              v              v
    [add "abc"]    [add "efg"]    (他のcalls...)
           |              |
           v              v
    [underscoredCall] [underscoredCall]
           |              |
           v              v
    x.add("abc")   x.add("efg")

出力AST:
  nnkStmtList
    ├── nnkCall(add, x, "abc")
    └── nnkCall(add, x, "efg")
```

### 11.4 関連ファイル一覧

| ファイル | 役割 | 行数 |
|---------|------|------|
| lib/std/with.nim | withマクロの公開インターフェース | 49 |
| lib/std/private/underscored_calls.nim | 内部AST変換ロジック | 57 |
| lib/core/macros.nim | マクロ基盤（NimNode操作） | - |

### 11.5 重要な実装詳細

#### ネストwithの処理（underscored_calls.nim 24-28行目）
```nim
if n[0].kind in {nnkIdent, nnkSym} and n[0].eqIdent("with"):
  expectKind n[1], {nnkIdent, nnkSym}
  result = newStmtList()
  underscoredCalls(result, n[2 .. ^1].newStmtList, newDotExpr(arg0, n[1]))
```

ネストした`with`は、外部の`arg0`と内部のフィールド名をドット結合して新たな対象オブジェクトを生成する。

#### アンダースコア位置検出（underscored_calls.nim 18-21行目）
```nim
proc underscorePos(n: NimNode): int =
  for i in 1 ..< n.len:
    if n[i].eqIdent("_"): return i
  return 0
```

`_`が見つからない場合は0を返し、引数リストの先頭（インデックス1の前）に`arg0`を挿入する。

#### 代入処理（underscored_calls.nim 37-42行目）
```nim
elif n.kind in {nnkAsgn, nnkExprEqExpr}:
  var field = n[0]
  if n[0].kind == nnkDotExpr and n[0][0].eqIdent("_"):
    field = n[0][1]
  result = newDotExpr(arg0, field).newAssignment n[1]
```

`field = value`を`arg0.field = value`に変換。`_.field = value`形式もサポートされる。
