luaur_analysis/methods/cfg_builder_lower_control_flow_graph_alt_e.rs
1//! Source: `Analysis/src/ControlFlowGraph.cpp:267-307` (hand-ported)
2//! C++ `void CFGBuilder::lower(AstStatIf* statIf)`.
3use crate::enums::block_kind::BlockKind;
4use crate::records::block::Block;
5use crate::records::cfg_builder::CfgBuilder;
6use alloc::string::ToString;
7use luaur_ast::records::ast_stat_if::AstStatIf;
8
9impl CfgBuilder {
10 pub fn lower_ast_stat_if(&mut self, stat_if: *mut AstStatIf) {
11 unsafe {
12 // Block* currBlock = currentBlock.get();
13 let curr_block: *mut Block = self.current_block;
14
15 // Block* thenBlock = newBlock(BlockKind::Linear, "then branch", currBlock);
16 let then_block =
17 self.new_block(BlockKind::Linear, "then branch".to_string(), curr_block);
18 // auto ref = resolveCondition(statIf->condition);
19 let ref_opt = self.resolve_condition((*stat_if).condition);
20 // if (ref) emitRefineInstruction(thenBlock, *ref);
21 if let Some(r) = ref_opt {
22 self.emit_refine_instruction(then_block, r);
23 }
24
25 // Then only has one predecessor
26 // seal(thenBlock);
27 self.seal(then_block);
28 // Block* thenExit;
29 // { BlockScope scope(*this, thenBlock); lower(statIf->thenbody); thenExit = currentBlock.get(); }
30 let then_exit: *mut Block = {
31 let saved = self.current_block;
32 self.block_scope_cfg_builder_block(then_block);
33 self.lower_ast_stat_block((*stat_if).thenbody);
34 let exit = self.current_block;
35 self.current_block = saved; // ~BlockScope restores currentBlock
36 exit
37 };
38
39 // Else branch (may be nullptr, another AstStatIf for elseif, or a block)
40 // Block* elseBlock = newBlock(BlockKind::Linear, "else branch", currBlock);
41 let else_block =
42 self.new_block(BlockKind::Linear, "else branch".to_string(), curr_block);
43 // Block* elseExit = elseBlock; // If there is an else body, overwrite this
44 let mut else_exit: *mut Block = else_block;
45 // seal(elseBlock);
46 self.seal(else_block);
47 // if (ref) emitRefineInstruction(elseBlock, allocator->refinementArena.negation(*ref));
48 if let Some(r) = ref_opt {
49 let neg = (*self.allocator).refinement_arena.negation_mut(r);
50 self.emit_refine_instruction(else_block, neg);
51 }
52
53 // if (statIf->elsebody) { BlockScope scope(*this, elseBlock); lower(statIf->elsebody); elseExit = currentBlock.get(); }
54 if !(*stat_if).elsebody.is_null() {
55 let saved = self.current_block;
56 self.block_scope_cfg_builder_block(else_block);
57 self.lower_ast_stat((*stat_if).elsebody);
58 else_exit = self.current_block;
59 self.current_block = saved; // ~BlockScope restores currentBlock
60 }
61
62 // Merge block — all paths converge here
63 // Block* mergeBlock = newBlock(BlockKind::Linear, "merge");
64 let merge_block = self.new_block(
65 BlockKind::Linear,
66 "merge".to_string(),
67 core::ptr::null_mut(),
68 );
69 // thenExit->addSuccessor(mergeBlock);
70 (*then_exit).add_successor(merge_block);
71 // elseExit->addSuccessor(mergeBlock);
72 (*else_exit).add_successor(merge_block);
73 // seal(mergeBlock);
74 self.seal(merge_block);
75 // currentBlock = NotNull{mergeBlock};
76 self.current_block = merge_block;
77 }
78 }
79}