refactor(joinir): unify policy decisions and trim routing
This commit is contained in:
@ -85,8 +85,8 @@
|
||||
- Reject理由は`error_tags::freeze()`でタグ付与
|
||||
|
||||
### Decision型の統一
|
||||
- `Decision` enum(None / Use(...) / Reject(String))を統一パターンとして使用
|
||||
- 例: `P5bEscapeDerivedDecision`, `TrimDecision`(将来)
|
||||
- `PolicyDecision<T>`(Use / Reject / None)をSSOTにする
|
||||
- 例: `P5bEscapeDerivedDecision = PolicyDecision<BodyLocalDerivedRecipe>`, `TrimPolicyResult`
|
||||
|
||||
## 使用パターン
|
||||
|
||||
|
||||
@ -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 94(P5b 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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user