Files
hakorune/src/mir/join_ir/lowering/loop_view_builder.rs
nyash-codex 6e778948db feat(joinir): Phase 202-A Pattern 1 uses JoinValueSpace
Migrated Pattern 1 (Simple While) to use JoinValueSpace for unified
ValueId allocation, following the same pattern as Pattern 2 (Phase 201).

Changes:
- simple_while_minimal.rs: Added join_value_space parameter, replaced
  value_counter with join_value_space.alloc_local()
- pattern1_minimal.rs: Create JoinValueSpace before calling lowerer
- loop_view_builder.rs: Create JoinValueSpace in try_pattern1()

Pattern 1 uses Local region (1000+) only, since it doesn't need
ConditionEnv (no Param region allocation required).

Tested:
- cargo build --release --lib: Success (0 errors, 4 warnings)
- cargo test --release --lib pattern: 119 passed
- E2E test apps/tests/loop_min_while.hako: Outputs "0 1 2" correctly

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-09 19:08:42 +09:00

261 lines
9.0 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! Phase 33-23: LoopViewBuilder - Loop lowering ディスパッチ箱
//!
//! LoopToJoinLowererからlowering選択責務を分離した専用モジュール。
//!
//! ## 責務
//!
//! - **Pattern検出**: Pattern 1 (Simple While)検出
//! - **Shape検出**: CaseALoweringShape検出
//! - **Lowerer選択**: Shape/名前ベースでlowerer選択
//! - **Lowerer呼び出し**: 適切なlowererに委譲
//!
//! ## 設計思想
//!
//! - **単一責任**: Lowering選択ロジックのみを集約
//! - **拡張性**: 新しいパターン追加が容易
//! - **テスト容易性**: 独立したBoxで単体テスト可能
use crate::mir::join_ir::lowering::generic_case_a;
use crate::mir::join_ir::lowering::loop_scope_shape::{CaseALoweringShape, LoopScopeShape};
use crate::mir::join_ir::lowering::loop_update_summary; // Phase 170-C-2b
use crate::mir::join_ir::JoinModule;
/// Loop lowering ディスパッチ箱
///
/// LoopScopeShapeからパターンを検出し、適切なlowererを選択する。
pub struct LoopViewBuilder {
/// デバッグモード(詳細ログ出力)
debug: bool,
}
impl Default for LoopViewBuilder {
fn default() -> Self {
Self::new()
}
}
impl LoopViewBuilder {
/// 新しいLoopViewBuilderを作成
pub fn new() -> Self {
let debug = std::env::var("NYASH_LOOPTOJOIN_DEBUG")
.map(|v| v == "1")
.unwrap_or(false);
Self { debug }
}
/// LoopScopeShapeからJoinModuleを生成
///
/// # 選択戦略Phase 170-A-2: Structure-based + Name fallback
///
/// 1. Pattern 1検出Simple While Loop
/// 2. Shape検出CaseALoweringShape
/// 3. Shape別ディスパッチ
/// 4. 名前ベースフォールバックGeneric/NotCaseAの場合
///
/// # Arguments
///
/// - `scope`: LoopScopeShape変数分類・構造情報
/// - `func_name`: 関数名(名前ベースフォールバック用)
///
/// # Returns
///
/// - `Some(JoinModule)`: Lowering成功
/// - `None`: 未サポートパターン(フォールバック経路へ)
pub fn build(
&self,
scope: LoopScopeShape,
func_name: Option<&str>,
) -> Option<JoinModule> {
let name = func_name.unwrap_or("");
// Phase 188-Impl-1: Pattern 1 (Simple While Loop) detection
// Try Pattern 1 FIRST for main function (loop_min_while.hako target)
if let Some(result) = self.try_pattern1(&scope, name) {
return Some(result);
}
// Phase 170-A-2: Structure-based routing with CaseALoweringShape
let carrier_names: Vec<String> = scope.carriers.iter().cloned().collect();
let update_summary = loop_update_summary::analyze_loop_updates(&carrier_names);
let stub_features = crate::mir::loop_pattern_detection::LoopFeatures {
has_break: false,
has_continue: false,
has_if: false,
has_if_else_phi: false,
carrier_count: scope.carriers.len(),
break_count: 0,
continue_count: 0,
update_summary: Some(update_summary),
};
let has_progress_carrier = scope.progress_carrier.is_some();
let carrier_count = scope.carriers.len();
let shape = CaseALoweringShape::detect_with_updates(
&stub_features,
carrier_count,
has_progress_carrier,
);
if self.debug {
eprintln!(
"[LoopViewBuilder] Phase 170-C-2b: shape={:?}, name={:?}, carriers={:?}",
shape.name(),
name,
carrier_names
);
}
// Shape-based dispatch
self.dispatch_by_shape(shape, scope, name)
}
/// Pattern 1 (Simple While Loop) 検出・lowering試行
///
/// # 検出条件
///
/// - 関数名に "main" が含まれる
/// - Pinned vars がない
/// - Carriers が1つ以上
///
/// # Phase 202-A: JoinValueSpace Integration
fn try_pattern1(&self, scope: &LoopScopeShape, name: &str) -> Option<JoinModule> {
if !name.contains("main") {
return None;
}
if scope.pinned.is_empty() && !scope.carriers.is_empty() {
if self.debug {
eprintln!("[LoopViewBuilder] Trying Pattern 1 lowering for {:?}", name);
}
// Phase 202-A: Create JoinValueSpace for Pattern 1
use super::join_value_space::JoinValueSpace;
let mut join_value_space = JoinValueSpace::new();
if let Some(result) = super::simple_while_minimal::lower_simple_while_minimal(
scope.clone(),
&mut join_value_space,
) {
if self.debug {
eprintln!("[LoopViewBuilder] Pattern 1 lowering succeeded for {:?}", name);
}
return Some(result);
}
if self.debug {
eprintln!("[LoopViewBuilder] Pattern 1 lowering failed, trying other lowerers");
}
}
None
}
/// Shape別にlowererをディスパッチ
///
/// # Shape種別
///
/// - **StringExamination**: skip_ws lowerer
/// - **ArrayAccumulation**: append_defs lowerer
/// - **IterationWithAccumulation**: stage1 lowerer
/// - **Generic/NotCaseA**: 名前ベースフォールバック
fn dispatch_by_shape(
&self,
shape: CaseALoweringShape,
scope: LoopScopeShape,
name: &str,
) -> Option<JoinModule> {
match shape {
CaseALoweringShape::StringExamination => {
if self.debug {
eprintln!("[LoopViewBuilder] Shape: StringExamination → skip_ws lowerer");
}
generic_case_a::lower_case_a_skip_ws_with_scope(scope)
}
CaseALoweringShape::ArrayAccumulation => {
if self.debug {
eprintln!("[LoopViewBuilder] Shape: ArrayAccumulation → append_defs lowerer");
}
generic_case_a::lower_case_a_append_defs_with_scope(scope)
}
CaseALoweringShape::IterationWithAccumulation => {
if self.debug {
eprintln!("[LoopViewBuilder] Shape: IterationWithAccumulation → stage1 lowerer");
}
generic_case_a::lower_case_a_stage1_usingresolver_with_scope(scope)
}
CaseALoweringShape::Generic | CaseALoweringShape::NotCaseA => {
if self.debug {
eprintln!(
"[LoopViewBuilder] Shape: {:?} → name-based fallback",
shape.name()
);
}
self.dispatch_by_name(scope, name)
}
}
}
/// 名前ベースフォールバックLegacy
///
/// # Phase 170-A-2 設計
///
/// Shape検出で未分類のループを名前で振り分ける。
/// 将来的にはShape検出を強化してこのフォールバックを削減する。
fn dispatch_by_name(&self, scope: LoopScopeShape, name: &str) -> Option<JoinModule> {
match name {
"Main.skip/1" => {
if self.debug {
eprintln!("[LoopViewBuilder] [fallback] dispatching to skip_ws lowerer");
}
generic_case_a::lower_case_a_skip_ws_with_scope(scope)
}
"FuncScannerBox.trim/1" => {
if self.debug {
eprintln!("[LoopViewBuilder] [fallback] dispatching to trim lowerer");
}
generic_case_a::lower_case_a_trim_with_scope(scope)
}
"FuncScannerBox.append_defs/2" => {
if self.debug {
eprintln!("[LoopViewBuilder] [fallback] dispatching to append_defs lowerer");
}
generic_case_a::lower_case_a_append_defs_with_scope(scope)
}
"Stage1UsingResolverBox.resolve_for_source/5" => {
if self.debug {
eprintln!("[LoopViewBuilder] [fallback] dispatching to stage1 lowerer");
}
generic_case_a::lower_case_a_stage1_usingresolver_with_scope(scope)
}
_ => {
// No shape match AND no whitelist match
if self.debug && self.generic_case_a_enabled() {
eprintln!(
"[LoopViewBuilder] generic Case-A candidate: {:?} (no lowerer yet)",
name
);
}
None
}
}
}
/// Phase 32 L-1.2: 汎用Case-A loweringが有効かどうか
fn generic_case_a_enabled(&self) -> bool {
crate::mir::join_ir::env_flag_is_1("NYASH_JOINIR_LOWER_GENERIC")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_builder_creation() {
let builder = LoopViewBuilder::new();
assert!(!builder.debug || builder.debug); // Just check it compiles
}
}