Skip to main content

luaur_analysis/methods/
cfg_builder_lower_control_flow_graph_alt_f.rs

1//! Source: `Analysis/src/ControlFlowGraph.cpp:310-345` (hand-ported)
2//! C++ `void CFGBuilder::lower(AstStatWhile* statWhile)`.
3use crate::enums::block_kind::BlockKind;
4use crate::records::block::Block;
5use crate::records::cfg_builder::CfgBuilder;
6use crate::type_aliases::refinement_id_control_flow_graph::RefinementId;
7use alloc::string::ToString;
8use luaur_ast::records::ast_stat_while::AstStatWhile;
9
10impl CfgBuilder {
11    pub fn lower_ast_stat_while(&mut self, stat_while: *mut AstStatWhile) {
12        unsafe {
13            // Block* preLoop = currentBlock.get();
14            let pre_loop: *mut Block = self.current_block;
15
16            // Loop header — receives the back-edge so we don't seal it yet. Resolve the
17            // condition inside the header's scope so reads of variables mutated in the
18            // body hit this unsealed block, emit an incomplete Join, and get their
19            // operands filled in when the header is sealed after the back-edge.
20            // Block* loopHeader = newBlock(BlockKind::Condition, "while-loop condition", preLoop);
21            let loop_header = self.new_block(
22                BlockKind::Condition,
23                "while-loop condition".to_string(),
24                pre_loop,
25            );
26            // std::optional<RefinementId> ref;
27            // { BlockScope scope(*this, loopHeader); ref = resolveCondition(statWhile->condition); }
28            let ref_opt: Option<RefinementId> = {
29                let saved = self.current_block;
30                self.block_scope_cfg_builder_block(loop_header);
31                let r = self.resolve_condition((*stat_while).condition);
32                self.current_block = saved; // ~BlockScope restores currentBlock
33                r
34            };
35
36            // Block* bodyBlock = newBlock(BlockKind::Linear, "while-loop body", loopHeader);
37            let body_block = self.new_block(
38                BlockKind::Linear,
39                "while-loop body".to_string(),
40                loop_header,
41            );
42            // if (ref) emitRefineInstruction(bodyBlock, *ref);
43            if let Some(r) = ref_opt {
44                self.emit_refine_instruction(body_block, r);
45            }
46            // seal(bodyBlock);
47            self.seal(body_block);
48            // Block* bodyExit;
49            // { BlockScope scope(*this, bodyBlock); lower(statWhile->body); bodyExit = currentBlock.get(); }
50            let body_exit: *mut Block = {
51                let saved = self.current_block;
52                self.block_scope_cfg_builder_block(body_block);
53                self.lower_ast_stat_block((*stat_while).body);
54                let exit = self.current_block;
55                self.current_block = saved; // ~BlockScope restores currentBlock
56                exit
57            };
58
59            // You can seal the loop header now because no predecessors will be added to it.
60            // bodyExit->addSuccessor(loopHeader);
61            (*body_exit).add_successor(loop_header);
62            // seal(loopHeader);
63            self.seal(loop_header);
64
65            // Block* exitBlock = newBlock(BlockKind::Linear, "while-loop exit", loopHeader);
66            let exit_block = self.new_block(
67                BlockKind::Linear,
68                "while-loop exit".to_string(),
69                loop_header,
70            );
71            // if (ref) emitRefineInstruction(exitBlock, allocator->refinementArena.negation(*ref));
72            if let Some(r) = ref_opt {
73                let neg = (*self.allocator).refinement_arena.negation_mut(r);
74                self.emit_refine_instruction(exit_block, neg);
75            }
76            // seal(exitBlock);
77            self.seal(exit_block);
78            // currentBlock = NotNull{exitBlock};
79            self.current_block = exit_block;
80        }
81    }
82}