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