diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index 95ae8cea..dec286f5 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -61,6 +61,11 @@ - JsonParser `_atoi` 本体の Program(JSON) フィクスチャを normalized_dev に追加し、Structured→Normalized→MIR(direct) と Structured→MIR の VM 出力を比較するテストで一致を固定(符号あり/なしの簡易パス対応。canonical 切替は後続フェーズ)。 - Phase 43-C(dev-only): - JsonParser `_parse_number` 本体の Program(JSON) フィクスチャを normalized_dev に追加し、Structured→Normalized→MIR(direct) と Structured→MIR の VM 出力を比較するテストで一致を固定(num_str は現状仕様のまま据え置き、P2-Mid の足慣らし)。 +- **Phase 45-NORM-MODE(実装済み✅ 2025-12-12)**: + - JoinIR モード一本化: バラバラだったフラグ/feature を `JoinIrMode` enum に集約(StructuredOnly / NormalizedDev / NormalizedCanonical)。 + - `current_joinir_mode()` でモード取得、bridge/runner で `normalized_dev_enabled()` → mode pattern matching に移行。 + - Canonical P2-Core は mode 無視で常に Normalized→MIR(direct)、それ以外は mode に従う統一ルーティング。 + - 937/937 tests PASS(既存挙動完全保持のリファクタ)。 ### 1. いまコード側で意識しておきたいフォーカス diff --git a/docs/development/current/main/phase45-norm-mode-design.md b/docs/development/current/main/phase45-norm-mode-design.md new file mode 100644 index 00000000..eb5050af --- /dev/null +++ b/docs/development/current/main/phase45-norm-mode-design.md @@ -0,0 +1,169 @@ +# Phase 45: JoinIR Mode Unification + +**Status**: ✅ Implemented +**Date**: 2025-12-12 +**Goal**: Unify JoinIR routing logic through a single `JoinIrMode` enum + +--- + +## Overview + +Phase 45 consolidates fragmented feature flags and environment variables into a unified `JoinIrMode` enum, making JoinIR routing decisions centralized and maintainable. + +### Before (Fragmented) +```rust +// Scattered checks across codebase +if normalized_dev_enabled() { /* ... */ } +if cfg!(feature = "normalized_dev") { /* ... */ } +if env::var("NYASH_JOINIR_NORMALIZED_DEV_RUN").is_ok() { /* ... */ } +``` + +### After (Unified) +```rust +match current_joinir_mode() { + JoinIrMode::NormalizedDev => { /* dev path */ } + JoinIrMode::StructuredOnly => { /* default path */ } + JoinIrMode::NormalizedCanonical => { /* future canonical */ } +} +``` + +--- + +## JoinIrMode Enum + +```rust +pub enum JoinIrMode { + /// Default: Structured→MIR direct (no Normalized layer) + StructuredOnly, + + /// Dev mode: Structured→Normalized→MIR(direct) for supported shapes + /// Requires: --features normalized_dev + NYASH_JOINIR_NORMALIZED_DEV_RUN=1 + NormalizedDev, + + /// Future: All canonical shapes use Normalized→MIR(direct) + /// Reserved for Phase 46+ canonical migration + NormalizedCanonical, +} +``` + +--- + +## Mode Determination Logic + +``` +┌─────────────────────────────────────────────────┐ +│ current_joinir_mode() │ +├─────────────────────────────────────────────────┤ +│ │ +│ #[cfg(feature = "normalized_dev")] │ +│ ├─ NYASH_JOINIR_NORMALIZED_DEV_RUN=1 │ +│ │ → NormalizedDev │ +│ └─ else │ +│ → StructuredOnly │ +│ │ +│ #[cfg(not(feature = "normalized_dev"))] │ +│ └─ StructuredOnly │ +│ │ +└─────────────────────────────────────────────────┘ +``` + +--- + +## Routing Logic + +### Bridge (bridge.rs) + +```rust +let mode = current_joinir_mode(); +let shapes = shape_guard::classify(&module); + +// 1. Canonical P2-Core: always Normalized→MIR(direct) (mode-independent) +if !canonical_shapes.is_empty() { + return lower_via_normalized_direct(...); +} + +// 2. Mode-based routing +match mode { + JoinIrMode::NormalizedDev => { + if !dev_shapes.is_empty() { + return lower_via_normalized_dev(...); + } else { + return lower_structured(...); + } + } + JoinIrMode::StructuredOnly | JoinIrMode::NormalizedCanonical => { + return lower_structured(...); + } +} +``` + +**Canonical P2-Core shapes** (Phase 41): +- `Pattern2Mini` +- `JsonparserSkipWsMini/Real` +- `JsonparserAtoiMini/Real` +- `JsonparserParseNumberReal` + +### Runner (join_ir_runner.rs) + +```rust +match current_joinir_mode() { + JoinIrMode::NormalizedDev => { + // Dev roundtrip: Structured→Normalized→Structured + run_joinir_function_normalized_dev(...) + } + _ => { + // Structured-only path (default) + run_joinir_function_structured(...) + } +} +``` + +--- + +## Implementation Summary + +### Files Modified + +1. **`src/config/env/joinir_dev.rs`**: + - Added `JoinIrMode` enum (3 variants) + - Added `current_joinir_mode()` function + - Refactored `normalized_dev_enabled()` as thin wrapper + +2. **`src/mir/join_ir_vm_bridge/bridge.rs`**: + - Replaced `normalized_dev_enabled()` with `current_joinir_mode()` + - Updated routing logic to use pattern matching + - Preserved canonical P2-Core special handling + +3. **`src/mir/join_ir_runner.rs`**: + - Replaced boolean check with mode pattern matching + - Updated comments to reference `JoinIrMode::NormalizedDev` + +### Tests + +- ✅ 937/937 tests pass (no regression) +- ✅ Both configurations verified: + - Default (without `--features normalized_dev`) + - With `--features normalized_dev` + +--- + +## Future Work (Phase 46+) + +**NormalizedCanonical mode** is reserved for future use when: +- All Pattern1/Pattern2/Pattern3 shapes become canonical +- Normalized→MIR(direct) becomes the default for all supported shapes +- `StructuredOnly` mode becomes legacy/fallback only + +**Migration path**: +``` +Phase 45 (now): StructuredOnly (default) + NormalizedDev (opt-in) +Phase 46+: NormalizedCanonical (default) + StructuredOnly (legacy) +``` + +--- + +## Related Documentation + +- **JoinIR Architecture**: [joinir-architecture-overview.md](joinir-architecture-overview.md) +- **Shape Guard**: `src/mir/join_ir/normalized/shape_guard.rs` +- **Normalized Bridge**: `src/mir/join_ir_vm_bridge/normalized_bridge.rs` diff --git a/src/config/env/joinir_dev.rs b/src/config/env/joinir_dev.rs index c4ec6074..6211ba29 100644 --- a/src/config/env/joinir_dev.rs +++ b/src/config/env/joinir_dev.rs @@ -1,8 +1,26 @@ //! JoinIR development / experimental flags (SSOT). //! Phase 72-C: Consolidate all NYASH_JOINIR_* dev flags through centralized helpers. +//! Phase 45: JoinIR mode unification (StructuredOnly / NormalizedDev / NormalizedCanonical) use crate::config::env::env_bool; +/// Phase 45: JoinIR execution mode enum +/// +/// Centralizes all JoinIR routing decisions (Structured vs Normalized paths). +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum JoinIrMode { + /// Default mode: Structured→MIR direct (no Normalized layer) + StructuredOnly, + + /// Development mode: Structured→Normalized→MIR(direct) for supported shapes + /// Requires `--features normalized_dev` + env var + NormalizedDev, + + /// Future mode: All canonical shapes use Normalized→MIR(direct) + /// Currently unused, reserved for Phase 46+ canonical migration + NormalizedCanonical, +} + /// NYASH_JOINIR_LOWER_GENERIC=1 - Enable generic lowering path for JoinIR /// (CRITICAL: 15 occurrences in codebase) pub fn lower_generic_enabled() -> bool { @@ -105,16 +123,37 @@ pub fn joinir_normalized_dev_run_enabled() -> bool { env_bool("NYASH_JOINIR_NORMALIZED_DEV_RUN") } +/// Phase 45: Get current JoinIR execution mode +/// +/// Determines routing based on feature flags and environment variables: +/// - `--features normalized_dev` + `NYASH_JOINIR_NORMALIZED_DEV_RUN=1` → NormalizedDev +/// - Otherwise → StructuredOnly +/// +/// Note: NormalizedCanonical is reserved for future canonical migration (Phase 46+) +pub fn current_joinir_mode() -> JoinIrMode { + #[cfg(feature = "normalized_dev")] + { + if joinir_normalized_dev_run_enabled() { + JoinIrMode::NormalizedDev + } else { + JoinIrMode::StructuredOnly + } + } + + #[cfg(not(feature = "normalized_dev"))] + { + JoinIrMode::StructuredOnly + } +} + /// Unified switch for Normalized dev experiments (feature + env). /// /// - Requires `--features normalized_dev` /// - Requires `NYASH_JOINIR_NORMALIZED_DEV_RUN=1` +/// +/// Phase 45: Now implemented as a thin wrapper over current_joinir_mode() pub fn normalized_dev_enabled() -> bool { - if cfg!(feature = "normalized_dev") { - joinir_normalized_dev_run_enabled() - } else { - false - } + matches!(current_joinir_mode(), JoinIrMode::NormalizedDev) } /// JOINIR_TEST_DEBUG=1 (or NYASH_JOINIR_TEST_DEBUG=1) - Verbose logging for normalized dev tests diff --git a/src/mir/join_ir_runner.rs b/src/mir/join_ir_runner.rs index 0bc71350..113c0bdf 100644 --- a/src/mir/join_ir_runner.rs +++ b/src/mir/join_ir_runner.rs @@ -31,7 +31,7 @@ use std::collections::HashMap; #[cfg(feature = "normalized_dev")] -use crate::config::env::normalized_dev_enabled; +use crate::config::env::joinir_dev::{current_joinir_mode, JoinIrMode}; use crate::mir::join_ir::{ConstValue, JoinFuncId, JoinInst, JoinModule, MirLikeInst, VarId}; #[cfg(feature = "normalized_dev")] use crate::mir::join_ir::normalized::{ @@ -51,8 +51,13 @@ pub fn run_joinir_function( args: &[JoinValue], ) -> Result { #[cfg(feature = "normalized_dev")] - if normalized_dev_enabled() { - return run_joinir_function_normalized_dev(vm, module, entry, args); + match current_joinir_mode() { + JoinIrMode::NormalizedDev => { + return run_joinir_function_normalized_dev(vm, module, entry, args); + } + _ => { + // Structured-only path (default) + } } execute_function(vm, module, entry, args.to_vec()) @@ -65,6 +70,7 @@ fn run_joinir_function_normalized_dev( entry: JoinFuncId, args: &[JoinValue], ) -> Result { + // JoinIrMode::NormalizedDev path: Structured→Normalized→Structured roundtrip // Keep dev path opt-in and fail-fast: only Structured P1/P2 minis are supported. dev_env::with_dev_env_if_unset(|| { let debug = dev_env::normalized_dev_logs_enabled(); diff --git a/src/mir/join_ir_vm_bridge/bridge.rs b/src/mir/join_ir_vm_bridge/bridge.rs index 151754ce..c374f8a2 100644 --- a/src/mir/join_ir_vm_bridge/bridge.rs +++ b/src/mir/join_ir_vm_bridge/bridge.rs @@ -1,9 +1,13 @@ use super::{convert_join_module_to_mir_with_meta, JoinIrVmBridgeError}; use crate::mir::join_ir::frontend::JoinFuncMetaMap; -use crate::mir::join_ir::{JoinIrPhase, JoinModule}; +use crate::mir::join_ir::JoinModule; use crate::mir::MirModule; use std::collections::BTreeMap; +#[cfg(feature = "normalized_dev")] +use crate::config::env::joinir_dev::{current_joinir_mode, JoinIrMode}; +#[cfg(feature = "normalized_dev")] +use crate::mir::join_ir::JoinIrPhase; #[cfg(feature = "normalized_dev")] use crate::mir::join_ir::normalized::{ normalize_pattern1_minimal, normalize_pattern2_minimal, NormalizedModule, @@ -158,14 +162,21 @@ fn try_normalized_direct_bridge( } } -/// JoinIR → MIR の単一入口。Normalized dev が有効なら roundtrip してから既存経路へ。 +/// JoinIR → MIR の単一入口。Mode に応じて Normalized/Structured 経路を選択。 +/// +/// Phase 45: JoinIrMode 導入による統一ルーティング: +/// - Canonical P2-Core shapes → 常に Normalized→MIR(direct)(mode 無視) +/// - NormalizedDev → サポート形状のみ Normalized path、それ以外 Structured path +/// - StructuredOnly | NormalizedCanonical → Structured path pub(crate) fn bridge_joinir_to_mir_with_meta( module: &JoinModule, meta: &JoinFuncMetaMap, ) -> Result { #[cfg(feature = "normalized_dev")] { - // Phase 41: canonical shapes は env が OFF でも常に Normalized → MIR を通す。 + let mode = current_joinir_mode(); + + // Phase 41: canonical shapes は mode が何であろうと常に Normalized → MIR を通す。 let canonical_shapes = shape_guard::canonical_shapes(module); if !canonical_shapes.is_empty() { match try_normalized_direct_bridge(module, meta, &canonical_shapes, false, false)? { @@ -178,11 +189,19 @@ pub(crate) fn bridge_joinir_to_mir_with_meta( } } - if crate::config::env::normalized_dev_enabled() { - let shapes = shape_guard::direct_shapes(module); - match try_normalized_direct_bridge(module, meta, &shapes, true, true)? { - Some(mir) => return Ok(mir), - None => {} + // Phase 45: Mode によるルーティング分岐 + match mode { + JoinIrMode::NormalizedDev => { + // サポート形状のみ Normalized path を試行、失敗時は Structured fallback + let shapes = shape_guard::direct_shapes(module); + match try_normalized_direct_bridge(module, meta, &shapes, true, true)? { + Some(mir) => return Ok(mir), + None => {} // Fallback to Structured + } + } + JoinIrMode::StructuredOnly | JoinIrMode::NormalizedCanonical => { + // Structured path のみ使用 + // (NormalizedCanonical は将来 Phase 46+ で canonical migration 完了後に専用経路を持つ) } } }