refactor(joinir): boxify Pattern2 routing and schedule facts

This commit is contained in:
nyash-codex
2025-12-17 21:24:46 +09:00
parent 950560a3d9
commit ae2a1d4339
11 changed files with 550 additions and 148 deletions

View File

@ -55,6 +55,23 @@
---
### loop_true_read_digits_policy.rs (Phase 104/105)
**現在の場所**: `patterns/policies/loop_true_read_digits_policy.rs`
**責務**: `loop(true)` + break-only digits`read_digits_from` familyの認識とルーティング
**判断基準**:
- `loop(true)` である
- read-digits(loop(true)) detector に一致する
- `ReadDigitsBreakConditionBox` が eos 条件 + digit 条件を抽出できる
**出力**:
- `PolicyDecision::Use(LoopTrueReadDigitsPolicyResult)` - `break_when_true := (ch == \"\") || !(digit_cond)``ch` allow-list
- `PolicyDecision::Reject(String)` - 検出失敗理由Fail-Fast
- `PolicyDecision::None` - 該当なし
---
### body_local_policy.rs
**現在の場所**: `patterns/body_local_policy.rs`

View File

@ -0,0 +1,61 @@
//! loop(true) + break-only digits (read_digits_from family) policy
//!
//! Goal: keep Pattern2 core lowering structural by moving shape recognition + routing
//! for loop(true) read-digits family into a dedicated policy box.
//!
//! This policy is intentionally narrow:
//! - It only triggers when the body matches the read-digits(loop(true)) detector.
//! - It returns a normalized "break when true" condition AST:
//! `break_when_true := (ch == "") || !(digit_cond)`
//! - It provides the single allowed body-local variable name (`ch`) for condition lowering.
use super::PolicyDecision;
use crate::ast::{ASTNode, BinaryOperator, Span, UnaryOperator};
pub(crate) struct LoopTrueReadDigitsPolicyResult {
pub break_condition_node: ASTNode,
pub allowed_ch_var: String,
}
pub(crate) fn classify_loop_true_read_digits(
condition: &ASTNode,
body: &[ASTNode],
) -> PolicyDecision<LoopTrueReadDigitsPolicyResult> {
use crate::mir::builder::control_flow::joinir::patterns::{
ast_feature_extractor::detect_read_digits_loop_true_pattern,
loop_true_counter_extractor::LoopTrueCounterExtractorBox,
read_digits_break_condition_box::ReadDigitsBreakConditionBox,
};
if !LoopTrueCounterExtractorBox::is_loop_true(condition) {
return PolicyDecision::None;
}
if detect_read_digits_loop_true_pattern(body).is_none() {
return PolicyDecision::None;
}
let (ch_var, eos_cond, digit_cond) =
match ReadDigitsBreakConditionBox::extract_eos_and_digit_condition(body) {
Ok(v) => v,
Err(e) => return PolicyDecision::Reject(e),
};
let break_on_not_digit = ASTNode::UnaryOp {
operator: UnaryOperator::Not,
operand: Box::new(digit_cond),
span: Span::unknown(),
};
let break_when_true = ASTNode::BinaryOp {
operator: BinaryOperator::Or,
left: Box::new(eos_cond),
right: Box::new(break_on_not_digit),
span: Span::unknown(),
};
PolicyDecision::Use(LoopTrueReadDigitsPolicyResult {
break_condition_node: break_when_true,
allowed_ch_var: ch_var,
})
}

View File

@ -32,3 +32,4 @@ pub enum PolicyDecision<T> {
pub(in crate::mir::builder) mod p5b_escape_derived_policy;
pub(in crate::mir::builder) mod trim_policy;
pub(in crate::mir::builder) mod loop_true_read_digits_policy;