refactor(normalized_shadow): Phase 138 - extract ReturnValueLowererBox (no behavior change)
Extract return value lowering logic to shared Box for SSOT: New Files: - common/return_value_lowerer_box.rs (~300 lines) - ReturnValueLowererBox::lower_to_value_id() - Supports: Variable, Integer literal, Add expression - 5 comprehensive unit tests - common/mod.rs (module export) Modified Files: - loop_true_break_once.rs - Removed lower_return_value_to_vid() method (~115 lines) - Added import: use super::common::return_value_lowerer_box::ReturnValueLowererBox - Updated 2 call sites (post_k, k_exit) - Updated SSOT documentation - mod.rs - Added pub mod common; Code Reduction: ~115 lines removed from loop_true_break_once.rs Tests: - cargo test --lib: 1194 tests PASS (+5 new unit tests) - Phase 137 regression: 6/6 PASS - Phase 97 regression: 2/2 PASS - Phase 131/135/136 regression: 3/3 PASS Behavior: Unchanged (all Phase 136/137 fixtures/smokes PASS) SSOT: common/return_value_lowerer_box.rs Next: Phase 139 P0 - Migrate post_if_post_k.rs to ReturnValueLowererBox 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
3
src/mir/control_tree/normalized_shadow/common/mod.rs
Normal file
3
src/mir/control_tree/normalized_shadow/common/mod.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
//! Common utilities for Normalized shadow (Phase 138+)
|
||||||
|
|
||||||
|
pub mod return_value_lowerer_box;
|
||||||
@ -0,0 +1,316 @@
|
|||||||
|
//! ReturnValueLowererBox: Return value lowering SSOT (Phase 138 P0)
|
||||||
|
//!
|
||||||
|
//! ## Responsibility
|
||||||
|
//!
|
||||||
|
//! Lower return values (variable, literal, expr) to ValueId for Normalized shadow paths
|
||||||
|
//!
|
||||||
|
//! ## Supported Patterns (Phase 136-137)
|
||||||
|
//!
|
||||||
|
//! - Variable: env lookup → ValueId
|
||||||
|
//! - Integer literal: Const generation → ValueId
|
||||||
|
//! - Add expr: (var|int) + int → BinOp(Add, lhs, rhs) → ValueId
|
||||||
|
//!
|
||||||
|
//! ## Fallback
|
||||||
|
//!
|
||||||
|
//! Out-of-scope patterns return `Ok(None)` for legacy routing
|
||||||
|
//!
|
||||||
|
//! ## Usage
|
||||||
|
//!
|
||||||
|
//! - Phase 138 P0: loop_true_break_once.rs
|
||||||
|
//! - Phase 139 P0: post_if_post_k.rs (planned)
|
||||||
|
|
||||||
|
use crate::ast::{ASTNode, BinaryOperator, LiteralValue};
|
||||||
|
use crate::mir::control_tree::step_tree::AstNodeHandle;
|
||||||
|
use crate::mir::join_ir::{BinOpKind, ConstValue, JoinInst, MirLikeInst};
|
||||||
|
use crate::mir::ValueId;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
/// Box-First: Return value lowering for Normalized shadow
|
||||||
|
pub struct ReturnValueLowererBox;
|
||||||
|
|
||||||
|
impl ReturnValueLowererBox {
|
||||||
|
/// Lower return value to ValueId
|
||||||
|
///
|
||||||
|
/// Phase 136-137: Support variable, integer literal, and add expression
|
||||||
|
///
|
||||||
|
/// Returns:
|
||||||
|
/// - Ok(Some(vid)): Successfully lowered to ValueId
|
||||||
|
/// - Ok(None): Out of scope (fallback to legacy routing)
|
||||||
|
/// - Err(_): Internal error (should not happen for valid AST)
|
||||||
|
///
|
||||||
|
/// Note: Does NOT return Err for unsupported patterns - returns Ok(None) instead
|
||||||
|
pub fn lower_to_value_id(
|
||||||
|
value_ast: &Option<AstNodeHandle>,
|
||||||
|
body: &mut Vec<JoinInst>,
|
||||||
|
next_value_id: &mut u32,
|
||||||
|
env: &BTreeMap<String, ValueId>,
|
||||||
|
) -> Result<Option<ValueId>, String> {
|
||||||
|
match value_ast {
|
||||||
|
None => {
|
||||||
|
// void return
|
||||||
|
Ok(Some(ValueId(0))) // Dummy - caller handles void separately
|
||||||
|
}
|
||||||
|
Some(ast_handle) => {
|
||||||
|
match ast_handle.0.as_ref() {
|
||||||
|
// Variable: lookup in env
|
||||||
|
ASTNode::Variable { name, .. } => {
|
||||||
|
if let Some(&vid) = env.get(name) {
|
||||||
|
Ok(Some(vid))
|
||||||
|
} else {
|
||||||
|
// Variable not in env - out of scope
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Integer literal: generate Const instruction (Phase 136)
|
||||||
|
ASTNode::Literal { value: LiteralValue::Integer(i), .. } => {
|
||||||
|
let const_vid = ValueId(*next_value_id);
|
||||||
|
*next_value_id += 1;
|
||||||
|
|
||||||
|
body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||||
|
dst: const_vid,
|
||||||
|
value: ConstValue::Integer(*i),
|
||||||
|
}));
|
||||||
|
|
||||||
|
Ok(Some(const_vid))
|
||||||
|
}
|
||||||
|
// Phase 137: BinaryOp (x + 2) support
|
||||||
|
ASTNode::BinaryOp { operator, left, right, .. } => {
|
||||||
|
Self::lower_binary_op(operator, left, right, body, next_value_id, env)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// Other return value types - out of scope
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Lower binary operation to ValueId (Phase 137)
|
||||||
|
fn lower_binary_op(
|
||||||
|
operator: &BinaryOperator,
|
||||||
|
left: &ASTNode,
|
||||||
|
right: &ASTNode,
|
||||||
|
body: &mut Vec<JoinInst>,
|
||||||
|
next_value_id: &mut u32,
|
||||||
|
env: &BTreeMap<String, ValueId>,
|
||||||
|
) -> Result<Option<ValueId>, String> {
|
||||||
|
// Phase 137 contract: Add only
|
||||||
|
if !matches!(operator, BinaryOperator::Add) {
|
||||||
|
return Ok(None); // out of scope
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lower LHS (Variable or Integer literal)
|
||||||
|
let lhs_vid = match left {
|
||||||
|
ASTNode::Variable { name, .. } => {
|
||||||
|
// Get from env
|
||||||
|
if let Some(&vid) = env.get(name) {
|
||||||
|
vid
|
||||||
|
} else {
|
||||||
|
// Variable not in env - out of scope
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ASTNode::Literal { value: LiteralValue::Integer(i), .. } => {
|
||||||
|
// Generate Const for LHS integer literal
|
||||||
|
let vid = ValueId(*next_value_id);
|
||||||
|
*next_value_id += 1;
|
||||||
|
body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||||
|
dst: vid,
|
||||||
|
value: ConstValue::Integer(*i),
|
||||||
|
}));
|
||||||
|
vid
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// Other LHS types - out of scope
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Lower RHS (Integer literal only)
|
||||||
|
let rhs_vid = match right {
|
||||||
|
ASTNode::Literal { value: LiteralValue::Integer(i), .. } => {
|
||||||
|
// Generate Const for RHS integer literal
|
||||||
|
let vid = ValueId(*next_value_id);
|
||||||
|
*next_value_id += 1;
|
||||||
|
body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||||
|
dst: vid,
|
||||||
|
value: ConstValue::Integer(*i),
|
||||||
|
}));
|
||||||
|
vid
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// Other RHS types - out of scope (e.g., return x + y)
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate BinOp Add
|
||||||
|
let result_vid = ValueId(*next_value_id);
|
||||||
|
*next_value_id += 1;
|
||||||
|
body.push(JoinInst::Compute(MirLikeInst::BinOp {
|
||||||
|
dst: result_vid,
|
||||||
|
op: BinOpKind::Add,
|
||||||
|
lhs: lhs_vid,
|
||||||
|
rhs: rhs_vid,
|
||||||
|
}));
|
||||||
|
|
||||||
|
Ok(Some(result_vid))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::ast::{ASTNode, BinaryOperator, LiteralValue, Span};
|
||||||
|
use crate::mir::control_tree::step_tree::AstNodeHandle;
|
||||||
|
|
||||||
|
fn make_span() -> Span {
|
||||||
|
Span::unknown()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_lower_variable() {
|
||||||
|
let mut body = vec![];
|
||||||
|
let mut next_value_id = 100;
|
||||||
|
let mut env = BTreeMap::new();
|
||||||
|
env.insert("x".to_string(), ValueId(42));
|
||||||
|
|
||||||
|
let var_ast = AstNodeHandle(Box::new(ASTNode::Variable {
|
||||||
|
name: "x".to_string(),
|
||||||
|
span: make_span(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
let result = ReturnValueLowererBox::lower_to_value_id(
|
||||||
|
&Some(var_ast),
|
||||||
|
&mut body,
|
||||||
|
&mut next_value_id,
|
||||||
|
&env,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result, Some(ValueId(42)));
|
||||||
|
assert_eq!(body.len(), 0); // No instructions emitted
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_lower_integer_literal() {
|
||||||
|
let mut body = vec![];
|
||||||
|
let mut next_value_id = 100;
|
||||||
|
let env = BTreeMap::new();
|
||||||
|
|
||||||
|
let int_ast = AstNodeHandle(Box::new(ASTNode::Literal {
|
||||||
|
value: LiteralValue::Integer(7),
|
||||||
|
span: make_span(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
let result = ReturnValueLowererBox::lower_to_value_id(
|
||||||
|
&Some(int_ast),
|
||||||
|
&mut body,
|
||||||
|
&mut next_value_id,
|
||||||
|
&env,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result, Some(ValueId(100)));
|
||||||
|
assert_eq!(body.len(), 1); // Const instruction emitted
|
||||||
|
assert_eq!(next_value_id, 101);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_lower_add_var_plus_int() {
|
||||||
|
let mut body = vec![];
|
||||||
|
let mut next_value_id = 100;
|
||||||
|
let mut env = BTreeMap::new();
|
||||||
|
env.insert("x".to_string(), ValueId(1));
|
||||||
|
|
||||||
|
let add_ast = AstNodeHandle(Box::new(ASTNode::BinaryOp {
|
||||||
|
operator: BinaryOperator::Add,
|
||||||
|
left: Box::new(ASTNode::Variable {
|
||||||
|
name: "x".to_string(),
|
||||||
|
span: make_span(),
|
||||||
|
}),
|
||||||
|
right: Box::new(ASTNode::Literal {
|
||||||
|
value: LiteralValue::Integer(2),
|
||||||
|
span: make_span(),
|
||||||
|
}),
|
||||||
|
span: make_span(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
let result = ReturnValueLowererBox::lower_to_value_id(
|
||||||
|
&Some(add_ast),
|
||||||
|
&mut body,
|
||||||
|
&mut next_value_id,
|
||||||
|
&env,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result, Some(ValueId(101))); // BinOp result
|
||||||
|
assert_eq!(body.len(), 2); // Const(2) + BinOp
|
||||||
|
assert_eq!(next_value_id, 102);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_lower_add_int_plus_int() {
|
||||||
|
let mut body = vec![];
|
||||||
|
let mut next_value_id = 100;
|
||||||
|
let env = BTreeMap::new();
|
||||||
|
|
||||||
|
let add_ast = AstNodeHandle(Box::new(ASTNode::BinaryOp {
|
||||||
|
operator: BinaryOperator::Add,
|
||||||
|
left: Box::new(ASTNode::Literal {
|
||||||
|
value: LiteralValue::Integer(5),
|
||||||
|
span: make_span(),
|
||||||
|
}),
|
||||||
|
right: Box::new(ASTNode::Literal {
|
||||||
|
value: LiteralValue::Integer(3),
|
||||||
|
span: make_span(),
|
||||||
|
}),
|
||||||
|
span: make_span(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
let result = ReturnValueLowererBox::lower_to_value_id(
|
||||||
|
&Some(add_ast),
|
||||||
|
&mut body,
|
||||||
|
&mut next_value_id,
|
||||||
|
&env,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result, Some(ValueId(102))); // BinOp result
|
||||||
|
assert_eq!(body.len(), 3); // Const(5) + Const(3) + BinOp
|
||||||
|
assert_eq!(next_value_id, 103);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_out_of_scope_subtract() {
|
||||||
|
let mut body = vec![];
|
||||||
|
let mut next_value_id = 100;
|
||||||
|
let mut env = BTreeMap::new();
|
||||||
|
env.insert("x".to_string(), ValueId(1));
|
||||||
|
|
||||||
|
let sub_ast = AstNodeHandle(Box::new(ASTNode::BinaryOp {
|
||||||
|
operator: BinaryOperator::Subtract,
|
||||||
|
left: Box::new(ASTNode::Variable {
|
||||||
|
name: "x".to_string(),
|
||||||
|
span: make_span(),
|
||||||
|
}),
|
||||||
|
right: Box::new(ASTNode::Literal {
|
||||||
|
value: LiteralValue::Integer(2),
|
||||||
|
span: make_span(),
|
||||||
|
}),
|
||||||
|
span: make_span(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
let result = ReturnValueLowererBox::lower_to_value_id(
|
||||||
|
&Some(sub_ast),
|
||||||
|
&mut body,
|
||||||
|
&mut next_value_id,
|
||||||
|
&env,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result, None); // Out of scope
|
||||||
|
assert_eq!(body.len(), 0); // No instructions emitted
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -26,9 +26,10 @@
|
|||||||
//! - Post-loop (Phase 132-P4): One assignment + return (reuse Phase 130's lower_assign_stmt)
|
//! - Post-loop (Phase 132-P4): One assignment + return (reuse Phase 130's lower_assign_stmt)
|
||||||
//! - Post-loop (Phase 133-P0): Multiple assignments + return (extend Phase 132-P4)
|
//! - Post-loop (Phase 133-P0): Multiple assignments + return (extend Phase 132-P4)
|
||||||
//!
|
//!
|
||||||
//! ## Return Value Lowering SSOT (Phase 137+)
|
//! ## Return Value Lowering SSOT (Phase 138+)
|
||||||
//!
|
//!
|
||||||
//! - Function: `lower_return_value_to_vid()`
|
//! - **SSOT Location**: `common/return_value_lowerer_box.rs`
|
||||||
|
//! - Function: `ReturnValueLowererBox::lower_to_value_id()`
|
||||||
//! - Responsibility: Lower return values (variable, literal, expr) to ValueId
|
//! - Responsibility: Lower return values (variable, literal, expr) to ValueId
|
||||||
//! - Supported patterns:
|
//! - Supported patterns:
|
||||||
//! - Variable: env lookup
|
//! - Variable: env lookup
|
||||||
@ -36,21 +37,21 @@
|
|||||||
//! - Add expr (Phase 137): x + 2 → BinOp(Add, env[x], Const(2))
|
//! - Add expr (Phase 137): x + 2 → BinOp(Add, env[x], Const(2))
|
||||||
//! - Fallback: Out-of-scope patterns return `Ok(None)` for legacy routing
|
//! - Fallback: Out-of-scope patterns return `Ok(None)` for legacy routing
|
||||||
//!
|
//!
|
||||||
//! ### Boxification Trigger
|
//! ### Usage
|
||||||
//!
|
//!
|
||||||
//! If 2+ files need identical return lowering logic, promote to:
|
//! - Phase 138 P0: loop_true_break_once.rs
|
||||||
//! - `normalized_shadow/common/return_value_lowerer_box.rs`
|
//! - Phase 139 P0: post_if_post_k.rs (planned)
|
||||||
//! - Single responsibility: return value → ValueId conversion
|
|
||||||
//!
|
//!
|
||||||
//! ## Fail-Fast
|
//! ## Fail-Fast
|
||||||
//!
|
//!
|
||||||
//! - Out of scope → Ok(None) (fallback to legacy)
|
//! - Out of scope → Ok(None) (fallback to legacy)
|
||||||
//! - In scope but conversion failed → Err (with freeze_with_hint in strict mode)
|
//! - In scope but conversion failed → Err (with freeze_with_hint in strict mode)
|
||||||
|
|
||||||
|
use super::common::return_value_lowerer_box::ReturnValueLowererBox;
|
||||||
use super::env_layout::EnvLayout;
|
use super::env_layout::EnvLayout;
|
||||||
use super::legacy::LegacyLowerer;
|
use super::legacy::LegacyLowerer;
|
||||||
use crate::ast::{ASTNode, BinaryOperator, LiteralValue};
|
use crate::ast::{ASTNode, LiteralValue};
|
||||||
use crate::mir::control_tree::step_tree::{AstNodeHandle, StepNode, StepStmtKind, StepTree};
|
use crate::mir::control_tree::step_tree::{StepNode, StepStmtKind, StepTree};
|
||||||
use crate::mir::join_ir::lowering::carrier_info::JoinFragmentMeta;
|
use crate::mir::join_ir::lowering::carrier_info::JoinFragmentMeta;
|
||||||
use crate::mir::join_ir::lowering::error_tags;
|
use crate::mir::join_ir::lowering::error_tags;
|
||||||
use crate::mir::join_ir::{BinOpKind, ConstValue, JoinFunction, JoinFuncId, JoinInst, JoinModule, MirLikeInst};
|
use crate::mir::join_ir::{BinOpKind, ConstValue, JoinFunction, JoinFuncId, JoinInst, JoinModule, MirLikeInst};
|
||||||
@ -413,7 +414,7 @@ impl LoopTrueBreakOnceBuilderBox {
|
|||||||
// Lower post-loop return (Phase 136: support variable + integer literal)
|
// Lower post-loop return (Phase 136: support variable + integer literal)
|
||||||
if let Some(_ast_handle) = value_ast {
|
if let Some(_ast_handle) = value_ast {
|
||||||
// Return with value
|
// Return with value
|
||||||
match Self::lower_return_value_to_vid(value_ast, &mut post_k_func.body, &mut next_value_id, &env_post_k)? {
|
match ReturnValueLowererBox::lower_to_value_id(value_ast, &mut post_k_func.body, &mut next_value_id, &env_post_k)? {
|
||||||
Some(vid) => {
|
Some(vid) => {
|
||||||
post_k_func.body.push(JoinInst::Ret { value: Some(vid) });
|
post_k_func.body.push(JoinInst::Ret { value: Some(vid) });
|
||||||
}
|
}
|
||||||
@ -477,7 +478,7 @@ impl LoopTrueBreakOnceBuilderBox {
|
|||||||
StepStmtKind::Return { value_ast } => {
|
StepStmtKind::Return { value_ast } => {
|
||||||
if let Some(_ast_handle) = value_ast {
|
if let Some(_ast_handle) = value_ast {
|
||||||
// Return with value (Phase 136: variable + integer literal)
|
// Return with value (Phase 136: variable + integer literal)
|
||||||
match Self::lower_return_value_to_vid(value_ast, &mut k_exit_func.body, &mut next_value_id, &env_k_exit)? {
|
match ReturnValueLowererBox::lower_to_value_id(value_ast, &mut k_exit_func.body, &mut next_value_id, &env_k_exit)? {
|
||||||
Some(vid) => {
|
Some(vid) => {
|
||||||
k_exit_func.body.push(JoinInst::Ret { value: Some(vid) });
|
k_exit_func.body.push(JoinInst::Ret { value: Some(vid) });
|
||||||
}
|
}
|
||||||
@ -625,122 +626,6 @@ impl LoopTrueBreakOnceBuilderBox {
|
|||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lower return value (variable or integer literal) to ValueId
|
|
||||||
///
|
|
||||||
/// Phase 136 P0: Support return variable and return integer literal
|
|
||||||
///
|
|
||||||
/// Returns:
|
|
||||||
/// - Ok(Some(vid)): variable from env or newly generated const
|
|
||||||
/// - Ok(None): out of scope (fallback to default behavior)
|
|
||||||
///
|
|
||||||
/// Note: Does NOT return Err - unsupported patterns return Ok(None) for fallback
|
|
||||||
fn lower_return_value_to_vid(
|
|
||||||
value_ast: &Option<AstNodeHandle>,
|
|
||||||
body: &mut Vec<JoinInst>,
|
|
||||||
next_value_id: &mut u32,
|
|
||||||
env: &BTreeMap<String, ValueId>,
|
|
||||||
) -> Result<Option<ValueId>, String> {
|
|
||||||
match value_ast {
|
|
||||||
None => {
|
|
||||||
// void return
|
|
||||||
Ok(Some(ValueId(0))) // Dummy - caller handles void separately
|
|
||||||
}
|
|
||||||
Some(ast_handle) => {
|
|
||||||
match ast_handle.0.as_ref() {
|
|
||||||
// Variable: lookup in env
|
|
||||||
ASTNode::Variable { name, .. } => {
|
|
||||||
if let Some(&vid) = env.get(name) {
|
|
||||||
Ok(Some(vid))
|
|
||||||
} else {
|
|
||||||
// Variable not in env - out of scope
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Integer literal: generate Const instruction (Phase 123 pattern)
|
|
||||||
ASTNode::Literal { value: LiteralValue::Integer(i), .. } => {
|
|
||||||
let const_vid = ValueId(*next_value_id);
|
|
||||||
*next_value_id += 1;
|
|
||||||
|
|
||||||
body.push(JoinInst::Compute(MirLikeInst::Const {
|
|
||||||
dst: const_vid,
|
|
||||||
value: ConstValue::Integer(*i),
|
|
||||||
}));
|
|
||||||
|
|
||||||
Ok(Some(const_vid))
|
|
||||||
}
|
|
||||||
// Phase 137 P0: BinaryOp (x + 2) support
|
|
||||||
ASTNode::BinaryOp { operator, left, right, .. } => {
|
|
||||||
// Phase 137 contract: Add only
|
|
||||||
if !matches!(operator, BinaryOperator::Add) {
|
|
||||||
return Ok(None); // out of scope
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lower LHS (Variable or Integer literal)
|
|
||||||
let lhs_vid = match left.as_ref() {
|
|
||||||
ASTNode::Variable { name, .. } => {
|
|
||||||
// Get from env
|
|
||||||
if let Some(&vid) = env.get(name) {
|
|
||||||
vid
|
|
||||||
} else {
|
|
||||||
// Variable not in env - out of scope
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ASTNode::Literal { value: LiteralValue::Integer(i), .. } => {
|
|
||||||
// Generate Const for LHS integer literal
|
|
||||||
let vid = ValueId(*next_value_id);
|
|
||||||
*next_value_id += 1;
|
|
||||||
body.push(JoinInst::Compute(MirLikeInst::Const {
|
|
||||||
dst: vid,
|
|
||||||
value: ConstValue::Integer(*i),
|
|
||||||
}));
|
|
||||||
vid
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// Other LHS types - out of scope
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Lower RHS (Integer literal only)
|
|
||||||
let rhs_vid = match right.as_ref() {
|
|
||||||
ASTNode::Literal { value: LiteralValue::Integer(i), .. } => {
|
|
||||||
// Generate Const for RHS integer literal
|
|
||||||
let vid = ValueId(*next_value_id);
|
|
||||||
*next_value_id += 1;
|
|
||||||
body.push(JoinInst::Compute(MirLikeInst::Const {
|
|
||||||
dst: vid,
|
|
||||||
value: ConstValue::Integer(*i),
|
|
||||||
}));
|
|
||||||
vid
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// Other RHS types - out of scope (e.g., return x + y)
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Generate BinOp Add
|
|
||||||
let result_vid = ValueId(*next_value_id);
|
|
||||||
*next_value_id += 1;
|
|
||||||
body.push(JoinInst::Compute(MirLikeInst::BinOp {
|
|
||||||
dst: result_vid,
|
|
||||||
op: BinOpKind::Add,
|
|
||||||
lhs: lhs_vid,
|
|
||||||
rhs: rhs_vid,
|
|
||||||
}));
|
|
||||||
|
|
||||||
Ok(Some(result_vid))
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// Other return value types - out of scope
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@ -41,6 +41,7 @@ pub mod dev_pipeline;
|
|||||||
pub mod parity_contract;
|
pub mod parity_contract;
|
||||||
pub mod available_inputs_collector; // Phase 126: available_inputs SSOT
|
pub mod available_inputs_collector; // Phase 126: available_inputs SSOT
|
||||||
pub mod exit_reconnector; // Phase 131 P1.5: Direct variable_map reconnection (Option B)
|
pub mod exit_reconnector; // Phase 131 P1.5: Direct variable_map reconnection (Option B)
|
||||||
|
pub mod common; // Phase 138: Common utilities (ReturnValueLowererBox)
|
||||||
|
|
||||||
pub use builder::StepTreeNormalizedShadowLowererBox;
|
pub use builder::StepTreeNormalizedShadowLowererBox;
|
||||||
pub use contracts::{CapabilityCheckResult, UnsupportedCapability};
|
pub use contracts::{CapabilityCheckResult, UnsupportedCapability};
|
||||||
|
|||||||
Reference in New Issue
Block a user