docs(phase134-a): mir_call.py unified 設計完成(指示書作成)
- 目標: 681行の giant ファイルを機能別に分割 - 箱化: グローバル/メソッド/コンストラクタ/クロージャ/値/外部関数の各呼び出し処理を分離 - レガシー削除: NYASH_MIR_UNIFIED_CALL フラグ廃止、legacy dispatcher 削除 - 互換層: JSON v0/v1 コード を mir_call_compat.py に外出し - 6タスク: 設計doc、棚卸し、compat実装、分割実装、統合確認、テスト
This commit is contained in:
444
docs/development/current/main/phase134_mir_call_unification.md
Normal file
444
docs/development/current/main/phase134_mir_call_unification.md
Normal file
@ -0,0 +1,444 @@
|
||||
# Phase 134-A: mir_call.py の未完成 unified 設計を完成
|
||||
|
||||
## 🎯 ゴール
|
||||
|
||||
**mir_call.py の「未完成 unified 設計」を構造的に完成** させる。
|
||||
|
||||
目的:
|
||||
- `NYASH_MIR_UNIFIED_CALL` フラグを廃止し、unified をcanonicalに統一
|
||||
- **681行の giant ファイル** を機能別に分割(global/method/constructor等)
|
||||
- **legacy dispatcher の未実装部分** を削除
|
||||
- JSON v0/v1 互換コードを専用モジュールに外出し
|
||||
|
||||
```
|
||||
Phase 133: ConsoleBox LLVM 統合(7/7達成)✅
|
||||
↓
|
||||
Phase 134-A: mir_call.py unified 設計完成 ← ← ここ!
|
||||
↓
|
||||
Phase 134-B: StringBox bridge 分離
|
||||
↓
|
||||
Phase 134-C: CollectionBox bridge 分離
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 スコープ(やること・やらないこと)
|
||||
|
||||
### ✅ やること
|
||||
- `lower_legacy_call()` の NotImplementedError を削除(削除するのが目的)
|
||||
- NYASH_MIR_UNIFIED_CALL フラグを廃止
|
||||
- mir_call.py(681行)を機能別に分割:
|
||||
- global_call.py, method_call.py, constructor_call.py, closure_call.py, value_call.py, extern_call.py
|
||||
- dispatcher (__init__.py) で統合
|
||||
- JSON v0/v1 互換コードを mir_call_compat.py に外出し
|
||||
- 分割後も機能・動作は一切変えない(既存テスト全て通過)
|
||||
|
||||
### ❌ やらないこと
|
||||
- MIR の意味論変更(Call 命令仕様は現状維持)
|
||||
- Python LLVM backend 以外の層への影響
|
||||
- 他のBox系bridge(StringBox/CollectionBox)の分離(Phase 134-B/C の役目)
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ 6 つのタスク
|
||||
|
||||
### Task 1: 設計ドキュメント作成
|
||||
|
||||
**ファイル**: `docs/development/current/main/phase134_mir_call_unification.md`(このファイル)
|
||||
|
||||
**書く内容**:
|
||||
|
||||
#### 現状整理
|
||||
|
||||
**mir_call.py の問題点**:
|
||||
1. **ファイルサイズが giant**: 681行
|
||||
- lower_global_call() - 行 117+
|
||||
- lower_method_call() - 複数メソッド
|
||||
- lower_constructor_call()
|
||||
- lower_closure_creation()
|
||||
- lower_value_call()
|
||||
- lower_extern_call()
|
||||
- すべて同一ファイル
|
||||
|
||||
2. **未完成の dispatcher**:
|
||||
- 行 34: `NYASH_MIR_UNIFIED_CALL` フラグで legacy/unified 切り替え
|
||||
- 行 110-114: `lower_legacy_call()` が `NotImplementedError` 即座
|
||||
- 実質的には unified のみが有効
|
||||
|
||||
3. **JSON v0/v1 互換コードの混在**:
|
||||
- 行 73-74, 86: JSON v0 "method", "box_type" キー
|
||||
- 行 92-93: JSON v1 "name", "box_name" キー
|
||||
- normalize_json_callee() が両対応
|
||||
|
||||
4. **責務混濁**:
|
||||
- call/boxcall/externcall との役割分界不明確
|
||||
- instruction_lower.py でも mir_call/call/boxcall/externcall が並列存在
|
||||
|
||||
#### 目指す構造
|
||||
|
||||
**Phase 133 ConsoleLlvmBridge パターを参考**:
|
||||
|
||||
```
|
||||
src/llvm_py/instructions/mir_call/
|
||||
├── __init__.py (dispatcher lower_mir_call)
|
||||
├── global.py (lower_global_call)
|
||||
├── method.py (lower_method_call)
|
||||
├── constructor.py (lower_constructor_call)
|
||||
├── closure.py (lower_closure_creation)
|
||||
├── value.py (lower_value_call)
|
||||
└── extern.py (lower_extern_call)
|
||||
|
||||
src/llvm_py/mir_call_compat.py (新規)
|
||||
- json_v0_to_v1_callee()
|
||||
- normalize_mir_call_shape()
|
||||
```
|
||||
|
||||
**ファイルサイズ目標**:
|
||||
- 現状: mir_call.py 681行
|
||||
- 分割後:
|
||||
- __init__.py: ~120行 (dispatcher + トレース)
|
||||
- global.py: ~120行
|
||||
- method.py: ~140行
|
||||
- constructor.py: ~100行
|
||||
- closure.py: ~80行
|
||||
- value.py: ~80行
|
||||
- extern.py: ~100行
|
||||
- mir_call_compat.py: ~70行
|
||||
- **合計: ~890行** だが、責務が明確化・テスト分割可能
|
||||
|
||||
---
|
||||
|
||||
### Task 2: 既存 mir_call.py の詳細棚卸し
|
||||
|
||||
**対象ファイル**: `src/llvm_py/instructions/mir_call.py`(681行)
|
||||
|
||||
**やること**:
|
||||
|
||||
1. **関数別の行数カウント**:
|
||||
```bash
|
||||
rg "^def " src/llvm_py/instructions/mir_call.py -A 1
|
||||
```
|
||||
- lower_global_call() - 約何行
|
||||
- lower_method_call() - 約何行
|
||||
- 各関数の依存関係(内部呼び出し)を把握
|
||||
|
||||
2. **JSON v0/v1 互換コードの抽出**:
|
||||
- normalize_json_callee() の処理
|
||||
- "method" vs "name" キーの判定ロジック
|
||||
- これらを mir_call_compat.py に移す候補を特定
|
||||
|
||||
3. **フラグ・環境変数の確認**:
|
||||
- 行 34: `NYASH_MIR_UNIFIED_CALL`
|
||||
- 行 81: `NYASH_TRACE_CALLS` など
|
||||
- どれが Phase 124+ で削除済みか確認
|
||||
|
||||
4. **テスト対象の確認**:
|
||||
```bash
|
||||
rg "mir_call|lower_.*_call" src/llvm_py/tests/ --type python
|
||||
```
|
||||
- 既存テストがどの関数をテストしているか把握
|
||||
- 分割後も同じテストが動くようにする
|
||||
|
||||
**結果記録**: phase134 ドキュメントの「実装計画」に記載
|
||||
|
||||
---
|
||||
|
||||
### Task 3: mir_call_compat.py の実装(JSON v0/v1 互換層)
|
||||
|
||||
**目的**: JSON v0/v1 互換コードを専用モジュールに集約
|
||||
|
||||
**実装方針**:
|
||||
|
||||
```python
|
||||
# src/llvm_py/mir_call_compat.py
|
||||
|
||||
import json
|
||||
from typing import Dict, Any
|
||||
|
||||
class MirCallCompat:
|
||||
"""
|
||||
JSON v0/v1 互換処理を一元管理
|
||||
|
||||
v0: {"method": "log", "box_type": "ConsoleBox"}
|
||||
v1: {"name": "log", "box_name": "ConsoleBox"}
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def normalize_callee(callee_json: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
JSON v0/v1 どちらでも統一形式に normalize
|
||||
|
||||
Args:
|
||||
callee_json: {"method"/"name": ..., "box_type"/"box_name": ...}
|
||||
|
||||
Returns:
|
||||
統一形式: {"method_name": ..., "box_name": ..., "receiver": ...}
|
||||
"""
|
||||
# v0 形式を v1 に統一
|
||||
method_name = callee_json.get("method") or callee_json.get("name")
|
||||
box_name = callee_json.get("box_type") or callee_json.get("box_name")
|
||||
receiver = callee_json.get("receiver")
|
||||
|
||||
return {
|
||||
"method_name": method_name,
|
||||
"box_name": box_name,
|
||||
"receiver": receiver
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def detect_format_version(callee_json: Dict[str, Any]) -> int:
|
||||
"""v0 or v1 を検出"""
|
||||
if "method" in callee_json:
|
||||
return 0
|
||||
elif "name" in callee_json:
|
||||
return 1
|
||||
else:
|
||||
raise ValueError(f"Unknown callee format: {callee_json}")
|
||||
```
|
||||
|
||||
**注意点**:
|
||||
- normalize 後は統一形式で使用(v0/v1 分岐をなくす)
|
||||
- Phase 124+ で v0 削除を想定(互換層を一箇所に集約することで削除容易化)
|
||||
|
||||
---
|
||||
|
||||
### Task 4: mir_call.py の機能別分割と dispatcher 実装
|
||||
|
||||
**方針**: Phase 133 ConsoleLlvmBridge パターンを参考
|
||||
|
||||
#### ステップ 1: 分割対象の関数抽出
|
||||
|
||||
```
|
||||
src/llvm_py/instructions/mir_call/
|
||||
├── __init__.py
|
||||
│ └── lower_mir_call(builder, module, callee, args) # dispatcher
|
||||
│
|
||||
├── global.py
|
||||
│ └── lower_global_call(builder, module, func_name, args)
|
||||
│
|
||||
├── method.py
|
||||
│ └── lower_method_call(builder, module, box_id, method_id, receiver, args)
|
||||
│
|
||||
├── constructor.py
|
||||
│ └── lower_constructor_call(builder, module, box_id, args)
|
||||
│
|
||||
├── closure.py
|
||||
│ └── lower_closure_creation(builder, module, closure_info, captured_vars)
|
||||
│
|
||||
├── value.py
|
||||
│ └── lower_value_call(builder, module, func_value, args)
|
||||
│
|
||||
└── extern.py
|
||||
└── lower_extern_call(builder, module, extern_name, args)
|
||||
```
|
||||
|
||||
#### ステップ 2: dispatcher 実装
|
||||
|
||||
```python
|
||||
# src/llvm_py/instructions/mir_call/__init__.py
|
||||
|
||||
from . import global as global_call
|
||||
from . import method as method_call
|
||||
from . import constructor as ctor_call
|
||||
from . import closure as closure_call
|
||||
from . import value as value_call
|
||||
from . import extern as extern_call
|
||||
from ..mir_call_compat import MirCallCompat
|
||||
|
||||
def lower_mir_call(builder, module, mir_call_inst):
|
||||
"""
|
||||
MIR Call 命令を LLVM IR に lowering(canonical dispatcher)
|
||||
|
||||
Args:
|
||||
builder: LLVM IRBuilder
|
||||
module: LLVM Module
|
||||
mir_call_inst: MIR Call instruction
|
||||
|
||||
Returns:
|
||||
LLVM Value (関数戻り値)
|
||||
"""
|
||||
# JSON v0/v1 互換処理
|
||||
callee_json = mir_call_inst.get("callee", {})
|
||||
if not callee_json:
|
||||
# legacy: callee なし → default path
|
||||
return lower_legacy_mir_call(builder, module, mir_call_inst)
|
||||
|
||||
# v0/v1 normalize
|
||||
normalized = MirCallCompat.normalize_callee(callee_json)
|
||||
|
||||
# callee タイプ判定
|
||||
callee_type = normalized.get("type") # "global", "method", "constructor", etc.
|
||||
|
||||
if callee_type == "global":
|
||||
return global_call.lower_global_call(builder, module, ...)
|
||||
elif callee_type == "method":
|
||||
return method_call.lower_method_call(builder, module, ...)
|
||||
elif callee_type == "constructor":
|
||||
return ctor_call.lower_constructor_call(builder, module, ...)
|
||||
elif callee_type == "closure":
|
||||
return closure_call.lower_closure_creation(builder, module, ...)
|
||||
elif callee_type == "value":
|
||||
return value_call.lower_value_call(builder, module, ...)
|
||||
elif callee_type == "extern":
|
||||
return extern_call.lower_extern_call(builder, module, ...)
|
||||
else:
|
||||
raise ValueError(f"Unknown callee type: {callee_type}")
|
||||
|
||||
|
||||
def lower_legacy_mir_call(builder, module, mir_call_inst):
|
||||
"""
|
||||
Legacy path(callee なし の場合)
|
||||
|
||||
Phase 124+ で削除予定
|
||||
"""
|
||||
# 暫定実装(callee 推論 or error)
|
||||
raise NotImplementedError("Legacy MIR Call path is deprecated, use Callee")
|
||||
```
|
||||
|
||||
#### ステップ 3: 各モジュールへの分割
|
||||
|
||||
**global.py**:
|
||||
```python
|
||||
def lower_global_call(builder, module, func_name, args):
|
||||
"""Global function call を LLVM に lowering"""
|
||||
func = module.declare_external_function(func_name, func_type)
|
||||
return builder.call(func, args)
|
||||
```
|
||||
|
||||
**method.py**:
|
||||
```python
|
||||
def lower_method_call(builder, module, box_id, method_id, receiver, args):
|
||||
"""Box method call を LLVM に lowering (BoxCall)"""
|
||||
# BoxCallBridge (Console) を使用
|
||||
# 他の Box は call_method router
|
||||
...
|
||||
```
|
||||
|
||||
など(既存 mir_call.py から該当コードを移動)
|
||||
|
||||
---
|
||||
|
||||
### Task 5: 既存 call.py/boxcall.py/externcall.py との統合確認
|
||||
|
||||
**やること**:
|
||||
|
||||
1. **現状確認**:
|
||||
```bash
|
||||
ls -la src/llvm_py/instructions/ | grep -E "call|boxcall|externcall"
|
||||
```
|
||||
- call.py, boxcall.py, externcall.py が並存しているか確認
|
||||
- instruction_lower.py での呼び出し経路を確認
|
||||
|
||||
2. **整合性チェック**:
|
||||
- mir_call/__init__.py (dispatcher) の外部呼び出しが:
|
||||
- boxcall.py か mir_call/method.py か
|
||||
- externcall.py か mir_call/extern.py か
|
||||
- 一貫性を確保
|
||||
|
||||
3. **統合判定**:
|
||||
- call.py/boxcall.py/externcall.py が **mir_call を呼んでいる** か
|
||||
- **mir_call が call.py/boxcall.py/externcall.py を呼んでいる** か
|
||||
- **両者が別パス** か(この場合、どちらかを削除)
|
||||
|
||||
**結果**: 統合されるべき場合は、Phase 134-D として計画に追加
|
||||
|
||||
---
|
||||
|
||||
### Task 6: テスト & ドキュメント更新
|
||||
|
||||
**やること**:
|
||||
|
||||
1. **既存テストの確認**:
|
||||
```bash
|
||||
# mir_call 関連テスト確認
|
||||
rg "mir_call|lower_.*_call" src/llvm_py/tests/ --type python
|
||||
|
||||
# テスト実行
|
||||
cargo test --release 2>&1 | grep -E "mir_call|Call"
|
||||
```
|
||||
- 全テストが通るまで分割コードを調整
|
||||
|
||||
2. **ドキュメント追記**:
|
||||
- phase134_mir_call_unification.md 末尾に「実装結果」を追記
|
||||
- 分割構造の図示
|
||||
- JSON v0/v1 互換処理の説明
|
||||
|
||||
3. **CURRENT_TASK.md 更新**:
|
||||
```markdown
|
||||
### Phase 134-A: mir_call.py unified 設計完成 ✅
|
||||
|
||||
**完了内容**:
|
||||
- NYASH_MIR_UNIFIED_CALL フラグ廃止
|
||||
- mir_call.py (681行) を機能別分割
|
||||
- JSON v0/v1 互換層を mir_call_compat.py に外出し
|
||||
- legacy dispatcher 削除(NotImplementedError 根治)
|
||||
|
||||
**修正箇所**:
|
||||
- src/llvm_py/instructions/mir_call/__init__.py (dispatcher)
|
||||
- src/llvm_py/instructions/mir_call/global.py
|
||||
- src/llvm_py/instructions/mir_call/method.py
|
||||
- src/llvm_py/instructions/mir_call/constructor.py
|
||||
- src/llvm_py/instructions/mir_call/closure.py
|
||||
- src/llvm_py/instructions/mir_call/value.py
|
||||
- src/llvm_py/instructions/mir_call/extern.py
|
||||
- src/llvm_py/mir_call_compat.py (新規)
|
||||
|
||||
**テスト結果**: 全テスト PASS
|
||||
|
||||
**成果**:
|
||||
- mir_call.py: 681行 → 분할(각 80-150行, 책임 명확)
|
||||
- 次の分割準備: Phase 134-B StringBox bridge
|
||||
|
||||
**次フェーズ**: Phase 134-B - StringBox bridge 分離
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ 完成チェックリスト(Phase 134-A)
|
||||
|
||||
- [ ] mir_call.py の詳細棚卸し(関数別行数、依存関係)
|
||||
- [ ] JSON v0/v1 互換コード抽出・分析
|
||||
- [ ] mir_call_compat.py 実装(normalize 関数)
|
||||
- [ ] mir_call/__init__.py dispatcher 実装
|
||||
- [ ] mir_call/global.py 実装(既存 lower_global_call 移動)
|
||||
- [ ] mir_call/method.py 実装(既存 lower_method_call 移動)
|
||||
- [ ] mir_call/constructor.py, closure.py, value.py, extern.py 実装
|
||||
- [ ] instruction_lower.py で mir_call/__init__.py を呼ぶようにリファクタ
|
||||
- [ ] NYASH_MIR_UNIFIED_CALL フラグ削除(src/ 全体で確認)
|
||||
- [ ] legacy dispatcher (lower_legacy_call) 削除
|
||||
- [ ] 既存テスト実行 & 全て PASS 確認
|
||||
- [ ] phase134_mir_call_unification.md に実装結果追記
|
||||
- [ ] CURRENT_TASK.md 更新
|
||||
- [ ] git commit で記録
|
||||
|
||||
---
|
||||
|
||||
## 所要時間
|
||||
|
||||
**5〜6 時間程度**
|
||||
|
||||
- Task 1-2 (設計 & 棚卸し): 1時間
|
||||
- Task 3 (mir_call_compat.py): 45分
|
||||
- Task 4 (分割実装): 2.5時間
|
||||
- Task 5-6 (統合確認・テスト): 1.5時間
|
||||
|
||||
---
|
||||
|
||||
## 次のステップ
|
||||
|
||||
**Phase 134-B: StringBox bridge 分離**
|
||||
- boxcall.py:130-282 の StringBox メソッド処理を stringbox.py に分離
|
||||
- Phase 133 ConsoleLlvmBridge パターンを参考
|
||||
|
||||
**Phase 134-C: CollectionBox bridge 分離**
|
||||
- boxcall.py:325-375 の Array/Map メソッド処理を collectionbox.py に分離
|
||||
|
||||
---
|
||||
|
||||
## 進捗
|
||||
|
||||
- ✅ Phase 130-133: JoinIR → LLVM 第3章完全クローズ
|
||||
- 🎯 Phase 134-A: mir_call.py unified 設計完成(← **現在のフェーズ**)
|
||||
- 📋 Phase 134-B: StringBox bridge 分離(予定)
|
||||
- 📋 Phase 134-C: CollectionBox bridge 分離(予定)
|
||||
- 📋 Phase 135: LLVM フラグカタログ化(予定)
|
||||
Reference in New Issue
Block a user