Files
hakorune/src/config/env/joinir_dev.rs
tomoaki 9336785680 feat(anf): Phase 146/147 - Loop/If Condition ANF with Compare support
## Phase 146 P0: ANF Routing SSOT Unified

**Goal**: Unify ANF routing in `lower_expr_with_scope()` L54-84, remove legacy lowering

**Changes**:
- expr_lowerer_box.rs: Added scope check (PureOnly → skip ANF, WithImpure → try ANF)
- post_if_post_k.rs: Removed legacy inline lowering (L271-285), added `lower_condition_legacy()` helper
- contract.rs: Already had `CondLoweringFailed` out-of-scope reason

**Test Results**:  Phase 146 P0 smoke (exit 7), 0 regressions

## Phase 146 P1: Compare Operator Support

**Goal**: Enable ANF for condition expressions with Compare operators

**Changes**:
- joinir_dev.rs: Added `anf_allow_pure_enabled()` (HAKO_ANF_ALLOW_PURE=1)
- expr_lowerer_box.rs: PureOnly scope ANF support (L56-66)
- execute_box.rs: Compare operator support (+122 lines)
  - `execute_compare_hoist()`, `execute_compare_recursive()`, `ast_compare_to_joinir()`
  - Extended `normalize_and_lower()` for Compare

**Test Results**:  Phase 146 P1 smoke (exit 7 with flags), 0 regressions

## Phase 147 P0: Recursive Comparison ANF

**Goal**: Extend recursive ANF to Compare operators

**Changes**:
- contract.rs: Added `AnfParentKind::Compare` variant
- plan_box.rs: Compare case in BinaryOp routing (L68-79, L134-139)
  - Distinguishes Compare vs arithmetic BinaryOp

**Benefits**: Enables recursive ANF for comparisons
- `s.length() == 3` → `t = s.length(); if (t == 3)` 
- `s1.length() < s2.length()` → `t1 = s1.length(); t2 = s2.length(); if (t1 < t2)` 

## Implementation Summary

**Files Modified** (9 files, +253 lines, -25 lines = +228 net):
1. src/config/env/joinir_dev.rs (+28 lines)
2. src/mir/control_tree/normalized_shadow/anf/contract.rs (+2 lines)
3. src/mir/control_tree/normalized_shadow/anf/execute_box.rs (+122 lines)
4. src/mir/control_tree/normalized_shadow/anf/plan_box.rs (+18 lines)
5. src/mir/control_tree/normalized_shadow/common/expr_lowerer_box.rs (+18 lines, -0 lines)
6. src/mir/control_tree/normalized_shadow/post_if_post_k.rs (+44 lines, -25 lines)
7. CURRENT_TASK.md
8. docs/development/current/main/10-Now.md
9. docs/development/current/main/30-Backlog.md

**Files Created** (7 files):
- apps/tests/phase146_p0_if_cond_unified_min.hako
- apps/tests/phase146_p1_if_cond_intrinsic_min.hako
- tools/smokes/.../phase146_p0_if_cond_unified_vm.sh
- tools/smokes/.../phase146_p0_if_cond_unified_llvm_exe.sh
- tools/smokes/.../phase146_p1_if_cond_intrinsic_vm.sh
- tools/smokes/.../phase146_p1_if_cond_intrinsic_llvm_exe.sh
- docs/development/current/main/phases/phase-146/README.md

**Acceptance Criteria**:  All met
- cargo build --release: PASS (0 errors, 0 warnings)
- Phase 145 regressions: PASS (exit 12, 18, 5)
- Phase 146 P0: PASS (exit 7)
- Phase 146 P1: PASS (exit 7 with HAKO_ANF_ALLOW_PURE=1)

**Architecture**:
- SSOT: ANF routing only in `lower_expr_with_scope()` L54-84
- Box-First: Phase 145 `anf/` module extended
- Legacy removed: post_if_post_k.rs unified with SSOT

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-19 17:03:56 +09:00

