From 3af98964ed3857c4baa67d28d8a26407be5859c6 Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Sat, 29 Nov 2025 09:04:18 +0900 Subject: [PATCH] feat(joinir): Phase P2-P4 Loop Pattern boxification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - P2: Create loop_patterns/ module structure - common.rs: shared helpers (ParsedProgram, LoopContext, etc.) - simple.rs: generic loop lowering - filter.rs, print_tokens.rs: delegate to simple - break_pattern.rs, continue_pattern.rs: new modules - P3: Create LoopFrontendBinding layer - Separate function name detection from pattern lowering - detect_loop_pattern() for pattern classification - P4: Break/Continue pattern migration - Move Break/Continue handling from loop_patterns_old.rs - Add LoopPattern::Break and LoopPattern::Continue variants - Design: 3-layer architecture - LoopFrontendBinding: function name → LoopPattern - loop_patterns: LoopPattern → JoinIR - Bridge/VM: Box semantics All 56 JoinIR tests pass. 🀖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../p2-loop-pattern-boxification-plan.md | 230 ++++++++++ .../ast_lowerer/loop_frontend_binding.rs | 146 +++++++ .../ast_lowerer/loop_patterns/README.md | 160 +++++++ .../loop_patterns/break_pattern.rs | 185 ++++++++ .../ast_lowerer/loop_patterns/common.rs | 407 ++++++++++++++++++ .../loop_patterns/continue_pattern.rs | 240 +++++++++++ .../ast_lowerer/loop_patterns/filter.rs | 53 +++ .../frontend/ast_lowerer/loop_patterns/mod.rs | 120 ++++++ .../ast_lowerer/loop_patterns/print_tokens.rs | 49 +++ .../ast_lowerer/loop_patterns/simple.rs | 151 +++++++ ...{loop_patterns.rs => loop_patterns_old.rs} | 0 src/mir/join_ir/frontend/ast_lowerer/mod.rs | 20 +- 12 files changed, 1753 insertions(+), 8 deletions(-) create mode 100644 docs/development/refactoring/p2-loop-pattern-boxification-plan.md create mode 100644 src/mir/join_ir/frontend/ast_lowerer/loop_frontend_binding.rs create mode 100644 src/mir/join_ir/frontend/ast_lowerer/loop_patterns/README.md create mode 100644 src/mir/join_ir/frontend/ast_lowerer/loop_patterns/break_pattern.rs create mode 100644 src/mir/join_ir/frontend/ast_lowerer/loop_patterns/common.rs create mode 100644 src/mir/join_ir/frontend/ast_lowerer/loop_patterns/continue_pattern.rs create mode 100644 src/mir/join_ir/frontend/ast_lowerer/loop_patterns/filter.rs create mode 100644 src/mir/join_ir/frontend/ast_lowerer/loop_patterns/mod.rs create mode 100644 src/mir/join_ir/frontend/ast_lowerer/loop_patterns/print_tokens.rs create mode 100644 src/mir/join_ir/frontend/ast_lowerer/loop_patterns/simple.rs rename src/mir/join_ir/frontend/ast_lowerer/{loop_patterns.rs => loop_patterns_old.rs} (100%) diff --git a/docs/development/refactoring/p2-loop-pattern-boxification-plan.md b/docs/development/refactoring/p2-loop-pattern-boxification-plan.md new file mode 100644 index 00000000..c72b20f3 --- /dev/null +++ b/docs/development/refactoring/p2-loop-pattern-boxification-plan.md @@ -0,0 +1,230 @@ +# Phase P2: Loop Pattern enum化 実装蚈画曞 + +## 目次 +1. [珟状分析](#1-珟状分析) +2. [LoopPattern enum 蚭蚈案](#2-looppattern-enum-蚭蚈案) +3. [モゞュヌル構造案](#3-モゞュヌル構造案) +4. [削枛芋蟌み](#4-削枛芋蟌み) +5. [実装ステップ](#5-実装ステップ) +6. [リスク評䟡](#6-リスク評䟡) +7. [テスト戊略](#7-テスト戊略) +8. [チェックリスト](#8-チェックリスト) + +--- + +## 1. 珟状分析 + +### 1.1 察象ファむル抂芁 + +**ファむル**: `src/mir/join_ir/frontend/ast_lowerer/loop_patterns.rs` + +**行数**: 895行 + +**䞻芁関数**: +1. `lower_loop_with_break_continue()` (43行) - **ディスパッチャヌ** +2. `lower_loop_case_a_simple()` (329行) - **Simple pattern** +3. `lower_loop_break_pattern()` (202行) - **Break pattern** +4. `lower_loop_continue_pattern()` (241行) - **Continue pattern** + +### 1.2 ルヌプパタヌンの分類 + +| パタヌン | 条件 | 関数 | 行数 | 耇雑床 | +|---------|------|------|------|--------| +| **Simple** | `!has_break && !has_continue` | `lower_loop_case_a_simple()` | 329 | 高 | +| **Break** | `has_break && !has_continue` | `lower_loop_break_pattern()` | 202 | äž­ | +| **Continue** | `has_continue && !has_break` | `lower_loop_continue_pattern()` | 241 | äž­ | +| **Mixed** | `has_break && has_continue` | panic! | 0 | 未実装 | + +### 1.3 P1 ずの比范 + +| 項目 | P1 (If Handler) | P2 (Loop Patterns) | +|------|-----------------|-------------------| +| **察象ファむル** | `stmt_handlers.rs` | `loop_patterns.rs` | +| **元の行数** | 154行 | 895行 | +| **パタヌン数** | 5個 | 4個1個未実装 | +| **最倧パタヌン** | 57行 | 329行 | +| **共通凊理** | 少ない | 倚い~85行 | + +--- + +## 2. LoopPattern enum 蚭蚈案 + +```rust +/// ルヌプパタヌンの分類 +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum LoopPattern { + /// Simple pattern: 条件付きルヌプbreak/continue なし + Simple { + cond_expr: Value, + has_me: bool, + external_refs: Vec<(String, ValueId)>, + }, + + /// Break pattern: 早期 return ルヌプ + Break { + break_cond_expr: Value, + }, + + /// Continue pattern: 条件付きスキップルヌプ + Continue { + loop_cond_expr: Value, + continue_cond_expr: Value, + }, + + /// Mixed pattern: break ず continue 䞡方未実装 + Mixed { + _marker: (), + }, +} +``` + +--- + +## 3. モゞュヌル構造案 + +``` +src/mir/join_ir/frontend/ast_lowerer/ +├── loop_patterns.rs (瞮小版: ~60行) +└── loop_patterns/ + ├── mod.rs (~50行) + ├── pattern.rs (~180行) - パタヌン怜出ロゞック + ├── common.rs (~150行) - 共通凊理ヘルパヌ + ├── lowering/ + │ ├── mod.rs (~30行) + │ ├── simple.rs (~180行) + │ ├── break_pattern.rs (~120行) + │ ├── continue_pattern.rs (~140行) + │ └── mixed.rs (~30行) + └── tests.rs (~150行) +``` + +--- + +## 4. 削枛芋蟌み + +| カテゎリ | Before | After | 削枛 | 削枛率 | +|---------|--------|-------|------|--------| +| **loop_patterns.rs** | 895 | 60 | -835 | **-93.3%** | +| **新芏モゞュヌル** | 0 | 1,090 | +1,090 | - | +| **玔増枛** | 895 | 1,150 | +255 | +28.5% | + +### P1 ずの比范 + +| 項目 | P1 (If Handler) | P2 (Loop Patterns) | +|------|-----------------|-------------------| +| **削枛率** | 93.5% | 93.3% | +| **新芏コスト** | +336行 (+218%) | +255行 (+28.5%) | + +**P2 の優䜍性**: 共通凊理の再利甚により、新芏コストが P1 より効率的 + +--- + +## 5. 実装ステップ + +### Step 1: 基瀎むンフラ構築3-4時間 +- ディレクトリ構造䜜成 +- `loop_patterns/mod.rs` 䜜成 +- `loop_patterns/pattern.rs` 実装LoopPattern enum + 怜出ロゞック +- `loop_patterns/common.rs` 実装共通凊理ヘルパヌ + +### Step 2: 各パタヌン lowering 実装6-8時間 +1. Break pattern (2時間) +2. Continue pattern (2.5時間) +3. Simple pattern (3時間) - 最耇雑 +4. Mixed pattern (0.5時間) +5. lowering/mod.rs 統合 (1時間) + +### Step 3: loop_patterns.rs リファクタリング1-2時間 +- 895行 → 60行に削枛 +- パタヌン怜出 → lowering 委譲 + +### Step 4: テスト远加2-3時間 +- パタヌン怜出テスト: 10個 +- 共通凊理テスト: 5個 +- lowering テスト: 12個 +- 統合テスト: 5個 + +### Step 5: 統合・怜蚌1-2時間 +- 既存テスト党通過 +- 回垰テスト11個の .hako ファむル + +**総掚定時間**: 13-19時間 + +--- + +## 6. リスク評䟡 + +### 6.1 P1 より耇雑な点 + +1. **Simple pattern の耇雑性** + - me/external_refs の動的パラメヌタ蚈算 + - P1 最倧57行 vs P2 最倧329行5.8倍 + +2. **共通凊理の量** + - 3関数構造生成entry/loop_step/k_exit + - P1: 共通凊理ほがなし vs P2: 150行 + +3. **Phase 52/56 機胜の保持** + - me パラメヌタ察応 + - external_refs 察応filter/map + +### 6.2 回避策 + +環境倉数制埡による段階的移行P1 ず同じ戊略 + +--- + +## 7. テスト戊略 + +### 7.1 回垰テストリスト + +```bash +# 基本ルヌプ +apps/tests/loop_min_while.hako +apps/tests/joinir_min_loop.hako + +# Break pattern +apps/tests/loopform_break_and_return.hako +apps/tests/nested_loop_inner_break_isolated.hako + +# Continue pattern +apps/tests/loop-continue-demo/main.hako +apps/tests/loopform_continue_break_scan.hako +``` + +--- + +## 8. チェックリスト + +### 基瀎むンフラ (Step 1) +- [ ] ディレクトリ構造䜜成完了 +- [ ] `loop_patterns/mod.rs` 䜜成完了 +- [ ] `loop_patterns/pattern.rs` 実装完了 +- [ ] `loop_patterns/common.rs` 実装完了 + +### パタヌン lowering (Step 2) +- [ ] `lowering/break_pattern.rs` 実装完了 +- [ ] `lowering/continue_pattern.rs` 実装完了 +- [ ] `lowering/simple.rs` 実装完了 +- [ ] `lowering/mixed.rs` 実装完了 + +### リファクタリング (Step 3) +- [ ] `loop_patterns.rs` 修正完了895行 → 60行 +- [ ] 既存テスト党通過 + +### テスト (Step 4) +- [ ] パタヌン怜出テスト10個 +- [ ] 共通凊理テスト5個 +- [ ] lowering テスト12個 + +### 統合・怜蚌 (Step 5) +- [ ] 党ナニットテスト通過 +- [ ] 既存回垰テスト通過 +- [ ] パフォヌマンス劣化なし + +--- + +**䜜成日**: 2025-11-29 +**Phase**: P2 (Loop Pattern enum化) +**前提**: P1 (If Handler 箱化モゞュヌル化) 完了 +**䜜成者**: Claude Code + Task agent (Plan mode) diff --git a/src/mir/join_ir/frontend/ast_lowerer/loop_frontend_binding.rs b/src/mir/join_ir/frontend/ast_lowerer/loop_frontend_binding.rs new file mode 100644 index 00000000..4f92f6e3 --- /dev/null +++ b/src/mir/join_ir/frontend/ast_lowerer/loop_frontend_binding.rs @@ -0,0 +1,146 @@ +//! Phase P3: LoopFrontendBinding - 関数名 → LoopPattern 倉換局 +//! +//! ## 責務1行で衚珟 +//! **関数名から適切な LoopPattern を決定し、loop_patterns 局にディスパッチする** +//! +//! ## この局の責務 +//! +//! - 関数名"simple", "filter" 等から `LoopPattern` enum を決定 +//! - Break/Continue の有無を怜出しおパタヌンを調敎 +//! - `loop_patterns::lower_loop_with_pattern()` に委譲 +//! +//! ## やらないこず +//! +//! - JSON body の詳现解析それは loop_patterns 局 +//! - Box 名・メ゜ッド名での刀定それは Bridge/VM 局 +//! +//! ## 蚭蚈原則 +//! +//! ChatGPT 掚奚の責務分離: +//! ``` +//! LoopFrontendBinding → 関数名ベヌスの刀定 +//! loop_patterns → LoopPattern enum での lowering +//! Bridge/VM → Box 名・メ゜ッド名での最適化 +//! ``` + +use super::loop_patterns::{self, LoopPattern, LoweringError}; +use super::loop_patterns_old; +use super::{AstToJoinIrLowerer, JoinModule}; + +/// 関数名から LoopPattern を怜出 +/// +/// # Arguments +/// * `func_name` - 関数名 +/// * `loop_body` - Loop body の JSONBreak/Continue 怜出甚 +/// +/// # Returns +/// 怜出された LoopPattern +pub fn detect_loop_pattern( + func_name: &str, + loop_body: Option<&[serde_json::Value]>, +) -> LoopPattern { + // Phase P3: 関数名ベヌスの刀定 + // 将来的には Box 名やアノテヌションも考慮可胜 + match func_name { + // Phase 55: PrintTokens パタヌン + "print_tokens" => LoopPattern::PrintTokens, + + // Phase 56: Filter パタヌン + "filter" => LoopPattern::Filter, + + // Phase 57+: Map パタヌン未実装 + "map" => LoopPattern::Map, + + // Phase 58+: Reduce パタヌン未実装 + "reduce" | "fold" => LoopPattern::Reduce, + + // デフォルト: Simple パタヌン + // ただし Break/Continue があれば別パタヌン + _ => { + if let Some(body) = loop_body { + if AstToJoinIrLowerer::has_break_in_loop_body(body) { + LoopPattern::Break + } else if AstToJoinIrLowerer::has_continue_in_loop_body(body) { + LoopPattern::Continue + } else { + LoopPattern::Simple + } + } else { + LoopPattern::Simple + } + } + } +} + +/// ルヌプパタヌンに基づいお lowering を実行 +/// +/// 関数名から LoopPattern を決定し、適切な lowering を実行する。 +/// +/// # Arguments +/// * `lowerer` - AstToJoinIrLowerer むンスタンス +/// * `program_json` - Program(JSON v0) +/// +/// # Returns +/// JoinModule たたは panic未察応パタヌン +pub fn lower_loop_by_function_name( + lowerer: &mut AstToJoinIrLowerer, + program_json: &serde_json::Value, +) -> JoinModule { + // 1. 関数名を取埗 + let defs = program_json["defs"] + .as_array() + .expect("Program(JSON v0) must have 'defs' array"); + + let func_def = defs + .get(0) + .expect("At least one function definition required"); + + let func_name = func_def["name"] + .as_str() + .expect("Function must have 'name'"); + + // 2. Loop body を取埗Break/Continue 怜出甚 + let body = &func_def["body"]["body"]; + let stmts = body.as_array().expect("Function body must be array"); + + let loop_body: Option<&[serde_json::Value]> = stmts + .iter() + .find(|stmt| stmt["type"].as_str() == Some("Loop")) + .and_then(|loop_node| loop_node["body"].as_array()) + .map(|v| v.as_slice()); + + // 3. LoopPattern を決定Break/Continue も新モゞュヌルで凊理 + let pattern = detect_loop_pattern(func_name, loop_body); + + // 4. loop_patterns 局に委譲 + match loop_patterns::lower_loop_with_pattern(pattern.clone(), lowerer, program_json) { + Ok(module) => module, + Err(LoweringError::UnimplementedPattern { pattern, reason }) => { + // 未実装パタヌンは loop_patterns_old にフォヌルバック + eprintln!( + "[LoopFrontendBinding] Pattern {:?} not implemented: {}. Falling back to old route.", + pattern, reason + ); + lowerer.lower_loop_with_break_continue(program_json) + } + Err(e) => panic!("LoopFrontendBinding error: {:?}", e), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_detect_loop_pattern_by_name() { + assert_eq!(detect_loop_pattern("filter", None), LoopPattern::Filter); + assert_eq!( + detect_loop_pattern("print_tokens", None), + LoopPattern::PrintTokens + ); + assert_eq!(detect_loop_pattern("map", None), LoopPattern::Map); + assert_eq!(detect_loop_pattern("reduce", None), LoopPattern::Reduce); + assert_eq!(detect_loop_pattern("simple", None), LoopPattern::Simple); + assert_eq!(detect_loop_pattern("unknown", None), LoopPattern::Simple); + } +} diff --git a/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/README.md b/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/README.md new file mode 100644 index 00000000..0409ee7c --- /dev/null +++ b/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/README.md @@ -0,0 +1,160 @@ +# Loop Patterns - JoinIR Frontend ルヌプパタヌン凊理局 + +## 📋 この局の責務 + +**JSON v0 のルヌプ body を、LoopFrontendBinding が枡しおきた LoopPattern に埓っお JoinIR 呜什列に倉換する** + +- LoopFrontendBinding から受け取った `LoopPattern` enum に基づいお適切な lowering 凊理を遞択 +- ルヌプ body の JSON AST を JoinIR 呜什Jump/Call/Select/MethodCall/ConditionalMethodCall 等に倉換 +- 各パタヌンに特化した最適な JoinIR 構造を生成3関数構造: entry/loop_step/k_exit + +## 🚫 やらないこず重芁 + +### ❌ 関数名ベヌスの刀定 +- **理由**: それは LoopFrontendBinding 局の責務 +- **䟋**: `"simple"` や `"filter"` ずいう関数名で分岐する凊理は**曞かない** +- **正しい蚭蚈**: LoopPattern enum を受け取っお、enum の variant で分岐 + +### ❌ Box 名・メ゜ッド名で意味論を倉える +- **理由**: それは JoinIR→MIR Bridge / VM 偎の責務 +- **䟋**: `ArrayExtBox.filter` だから特別凊理、ずいう刀定は**曞かない** +- **正しい蚭蚈**: JSON の "type" フィヌルドVar/Method/Call等だけで刀定 + +### ❌ AST 構造に螏み蟌みすぎる +- **理由**: JSON v0 の "type" フィヌルドで十分刀定できる +- **䟋**: "kind" フィヌルドを芋お詳现な AST ノヌド型を刀定する凊理は**曞かない** +- **正しい蚭蚈**: "type": "Method" / "Var" / "Int" 等だけで凊理 + +## 🏗 蚭蚈原則 + +### 1. パタヌン = 1ç®± = 1責務 + +各 LoopPattern の lowering 凊理は、独立したモゞュヌルファむルに分離 + +``` +loop_patterns/ +├── filter.rs # Filter パタヌン: pred が true のずきだけ push +├── print_tokens.rs # PrintTokens パタヌン: token を順番に print +├── map.rs # Map パタヌン未実装 +├── reduce.rs # Reduce パタヌン未実装 +└── simple.rs # Simple パタヌン: 汎甚ルヌプ +``` + +**各ファむルの責務を 1 行で衚珟** +- `filter.rs`: 「pred が true のずきだけ push するルヌプを ConditionalMethodCall に萜ずす」 +- `print_tokens.rs`: 「token を順番に取り出しお print するルヌプを Jump/Call/MethodCall に萜ずす」 + +### 2. 共通凊理は最小限 + +- JSON パヌス、ExtractCtx 初期化、3関数構造生成の**本圓に共通な郚分だけ**をヘルパヌ化 +- パタヌン固有のロゞックは各モゞュヌルに閉じる + +### 3. ゚ラヌハンドリング + +- 耇雑すぎるパタヌンは玠盎に `Err(UnimplementedPattern)` を返す +- フェヌズを分けお段階的に拡匵しやすくする + +### 4. trait による統䞀むンタヌフェヌス + +```rust +pub trait LoopPatternLowerer { + fn lower( + &self, + lowerer: &mut AstToJoinIrLowerer, + program_json: &serde_json::Value, + ) -> Result; +} +``` + +## 📊 LoopPattern の分類 + +### ナヌスケヌスベヌスの分類Phase 55/56 実装枈み + +| Pattern | 実装状況 | 責務 | 代衚関数 | +|---------|---------|------|---------| +| **PrintTokens** | ✅ Phase 55 | token を順番に print | `JsonTokenizer.print_tokens` | +| **Filter** | ✅ Phase 56 | pred が true のずきだけ push | `ArrayExtBox.filter` | +| **Map** | 🔜 Phase 57+ | 各芁玠を倉換しお新配列䜜成 | `ArrayExtBox.map` | +| **Reduce** | 🔜 Phase 58+ | 环積蚈算fold | `ArrayExtBox.reduce` | +| **Simple** | ✅ Phase 34 | 汎甚ルヌプ䞊蚘以倖 | 各皮ルヌプ | + +### 制埡構造ベヌスの分類参考 + +実際の実装では**ナヌスケヌス優先**だが、内郚的には制埡構造も考慮 + +- **Simple**: break/continue なし +- **Break**: 早期 return ルヌプ +- **Continue**: 条件付きスキップルヌプ +- **Mixed**: break + continue 䞡方未実装 + +## 🔄 デヌタフロヌ + +``` +1. LoopFrontendBinding å±€ + ↓ (関数名ベヌス刀定) + LoopPattern enum を決定 + +2. loop_patterns.rs (ディスパッチ箱) + ↓ (enum の variant で分岐) + 適切な lowering モゞュヌルを遞択 + +3. 各 lowering モゞュヌル (filter.rs 等) + ↓ (JSON "type" フィヌルドで刀定) + JoinIR 呜什列を生成 + +4. JoinIR→MIR Bridge + ↓ (Box 名・メ゜ッド名で最適化) + MIR 呜什に倉換 +``` + +## 🎯 今埌の拡匵 + +新しいルヌプパタヌンを远加する手順 + +1. `LoopPattern` enum に variant 远加 +2. 新しい lowering モゞュヌル䜜成䟋: `map.rs` +3. 責務を 1 行で定矩 +4. `trait LoopPatternLowerer` を実装 +5. `loop_patterns.rs` のディスパッチに 1 行远加 + +**蚭蚈思想**: 各パタヌンが独立した箱なので、远加・削陀・眮き換えが容易 + +## 📊 珟圚の状態ず移行蚈画 + +### 珟圚の状態Phase P2 完了 + +``` +loop_patterns/ # 新モゞュヌル構造将来の呌び出し甚 +├── mod.rs # LoopPattern enum + ディスパッチ +├── common.rs # 共通凊理parse/ctx/entry/k_exit 生成 +├── filter.rs # Filter パタヌン→simple に委譲 +├── print_tokens.rs # PrintTokens パタヌン→simple に委譲 +└── simple.rs # Simple パタヌン実装枈み + +loop_patterns_old.rs # 珟行コヌド関数名ベヌス刀定を含む +``` + +### 移行蚈画Future Work + +1. **LoopFrontendBinding 局の䜜成** (Phase P3+ 予定) + - 関数名 → LoopPattern enum の倉換を担圓 + - `lower_program_json()` から呌び出し + +2. **loop_patterns_old.rs の廃止** + - Break/Continue パタヌンも新モゞュヌルに移行埌 + - `loop_patterns_old.rs` を削陀 + +3. **完党移行埌の呌び出し構造** + ```rust + // LoopFrontendBinding 局新蚭 + let pattern = detect_loop_pattern(func_name); + + // loop_patterns 局新モゞュヌル + loop_patterns::lower_loop_with_pattern(pattern, lowerer, json) + ``` + +--- + +**Phase**: P2 (Loop Pattern 箱化モゞュヌル化) +**䜜成日**: 2025-11-29 +**原則**: 関数名刀定は Binding 局、Box名刀定は Bridge/VM 局、この局は LoopPattern だけを芋る diff --git a/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/break_pattern.rs b/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/break_pattern.rs new file mode 100644 index 00000000..0f241b6c --- /dev/null +++ b/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/break_pattern.rs @@ -0,0 +1,185 @@ +//! Phase P4: Break パタヌン lowering +//! +//! ## 責務1行で衚珟 +//! **if break 条件で早期 return するルヌプを Jump(k_exit, cond) に萜ずす** +//! +//! ## パタヌン䟋 +//! ```nyash +//! loop { +//! if i >= n { break } +//! acc = acc + i +//! i = i + 1 +//! } +//! ``` +//! +//! ## 生成する JoinIR 構造 +//! - entry 関数: Call(loop_step) +//! - loop_step 関数: +//! - break 条件評䟡 +//! - true: Jump(k_exit, acc) +//! - false: body 凊理 + 再垰 +//! - k_exit 関数: Return(acc) + +use super::common::{ + build_join_module, build_step_params, create_k_exit_function, create_loop_context, + parse_program_json, process_local_inits, +}; +use super::{AstToJoinIrLowerer, JoinModule, LoweringError}; +use crate::mir::join_ir::{JoinFunction, JoinInst}; +use crate::mir::ValueId; + +/// Break パタヌンを JoinModule に倉換 +/// +/// # Arguments +/// * `lowerer` - AstToJoinIrLowerer むンスタンス +/// * `program_json` - Program(JSON v0) +pub fn lower( + lowerer: &mut AstToJoinIrLowerer, + program_json: &serde_json::Value, +) -> Result { + // 1. Program(JSON) をパヌス + let parsed = parse_program_json(program_json); + + // 2. LoopContext ず entry_ctx を䜜成 + let (ctx, mut entry_ctx) = create_loop_context(lowerer, &parsed); + + // 3. Local 初期化を凊理 + let init_insts = process_local_inits(lowerer, &parsed, &mut entry_ctx); + + // 4. Loop body から Break If を探す + let loop_node = &parsed.stmts[parsed.loop_node_idx]; + let loop_body = loop_node["body"] + .as_array() + .ok_or_else(|| LoweringError::InvalidLoopBody { + message: "Loop must have 'body' array".to_string(), + })?; + + let break_if_stmt = loop_body + .iter() + .find(|stmt| { + stmt["type"].as_str() == Some("If") + && stmt["then"].as_array().map_or(false, |then| { + then.iter().any(|s| s["type"].as_str() == Some("Break")) + }) + }) + .ok_or_else(|| LoweringError::InvalidLoopBody { + message: "Break pattern must have If + Break".to_string(), + })?; + + let break_cond_expr = &break_if_stmt["cond"]; + + // 5. entry 関数を生成 + let entry_func = create_entry_function_break(&ctx, &parsed, init_insts, &mut entry_ctx); + + // 6. loop_step 関数を生成 + let loop_step_func = + create_loop_step_function_break(lowerer, &ctx, &parsed.func_name, break_cond_expr, loop_body)?; + + // 7. k_exit 関数を生成 + let k_exit_func = create_k_exit_function(&ctx, &parsed.func_name); + + // 8. JoinModule を構築 + Ok(build_join_module(entry_func, loop_step_func, k_exit_func)) +} + +/// Break パタヌン甚 entry 関数を生成 +fn create_entry_function_break( + ctx: &super::common::LoopContext, + parsed: &super::common::ParsedProgram, + init_insts: Vec, + entry_ctx: &mut super::super::context::ExtractCtx, +) -> JoinFunction { + // i, acc, n を取埗 + let i_init = entry_ctx.get_var("i").expect("i must be initialized"); + let acc_init = entry_ctx.get_var("acc").expect("acc must be initialized"); + let n_param = entry_ctx.get_var("n").expect("n must be parameter"); + + let loop_result = entry_ctx.alloc_var(); + + let mut body = init_insts; + body.push(JoinInst::Call { + func: ctx.loop_step_id, + args: vec![i_init, acc_init, n_param], + k_next: None, + dst: Some(loop_result), + }); + body.push(JoinInst::Ret { + value: Some(loop_result), + }); + + JoinFunction { + id: ctx.entry_id, + name: parsed.func_name.clone(), + params: (0..parsed.param_names.len()) + .map(|i| ValueId(i as u32)) + .collect(), + body, + exit_cont: None, + } +} + +/// Break パタヌン甚 loop_step 関数を生成 +fn create_loop_step_function_break( + lowerer: &mut AstToJoinIrLowerer, + ctx: &super::common::LoopContext, + func_name: &str, + break_cond_expr: &serde_json::Value, + loop_body: &[serde_json::Value], +) -> Result { + use super::super::context::ExtractCtx; + + // step_ctx を䜜成Break パタヌンは me/external_refs なし + let step_i = ValueId(0); + let step_acc = ValueId(1); + let step_n = ValueId(2); + + let mut step_ctx = ExtractCtx::new(3); + step_ctx.register_param("i".to_string(), step_i); + step_ctx.register_param("acc".to_string(), step_acc); + step_ctx.register_param("n".to_string(), step_n); + + // Break 条件を評䟡 + let (break_cond_var, break_cond_insts) = lowerer.extract_value(break_cond_expr, &mut step_ctx); + + let mut body = break_cond_insts; + + // 早期 return: break_cond が true なら k_exit ぞ Jump + body.push(JoinInst::Jump { + cont: ctx.k_exit_id.as_cont(), + args: vec![step_acc], + cond: Some(break_cond_var), + }); + + // Loop body を凊理If + Break はスキップ + for body_stmt in loop_body { + if body_stmt["type"].as_str() == Some("If") { + continue; + } + + let (insts, _effect) = lowerer.lower_statement(body_stmt, &mut step_ctx); + body.extend(insts); + } + + // 再垰呌び出し + let i_next = step_ctx.get_var("i").expect("i must be updated"); + let acc_next = step_ctx.get_var("acc").expect("acc must be updated"); + + let recurse_result = step_ctx.alloc_var(); + body.push(JoinInst::Call { + func: ctx.loop_step_id, + args: vec![i_next, acc_next, step_n], + k_next: None, + dst: Some(recurse_result), + }); + body.push(JoinInst::Ret { + value: Some(recurse_result), + }); + + Ok(JoinFunction { + id: ctx.loop_step_id, + name: format!("{}_loop_step", func_name), + params: vec![step_i, step_acc, step_n], + body, + exit_cont: None, + }) +} diff --git a/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/common.rs b/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/common.rs new file mode 100644 index 00000000..c48f3911 --- /dev/null +++ b/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/common.rs @@ -0,0 +1,407 @@ +//! Phase P2: Loop Patterns 共通凊理 +//! +//! ## 責務 +//! 各 LoopPattern lowering で共通する凊理を提䟛する。 +//! +//! ## 提䟛する機胜 +//! - `ParsedProgram`: Program(JSON) のパヌス結果を保持 +//! - `LoopContext`: 3関数構造entry/loop_step/k_exitのコンテキスト +//! - `parse_program_json()`: Program(JSON) からパヌス結果を抜出 +//! - `process_local_inits()`: Loop 前の Local 初期化を凊理 +//! - `collect_external_refs()`: Phase 56 external_refs 収集 +//! - `create_entry_function()`: entry 関数生成 +//! - `create_k_exit_function()`: k_exit 関数生成 + +use super::{AstToJoinIrLowerer, JoinModule}; +use crate::mir::join_ir::{ConstValue, JoinFuncId, JoinFunction, JoinInst}; +use crate::mir::ValueId; +use std::collections::BTreeMap; + +use super::super::context::ExtractCtx; + +/// Program(JSON) のパヌス結果 +pub struct ParsedProgram { + /// 関数名 + pub func_name: String, + /// パラメヌタ名リスト + pub param_names: Vec, + /// 関数 body の statements + pub stmts: Vec, + /// Loop ノヌドのむンデックス + pub loop_node_idx: usize, +} + +/// 3関数構造のコンテキスト +pub struct LoopContext { + /// entry 関数 ID + pub entry_id: JoinFuncId, + /// loop_step 関数 ID + pub loop_step_id: JoinFuncId, + /// k_exit 関数 ID + pub k_exit_id: JoinFuncId, + /// "me" パラメヌタが存圚するか + pub has_me: bool, + /// external_refsPhase 56: arr, pred など + pub external_refs: Vec<(String, ValueId)>, +} + +/// Program(JSON) をパヌスしお ParsedProgram を返す +/// +/// # Arguments +/// * `program_json` - Program(JSON v0) +/// +/// # Returns +/// パヌス結果 +pub fn parse_program_json(program_json: &serde_json::Value) -> ParsedProgram { + // 1. defs 配列を取埗 + let defs = program_json["defs"] + .as_array() + .expect("Program(JSON v0) must have 'defs' array"); + + // 2. 最初の関数定矩を取埗 + let func_def = defs + .get(0) + .expect("At least one function definition required"); + + let func_name = func_def["name"] + .as_str() + .expect("Function must have 'name'") + .to_string(); + + let params = func_def["params"] + .as_array() + .expect("Function must have 'params' array"); + + let param_names: Vec = params + .iter() + .map(|p| p.as_str().expect("Parameter must be string").to_string()) + .collect(); + + // 3. body を取埗 + let body = &func_def["body"]["body"]; + let stmts: Vec = body + .as_array() + .expect("Function body must be array") + .clone(); + + // 4. Loop ノヌドのむンデックスを探す + let loop_node_idx = stmts + .iter() + .position(|stmt| stmt["type"].as_str() == Some("Loop")) + .expect("Loop node not found"); + + ParsedProgram { + func_name, + param_names, + stmts, + loop_node_idx, + } +} + +/// Loop 前の Local 初期化を凊理 +/// +/// # Arguments +/// * `lowerer` - AstToJoinIrLowerer むンスタンス +/// * `parsed` - パヌス枈み Program +/// * `ctx` - ExtractCtx +/// +/// # Returns +/// 初期化呜什列 +pub fn process_local_inits( + lowerer: &mut AstToJoinIrLowerer, + parsed: &ParsedProgram, + ctx: &mut ExtractCtx, +) -> Vec { + let mut init_insts = Vec::new(); + + for stmt in &parsed.stmts[..parsed.loop_node_idx] { + let stmt_type = stmt["type"].as_str().expect("Statement must have type"); + + match stmt_type { + "Local" => { + let var_name = stmt["name"] + .as_str() + .expect("Local must have 'name'") + .to_string(); + let expr = &stmt["expr"]; + + // extract_value で匏を評䟡 + let (var_id, insts) = lowerer.extract_value(expr, ctx); + init_insts.extend(insts); + + // 同名再宣蚀 = var_map を曎新再代入の意味論 + ctx.register_param(var_name, var_id); + } + _ => panic!("Unexpected statement type before Loop: {}", stmt_type), + } + } + + init_insts +} + +/// Phase 56: external_refs を収集 +/// +/// パラメヌタのうち、ルヌプ制埡倉数me, i, acc, n以倖を収集する。 +/// filter(arr, pred) などで䜿甚。 +/// +/// # Arguments +/// * `param_names` - パラメヌタ名リスト +/// +/// # Returns +/// external_refs のリスト名前, ValueId +pub fn collect_external_refs(param_names: &[String]) -> Vec<(String, ValueId)> { + const RESERVED_VARS: [&str; 4] = ["me", "i", "acc", "n"]; + + param_names + .iter() + .enumerate() + .filter_map(|(idx, name)| { + if !RESERVED_VARS.contains(&name.as_str()) { + Some((name.clone(), ValueId(idx as u32))) + } else { + None + } + }) + .collect() +} + +/// LoopContext ず entry 甹 ExtractCtx を䜜成 +/// +/// 3関数構造の ID 生成ず ExtractCtx 初期化を行う。 +/// +/// # Arguments +/// * `lowerer` - AstToJoinIrLowerer むンスタンス +/// * `parsed` - パヌス枈み Program +/// +/// # Returns +/// (LoopContext, ExtractCtx) +pub fn create_loop_context( + lowerer: &mut AstToJoinIrLowerer, + parsed: &ParsedProgram, +) -> (LoopContext, ExtractCtx) { + // 3関数 ID 生成 + let entry_id = lowerer.next_func_id(); + let loop_step_id = lowerer.next_func_id(); + let k_exit_id = lowerer.next_func_id(); + + // ExtractCtx 䜜成ずパラメヌタ登録 + let mut entry_ctx = ExtractCtx::new(parsed.param_names.len() as u32); + for (i, name) in parsed.param_names.iter().enumerate() { + entry_ctx.register_param(name.clone(), ValueId(i as u32)); + } + + // me パラメヌタ確認 + let has_me = parsed.param_names.iter().any(|n| n == "me"); + + // external_refs 収集 + let external_refs = collect_external_refs(&parsed.param_names); + + let ctx = LoopContext { + entry_id, + loop_step_id, + k_exit_id, + has_me, + external_refs, + }; + + (ctx, entry_ctx) +} + +/// entry 関数を生成 +/// +/// # Arguments +/// * `ctx` - LoopContext +/// * `parsed` - パヌス枈み Program +/// * `init_insts` - 初期化呜什列 +/// +/// # Returns +/// entry JoinFunction +pub fn create_entry_function( + ctx: &LoopContext, + parsed: &ParsedProgram, + init_insts: Vec, + entry_ctx: &mut ExtractCtx, +) -> JoinFunction { + // i, acc, n を取埗 + let i_init = entry_ctx.get_var("i").expect("i must be initialized"); + let acc_init = entry_ctx.get_var("acc").expect("acc must be initialized"); + let n_param = entry_ctx.get_var("n").expect("n must be parameter"); + + // me パラメヌタ取埗 + let me_param = entry_ctx.get_var("me"); + + let loop_result = entry_ctx.alloc_var(); + + // Call args 構築me?, i, acc, n, ...external_refs + let mut call_args = if let Some(me_id) = me_param { + vec![me_id, i_init, acc_init, n_param] + } else { + vec![i_init, acc_init, n_param] + }; + + // external_refs を远加 + for (name, _) in &ctx.external_refs { + if let Some(var_id) = entry_ctx.get_var(name) { + call_args.push(var_id); + } + } + + let mut body = init_insts; + body.push(JoinInst::Call { + func: ctx.loop_step_id, + args: call_args, + k_next: None, + dst: Some(loop_result), + }); + body.push(JoinInst::Ret { + value: Some(loop_result), + }); + + JoinFunction { + id: ctx.entry_id, + name: parsed.func_name.clone(), + params: (0..parsed.param_names.len()) + .map(|i| ValueId(i as u32)) + .collect(), + body, + exit_cont: None, + } +} + +/// k_exit 関数を生成 +/// +/// # Arguments +/// * `ctx` - LoopContext +/// * `func_name` - 関数名 +/// +/// # Returns +/// k_exit JoinFunction +pub fn create_k_exit_function(ctx: &LoopContext, func_name: &str) -> JoinFunction { + let k_exit_acc = ValueId(0); + + JoinFunction { + id: ctx.k_exit_id, + name: format!("{}_k_exit", func_name), + params: vec![k_exit_acc], + body: vec![JoinInst::Ret { + value: Some(k_exit_acc), + }], + exit_cont: None, + } +} + +/// loop_step 甚の ExtractCtx を䜜成 +/// +/// # Arguments +/// * `ctx` - LoopContext +/// +/// # Returns +/// loop_step 甹 ExtractCtx +pub fn create_step_ctx(ctx: &LoopContext) -> ExtractCtx { + // パラメヌタ数: me?, i, acc, n, ...external_refs + let base_params: u32 = if ctx.has_me { 4 } else { 3 }; + let num_params = base_params + ctx.external_refs.len() as u32; + + let mut step_ctx = ExtractCtx::new(num_params); + + // ValueId 割り圓お + let (step_i, step_acc, step_n) = if ctx.has_me { + step_ctx.register_param("me".to_string(), ValueId(0)); + (ValueId(1), ValueId(2), ValueId(3)) + } else { + (ValueId(0), ValueId(1), ValueId(2)) + }; + + step_ctx.register_param("i".to_string(), step_i); + step_ctx.register_param("acc".to_string(), step_acc); + step_ctx.register_param("n".to_string(), step_n); + + // external_refs 登録 + let ext_offset = base_params; + for (i, (name, _)) in ctx.external_refs.iter().enumerate() { + step_ctx.register_param(name.clone(), ValueId(ext_offset + i as u32)); + } + + step_ctx +} + +/// loop_step 関数のパラメヌタリストを構築 +/// +/// # Arguments +/// * `ctx` - LoopContext +/// +/// # Returns +/// パラメヌタ ValueId リスト +pub fn build_step_params(ctx: &LoopContext) -> Vec { + let base_params: u32 = if ctx.has_me { 4 } else { 3 }; + + let mut params = if ctx.has_me { + vec![ValueId(0), ValueId(1), ValueId(2), ValueId(3)] + } else { + vec![ValueId(0), ValueId(1), ValueId(2)] + }; + + // external_refs を远加 + for (i, _) in ctx.external_refs.iter().enumerate() { + params.push(ValueId(base_params + i as u32)); + } + + params +} + +/// 再垰呌び出し args を構築 +/// +/// # Arguments +/// * `ctx` - LoopContext +/// * `step_ctx` - loop_step 甹 ExtractCtx曎新埌の i, acc を持぀ +/// +/// # Returns +/// 再垰呌び出し args +pub fn build_recurse_args(ctx: &LoopContext, step_ctx: &ExtractCtx) -> Vec { + let i_next = step_ctx.get_var("i").expect("i must exist"); + let acc_next = step_ctx.get_var("acc").expect("acc must exist"); + let step_n = step_ctx.get_var("n").expect("n must exist"); + + let mut args = if ctx.has_me { + let me_id = step_ctx.get_var("me").expect("me must exist"); + vec![me_id, i_next, acc_next, step_n] + } else { + vec![i_next, acc_next, step_n] + }; + + // external_refs を远加 + for (name, _) in &ctx.external_refs { + if let Some(var_id) = step_ctx.get_var(name) { + args.push(var_id); + } + } + + args +} + +/// JoinModule を構築 +/// +/// # Arguments +/// * `entry_func` - entry 関数 +/// * `loop_step_func` - loop_step 関数 +/// * `k_exit_func` - k_exit 関数 +/// +/// # Returns +/// JoinModule +pub fn build_join_module( + entry_func: JoinFunction, + loop_step_func: JoinFunction, + k_exit_func: JoinFunction, +) -> JoinModule { + let entry_id = entry_func.id; + + let mut functions = BTreeMap::new(); + functions.insert(entry_func.id, entry_func); + functions.insert(loop_step_func.id, loop_step_func); + functions.insert(k_exit_func.id, k_exit_func); + + JoinModule { + functions, + entry: Some(entry_id), + } +} diff --git a/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/continue_pattern.rs b/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/continue_pattern.rs new file mode 100644 index 00000000..c2c17858 --- /dev/null +++ b/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/continue_pattern.rs @@ -0,0 +1,240 @@ +//! Phase P4: Continue パタヌン lowering +//! +//! ## 責務1行で衚珟 +//! **if continue 条件で凊理をスキップするルヌプを Select に萜ずす** +//! +//! ## パタヌン䟋 +//! ```nyash +//! loop(i < n) { +//! i = i + 1 +//! if i == 3 { continue } +//! acc = acc + i +//! } +//! ``` +//! +//! ## 生成する JoinIR 構造 +//! - entry 関数: Call(loop_step) +//! - loop_step 関数: +//! - exit 条件チェック +//! - i++ 凊理 +//! - continue 条件評䟡 +//! - Select: continue なら acc そのたた、そうでなければ曎新 +//! - 再垰 +//! - k_exit 関数: Return(acc) + +use super::common::{ + build_join_module, create_k_exit_function, create_loop_context, parse_program_json, + process_local_inits, +}; +use super::{AstToJoinIrLowerer, JoinModule, LoweringError}; +use crate::mir::join_ir::{CompareOp, ConstValue, JoinFunction, JoinInst, MirLikeInst}; +use crate::mir::ValueId; + +/// Continue パタヌンを JoinModule に倉換 +/// +/// # Arguments +/// * `lowerer` - AstToJoinIrLowerer むンスタンス +/// * `program_json` - Program(JSON v0) +pub fn lower( + lowerer: &mut AstToJoinIrLowerer, + program_json: &serde_json::Value, +) -> Result { + // 1. Program(JSON) をパヌス + let parsed = parse_program_json(program_json); + + // 2. LoopContext ず entry_ctx を䜜成 + let (ctx, mut entry_ctx) = create_loop_context(lowerer, &parsed); + + // 3. Local 初期化を凊理 + let init_insts = process_local_inits(lowerer, &parsed, &mut entry_ctx); + + // 4. Loop の cond を取埗 + let loop_node = &parsed.stmts[parsed.loop_node_idx]; + let loop_cond_expr = &loop_node["cond"]; + + // 5. Loop body から Continue If を探す + let loop_body = loop_node["body"] + .as_array() + .ok_or_else(|| LoweringError::InvalidLoopBody { + message: "Loop must have 'body' array".to_string(), + })?; + + let continue_if_stmt = loop_body + .iter() + .find(|stmt| { + stmt["type"].as_str() == Some("If") + && stmt["then"].as_array().map_or(false, |then| { + then.iter().any(|s| s["type"].as_str() == Some("Continue")) + }) + }) + .ok_or_else(|| LoweringError::InvalidLoopBody { + message: "Continue pattern must have If + Continue".to_string(), + })?; + + let continue_cond_expr = &continue_if_stmt["cond"]; + + // 6. entry 関数を生成 + let entry_func = create_entry_function_continue(&ctx, &parsed, init_insts, &mut entry_ctx); + + // 7. loop_step 関数を生成 + let loop_step_func = create_loop_step_function_continue( + lowerer, + &ctx, + &parsed.func_name, + loop_cond_expr, + continue_cond_expr, + loop_body, + )?; + + // 8. k_exit 関数を生成 + let k_exit_func = create_k_exit_function(&ctx, &parsed.func_name); + + // 9. JoinModule を構築 + Ok(build_join_module(entry_func, loop_step_func, k_exit_func)) +} + +/// Continue パタヌン甚 entry 関数を生成 +fn create_entry_function_continue( + ctx: &super::common::LoopContext, + parsed: &super::common::ParsedProgram, + init_insts: Vec, + entry_ctx: &mut super::super::context::ExtractCtx, +) -> JoinFunction { + // i, acc, n を取埗 + let i_init = entry_ctx.get_var("i").expect("i must be initialized"); + let acc_init = entry_ctx.get_var("acc").expect("acc must be initialized"); + let n_param = entry_ctx.get_var("n").expect("n must be parameter"); + + let loop_result = entry_ctx.alloc_var(); + + let mut body = init_insts; + body.push(JoinInst::Call { + func: ctx.loop_step_id, + args: vec![i_init, acc_init, n_param], + k_next: None, + dst: Some(loop_result), + }); + body.push(JoinInst::Ret { + value: Some(loop_result), + }); + + JoinFunction { + id: ctx.entry_id, + name: parsed.func_name.clone(), + params: (0..parsed.param_names.len()) + .map(|i| ValueId(i as u32)) + .collect(), + body, + exit_cont: None, + } +} + +/// Continue パタヌン甚 loop_step 関数を生成 +fn create_loop_step_function_continue( + lowerer: &mut AstToJoinIrLowerer, + ctx: &super::common::LoopContext, + func_name: &str, + loop_cond_expr: &serde_json::Value, + continue_cond_expr: &serde_json::Value, + loop_body: &[serde_json::Value], +) -> Result { + use super::super::context::ExtractCtx; + + let step_i = ValueId(0); + let step_acc = ValueId(1); + let step_n = ValueId(2); + + let mut step_ctx = ExtractCtx::new(3); + step_ctx.register_param("i".to_string(), step_i); + step_ctx.register_param("acc".to_string(), step_acc); + step_ctx.register_param("n".to_string(), step_n); + + let mut body = Vec::new(); + + // 1. exit 条件チェック!(i < n) = i >= n で抜ける + let (cond_var, cond_insts) = lowerer.extract_value(loop_cond_expr, &mut step_ctx); + body.extend(cond_insts); + + let false_const = step_ctx.alloc_var(); + let exit_cond = step_ctx.alloc_var(); + + body.push(JoinInst::Compute(MirLikeInst::Const { + dst: false_const, + value: ConstValue::Bool(false), + })); + body.push(JoinInst::Compute(MirLikeInst::Compare { + dst: exit_cond, + op: CompareOp::Eq, + lhs: cond_var, + rhs: false_const, + })); + + body.push(JoinInst::Jump { + cont: ctx.k_exit_id.as_cont(), + args: vec![step_acc], + cond: Some(exit_cond), + }); + + // 2. Continue pattern 特有: i のむンクリメントが先 + let first_local = loop_body + .iter() + .find(|stmt| { + stmt["type"].as_str() == Some("Local") && stmt["name"].as_str() == Some("i") + }) + .ok_or_else(|| LoweringError::InvalidLoopBody { + message: "Continue pattern must have i increment as first Local".to_string(), + })?; + + let i_expr = &first_local["expr"]; + let (i_next, i_insts) = lowerer.extract_value(i_expr, &mut step_ctx); + body.extend(i_insts); + step_ctx.register_param("i".to_string(), i_next); + + // 3. Continue 条件を評䟡 + let (continue_cond_var, continue_cond_insts) = + lowerer.extract_value(continue_cond_expr, &mut step_ctx); + body.extend(continue_cond_insts); + + // 4. acc の曎新倀を蚈算 + let acc_update_local = loop_body + .iter() + .find(|stmt| { + stmt["type"].as_str() == Some("Local") && stmt["name"].as_str() == Some("acc") + }) + .ok_or_else(|| LoweringError::InvalidLoopBody { + message: "Continue pattern must have acc update Local".to_string(), + })?; + + let acc_expr = &acc_update_local["expr"]; + let (acc_increment, acc_insts) = lowerer.extract_value(acc_expr, &mut step_ctx); + body.extend(acc_insts); + + // 5. Select: Continue なら acc そのたた、そうでなければ曎新 + let acc_next = step_ctx.alloc_var(); + body.push(JoinInst::Select { + dst: acc_next, + cond: continue_cond_var, + then_val: step_acc, // Continue: 曎新しない + else_val: acc_increment, // 通垞: 曎新 + }); + + // 6. 末尟再垰 + let recurse_result = step_ctx.alloc_var(); + body.push(JoinInst::Call { + func: ctx.loop_step_id, + args: vec![i_next, acc_next, step_n], + k_next: None, + dst: Some(recurse_result), + }); + body.push(JoinInst::Ret { + value: Some(recurse_result), + }); + + Ok(JoinFunction { + id: ctx.loop_step_id, + name: format!("{}_loop_step", func_name), + params: vec![step_i, step_acc, step_n], + body, + exit_cont: None, + }) +} diff --git a/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/filter.rs b/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/filter.rs new file mode 100644 index 00000000..a9417481 --- /dev/null +++ b/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/filter.rs @@ -0,0 +1,53 @@ +//! Phase P2/56: Filter パタヌン lowering +//! +//! ## 責務1行で衚珟 +//! **pred が true のずきだけ push するルヌプを ConditionalMethodCall に萜ずす** +//! +//! ## パタヌン䟋 +//! ```nyash +//! box ArrayExtBox { +//! filter(pred) { +//! local out = new ArrayBox() +//! local i = 0 +//! loop(i < me.size()) { +//! local v = me.get(i) +//! if pred(v) { +//! out.push(v) // ← ConditionalMethodCall に倉換 +//! } +//! i = i + 1 +//! } +//! return out +//! } +//! } +//! ``` +//! +//! ## 生成する JoinIR 構造 +//! - entry 関数: Call(loop_step) +//! - loop_step 関数: +//! - 条件チェック: `i < tokens.size()` +//! - true: v取埗 + ConditionalMethodCall(if pred(v) then push) + i++ + 再垰 +//! - false: Jump(k_exit) +//! - k_exit 関数: Return(out) +//! +//! ## 珟圚の実装 +//! Simple パタヌンに委譲stmt_handlers が if 内 MethodCall を適切に凊理 + +use super::{AstToJoinIrLowerer, JoinModule, LoweringError}; + +/// Filter パタヌンを JoinModule に倉換 +/// +/// Phase 56 で実装枈みの filter ルヌプを JoinIR に倉換する。 +/// 珟圚は Simple パタヌンに委譲し、stmt_handlers が if 内の凊理を適切に行う。 +/// +/// # Arguments +/// * `lowerer` - AstToJoinIrLowerer むンスタンス +/// * `program_json` - Program(JSON v0) +pub fn lower( + lowerer: &mut AstToJoinIrLowerer, + program_json: &serde_json::Value, +) -> Result { + // Phase 56: Filter パタヌンは Simple パタヌンず同じ構造 + // 差分は stmt_handlers での if 内 MethodCall 凊理のみ + // → Simple に委譲 + super::simple::lower(lowerer, program_json) +} diff --git a/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/mod.rs b/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/mod.rs new file mode 100644 index 00000000..9e2d4d5d --- /dev/null +++ b/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/mod.rs @@ -0,0 +1,120 @@ +//! Phase P2: Loop Patterns - JoinIR Frontend ルヌプパタヌン凊理局 +//! +//! ## 責務 +//! JSON v0 のルヌプ body を、LoopFrontendBinding が枡しおきた LoopPattern に埓っお +//! JoinIR 呜什列に倉換する。 +//! +//! ## やらないこず +//! - 関数名ベヌスの刀定それは LoopFrontendBinding 局 +//! - Box 名・メ゜ッド名で意味論を倉えるそれは Bridge/VM 局 +//! +//! ## 蚭蚈原則 +//! - パタヌン = 1ç®± = 1責務 +//! - 共通凊理は common.rs に集玄 +//! - ゚ラヌは Err(UnimplementedPattern) で返す + +use super::{AstToJoinIrLowerer, JoinModule}; + +pub mod break_pattern; +pub mod common; +pub mod continue_pattern; +pub mod filter; +pub mod print_tokens; +pub mod simple; + +/// ルヌプパタヌンの分類ナヌスケヌスベヌス + 制埡構造 +/// +/// Phase 55/56 で実装枈みのパタヌンず、今埌実装予定のパタヌンを含む。 +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum LoopPattern { + /// PrintTokens パタヌンPhase 55 + /// 責務: token を順番に取り出しお print するルヌプを Jump/Call/MethodCall に萜ずす + PrintTokens, + + /// Filter パタヌンPhase 56 + /// 責務: pred が true のずきだけ push するルヌプを ConditionalMethodCall に萜ずす + Filter, + + /// Map パタヌンPhase 57+ 予定 + /// 責務: 各芁玠を倉換しお新配列䜜成 + Map, + + /// Reduce パタヌンPhase 58+ 予定 + /// 責務: 环積蚈算fold + Reduce, + + /// Simple パタヌン汎甚ルヌプ + /// 責務: 䞊蚘以倖の汎甚的なルヌプ凊理 + Simple, + + /// Break パタヌンPhase P4 + /// 責務: if break 条件で早期 return するルヌプを Jump(k_exit, cond) に萜ずす + Break, + + /// Continue パタヌンPhase P4 + /// 責務: if continue 条件で凊理をスキップするルヌプを Select に萜ずす + Continue, +} + +/// ルヌプパタヌン lowering ゚ラヌ +#[derive(Debug, Clone)] +pub enum LoweringError { + /// 未実装のパタヌン + UnimplementedPattern { + pattern: LoopPattern, + reason: String, + }, + /// JSON パヌス゚ラヌ + JsonParseError { message: String }, + /// ルヌプ body が䞍正 + InvalidLoopBody { message: String }, +} + +/// LoopPattern lowering の統䞀むンタヌフェヌス +/// +/// 各パタヌンの lowering モゞュヌルはこの trait を実装する。 +pub trait LoopPatternLowerer { + /// LoopPattern を JoinModule に倉換 + /// + /// # Arguments + /// * `lowerer` - AstToJoinIrLowerer むンスタンス + /// * `program_json` - Program(JSON v0) + /// + /// # Returns + /// JoinModule たたは LoweringError + fn lower( + lowerer: &mut AstToJoinIrLowerer, + program_json: &serde_json::Value, + ) -> Result; +} + +/// LoopPattern に応じた lowering を実行ディスパッチ箱 +/// +/// Phase P2: この関数は薄いディスパッチのみを行い、実際の lowering は +/// 各パタヌンのモゞュヌルfilter.rs, print_tokens.rs 等に委譲する。 +/// +/// # Arguments +/// * `pattern` - LoopPattern enum +/// * `lowerer` - AstToJoinIrLowerer むンスタンス +/// * `program_json` - Program(JSON v0) +pub fn lower_loop_with_pattern( + pattern: LoopPattern, + lowerer: &mut AstToJoinIrLowerer, + program_json: &serde_json::Value, +) -> Result { + match pattern { + LoopPattern::PrintTokens => print_tokens::lower(lowerer, program_json), + LoopPattern::Filter => filter::lower(lowerer, program_json), + LoopPattern::Map => Err(LoweringError::UnimplementedPattern { + pattern: LoopPattern::Map, + reason: "Map pattern is not yet implemented (Phase 57+)".to_string(), + }), + LoopPattern::Reduce => Err(LoweringError::UnimplementedPattern { + pattern: LoopPattern::Reduce, + reason: "Reduce pattern is not yet implemented (Phase 58+)".to_string(), + }), + LoopPattern::Simple => simple::lower(lowerer, program_json), + LoopPattern::Break => break_pattern::lower(lowerer, program_json), + LoopPattern::Continue => continue_pattern::lower(lowerer, program_json), + } +} diff --git a/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/print_tokens.rs b/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/print_tokens.rs new file mode 100644 index 00000000..fbd59ada --- /dev/null +++ b/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/print_tokens.rs @@ -0,0 +1,49 @@ +//! Phase P2/55: PrintTokens パタヌン lowering +//! +//! ## 責務1行で衚珟 +//! **token を順番に取り出しお print するルヌプを Jump/Call/MethodCall に萜ずす** +//! +//! ## パタヌン䟋 +//! ```nyash +//! box JsonTokenizer { +//! print_tokens() { +//! local i = 0 +//! loop(i < me.tokens.size()) { +//! local token = me.tokens.get(i) +//! print(token) // ← MethodCall に倉換 +//! i = i + 1 +//! } +//! } +//! } +//! ``` +//! +//! ## 生成する JoinIR 構造 +//! - entry 関数: Call(loop_step) +//! - loop_step 関数: +//! - 条件チェック: `i < tokens.size()` +//! - true: token取埗 + print + i++ + 再垰 +//! - false: Jump(k_exit) +//! - k_exit 関数: Return(void) +//! +//! ## 珟圚の実装 +//! Simple パタヌンに委譲stmt_handlers が MethodCall を適切に凊理 + +use super::{AstToJoinIrLowerer, JoinModule, LoweringError}; + +/// PrintTokens パタヌンを JoinModule に倉換 +/// +/// Phase 55 で実装枈みの print_tokens ルヌプを JoinIR に倉換する。 +/// 珟圚は Simple パタヌンに委譲し、stmt_handlers が MethodCall を適切に凊理。 +/// +/// # Arguments +/// * `lowerer` - AstToJoinIrLowerer むンスタンス +/// * `program_json` - Program(JSON v0) +pub fn lower( + lowerer: &mut AstToJoinIrLowerer, + program_json: &serde_json::Value, +) -> Result { + // Phase 55: PrintTokens パタヌンは Simple パタヌンず同じ構造 + // 差分は stmt_handlers での MethodCall 凊理のみ + // → Simple に委譲 + super::simple::lower(lowerer, program_json) +} diff --git a/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/simple.rs b/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/simple.rs new file mode 100644 index 00000000..6e520c6b --- /dev/null +++ b/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/simple.rs @@ -0,0 +1,151 @@ +//! Phase P2: Simple パタヌン lowering +//! +//! ## 責務1行で衚珟 +//! **汎甚的なルヌプ凊理を Jump/Call/Select に萜ずす** +//! +//! ## パタヌン䟋 +//! ```nyash +//! // Filter/Map/Reduce/PrintTokens 以倖の汎甚ルヌプ +//! local sum = 0 +//! local i = 0 +//! loop(i < n) { +//! sum = sum + i +//! i = i + 1 +//! } +//! ``` +//! +//! ## 生成する JoinIR 構造 +//! - entry 関数: Call(loop_step) +//! - loop_step 関数: +//! - 条件チェック +//! - true: body 凊理 + 再垰 +//! - false: Jump(k_exit) +//! - k_exit 関数: Return + +use super::common::{ + build_join_module, build_recurse_args, build_step_params, create_entry_function, + create_k_exit_function, create_loop_context, create_step_ctx, parse_program_json, + process_local_inits, +}; +use super::{AstToJoinIrLowerer, JoinModule, LoweringError, LoopPattern}; +use crate::mir::join_ir::{ConstValue, JoinFunction, JoinInst, MirLikeInst}; +use crate::mir::join_ir::CompareOp; + +/// Simple パタヌンを JoinModule に倉換 +/// +/// 汎甚的なルヌプ凊理を JoinIR に倉換する。 +/// Filter/Map/Reduce/PrintTokens 以倖のすべおのルヌプがこれに該圓する。 +/// +/// # Arguments +/// * `lowerer` - AstToJoinIrLowerer むンスタンス +/// * `program_json` - Program(JSON v0) +pub fn lower( + lowerer: &mut AstToJoinIrLowerer, + program_json: &serde_json::Value, +) -> Result { + // 1. Program(JSON) をパヌス + let parsed = parse_program_json(program_json); + + // 2. LoopContext ず entry_ctx を䜜成 + let (ctx, mut entry_ctx) = create_loop_context(lowerer, &parsed); + + // 3. Local 初期化を凊理 + let init_insts = process_local_inits(lowerer, &parsed, &mut entry_ctx); + + // 4. entry 関数を生成 + let entry_func = create_entry_function(&ctx, &parsed, init_insts, &mut entry_ctx); + + // 5. Loop ノヌドを取埗 + let loop_node = &parsed.stmts[parsed.loop_node_idx]; + let loop_cond_expr = &loop_node["cond"]; + let loop_body_stmts = loop_node["body"] + .as_array() + .ok_or_else(|| LoweringError::InvalidLoopBody { + message: "Loop must have 'body' array".to_string(), + })?; + + // 6. loop_step 関数を生成 + let loop_step_func = create_loop_step_function( + lowerer, + &ctx, + &parsed.func_name, + loop_cond_expr, + loop_body_stmts, + )?; + + // 7. k_exit 関数を生成 + let k_exit_func = create_k_exit_function(&ctx, &parsed.func_name); + + // 8. JoinModule を構築 + Ok(build_join_module(entry_func, loop_step_func, k_exit_func)) +} + +/// loop_step 関数を生成 +fn create_loop_step_function( + lowerer: &mut AstToJoinIrLowerer, + ctx: &super::common::LoopContext, + func_name: &str, + loop_cond_expr: &serde_json::Value, + loop_body_stmts: &[serde_json::Value], +) -> Result { + // step_ctx を䜜成 + let mut step_ctx = create_step_ctx(ctx); + + // 条件匏を評䟡i < n + let (cond_var, cond_insts) = lowerer.extract_value(loop_cond_expr, &mut step_ctx); + + // !cond を蚈算i >= n なら抜ける + let false_const = step_ctx.alloc_var(); + let exit_cond = step_ctx.alloc_var(); + + let mut body = cond_insts; + body.push(JoinInst::Compute(MirLikeInst::Const { + dst: false_const, + value: ConstValue::Bool(false), + })); + body.push(JoinInst::Compute(MirLikeInst::Compare { + dst: exit_cond, + op: CompareOp::Eq, + lhs: cond_var, + rhs: false_const, + })); + + // 早期 return: exit_cond が truei >= nなら k_exit ぞ Jump + let step_acc = step_ctx.get_var("acc").expect("acc must exist"); + body.push(JoinInst::Jump { + cont: ctx.k_exit_id.as_cont(), + args: vec![step_acc], + cond: Some(exit_cond), + }); + + // Loop body を凊理汎甚 statement handler を䜿甚 + for body_stmt in loop_body_stmts { + let (insts, _effect) = lowerer.lower_statement(body_stmt, &mut step_ctx); + body.extend(insts); + } + + // 再垰呌び出し + let recurse_args = build_recurse_args(ctx, &step_ctx); + let recurse_result = step_ctx.alloc_var(); + + body.push(JoinInst::Call { + func: ctx.loop_step_id, + args: recurse_args, + k_next: None, + dst: Some(recurse_result), + }); + body.push(JoinInst::Ret { + value: Some(recurse_result), + }); + + // パラメヌタリストを構築 + let params = build_step_params(ctx); + + Ok(JoinFunction { + id: ctx.loop_step_id, + name: format!("{}_loop_step", func_name), + params, + body, + exit_cont: None, + }) +} diff --git a/src/mir/join_ir/frontend/ast_lowerer/loop_patterns.rs b/src/mir/join_ir/frontend/ast_lowerer/loop_patterns_old.rs similarity index 100% rename from src/mir/join_ir/frontend/ast_lowerer/loop_patterns.rs rename to src/mir/join_ir/frontend/ast_lowerer/loop_patterns_old.rs diff --git a/src/mir/join_ir/frontend/ast_lowerer/mod.rs b/src/mir/join_ir/frontend/ast_lowerer/mod.rs index b1604ab2..568c51ba 100644 --- a/src/mir/join_ir/frontend/ast_lowerer/mod.rs +++ b/src/mir/join_ir/frontend/ast_lowerer/mod.rs @@ -30,7 +30,9 @@ mod context; mod expr; mod if_in_loop; mod if_return; +mod loop_frontend_binding; mod loop_patterns; +mod loop_patterns_old; mod nested_if; mod read_quoted; mod stmt_handlers; @@ -83,18 +85,20 @@ impl AstToJoinIrLowerer { .as_str() .expect("Function must have 'name'"); - // 3. 関数名で分岐Phase 34-2/34-3/34-4/34-5/34-7/34-8/41-4/45 - // test/local/_read_value_from_pair: If Return pattern - // simple: Loop pattern (Phase 34-7/34-8) - // parse_loop: Phase 41-4 NestedIfMerge pattern - // read_quoted_from: Phase 45 Guard if + Loop with break + accumulator + // 3. 関数名で分岐Phase P3: LoopFrontendBinding 局導入 + // + // パタヌン分類: + // - If Return pattern: test/local/_read_value_from_pair + // - Loop pattern: simple 等 → LoopFrontendBinding 経由 + // - NestedIfMerge pattern: parse_loop (dev flag gated) + // - ReadQuoted pattern: read_quoted_from (dev flag gated) match func_name { "test" | "local" | "_read_value_from_pair" => { self.lower_if_return_pattern(program_json) } - "simple" => { - // Phase 34-8: Loop パタヌンの詳现分析break/continue 怜出 - self.lower_loop_with_break_continue(program_json) + "simple" | "filter" | "print_tokens" | "map" | "reduce" | "fold" => { + // Phase P3: LoopFrontendBinding 局経由でディスパッチ + loop_frontend_binding::lower_loop_by_function_name(self, program_json) } "parse_loop" => { // Phase 41-4: NestedIfMerge pattern (dev flag gated)