refactor(joinir): Phase 82 SSOT統一化 - テーブル化とヘルパー抽象化

Phase 82: JoinIR関数リストとExecルートの SSOT 統一化

## 変更内容

### 1. JOINIR_TARGETS テーブル統一化
**targets.rs**: vm_bridge_dispatch テーブルが唯一のSSO
- FuncScannerBox.append_defs/2 を Exec に追加
- is_loop_lowered_function() はここから参照
- コメントに Phase 82 SSOT マーク

**mod.rs**: is_loop_lowered_function() 簡素化
- JOINIR_TARGETS テーブルから参照に統一
- Exec/LowerOnly 両方を Loop lowered対象とする
- ハードコード関数リストを削除 

### 2. Exec routes 統一ヘルパー
**exec_routes.rs**: run_generic_joinir_route() 追加
- try_run_skip_ws() / try_run_trim() の共通パターンを抽象化
- 入出力値フォーマッタ、終了コードエキスプレッサをコールバック化
- 後方互換性のため既存関数は保持
- 将来フェーズで統合可能 (#[allow(dead_code)])

## テスト結果
 test_is_loop_lowered_function PASS
 cargo build --release SUCCESS

## 重複排除の効果
- テーブル重複: ハードコード関数リスト完全排除
- ロジック重複: 統一ヘルパーで28行削減可能(将来)

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-02 14:01:44 +09:00
parent a9e10d2a6a
commit 93f51e40ae
3 changed files with 100 additions and 11 deletions

View File

@ -59,6 +59,9 @@ use crate::mir::{BasicBlockId, MirFunction};
/// これらの関数は Phase 32/33 で LoopToJoinLowerer によって処理されます。 /// これらの関数は Phase 32/33 で LoopToJoinLowerer によって処理されます。
/// If lowering (Select/IfMerge) の対象から除外することで、Loop/If の責務を明確に分離します。 /// If lowering (Select/IfMerge) の対象から除外することで、Loop/If の責務を明確に分離します。
/// ///
/// Phase 82 SSOT: JOINIR_TARGETS テーブルから Exec 対象を参照
/// (テーブルは vm_bridge_dispatch/targets.rs で一元管理)
///
/// ## 対象関数6本 /// ## 対象関数6本
/// - Main.skip/1: 空白スキップループ /// - Main.skip/1: 空白スキップループ
/// - FuncScannerBox.trim/1: 前後空白削除ループ /// - FuncScannerBox.trim/1: 前後空白削除ループ
@ -70,16 +73,12 @@ use crate::mir::{BasicBlockId, MirFunction};
/// ## 将来の拡張 /// ## 将来の拡張
/// NYASH_JOINIR_LOWER_GENERIC=1 で汎用 Case-A ループにも拡張可能 /// NYASH_JOINIR_LOWER_GENERIC=1 で汎用 Case-A ループにも拡張可能
pub(crate) fn is_loop_lowered_function(name: &str) -> bool { pub(crate) fn is_loop_lowered_function(name: &str) -> bool {
const LOOP_LOWERED_FUNCTIONS: &[&str] = &[ // Phase 82 SSOT: vm_bridge_dispatch テーブルから Loop 関数を抽出
"Main.skip/1", // Phase 33-9.1: If lowering の除外対象は、JOINIR_TARGETS に登録されたすべての関数
"FuncScannerBox.trim/1", // Exec/LowerOnly 問わず、ループ専任関数として Loop lowering で処理)
"FuncScannerBox.append_defs/2", crate::mir::join_ir_vm_bridge_dispatch::JOINIR_TARGETS
"Stage1UsingResolverBox.resolve_for_source/5", .iter()
"StageBBodyExtractorBox.build_body_src/2", .any(|t| t.func_name == name)
"StageBFuncScannerBox.scan_all_boxes/1",
];
LOOP_LOWERED_FUNCTIONS.contains(&name)
} }
// ============================================================================ // ============================================================================

View File

@ -122,3 +122,84 @@ pub(crate) fn try_run_trim(module: &MirModule, quiet_pipe: bool) -> bool {
} }
} }
} }
// ============================================================================
// Phase 82: Exec routes 統一ヘルパー(重複ロジック排除)
// ============================================================================
/// JoinIR 実行ルートの統一ヘルパー
///
/// `try_run_skip_ws()` と `try_run_trim()` の共通パターンを吸収。
///
/// # Phase 82 SSOT 統一
/// 現在は後方互換性のため既存関数を保持。
/// 将来のフェーズで try_run_skip_ws/try_run_trim を このヘルパーで統合可能。
///
/// # Arguments
/// - `lowerer`: JoinIR に lowering する関数(返り値 Option<JoinModule>
/// - `input_val`: 入力値JoinValue形式
/// - `output_formatter`: 出力値を文字列に変換する関数
/// - `exit_code_extractor`: 出力値から終了コードを抽出する関数
/// - `route_name`: ログ出力用の名前(例: "Main.skip", "FuncScannerBox.trim"
#[allow(dead_code)]
fn run_generic_joinir_route<F, G, H>(
lowerer: F,
input_val: JoinValue,
output_formatter: G,
exit_code_extractor: H,
route_name: &str,
quiet_pipe: bool,
) -> bool
where
F: FnOnce() -> Option<crate::mir::join_ir::JoinModule>,
G: Fn(&JoinValue) -> String,
H: Fn(&JoinValue) -> i32,
{
eprintln!("[joinir/vm_bridge] Attempting JoinIR path for {}", route_name);
let Some(join_module) = lowerer() else {
eprintln!(
"[joinir/vm_bridge] lower_{} returned None",
route_name.replace(".", "_").to_lowercase()
);
eprintln!("[joinir/vm_bridge] Falling back to normal VM path");
return false;
};
let dev_bridge = joinir_dev_enabled()
|| std::env::var("NYASH_EMIT_MIR_TRACE").ok().as_deref() == Some("1");
let strict = joinir_strict_enabled();
match run_joinir_via_vm(&join_module, JoinFuncId::new(0), &[input_val]) {
Ok(result) => {
eprintln!("[joinir/vm_bridge] ✅ JoinIR result: {:?}", result);
let output = output_formatter(&result);
let exit_code = exit_code_extractor(&result);
if dev_bridge {
if !quiet_pipe {
println!("{}", output);
}
return true;
} else if strict {
if !quiet_pipe {
println!("{}", output);
}
process::exit(exit_code);
} else {
if !quiet_pipe {
println!("{}", output);
}
process::exit(exit_code);
}
}
Err(e) => {
eprintln!(
"[joinir/vm_bridge] ❌ JoinIR {} failed: {:?}",
route_name, e
);
eprintln!("[joinir/vm_bridge] Falling back to normal VM path");
false
}
}
}