298 lines
9.7 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! 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 {
env_bool("NYASH_JOINIR_LOWER_GENERIC")
}
/// NYASH_JOINIR_MAINLINE_DEBUG=1 - Debug output for mainline JoinIR lowering
pub fn mainline_debug_enabled() -> bool {
env_bool("NYASH_JOINIR_MAINLINE_DEBUG")
}
/// NYASH_JOINIR_IF_MERGE=1 - Enable If-merge experimental mode
pub fn if_merge_enabled() -> bool {
env_bool("NYASH_JOINIR_IF_MERGE")
}
/// NYASH_JOINIR_DEBUG=1 - General debug mode (deprecated, prefer mainline_debug)
pub fn debug_enabled() -> bool {
env_bool("NYASH_JOINIR_DEBUG")
}
/// NYASH_JOINIR_VM_BRIDGE=1 - Enable VM bridge mode
pub fn vm_bridge_enabled() -> bool {
env_bool("NYASH_JOINIR_VM_BRIDGE")
}
/// HAKO_JOINIR_STRICT=1 or NYASH_JOINIR_STRICT=1 - Strict validation mode
///
/// Phase 138-P2-A: Supports both HAKO_ and NYASH_ prefixes for compatibility
pub fn strict_enabled() -> bool {
env_bool("HAKO_JOINIR_STRICT") || env_bool("NYASH_JOINIR_STRICT")
}
/// NYASH_JOINIR_SNAPSHOT_GENERATE=1 - Generate snapshot for testing
pub fn snapshot_generate_enabled() -> bool {
env_bool("NYASH_JOINIR_SNAPSHOT_GENERATE")
}
/// NYASH_JOINIR_SNAPSHOT_TEST=1 - Test using snapshot
pub fn snapshot_test_enabled() -> bool {
env_bool("NYASH_JOINIR_SNAPSHOT_TEST")
}
/// NYASH_JOINIR_INPUT=* - Input source or mode
pub fn input_mode() -> Option<String> {
std::env::var("NYASH_JOINIR_INPUT").ok()
}
/// NYASH_JOINIR_LOWER_FROM_MIR=1 - Enable lowering from MIR mode
pub fn lower_from_mir_enabled() -> bool {
env_bool("NYASH_JOINIR_LOWER_FROM_MIR")
}
/// NYASH_JOINIR_LLVM_EXPERIMENT=1 - LLVM experimental mode
pub fn llvm_experiment_enabled() -> bool {
env_bool("NYASH_JOINIR_LLVM_EXPERIMENT")
}
/// HAKO_JOINIR_IF_TOPLEVEL=1 - Enable If-select for top-level if statements
pub fn if_toplevel_enabled() -> bool {
env_bool("HAKO_JOINIR_IF_TOPLEVEL")
}
/// HAKO_JOINIR_IF_TOPLEVEL_TRACE=1 - Debug trace for top-level if
pub fn if_toplevel_trace_enabled() -> bool {
env_bool("HAKO_JOINIR_IF_TOPLEVEL_TRACE")
}
/// HAKO_JOINIR_IF_IN_LOOP_TRACE=1 - Debug trace for if in loop
pub fn if_in_loop_trace_enabled() -> bool {
env_bool("HAKO_JOINIR_IF_IN_LOOP_TRACE")
}
/// HAKO_JOINIR_NESTED_IF=1 - Enable nested if lowering
pub fn nested_if_enabled() -> bool {
env_bool("HAKO_JOINIR_NESTED_IF")
}
/// HAKO_JOINIR_PRINT_TOKENS_MAIN=1 - Print tokens for main
pub fn print_tokens_main_enabled() -> bool {
env_bool("HAKO_JOINIR_PRINT_TOKENS_MAIN")
}
/// HAKO_JOINIR_ARRAY_FILTER_MAIN=1 - Array filter main mode
pub fn array_filter_main_enabled() -> bool {
env_bool("HAKO_JOINIR_ARRAY_FILTER_MAIN")
}
/// HAKO_JOINIR_READ_QUOTED=1 - Read quoted mode
pub fn read_quoted_enabled() -> bool {
env_bool("HAKO_JOINIR_READ_QUOTED")
}
/// HAKO_JOINIR_READ_QUOTED_IFMERGE=1 - Read quoted with if-merge
pub fn read_quoted_ifmerge_enabled() -> bool {
env_bool("HAKO_JOINIR_READ_QUOTED_IFMERGE")
}
/// NYASH_JOINIR_NORMALIZED_DEV_RUN=1 - Run JoinIR runner through Normalized roundtrip (dev only)
pub fn joinir_normalized_dev_run_enabled() -> bool {
// Feature gate at call sites still applies; this helper just centralizes the env read.
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 {
matches!(current_joinir_mode(), JoinIrMode::NormalizedDev)
}
/// JOINIR_TEST_DEBUG=1 (or NYASH_JOINIR_TEST_DEBUG=1) - Verbose logging for normalized dev tests
pub fn joinir_test_debug_enabled() -> bool {
env_bool("JOINIR_TEST_DEBUG") || env_bool("NYASH_JOINIR_TEST_DEBUG")
}
/// Phase 82: NYASH_PHI_FALLBACK_DISABLED=1 - Disable if_phi fallback (dev mode)
///
/// lifecycle.rs の infer_type_from_phi* callsite を封じて、
/// 実際に呼ばれているかどうかを確認するためのフラグ。
///
/// # 使用方法
///
/// ```bash
/// NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release mir_joinir_if_select
/// ```
///
/// # 期待される動作
///
/// - callsite が呼ばれる → panic (関数名・ValueId・Case を出力)
/// - callsite が一度も呼ばれない → テスト成功(削除候補確定)
///
/// # Case 分類
///
/// - **Case A**: P1/P2/P3-A/P3-B + hint 成功hint 即座に返す)
/// - **Case B**: P1/P2/P3-A/P3-B + hint 失敗PHI 走査)
/// - **Case D**: P3-C + GenericTypeResolver 失敗PHI 走査・無駄な再実行)
///
/// Phase 84-5: if_phi.rs 削除後は常に true
/// 環境変数は統計目的でのみ残す
pub fn phi_fallback_disabled() -> bool {
true // Phase 84-5: Always disabled after if_phi.rs deletion
}
/// Phase 84-5: 統計・メトリクス用(オプション)
#[allow(dead_code)]
pub fn phi_metrics_enabled() -> bool {
env_bool("NYASH_PHI_METRICS")
}
/// Phase 183: NYASH_LEGACY_LOOPBUILDER=1 - Legacy LoopBuilder 経路を明示的に opt-in
///
/// デフォルトはJoinIR優先。どうしても古いLoopBuilder経路を使う必要がある場合のみ設定。
/// 本線では使用しない開発専用フラグ。
pub fn legacy_loopbuilder_enabled() -> bool {
env_bool("NYASH_LEGACY_LOOPBUILDER")
}
/// Phase 145 P0: HAKO_ANF_DEV=1 - ANF (A-Normal Form) transformation development mode
///
/// Enables ANF transformation routing in NormalizedExprLowererBox.
/// P0: Debug logging only (execute_box is stub, returns Ok(None)).
/// P1+: Actual transformation (String.length() hoist, compound expression ANF).
///
/// # Usage
///
/// ```bash
/// HAKO_ANF_DEV=1 cargo test --release
/// HAKO_ANF_DEV=1 ./target/release/hakorune program.hako
/// ```
///
/// # Expected Behavior (P0)
///
/// - ANF routing enabled: AnfPlanBox detects impure expressions
/// - Debug log: "[phase145/debug] ANF plan found but execute returned None (P0 stub)"
/// - Existing behavior unchanged: execute_box returns Ok(None) → fallback to legacy
///
/// # Future Behavior (P1+)
///
/// - String.length() hoist: `x + s.length()` → ANF transformation
/// - Compound expression ANF: Recursive left-to-right linearization
pub fn anf_dev_enabled() -> bool {
env_bool("HAKO_ANF_DEV")
}
/// Phase 145 P2: ANF strict mode (fail-fast on violations)
///
/// When enabled, ANF transformation errors result in immediate failure
/// instead of graceful fallback to legacy lowering.
///
/// # Environment Variable
///
/// `HAKO_ANF_STRICT=1` enables strict mode (default: OFF)
///
/// # Behavior
///
/// - **ON**: ANF violations return Err() with detailed error tags
/// - **OFF**: ANF violations gracefully fallback to legacy lowering (Ok(None))
///
/// # Use Cases
///
/// - **Development**: Catch order violations, pure-required violations early
/// - **Testing**: Verify ANF transformation correctness with fail-fast
/// - **Production**: Keep OFF for backward compatibility
///
/// # Example
///
/// ```bash
/// # Strict mode: Fail on `f() + g()` without ANF
/// HAKO_ANF_STRICT=1 ./hakorune program.hako
/// # Error: [joinir/anf/order_violation] f() + g(): both calls not hoisted
///
/// # Graceful mode (default): Fallback to legacy
/// ./hakorune program.hako
/// # OK: Legacy lowering used
/// ```
pub fn anf_strict_enabled() -> bool {
env_bool("HAKO_ANF_STRICT")
}
/// Phase 146 P1: HAKO_ANF_ALLOW_PURE=1 - Allow ANF in PureOnly scope (dev-only)
///
/// Enables ANF transformation for PureOnly expression scopes (e.g., loop/if conditions).
/// Requires HAKO_ANF_DEV=1 to be set as well.
///
/// # Environment Variable
///
/// `HAKO_ANF_ALLOW_PURE=1` enables PureOnly ANF routing (default: OFF)
///
/// # Behavior
///
/// - **OFF (P0)**: ANF only for WithImpure scope (compound assignments)
/// - **ON (P1)**: ANF also for PureOnly scope (loop/if conditions with Compare)
///
/// # Use Cases
///
/// - **P1**: Enable `if (s.length() == 3)` ANF transformation
/// - **P147**: Enable `if (s1.length() < s2.length())` compound condition ANF
///
/// # Example
///
/// ```bash
/// # Enable condition ANF
/// HAKO_ANF_DEV=1 HAKO_ANF_ALLOW_PURE=1 ./hakorune program.hako
/// ```
pub fn anf_allow_pure_enabled() -> bool {
env_bool("HAKO_ANF_ALLOW_PURE")
}