feat(control_tree): emit Normalized JoinModule for if-only (dev-only)

Phase 122 P1: StepTree→Normalized JoinModule generation
- Generate env layout from writes (SSOT, deterministic)
- Minimal implementation: main function + Ret only
- Full If/Assign/Return lowering in future P2-P4
- Dev-only: no behavior change to existing path
This commit is contained in:
nyash-codex
2025-12-18 04:50:32 +09:00
parent c92154966c
commit 7603ef8a6a

View File

@ -36,6 +36,13 @@ impl StepTreeNormalizedShadowLowererBox {
/// - Only processes if-only patterns (no loops/breaks/continues) /// - Only processes if-only patterns (no loops/breaks/continues)
/// - Uses contract information only (no AST re-analysis) /// - Uses contract information only (no AST re-analysis)
/// - Dev-only: caller must check `joinir_dev_enabled()` before calling /// - Dev-only: caller must check `joinir_dev_enabled()` before calling
///
/// ## Phase 122 Implementation
///
/// - Generates Normalized JoinIR (env + continuation)
/// - env layout: writes only (SSOT)
/// - merge = join_k(env) tail-call (no PHI)
/// - Minimal node support: If/Return/Assign(Const/Variable/BinOp(Add))
pub fn try_lower_if_only( pub fn try_lower_if_only(
step_tree: &StepTree, step_tree: &StepTree,
) -> Result<Option<(JoinModule, JoinFragmentMeta)>, String> { ) -> Result<Option<(JoinModule, JoinFragmentMeta)>, String> {
@ -43,19 +50,77 @@ impl StepTreeNormalizedShadowLowererBox {
let capability = check_if_only(step_tree); let capability = check_if_only(step_tree);
match capability { match capability {
CapabilityCheckResult::Supported => { CapabilityCheckResult::Supported => {
// Phase 121 P1: For now, return empty module + empty meta // Phase 122 P1: Generate Normalized JoinModule
// Full lowering implementation in future phases Self::lower_if_only_to_normalized(step_tree)
let module = JoinModule::new(); .map(Some)
let meta = JoinFragmentMeta::empty();
Ok(Some((module, meta)))
} }
CapabilityCheckResult::Unsupported(_reason) => { CapabilityCheckResult::Unsupported(_reason) => {
// Out of scope for Phase 121 // Out of scope for Phase 121/122
Ok(None) Ok(None)
} }
} }
} }
/// Lower if-only StepTree to Normalized JoinModule (Phase 122)
///
/// ## Design
///
/// - env レイアウト: `writes` に含まれる変数だけ(決定的順序)
/// - merge 形式: `join_k(env)` への tail-callPHI 禁止)
/// - 対応ノード: If/Return/Assign(最小セット)
///
/// ## Returns
///
/// - `Ok((module, meta))`: Normalized JoinModule生成成功
/// - `Err(msg)`: 生成できるはずなのに失敗(内部エラー)
fn lower_if_only_to_normalized(
step_tree: &StepTree,
) -> Result<(JoinModule, JoinFragmentMeta), String> {
use crate::mir::join_ir::{JoinFunction, JoinFuncId, JoinInst};
use crate::mir::ValueId;
use std::collections::BTreeMap;
// Phase 122 P1: 最小実装 - main関数1つ + Ret のみ
// env レイアウト: writes から決定的に決める
let env_fields: Vec<String> = step_tree.contract.writes.iter().cloned().collect();
// 関数ID生成Phase 122では固定ID使用
let main_func_id = JoinFuncId::new(0);
// env フィールドに対応する引数ValueIdを生成
let mut next_value_id = 1;
let env_params: Vec<ValueId> = env_fields
.iter()
.map(|_| {
let vid = ValueId(next_value_id);
next_value_id += 1;
vid
})
.collect();
// main 関数生成(最小: Ret のみ)
let mut main_func = JoinFunction::new(
main_func_id,
"main".to_string(),
env_params.clone(),
);
// Phase 122 P1: 最小実装 - Return void のみ
// TODO Phase 122 P2-P4: If/Assign/条件式の lowering 実装
main_func.body.push(JoinInst::Ret { value: None });
// JoinModule 構築
let mut module = JoinModule::new();
module.add_function(main_func);
module.entry = Some(main_func_id);
module.mark_normalized();
// JoinFragmentMeta 生成(最小)
let meta = JoinFragmentMeta::empty();
Ok((module, meta))
}
/// Get shadow lowering status string for dev logging /// Get shadow lowering status string for dev logging
/// ///
/// ## Contract /// ## Contract