feat(control_tree): add StepTree→Normalized shadow lowerer (if-only, dev-only)
This commit is contained in:
168
src/mir/control_tree/normalized_shadow/builder.rs
Normal file
168
src/mir/control_tree/normalized_shadow/builder.rs
Normal file
@ -0,0 +1,168 @@
|
||||
//! 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
|
||||
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 121 P1: For now, return empty module + empty meta
|
||||
// Full lowering implementation in future phases
|
||||
let module = JoinModule::new();
|
||||
let meta = JoinFragmentMeta::empty();
|
||||
Ok(Some((module, meta)))
|
||||
}
|
||||
CapabilityCheckResult::Unsupported(_reason) => {
|
||||
// Out of scope for Phase 121
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user