Files
hakorune/src/mir/join_ir/frontend/ast_lowerer/mod.rs
nyash-codex 3af98964ed feat(joinir): Phase P2-P4 Loop Pattern boxification
- 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 <noreply@anthropic.com>
2025-11-29 09:04:18 +09:00

145 lines
5.2 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.

//! AST/CFG → JoinIR Lowering
//!
//! このモジュールは AST/CFG ノードを JoinIR 命令に変換する。
//!
//! ## 責務
//!
//! - **If 文→Select/IfMerge 変換**: 条件分岐を JoinIR の継続渡しスタイルに変換
//! - **Loop 文→loop_step/k_exit 変換**: ループを関数呼び出しと継続に正規化
//! - **Break/Continue/Return→k_* 変換**: 制御フローを継続 ID として表現
//!
//! ## Phase 34-2 での実装スコープ
//!
//! 最初は `IfSelectTest.*` 相当の tiny ケースのみ対応:
//! - Simple pattern: `if cond { return 1 } else { return 2 }`
//!
//! ## 設計原則
//!
//! - **JoinIR = PHI 生成器**: 既存 PHI の変換器にはしないPhase 33-10 原則)
//! - **段階的移行**: 既存 MIR Builder 経路は保持、新経路はデフォルト OFF
//! - **A/B テスト可能**: 既存経路と新経路の両方で実行して比較検証
pub(crate) use crate::mir::join_ir::{
BinOpKind, CompareOp, ConstValue, JoinFuncId, JoinFunction, JoinInst, JoinModule, MergePair,
VarId,
};
pub(crate) use std::collections::{BTreeMap, HashSet};
mod analysis;
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;
#[cfg(test)]
mod tests;
pub(crate) use context::ExtractCtx;
pub(crate) use stmt_handlers::StatementEffect;
/// AST/CFG → JoinIR 変換器
///
/// Phase 34-2: Program(JSON v0) から tiny IfSelect ケースを JoinIR に変換
pub struct AstToJoinIrLowerer {
pub(crate) next_func_id: u32,
#[allow(dead_code)]
pub(crate) next_var_id: u32,
}
impl AstToJoinIrLowerer {
/// 新しい lowerer を作成
pub fn new() -> Self {
Self {
next_func_id: 0,
next_var_id: 0,
}
}
/// Program(JSON v0) → JoinModule
///
/// Phase 34-2/34-3/34-4: simple/local/json_shape pattern に対応
/// Phase 34-5: extract_value 統一化Int/Var/Method 構造まで)
///
/// # Panics
///
/// - パターンに合わない Program(JSON) が来た場合Phase 34 は tiny テスト専用)
/// - ループ・複数変数・副作用付き ifPhase 34-6 以降で対応予定)
pub fn lower_program_json(&mut self, program_json: &serde_json::Value) -> JoinModule {
// 1. Program(JSON) から 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'");
// 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" | "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)
// Guard: HAKO_JOINIR_NESTED_IF=1 を要求
if std::env::var("HAKO_JOINIR_NESTED_IF").ok().as_deref() == Some("1") {
self.lower_nested_if_pattern(program_json)
} else {
// Dev flag が OFF の場合は panic旧ルートにフォールバックするため
panic!(
"parse_loop NestedIfMerge requires HAKO_JOINIR_NESTED_IF=1. \
Set env var to enable Phase 41-4 route."
);
}
}
"read_quoted_from" => {
// Phase 45: read_quoted_from pattern (dev flag gated)
// Guard if + Loop with break + accumulator
if std::env::var("HAKO_JOINIR_READ_QUOTED").ok().as_deref() == Some("1") {
self.lower_read_quoted_pattern(program_json)
} else {
panic!(
"read_quoted_from JoinIR requires HAKO_JOINIR_READ_QUOTED=1. \
Set env var to enable Phase 45 route."
);
}
}
_ => panic!("Unsupported function: {}", func_name),
}
}
/// 次の関数 ID を生成
pub(crate) fn next_func_id(&mut self) -> JoinFuncId {
let id = JoinFuncId::new(self.next_func_id);
self.next_func_id += 1;
id
}
}
impl Default for AstToJoinIrLowerer {
fn default() -> Self {
Self::new()
}
}