Files
hakorune/src/runner/json_v0_bridge/lowering/match_expr.rs

71 lines
2.7 KiB
Rust
Raw Normal View History

//! Match/expr-block lowering for JSON v0 bridge.
use super::merge::new_block;
use super::BridgeEnv;
use crate::mir::{BasicBlockId, CompareOp, ConstValue, MirFunction, MirInstruction, ValueId};
use super::super::ast::{ExprV0, MatchArmV0};
use super::expr::{lower_expr_with_scope, VarScope};
pub(super) fn lower_match_expr_with_scope<S: VarScope>(
env: &BridgeEnv,
f: &mut MirFunction,
cur_bb: BasicBlockId,
scrutinee: &ExprV0,
arms: &[MatchArmV0],
else_expr: &ExprV0,
vars: &mut S,
) -> Result<(ValueId, BasicBlockId), String> {
// Evaluate scrutinee
let (scr_val, start_bb) = lower_expr_with_scope(env, f, cur_bb, scrutinee, vars)?;
// Set up blocks
let dispatch_bb = new_block(f);
if let Some(bb) = f.get_block_mut(start_bb) {
if !bb.is_terminated() { crate::mir::ssot::cf_common::set_jump(f, start_bb, dispatch_bb); }
}
let else_bb = new_block(f);
let merge_bb = new_block(f);
// Chain dispatch over arms
let mut cur_dispatch = dispatch_bb;
let mut phi_inputs: Vec<(BasicBlockId, ValueId)> = Vec::new();
for (i, arm) in arms.iter().enumerate() {
let then_bb = new_block(f);
let next_dispatch = if i + 1 < arms.len() { Some(new_block(f)) } else { None };
let fall_bb = next_dispatch.unwrap_or(else_bb);
// Pre-allocate ids to avoid double borrow
let ldst = f.next_value_id();
let cond = f.next_value_id();
if let Some(bb) = f.get_block_mut(cur_dispatch) {
// compare scr_val == label
bb.add_instruction(MirInstruction::Const { dst: ldst, value: ConstValue::String(arm.label.clone()) });
}
crate::mir::ssot::cf_common::emit_compare_func(f, cur_dispatch, cond, CompareOp::Eq, scr_val, ldst);
crate::mir::ssot::cf_common::set_branch(f, cur_dispatch, cond, then_bb, fall_bb);
// Then arm body
let (tval, tend) = lower_expr_with_scope(env, f, then_bb, &arm.expr, vars)?;
if let Some(bb) = f.get_block_mut(tend) {
if !bb.is_terminated() { crate::mir::ssot::cf_common::set_jump(f, tend, merge_bb); }
}
phi_inputs.push((tend, tval));
cur_dispatch = fall_bb;
}
// Else body
let (eval, eend) = lower_expr_with_scope(env, f, else_bb, else_expr, vars)?;
if let Some(bb) = f.get_block_mut(eend) {
if !bb.is_terminated() { crate::mir::ssot::cf_common::set_jump(f, eend, merge_bb); }
}
phi_inputs.push((eend, eval));
// Merge result
let out = f.next_value_id();
// フェーズM.2: PHI統一処理no_phi分岐削除
let inputs = phi_inputs;
crate::mir::ssot::cf_common::insert_phi_at_head(f, merge_bb, out, inputs);
Ok((out, merge_bb))
}