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
234 lines
8.0 KiB
Rust
234 lines
8.0 KiB
Rust
//! 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-call(PHI 禁止)
|
||
/// - 対応ノード: 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"));
|
||
}
|
||
}
|