2025-12-05 22:11:39 +09:00
|
|
|
//! Pattern Router - Table-driven dispatch for loop patterns
|
|
|
|
|
//!
|
|
|
|
|
//! Phase 194: Replace if/else chain with table-driven routing
|
|
|
|
|
//!
|
|
|
|
|
//! # Architecture
|
|
|
|
|
//!
|
|
|
|
|
//! - Each pattern registers a detect function and a lower function
|
|
|
|
|
//! - Patterns are tried in priority order (lower = tried first)
|
|
|
|
|
//! - First matching pattern wins
|
2025-12-06 03:30:03 +09:00
|
|
|
//! - Feature extraction delegated to ast_feature_extractor module
|
2025-12-05 22:11:39 +09:00
|
|
|
//!
|
|
|
|
|
//! # Adding New Patterns
|
|
|
|
|
//!
|
|
|
|
|
//! 1. Create a new module in `patterns/` (e.g., `pattern4_your_name.rs`)
|
|
|
|
|
//! 2. Implement `pub fn can_lower(ctx: &LoopPatternContext) -> bool`
|
|
|
|
|
//! 3. Implement `pub fn lower(builder: &mut MirBuilder, ctx: &LoopPatternContext) -> Result<Option<ValueId>, String>`
|
|
|
|
|
//! 4. Add entry to `LOOP_PATTERNS` table below
|
|
|
|
|
//!
|
|
|
|
|
//! That's it! No need to modify routing logic.
|
|
|
|
|
|
|
|
|
|
use crate::ast::ASTNode;
|
|
|
|
|
use crate::mir::builder::MirBuilder;
|
|
|
|
|
use crate::mir::ValueId;
|
|
|
|
|
|
2025-12-06 03:30:03 +09:00
|
|
|
use crate::mir::loop_pattern_detection::{LoopFeatures, LoopPatternKind};
|
|
|
|
|
|
2025-12-22 22:42:56 +09:00
|
|
|
// Phase 273 P1: Import Plan components (DomainPlan → Normalizer → Verifier → Lowerer)
|
|
|
|
|
use crate::mir::builder::control_flow::plan::lowerer::PlanLowerer;
|
|
|
|
|
use crate::mir::builder::control_flow::plan::normalizer::PlanNormalizer;
|
|
|
|
|
use crate::mir::builder::control_flow::plan::verifier::PlanVerifier;
|
|
|
|
|
|
2025-12-23 05:35:42 +09:00
|
|
|
/// AST Feature Extractor (declared in mod.rs as pub module, import from parent)
|
2025-12-06 03:30:03 +09:00
|
|
|
use super::ast_feature_extractor as ast_features;
|
|
|
|
|
|
2025-12-16 15:22:29 +09:00
|
|
|
/// Phase 92 P0-2: Import LoopSkeleton for Option A
|
|
|
|
|
use crate::mir::loop_canonicalizer::LoopSkeleton;
|
|
|
|
|
|
2025-12-05 22:11:39 +09:00
|
|
|
/// Context passed to pattern detect/lower functions
|
2025-12-11 19:11:26 +09:00
|
|
|
pub(crate) struct LoopPatternContext<'a> {
|
2025-12-05 22:11:39 +09:00
|
|
|
/// Loop condition AST node
|
|
|
|
|
pub condition: &'a ASTNode,
|
|
|
|
|
|
|
|
|
|
/// Loop body statements
|
|
|
|
|
pub body: &'a [ASTNode],
|
|
|
|
|
|
|
|
|
|
/// Current function name (for routing)
|
|
|
|
|
pub func_name: &'a str,
|
|
|
|
|
|
|
|
|
|
/// Debug logging enabled
|
|
|
|
|
pub debug: bool,
|
2025-12-06 00:10:27 +09:00
|
|
|
|
|
|
|
|
/// Has continue statement(s) in body? (Phase 194+)
|
2025-12-10 00:01:53 +09:00
|
|
|
#[allow(dead_code)]
|
2025-12-06 00:10:27 +09:00
|
|
|
pub has_continue: bool,
|
|
|
|
|
|
|
|
|
|
/// Has break statement(s) in body? (Phase 194+)
|
2025-12-10 00:01:53 +09:00
|
|
|
#[allow(dead_code)]
|
2025-12-06 00:10:27 +09:00
|
|
|
pub has_break: bool,
|
2025-12-06 03:30:03 +09:00
|
|
|
|
|
|
|
|
/// Phase 192: Loop features extracted from AST
|
2025-12-10 00:01:53 +09:00
|
|
|
#[allow(dead_code)]
|
2025-12-06 03:30:03 +09:00
|
|
|
pub features: LoopFeatures,
|
|
|
|
|
|
|
|
|
|
/// Phase 192: Pattern classification based on features
|
|
|
|
|
pub pattern_kind: LoopPatternKind,
|
2025-12-09 18:32:03 +09:00
|
|
|
|
|
|
|
|
/// Phase 200-C: Optional function body AST for capture analysis
|
|
|
|
|
/// None if not available, Some(&[ASTNode]) if function body is accessible
|
|
|
|
|
pub fn_body: Option<&'a [ASTNode]>,
|
2025-12-16 15:22:29 +09:00
|
|
|
|
|
|
|
|
/// Phase 92 P0-2: Optional LoopSkeleton from canonicalizer
|
|
|
|
|
/// This provides ConditionalStep information for Pattern2 lowering.
|
|
|
|
|
/// None if canonicalizer hasn't run yet (backward compatibility).
|
|
|
|
|
/// SSOT Principle: Avoid re-detecting ConditionalStep in lowering phase.
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
pub skeleton: Option<&'a LoopSkeleton>,
|
2025-12-05 22:11:39 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> LoopPatternContext<'a> {
|
|
|
|
|
/// Create new context from routing parameters
|
2025-12-06 00:10:27 +09:00
|
|
|
///
|
2025-12-23 05:35:42 +09:00
|
|
|
/// Automatically detects continue/break statements in body
|
|
|
|
|
/// Extracts features and classifies pattern from AST
|
|
|
|
|
/// Detects infinite loop condition
|
|
|
|
|
/// Uses choose_pattern_kind() SSOT entry point
|
2025-12-11 19:11:26 +09:00
|
|
|
pub(crate) fn new(
|
2025-12-05 22:11:39 +09:00
|
|
|
condition: &'a ASTNode,
|
|
|
|
|
body: &'a [ASTNode],
|
|
|
|
|
func_name: &'a str,
|
|
|
|
|
debug: bool,
|
|
|
|
|
) -> Self {
|
2025-12-23 05:35:42 +09:00
|
|
|
// Use AST Feature Extractor for break/continue detection
|
2025-12-06 03:30:03 +09:00
|
|
|
let has_continue = ast_features::detect_continue_in_body(body);
|
|
|
|
|
let has_break = ast_features::detect_break_in_body(body);
|
|
|
|
|
|
2025-12-23 05:35:42 +09:00
|
|
|
// Extract features (includes infinite loop detection)
|
2025-12-14 09:59:34 +09:00
|
|
|
let features = ast_features::extract_features(condition, body, has_continue, has_break);
|
2025-12-06 03:30:03 +09:00
|
|
|
|
2025-12-16 07:37:23 +09:00
|
|
|
// Phase 137-6-S1: Use SSOT pattern selection entry point
|
|
|
|
|
use crate::mir::builder::control_flow::joinir::routing::choose_pattern_kind;
|
|
|
|
|
let pattern_kind = choose_pattern_kind(condition, body);
|
2025-12-06 00:10:27 +09:00
|
|
|
|
2025-12-05 22:11:39 +09:00
|
|
|
Self {
|
|
|
|
|
condition,
|
|
|
|
|
body,
|
|
|
|
|
func_name,
|
|
|
|
|
debug,
|
2025-12-06 00:10:27 +09:00
|
|
|
has_continue,
|
|
|
|
|
has_break,
|
2025-12-06 03:30:03 +09:00
|
|
|
features,
|
|
|
|
|
pattern_kind,
|
2025-12-09 18:32:03 +09:00
|
|
|
fn_body: None, // Phase 200-C: Default to None
|
2025-12-16 15:22:29 +09:00
|
|
|
skeleton: None, // Phase 92 P0-2: Default to None
|
2025-12-06 00:10:27 +09:00
|
|
|
}
|
|
|
|
|
}
|
2025-12-09 18:32:03 +09:00
|
|
|
|
|
|
|
|
/// Phase 200-C: Create context with fn_body for capture analysis
|
2025-12-11 19:11:26 +09:00
|
|
|
pub(crate) fn with_fn_body(
|
2025-12-09 18:32:03 +09:00
|
|
|
condition: &'a ASTNode,
|
|
|
|
|
body: &'a [ASTNode],
|
|
|
|
|
func_name: &'a str,
|
|
|
|
|
debug: bool,
|
|
|
|
|
fn_body: &'a [ASTNode],
|
|
|
|
|
) -> Self {
|
|
|
|
|
let mut ctx = Self::new(condition, body, func_name, debug);
|
|
|
|
|
ctx.fn_body = Some(fn_body);
|
|
|
|
|
ctx
|
|
|
|
|
}
|
2025-12-16 15:22:29 +09:00
|
|
|
|
|
|
|
|
/// Phase 92 P0-2: Set skeleton (for canonicalizer integration)
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
pub(crate) fn with_skeleton(mut self, skeleton: &'a LoopSkeleton) -> Self {
|
|
|
|
|
self.skeleton = Some(skeleton);
|
|
|
|
|
self
|
|
|
|
|
}
|
2025-12-06 00:10:27 +09:00
|
|
|
}
|
|
|
|
|
|
2025-12-22 14:48:37 +09:00
|
|
|
/// Phase 272 P0.2 Refactoring: can_lower() strategy classification
|
|
|
|
|
///
|
|
|
|
|
/// Clarifies the two main detection strategies used across patterns:
|
|
|
|
|
///
|
|
|
|
|
/// ## ExtractionBased (SSOT Approach)
|
|
|
|
|
/// - Used by: Pattern6, Pattern7
|
|
|
|
|
/// - Strategy: Try pattern extraction, if successful → match
|
|
|
|
|
/// - Pros: Single source of truth (extract function defines pattern)
|
|
|
|
|
/// - Cons: Extraction can be expensive (but amortized over lowering)
|
|
|
|
|
///
|
|
|
|
|
/// ## StructureBased (Feature Classification)
|
|
|
|
|
/// - Used by: Pattern1, Pattern2, Pattern3, Pattern4, Pattern5, Pattern8, Pattern9
|
|
|
|
|
/// - Strategy: Check pattern_kind (from LoopPatternContext), plus optional structural checks
|
|
|
|
|
/// - Pros: Fast classification, reuses centralized feature detection
|
|
|
|
|
/// - Cons: Two sources of truth (classify + structural checks)
|
|
|
|
|
///
|
|
|
|
|
/// ## Rationale for Dual Strategy:
|
|
|
|
|
/// - Pattern6/7: Complex extraction logic (variable step, carrier tracking)
|
|
|
|
|
/// → ExtractionBased avoids duplication between detect and extract
|
|
|
|
|
/// - Other patterns: Simple structural features (break/continue/if-phi)
|
|
|
|
|
/// → StructureBased leverages centralized LoopFeatures classification
|
|
|
|
|
///
|
|
|
|
|
/// This documentation prevents bugs like Phase 272 P0.2's Pattern7 issue
|
|
|
|
|
/// (pattern_kind check was too restrictive, extraction-based approach fixed it).
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
|
#[allow(dead_code)] // Documentation purpose - not enforced in code yet
|
|
|
|
|
pub(crate) enum CanLowerStrategy {
|
|
|
|
|
/// Extraction-based detection: Try extract(), success → match
|
|
|
|
|
/// Used by Pattern6, Pattern7
|
|
|
|
|
ExtractionBased,
|
|
|
|
|
|
|
|
|
|
/// Structure-based detection: Check pattern_kind from LoopPatternContext
|
|
|
|
|
/// Used by Pattern1, Pattern2, Pattern3, Pattern4, Pattern5, Pattern8, Pattern9
|
|
|
|
|
StructureBased,
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-05 22:11:39 +09:00
|
|
|
/// Entry in the loop pattern router table.
|
|
|
|
|
/// Each pattern registers a detect function and a lower function.
|
2025-12-11 19:11:26 +09:00
|
|
|
pub(crate) struct LoopPatternEntry {
|
2025-12-05 22:11:39 +09:00
|
|
|
/// Human-readable pattern name for debugging
|
2025-12-11 19:11:26 +09:00
|
|
|
pub(crate) name: &'static str,
|
2025-12-05 22:11:39 +09:00
|
|
|
|
|
|
|
|
/// Detection function: returns true if this pattern matches
|
2025-12-11 19:11:26 +09:00
|
|
|
pub(crate) detect: fn(&MirBuilder, &LoopPatternContext) -> bool,
|
2025-12-05 22:11:39 +09:00
|
|
|
|
|
|
|
|
/// Lowering function: performs the actual JoinIR generation
|
2025-12-11 19:11:26 +09:00
|
|
|
pub(crate) lower: fn(&mut MirBuilder, &LoopPatternContext) -> Result<Option<ValueId>, String>,
|
2025-12-05 22:11:39 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Static table of all registered loop patterns.
|
2025-12-15 03:27:47 +09:00
|
|
|
///
|
|
|
|
|
/// **IMPORTANT**: Patterns are tried in array order (SSOT).
|
|
|
|
|
/// Array order defines priority - earlier entries are tried first.
|
|
|
|
|
/// Pattern5 (most specific) → Pattern4 → Pattern3 → Pattern1 → Pattern2
|
2025-12-05 22:11:39 +09:00
|
|
|
///
|
2025-12-23 05:35:42 +09:00
|
|
|
/// # Current Patterns (Structure-based detection, established Phase 131-11+)
|
2025-12-06 03:30:03 +09:00
|
|
|
///
|
2025-12-23 05:35:42 +09:00
|
|
|
/// Pattern detection strategies (updated Phase 282 P0):
|
|
|
|
|
/// - Pattern6/7: ExtractionBased (Plan line, Phase 273+)
|
|
|
|
|
/// - Pattern8/9: ExtractionBased (extraction functions, already implemented)
|
|
|
|
|
/// - Pattern1-5: StructureBased (LoopFeatures classification, legacy)
|
2025-12-05 22:11:39 +09:00
|
|
|
///
|
2025-12-15 03:27:47 +09:00
|
|
|
/// - Pattern 5: Infinite Loop with Early Exit (llvm_stage3_loop_only.hako) [Phase 131-11]
|
2025-12-14 09:59:34 +09:00
|
|
|
/// - Detection: pattern_kind == InfiniteEarlyExit
|
|
|
|
|
/// - Structure: is_infinite_loop && has_break && has_continue
|
|
|
|
|
///
|
2025-12-15 03:27:47 +09:00
|
|
|
/// - Pattern 4: Loop with Continue (loop_continue_pattern4.hako)
|
2025-12-06 03:30:03 +09:00
|
|
|
/// - Detection: pattern_kind == Pattern4Continue
|
|
|
|
|
/// - Structure: has_continue && !has_break
|
|
|
|
|
///
|
2025-12-15 03:27:47 +09:00
|
|
|
/// - Pattern 3: Loop with If-Else PHI (loop_if_phi.hako)
|
2025-12-06 03:30:03 +09:00
|
|
|
/// - Detection: pattern_kind == Pattern3IfPhi
|
|
|
|
|
/// - Structure: has_if_else_phi && !has_break && !has_continue
|
2025-12-06 00:10:27 +09:00
|
|
|
///
|
2025-12-15 03:27:47 +09:00
|
|
|
/// - Pattern 1: Simple While Loop (loop_min_while.hako)
|
2025-12-06 03:30:03 +09:00
|
|
|
/// - Detection: pattern_kind == Pattern1SimpleWhile
|
|
|
|
|
/// - Structure: !has_break && !has_continue && !has_if_else_phi
|
2025-12-05 22:11:39 +09:00
|
|
|
///
|
2025-12-15 03:27:47 +09:00
|
|
|
/// - Pattern 2: Loop with Conditional Break (joinir_min_loop.hako)
|
2025-12-06 03:30:03 +09:00
|
|
|
/// - Detection: pattern_kind == Pattern2Break
|
|
|
|
|
/// - Structure: has_break && !has_continue
|
2025-12-05 22:11:39 +09:00
|
|
|
///
|
2025-12-06 03:30:03 +09:00
|
|
|
/// Note: func_name is now only used for debug logging, not pattern detection
|
2025-12-11 19:11:26 +09:00
|
|
|
pub(crate) static LOOP_PATTERNS: &[LoopPatternEntry] = &[
|
2025-12-14 09:59:34 +09:00
|
|
|
LoopPatternEntry {
|
|
|
|
|
name: "Pattern5_InfiniteEarlyExit",
|
|
|
|
|
detect: super::pattern5_infinite_early_exit::can_lower,
|
|
|
|
|
lower: super::pattern5_infinite_early_exit::lower,
|
|
|
|
|
},
|
2025-12-06 00:10:27 +09:00
|
|
|
LoopPatternEntry {
|
|
|
|
|
name: "Pattern4_WithContinue",
|
|
|
|
|
detect: super::pattern4_with_continue::can_lower,
|
|
|
|
|
lower: super::pattern4_with_continue::lower,
|
|
|
|
|
},
|
2025-12-22 22:42:56 +09:00
|
|
|
// Phase 273 P0.1: Pattern6 entry removed (migrated to Plan-based routing)
|
|
|
|
|
// Pattern6_ScanWithInit now handled via extract_scan_with_init_plan() + PlanLowerer
|
2025-12-22 23:35:43 +09:00
|
|
|
// Phase 273 P2: Pattern7 entry removed (migrated to Plan-based routing)
|
|
|
|
|
// Pattern7_SplitScan now handled via extract_split_scan_plan() + PlanLowerer
|
2025-12-21 02:40:07 +09:00
|
|
|
LoopPatternEntry {
|
|
|
|
|
name: "Pattern8_BoolPredicateScan", // Phase 259 P0: boolean predicate scan (is_integer/is_valid)
|
|
|
|
|
detect: super::pattern8_scan_bool_predicate::can_lower,
|
|
|
|
|
lower: super::pattern8_scan_bool_predicate::lower,
|
|
|
|
|
},
|
2025-12-21 23:12:52 +09:00
|
|
|
LoopPatternEntry {
|
|
|
|
|
name: "Pattern9_AccumConstLoop", // Phase 270 P1: accumulator const loop (橋渡しパターン, before P1)
|
|
|
|
|
detect: super::pattern9_accum_const_loop::can_lower,
|
|
|
|
|
lower: super::pattern9_accum_const_loop::lower,
|
|
|
|
|
},
|
2025-12-05 22:11:39 +09:00
|
|
|
LoopPatternEntry {
|
|
|
|
|
name: "Pattern3_WithIfPhi",
|
|
|
|
|
detect: super::pattern3_with_if_phi::can_lower,
|
|
|
|
|
lower: super::pattern3_with_if_phi::lower,
|
|
|
|
|
},
|
|
|
|
|
LoopPatternEntry {
|
|
|
|
|
name: "Pattern1_Minimal",
|
|
|
|
|
detect: super::pattern1_minimal::can_lower,
|
|
|
|
|
lower: super::pattern1_minimal::lower,
|
|
|
|
|
},
|
|
|
|
|
LoopPatternEntry {
|
|
|
|
|
name: "Pattern2_WithBreak",
|
|
|
|
|
detect: super::pattern2_with_break::can_lower,
|
|
|
|
|
lower: super::pattern2_with_break::lower,
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
/// Try all registered patterns in priority order.
|
|
|
|
|
///
|
|
|
|
|
/// Returns Ok(Some(value_id)) if a pattern matched and lowered successfully.
|
|
|
|
|
/// Returns Ok(None) if no pattern matched.
|
|
|
|
|
/// Returns Err if a pattern matched but lowering failed.
|
2025-12-08 22:17:06 +09:00
|
|
|
///
|
2025-12-23 05:35:42 +09:00
|
|
|
/// # Router Architecture (Structure-based routing established Phase 183)
|
2025-12-08 22:17:06 +09:00
|
|
|
///
|
2025-12-23 05:35:42 +09:00
|
|
|
/// This router uses multiple detection strategies:
|
|
|
|
|
/// - Plan-based (Pattern6/7): extract_*_plan() → DomainPlan (Phase 273+ SSOT)
|
|
|
|
|
/// - Extraction-based (Pattern8/9): extract_*() functions (already implemented)
|
|
|
|
|
/// - Structure-based (Pattern1-5): ctx.pattern_kind classification (legacy)
|
2025-12-22 22:42:56 +09:00
|
|
|
///
|
2025-12-23 05:35:42 +09:00
|
|
|
/// # Plan Line SSOT for Pattern6/7 (Phase 273+)
|
2025-12-22 22:42:56 +09:00
|
|
|
///
|
2025-12-23 00:34:38 +09:00
|
|
|
/// This function implements the following routing strategy:
|
|
|
|
|
/// 1. Try Plan-based Pattern6 (extract_scan_with_init_plan) → DomainPlan
|
|
|
|
|
/// 2. Try Plan-based Pattern7 (extract_split_scan_plan) → DomainPlan
|
|
|
|
|
/// 3. Fall through to legacy Pattern1-5 table for other patterns
|
|
|
|
|
///
|
|
|
|
|
/// The Plan line (Extractor → Normalizer → Verifier → Lowerer) is the
|
|
|
|
|
/// current operational SSOT for Pattern6/7. Legacy patterns (1-5) use
|
|
|
|
|
/// the traditional LoopPatternContext-based routing.
|
|
|
|
|
///
|
|
|
|
|
/// Plan-based architecture (Phase 273 P1-P3):
|
|
|
|
|
/// - extract_*_plan() → DomainPlan (pure extraction, no builder)
|
|
|
|
|
/// - PlanNormalizer::normalize() → CorePlan (pattern knowledge expansion, SSOT)
|
2025-12-22 22:42:56 +09:00
|
|
|
/// - PlanVerifier::verify() → fail-fast validation
|
2025-12-23 00:34:38 +09:00
|
|
|
/// - PlanLowerer::lower() → MIR emission (pattern-agnostic, emit_frag SSOT)
|
|
|
|
|
///
|
|
|
|
|
/// SSOT Entry Points:
|
|
|
|
|
/// - Pattern6: src/mir/builder/control_flow/plan/normalizer.rs (ScanWithInit normalization)
|
|
|
|
|
/// - Pattern7: src/mir/builder/control_flow/plan/normalizer.rs (SplitScan normalization)
|
|
|
|
|
/// - Pattern1-5: src/mir/builder/control_flow/joinir/patterns/pattern*.rs (direct lowering)
|
2025-12-11 19:11:26 +09:00
|
|
|
pub(crate) fn route_loop_pattern(
|
2025-12-05 22:11:39 +09:00
|
|
|
builder: &mut MirBuilder,
|
|
|
|
|
ctx: &LoopPatternContext,
|
|
|
|
|
) -> Result<Option<ValueId>, String> {
|
feat(joinir): Phase 195 - Unified JoinLoopTrace for all JoinIR debug output
Created centralized tracing module for JoinIR loop lowering operations,
consolidating scattered eprintln! calls into a single SSOT interface.
# Implementation
1. **Created trace.rs module** (~233 lines)
- JoinLoopTrace struct with env var controls
- Unified API: pattern(), varmap(), joinir_stats(), phi(), merge(), etc.
- Global singleton via trace() function
- Supports 5 env vars: NYASH_TRACE_VARMAP, NYASH_JOINIR_DEBUG,
NYASH_OPTION_C_DEBUG, NYASH_JOINIR_MAINLINE_DEBUG, NYASH_LOOPFORM_DEBUG
2. **Updated debug.rs** - Delegates trace_varmap() to JoinLoopTrace
3. **Updated routing.rs** - All eprintln! replaced with trace calls (10 instances)
4. **Updated pattern routers** - All 3 patterns now use unified trace
- pattern1_minimal.rs: 6 replacements
- pattern2_with_break.rs: 6 replacements
- pattern3_with_if_phi.rs: 6 replacements
- router.rs: 2 replacements
5. **Updated merge/block_allocator.rs** - 6 eprintln! → trace calls
# Benefits
- **Single Source of Truth**: All trace control through environment variables
- **Consistent Format**: Unified [trace:*] prefix for easy filtering
- **Zero Overhead**: No output when env vars unset
- **Easy Extension**: Add new trace points via existing API
- **Better Debug Experience**: Structured output with clear categories
# Testing
✅ cargo build --release - Success
✅ NYASH_TRACE_VARMAP=1 - Shows varmap traces only
✅ NYASH_JOINIR_DEBUG=1 - Shows joinir + blocks + routing traces
✅ No env vars - No debug output
✅ apps/tests/loop_min_while.hako - All tests pass
# Related
- Phase 191-194 groundwork (modular merge structure)
- NYASH_TRACE_VARMAP added today for variable_map debugging
- Consolidates ~80 scattered eprintln! calls across JoinIR
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 22:23:51 +09:00
|
|
|
use super::super::trace;
|
|
|
|
|
|
2025-12-22 22:42:56 +09:00
|
|
|
// Phase 273 P1: Try Plan-based Pattern6 first (before table iteration)
|
|
|
|
|
// Flow: Extract → Normalize → Verify → Lower
|
|
|
|
|
match super::pattern6_scan_with_init::extract_scan_with_init_plan(
|
|
|
|
|
ctx.condition,
|
|
|
|
|
ctx.body,
|
|
|
|
|
ctx.fn_body,
|
|
|
|
|
)? {
|
|
|
|
|
Some(domain_plan) => {
|
|
|
|
|
// DomainPlan extracted successfully
|
2025-12-23 05:03:25 +09:00
|
|
|
trace::trace().pattern("route", "route=plan pattern=Pattern6_ScanWithInit (Phase 273)", true);
|
2025-12-22 22:42:56 +09:00
|
|
|
|
|
|
|
|
// Step 1: Normalize DomainPlan → CorePlan
|
|
|
|
|
let core_plan = PlanNormalizer::normalize(builder, domain_plan, ctx)?;
|
|
|
|
|
|
|
|
|
|
// Step 2: Verify CorePlan invariants (fail-fast)
|
|
|
|
|
PlanVerifier::verify(&core_plan)?;
|
|
|
|
|
|
|
|
|
|
// Step 3: Lower CorePlan → MIR
|
|
|
|
|
return PlanLowerer::lower(builder, core_plan, ctx);
|
|
|
|
|
}
|
|
|
|
|
None => {
|
|
|
|
|
// Not Pattern6 - continue to other patterns
|
|
|
|
|
if ctx.debug {
|
|
|
|
|
trace::trace().debug(
|
|
|
|
|
"route",
|
|
|
|
|
"Pattern6 Plan extraction returned None, trying other patterns",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-22 23:35:43 +09:00
|
|
|
// Phase 273 P2: Try Plan-based Pattern7 (SplitScan)
|
|
|
|
|
// Flow: Extract → Normalize → Verify → Lower
|
|
|
|
|
match super::pattern7_split_scan::extract_split_scan_plan(
|
|
|
|
|
ctx.condition,
|
|
|
|
|
ctx.body,
|
|
|
|
|
&[],
|
|
|
|
|
)? {
|
|
|
|
|
Some(domain_plan) => {
|
|
|
|
|
// DomainPlan extracted successfully
|
2025-12-23 05:03:25 +09:00
|
|
|
trace::trace().pattern("route", "route=plan pattern=Pattern7_SplitScan (Phase 273)", true);
|
2025-12-22 23:35:43 +09:00
|
|
|
|
|
|
|
|
// Step 1: Normalize DomainPlan → CorePlan
|
|
|
|
|
let core_plan = PlanNormalizer::normalize(builder, domain_plan, ctx)?;
|
|
|
|
|
|
|
|
|
|
// Step 2: Verify CorePlan invariants (fail-fast)
|
|
|
|
|
PlanVerifier::verify(&core_plan)?;
|
|
|
|
|
|
|
|
|
|
// Step 3: Lower CorePlan → MIR
|
|
|
|
|
return PlanLowerer::lower(builder, core_plan, ctx);
|
|
|
|
|
}
|
|
|
|
|
None => {
|
|
|
|
|
// Not Pattern7 - continue to other patterns
|
|
|
|
|
if ctx.debug {
|
|
|
|
|
trace::trace().debug(
|
|
|
|
|
"route",
|
|
|
|
|
"Pattern7 Plan extraction returned None, trying other patterns",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-08 22:17:06 +09:00
|
|
|
// Phase 183: Route based on pre-classified pattern kind
|
|
|
|
|
// Pattern kind was already determined by ctx.pattern_kind in LoopPatternContext::new()
|
|
|
|
|
// This eliminates duplicate detection logic across routers.
|
2025-12-05 22:11:39 +09:00
|
|
|
|
2025-12-08 22:17:06 +09:00
|
|
|
// Find matching pattern entry based on pattern_kind
|
2025-12-22 22:42:56 +09:00
|
|
|
// Phase 273 P0.1: Pattern6 skip logic removed (entry no longer in LOOP_PATTERNS)
|
2025-12-05 22:11:39 +09:00
|
|
|
for entry in LOOP_PATTERNS {
|
|
|
|
|
if (entry.detect)(builder, ctx) {
|
2025-12-23 05:03:25 +09:00
|
|
|
let log_msg = format!("route=joinir pattern={} (Phase 194+)", entry.name);
|
|
|
|
|
trace::trace().pattern("route", &log_msg, true);
|
2025-12-05 22:11:39 +09:00
|
|
|
return (entry.lower)(builder, ctx);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-08 18:36:13 +09:00
|
|
|
// No pattern matched - return None (caller will handle error)
|
2025-12-05 22:11:39 +09:00
|
|
|
if ctx.debug {
|
2025-12-11 19:11:26 +09:00
|
|
|
trace::trace().debug(
|
|
|
|
|
"route",
|
|
|
|
|
&format!(
|
2025-12-23 05:03:25 +09:00
|
|
|
"route=none (no pattern matched) func='{}' pattern_kind={:?} (exhausted: plan+joinir)",
|
2025-12-11 19:11:26 +09:00
|
|
|
ctx.func_name, ctx.pattern_kind
|
|
|
|
|
),
|
|
|
|
|
);
|
2025-12-05 22:11:39 +09:00
|
|
|
}
|
|
|
|
|
Ok(None)
|
|
|
|
|
}
|