Files
hakorune/src/mir/control_tree/normalized_shadow/builder.rs
nyash-codex 7603ef8a6a 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
2025-12-18 04:50:32 +09:00

234 lines
8.0 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.

//! Phase 121: StepTree → JoinModule shadow lowering (if-only)
//!
//! ## Responsibility
//!
//! - Convert StepTree to JoinModule (Normalized dialect)
//! - Only for if-only patterns (no loops)
//! - Returns None for out-of-scope patterns
//! - Returns Err for patterns that should be supported but conversion failed
//!
//! ## Design
//!
//! - Input: `&StepTree` with pre-computed contract
//! - No AST re-analysis (contract-only decisions)
//! - Single responsibility: structure → JoinIR conversion
use crate::mir::control_tree::step_tree::StepTree;
use crate::mir::join_ir::lowering::carrier_info::{ExitMeta, JoinFragmentMeta};
use crate::mir::join_ir::JoinModule;
use super::contracts::{check_if_only, CapabilityCheckResult};
/// Box-First: StepTree → Normalized shadow lowering
pub struct StepTreeNormalizedShadowLowererBox;
impl StepTreeNormalizedShadowLowererBox {
/// Try to lower an if-only StepTree to normalized form
///
/// ## Returns
///
/// - `Ok(None)`: Out of scope (e.g., contains loops)
/// - `Ok(Some(...))`: Shadow generation succeeded
/// - `Err(...)`: Should be supported but conversion failed (internal error)
///
/// ## Contract
///
/// - Only processes if-only patterns (no loops/breaks/continues)
/// - Uses contract information only (no AST re-analysis)
/// - 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(
step_tree: &StepTree,
) -> Result<Option<(JoinModule, JoinFragmentMeta)>, String> {
// Phase 121 P1: Capability check (if-only scope)
let capability = check_if_only(step_tree);
match capability {
CapabilityCheckResult::Supported => {
// Phase 122 P1: Generate Normalized JoinModule
Self::lower_if_only_to_normalized(step_tree)
.map(Some)
}
CapabilityCheckResult::Unsupported(_reason) => {
// Out of scope for Phase 121/122
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
///
/// ## Contract
///
/// - Returns 1-line summary: "shadow_lowered=true/false reason=..."
/// - Does not perform actual lowering (use `try_lower_if_only` for that)
pub fn get_status_string(step_tree: &StepTree) -> String {
let capability = check_if_only(step_tree);
match capability {
CapabilityCheckResult::Supported => {
format!(
"shadow_lowered=true step_tree_sig={} exits={:?} writes={:?}",
step_tree.signature_basis_string(),
step_tree.contract.exits,
step_tree.contract.writes
)
}
CapabilityCheckResult::Unsupported(reason) => {
format!(
"shadow_lowered=false reason=\"{}\" step_tree_sig={}",
reason.reason(),
step_tree.signature_basis_string()
)
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::mir::control_tree::step_tree::{StepNode, StepTreeFeatures, StepTreeSignature};
use crate::mir::control_tree::step_tree_contract_box::StepTreeContract;
fn make_if_only_tree() -> StepTree {
StepTree {
root: StepNode::Block(vec![]),
features: StepTreeFeatures {
has_if: true,
has_loop: false,
has_break: false,
has_continue: false,
has_return: false,
max_if_depth: 1,
max_loop_depth: 0,
},
contract: StepTreeContract {
exits: Default::default(),
writes: Default::default(),
required_caps: Default::default(),
cond_sig: Default::default(),
},
signature: StepTreeSignature(0),
}
}
fn make_loop_tree() -> StepTree {
StepTree {
root: StepNode::Block(vec![]),
features: StepTreeFeatures {
has_if: false,
has_loop: true,
has_break: false,
has_continue: false,
has_return: false,
max_if_depth: 0,
max_loop_depth: 1,
},
contract: StepTreeContract {
exits: Default::default(),
writes: Default::default(),
required_caps: Default::default(),
cond_sig: Default::default(),
},
signature: StepTreeSignature(0),
}
}
#[test]
fn test_if_only_supported() {
let tree = make_if_only_tree();
let result = StepTreeNormalizedShadowLowererBox::try_lower_if_only(&tree);
assert!(result.is_ok());
assert!(result.unwrap().is_some());
}
#[test]
fn test_loop_rejected() {
let tree = make_loop_tree();
let result = StepTreeNormalizedShadowLowererBox::try_lower_if_only(&tree);
assert!(result.is_ok());
assert!(result.unwrap().is_none());
}
#[test]
fn test_status_string_if_only() {
let tree = make_if_only_tree();
let status = StepTreeNormalizedShadowLowererBox::get_status_string(&tree);
assert!(status.contains("shadow_lowered=true"));
assert!(status.contains("step_tree_sig="));
}
#[test]
fn test_status_string_loop() {
let tree = make_loop_tree();
let status = StepTreeNormalizedShadowLowererBox::get_status_string(&tree);
assert!(status.contains("shadow_lowered=false"));
assert!(status.contains("reason=\"contains loop"));
}
}