refactor(joinir): unify policy decisions and trim routing

This commit is contained in:
nyash-codex
2025-12-17 01:20:35 +09:00
parent 8e17534829
commit ad67d50798
7 changed files with 110 additions and 94 deletions

View File

@ -85,8 +85,8 @@
- Reject理由は`error_tags::freeze()`でタグ付与
### Decision型の統一
- `Decision` enumNone / Use(...) / Reject(String))を統一パターンとして使用
- 例: `P5bEscapeDerivedDecision`, `TrimDecision`(将来)
- `PolicyDecision<T>`Use / Reject / NoneをSSOTにする
- 例: `P5bEscapeDerivedDecision = PolicyDecision<BodyLocalDerivedRecipe>`, `TrimPolicyResult`
## 使用パターン

View File

@ -8,6 +8,10 @@
//! - ルーティング決定: 適用可能なLoweringパターンを決定
//! - Recipe生成: Pattern固有の情報ConditionOnlyRecipe, BodyLocalDerivedRecipe, etc.)を生成
//!
//! ## 決定型のSSOT
//! - `PolicyDecision<T>` に統一Use / Reject / None
//! - BodyLocal, Trim, P5b escape などすべてここ経由で route することで Pattern2 側の分岐を簡潔に保つ
//!
//! ## 設計原則
//! - **単一判断の原則**: 各policy箱は1つのパターン判断のみ
//! - **非破壊的判断**: 入力を変更せず、Decision型で結果を返す
@ -17,11 +21,14 @@
//! policies/ は「認識とルーティング決定policy」を分離する受け皿です。
//! Phase 94P5b derivedから段階的に移設を開始しました。
//!
//! ### 段階的な移行計画
//! - Phase 1: ディレクトリ準備 ✅
//! - Phase 2: 既存policy箱の移動進行中
//! - Phase 3: インターフェース統一(将来)
//!
//! 詳細は [README.md](README.md) を参照してください。
#[derive(Debug, Clone)]
pub enum PolicyDecision<T> {
Use(T),
Reject(String),
None,
}
pub(in crate::mir::builder) mod p5b_escape_derived_policy;
pub(in crate::mir::builder) mod trim_policy;

View File

@ -13,13 +13,9 @@ use crate::config::env::joinir_dev;
use crate::mir::builder::control_flow::joinir::patterns::escape_pattern_recognizer::EscapeSkipPatternInfo;
use crate::mir::join_ir::lowering::common::body_local_derived_emitter::BodyLocalDerivedRecipe;
use crate::mir::join_ir::lowering::error_tags;
use super::PolicyDecision;
#[derive(Debug)]
pub enum P5bEscapeDerivedDecision {
None,
UseDerived(BodyLocalDerivedRecipe),
Reject(String),
}
pub type P5bEscapeDerivedDecision = PolicyDecision<BodyLocalDerivedRecipe>;
/// Detect a P5b derived body-local (`ch`) recipe from a Pattern2 loop body.
///
@ -43,7 +39,7 @@ pub fn classify_p5b_escape_derived(
}
match build_recipe_from_info(body, &info) {
Ok(Some(recipe)) => P5bEscapeDerivedDecision::UseDerived(recipe),
Ok(Some(recipe)) => P5bEscapeDerivedDecision::Use(recipe),
Ok(None) => {
// Escape pattern exists but there is no body-local reassignment to cover.
P5bEscapeDerivedDecision::None
@ -257,7 +253,7 @@ mod tests {
];
match classify_p5b_escape_derived(&body, "i") {
P5bEscapeDerivedDecision::UseDerived(recipe) => {
P5bEscapeDerivedDecision::Use(recipe) => {
assert_eq!(recipe.name, "ch");
assert_eq!(recipe.loop_counter_name, "i");
assert_eq!(recipe.pre_delta, 1);

View File

@ -0,0 +1,51 @@
//! Trim pattern policy box (判定専用)
//!
//! 目的: Trim 形状かどうかを判定し、ConditionScope を返すだけに責務を絞る。
//! 生成loweringは従来通り TrimLoopLowerer 側が担当する。
use crate::ast::ASTNode;
use crate::mir::builder::control_flow::joinir::patterns::trim_loop_lowering::TrimLoopLowerer;
use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape;
use crate::mir::loop_pattern_detection::loop_condition_scope::{
CondVarInfo, CondVarScope, LoopConditionScope, LoopConditionScopeBox,
};
use super::PolicyDecision;
/// 判定結果(生成に必要な最小情報だけ運ぶ)
#[derive(Debug, Clone)]
pub struct TrimPolicyResult {
pub cond_scope: LoopConditionScope,
pub condition_body_locals: Vec<CondVarInfo>,
}
pub fn classify_trim_like_loop(
scope: &LoopScopeShape,
loop_cond: &ASTNode,
break_cond: &ASTNode,
loop_var_name: &str,
) -> PolicyDecision<TrimPolicyResult> {
let cond_scope =
LoopConditionScopeBox::analyze(loop_var_name, &[loop_cond, break_cond], Some(scope));
if !cond_scope.has_loop_body_local() {
return PolicyDecision::None;
}
let condition_body_locals: Vec<_> = cond_scope
.vars
.iter()
.filter(|v| v.scope == CondVarScope::LoopBodyLocal)
.filter(|v| TrimLoopLowerer::is_var_used_in_condition(&v.name, break_cond))
.cloned()
.collect();
if condition_body_locals.is_empty() {
return PolicyDecision::None;
}
PolicyDecision::Use(TrimPolicyResult {
cond_scope,
condition_body_locals,
})
}