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}