View File

@ -25,18 +25,21 @@ pub struct JoinIrTargetDesc {
pub default_enabled: bool, pub default_enabled: bool,
} }
/// JoinIR ブリッジ対象テーブル /// JoinIR ブリッジ対象テーブルSSOT
/// ///
/// Phase 32 L-4: 全対象関数を一覧化し、Exec/LowerOnly の区分を明示する。 /// Phase 32 L-4: 全対象関数を一覧化し、Exec/LowerOnly の区分を明示する。
/// Phase 82: このテーブルが唯一の SSOT。is_loop_lowered_function() はここから参照。
/// ///
/// | 関数 | Kind | デフォルト有効 | 備考 | /// | 関数 | Kind | デフォルト有効 | 備考 |
/// |-----|------|---------------|------| /// |-----|------|---------------|------|
/// | Main.skip/1 | Exec | No | PHI canary のため env 必須 | /// | Main.skip/1 | Exec | No | PHI canary のため env 必須 |
/// | FuncScannerBox.trim/1 | Exec | Yes | A/B 実証済み、事実上本線 | /// | FuncScannerBox.trim/1 | Exec | Yes | A/B 実証済み、事実上本線 |
/// | FuncScannerBox.append_defs/2 | Exec | No | Phase 82 SSOT統一で追加 |
/// | Stage1UsingResolverBox.resolve_for_source/5 | LowerOnly | No | 構造検証のみ | /// | Stage1UsingResolverBox.resolve_for_source/5 | LowerOnly | No | 構造検証のみ |
/// | StageBBodyExtractorBox.build_body_src/2 | LowerOnly | No | 構造検証のみ | /// | StageBBodyExtractorBox.build_body_src/2 | LowerOnly | No | 構造検証のみ |
/// | StageBFuncScannerBox.scan_all_boxes/1 | LowerOnly | No | 構造検証のみ | /// | StageBFuncScannerBox.scan_all_boxes/1 | LowerOnly | No | 構造検証のみ |
pub const JOINIR_TARGETS: &[JoinIrTargetDesc] = &[ pub const JOINIR_TARGETS: &[JoinIrTargetDesc] = &[
// Loop Exec実行対応
JoinIrTargetDesc { JoinIrTargetDesc {
func_name: "Main.skip/1", func_name: "Main.skip/1",
kind: JoinIrBridgeKind::Exec, kind: JoinIrBridgeKind::Exec,
@ -47,6 +50,12 @@ pub const JOINIR_TARGETS: &[JoinIrTargetDesc] = &[
kind: JoinIrBridgeKind::Exec, kind: JoinIrBridgeKind::Exec,
default_enabled: true, // A/B 実証済み、事実上本線 default_enabled: true, // A/B 実証済み、事実上本線
}, },
JoinIrTargetDesc {
func_name: "FuncScannerBox.append_defs/2",
kind: JoinIrBridgeKind::Exec,
default_enabled: false,
},
// Loop LowerOnly構造検証のみ
JoinIrTargetDesc { JoinIrTargetDesc {
func_name: "Stage1UsingResolverBox.resolve_for_source/5", func_name: "Stage1UsingResolverBox.resolve_for_source/5",
kind: JoinIrBridgeKind::LowerOnly, kind: JoinIrBridgeKind::LowerOnly,