feat(joinir): Phase 45 - JoinIR mode unification
Unified JoinIR routing logic through centralized JoinIrMode enum: Key changes: - Added JoinIrMode enum (StructuredOnly / NormalizedDev / NormalizedCanonical) - Added current_joinir_mode() for centralized mode determination - Refactored normalized_dev_enabled() as thin wrapper over mode enum - Updated bridge.rs: mode-based routing with canonical P2-Core special handling - Updated runner.rs: mode pattern matching for dev roundtrip path Files modified: - joinir_dev.rs: JoinIrMode enum + current_joinir_mode() (+49 lines) - bridge.rs: Replaced boolean checks with mode pattern matching (+29 lines) - runner.rs: Mode-based routing logic (+9 lines) - CURRENT_TASK.md: Phase 45 implementation summary Documentation: - phase45-norm-mode-design.md: Complete design spec and implementation guide Behavior preservation: - Canonical P2-Core shapes: always Normalized→MIR(direct) (mode-independent) - NormalizedDev mode: Structured→Normalized→MIR for supported shapes - StructuredOnly mode: Structured→MIR direct (default) Tests: 937/937 PASS (no regression, pure refactor) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -61,6 +61,11 @@
|
|||||||
- JsonParser `_atoi` 本体の Program(JSON) フィクスチャを normalized_dev に追加し、Structured→Normalized→MIR(direct) と Structured→MIR の VM 出力を比較するテストで一致を固定(符号あり/なしの簡易パス対応。canonical 切替は後続フェーズ)。
|
- JsonParser `_atoi` 本体の Program(JSON) フィクスチャを normalized_dev に追加し、Structured→Normalized→MIR(direct) と Structured→MIR の VM 出力を比較するテストで一致を固定(符号あり/なしの簡易パス対応。canonical 切替は後続フェーズ)。
|
||||||
- Phase 43-C(dev-only):
|
- Phase 43-C(dev-only):
|
||||||
- JsonParser `_parse_number` 本体の Program(JSON) フィクスチャを normalized_dev に追加し、Structured→Normalized→MIR(direct) と Structured→MIR の VM 出力を比較するテストで一致を固定(num_str は現状仕様のまま据え置き、P2-Mid の足慣らし)。
|
- 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. いまコード側で意識しておきたいフォーカス
|
### 1. いまコード側で意識しておきたいフォーカス
|
||||||
|
|
||||||
|
|||||||
169
docs/development/current/main/phase45-norm-mode-design.md
Normal file
169
docs/development/current/main/phase45-norm-mode-design.md
Normal file
@ -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`
|
||||||
49
src/config/env/joinir_dev.rs
vendored
49
src/config/env/joinir_dev.rs
vendored
@ -1,8 +1,26 @@
|
|||||||
//! JoinIR development / experimental flags (SSOT).
|
//! JoinIR development / experimental flags (SSOT).
|
||||||
//! Phase 72-C: Consolidate all NYASH_JOINIR_* dev flags through centralized helpers.
|
//! 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;
|
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
|
/// NYASH_JOINIR_LOWER_GENERIC=1 - Enable generic lowering path for JoinIR
|
||||||
/// (CRITICAL: 15 occurrences in codebase)
|
/// (CRITICAL: 15 occurrences in codebase)
|
||||||
pub fn lower_generic_enabled() -> bool {
|
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")
|
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).
|
/// Unified switch for Normalized dev experiments (feature + env).
|
||||||
///
|
///
|
||||||
/// - Requires `--features normalized_dev`
|
/// - Requires `--features normalized_dev`
|
||||||
/// - Requires `NYASH_JOINIR_NORMALIZED_DEV_RUN=1`
|
/// - 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 {
|
pub fn normalized_dev_enabled() -> bool {
|
||||||
if cfg!(feature = "normalized_dev") {
|
matches!(current_joinir_mode(), JoinIrMode::NormalizedDev)
|
||||||
joinir_normalized_dev_run_enabled()
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// JOINIR_TEST_DEBUG=1 (or NYASH_JOINIR_TEST_DEBUG=1) - Verbose logging for normalized dev tests
|
/// JOINIR_TEST_DEBUG=1 (or NYASH_JOINIR_TEST_DEBUG=1) - Verbose logging for normalized dev tests
|
||||||
|
|||||||
@ -31,7 +31,7 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[cfg(feature = "normalized_dev")]
|
#[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};
|
use crate::mir::join_ir::{ConstValue, JoinFuncId, JoinInst, JoinModule, MirLikeInst, VarId};
|
||||||
#[cfg(feature = "normalized_dev")]
|
#[cfg(feature = "normalized_dev")]
|
||||||
use crate::mir::join_ir::normalized::{
|
use crate::mir::join_ir::normalized::{
|
||||||
@ -51,9 +51,14 @@ pub fn run_joinir_function(
|
|||||||
args: &[JoinValue],
|
args: &[JoinValue],
|
||||||
) -> Result<JoinValue, JoinRuntimeError> {
|
) -> Result<JoinValue, JoinRuntimeError> {
|
||||||
#[cfg(feature = "normalized_dev")]
|
#[cfg(feature = "normalized_dev")]
|
||||||
if normalized_dev_enabled() {
|
match current_joinir_mode() {
|
||||||
|
JoinIrMode::NormalizedDev => {
|
||||||
return run_joinir_function_normalized_dev(vm, module, entry, args);
|
return run_joinir_function_normalized_dev(vm, module, entry, args);
|
||||||
}
|
}
|
||||||
|
_ => {
|
||||||
|
// Structured-only path (default)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
execute_function(vm, module, entry, args.to_vec())
|
execute_function(vm, module, entry, args.to_vec())
|
||||||
}
|
}
|
||||||
@ -65,6 +70,7 @@ fn run_joinir_function_normalized_dev(
|
|||||||
entry: JoinFuncId,
|
entry: JoinFuncId,
|
||||||
args: &[JoinValue],
|
args: &[JoinValue],
|
||||||
) -> Result<JoinValue, JoinRuntimeError> {
|
) -> Result<JoinValue, JoinRuntimeError> {
|
||||||
|
// JoinIrMode::NormalizedDev path: Structured→Normalized→Structured roundtrip
|
||||||
// Keep dev path opt-in and fail-fast: only Structured P1/P2 minis are supported.
|
// Keep dev path opt-in and fail-fast: only Structured P1/P2 minis are supported.
|
||||||
dev_env::with_dev_env_if_unset(|| {
|
dev_env::with_dev_env_if_unset(|| {
|
||||||
let debug = dev_env::normalized_dev_logs_enabled();
|
let debug = dev_env::normalized_dev_logs_enabled();
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
use super::{convert_join_module_to_mir_with_meta, JoinIrVmBridgeError};
|
use super::{convert_join_module_to_mir_with_meta, JoinIrVmBridgeError};
|
||||||
use crate::mir::join_ir::frontend::JoinFuncMetaMap;
|
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 crate::mir::MirModule;
|
||||||
use std::collections::BTreeMap;
|
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")]
|
#[cfg(feature = "normalized_dev")]
|
||||||
use crate::mir::join_ir::normalized::{
|
use crate::mir::join_ir::normalized::{
|
||||||
normalize_pattern1_minimal, normalize_pattern2_minimal, NormalizedModule,
|
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(
|
pub(crate) fn bridge_joinir_to_mir_with_meta(
|
||||||
module: &JoinModule,
|
module: &JoinModule,
|
||||||
meta: &JoinFuncMetaMap,
|
meta: &JoinFuncMetaMap,
|
||||||
) -> Result<MirModule, JoinIrVmBridgeError> {
|
) -> Result<MirModule, JoinIrVmBridgeError> {
|
||||||
#[cfg(feature = "normalized_dev")]
|
#[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);
|
let canonical_shapes = shape_guard::canonical_shapes(module);
|
||||||
if !canonical_shapes.is_empty() {
|
if !canonical_shapes.is_empty() {
|
||||||
match try_normalized_direct_bridge(module, meta, &canonical_shapes, false, false)? {
|
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() {
|
// Phase 45: Mode によるルーティング分岐
|
||||||
|
match mode {
|
||||||
|
JoinIrMode::NormalizedDev => {
|
||||||
|
// サポート形状のみ Normalized path を試行、失敗時は Structured fallback
|
||||||
let shapes = shape_guard::direct_shapes(module);
|
let shapes = shape_guard::direct_shapes(module);
|
||||||
match try_normalized_direct_bridge(module, meta, &shapes, true, true)? {
|
match try_normalized_direct_bridge(module, meta, &shapes, true, true)? {
|
||||||
Some(mir) => return Ok(mir),
|
Some(mir) => return Ok(mir),
|
||||||
None => {}
|
None => {} // Fallback to Structured
|
||||||
|
}
|
||||||
|
}
|
||||||
|
JoinIrMode::StructuredOnly | JoinIrMode::NormalizedCanonical => {
|
||||||
|
// Structured path のみ使用
|
||||||
|
// (NormalizedCanonical は将来 Phase 46+ で canonical migration 完了後に専用経路を持つ)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user