Skip to main content

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}