Skip to main content

luaur_compiler/methods/
compiler_compile_stat_while.rs

1use crate::records::compiler::Compiler;
2use luaur_ast::records::ast_node::AstNode;
3use luaur_ast::records::ast_stat_while::AstStatWhile;
4use luaur_common::enums::luau_opcode::LuauOpcode;
5
6impl Compiler {
7    pub fn compile_stat_while(&mut self, stat: *mut AstStatWhile) {
8        unsafe {
9            let stat_ref = &*stat;
10
11            // Optimization: condition is always false => there's no loop!
12            if self.is_constant_false(stat_ref.condition) {
13                return;
14            }
15
16            let old_jumps = self.loop_jumps.len();
17            let old_locals = self.local_stack.len();
18
19            self.loops.push(crate::records::r#loop::Loop {
20                local_offset: old_locals,
21                local_offset_continue: old_locals,
22                continue_used: core::ptr::null_mut(),
23            });
24            self.has_loops = true;
25
26            let loop_label = (*self.bytecode).emit_label();
27
28            let mut else_jump = Vec::new();
29            self.compile_condition_value(
30                stat_ref.condition,
31                core::ptr::null(),
32                &mut else_jump,
33                false,
34            );
35
36            self.compile_stat(stat_ref.body as *mut luaur_ast::records::ast_stat::AstStat);
37
38            let cont_label = (*self.bytecode).emit_label();
39            let back_label = (*self.bytecode).emit_label();
40
41            self.set_debug_line_ast_node(stat as *mut AstNode);
42
43            // Note: this is using JUMPBACK, not JUMP, since JUMPBACK is interruptable and we want all loops to have at least one interruptable instruction
44            (*self.bytecode).emit_ad(LuauOpcode::LOP_JUMPBACK, 0, 0);
45
46            let end_label = (*self.bytecode).emit_label();
47
48            self.patch_jump(stat as *mut AstNode, back_label, loop_label);
49            self.patch_jumps(stat as *mut AstNode, &mut else_jump, end_label);
50
51            self.patch_loop_jumps(stat as *mut AstNode, old_jumps, end_label, cont_label);
52            self.loop_jumps.resize(
53                old_jumps,
54                crate::records::loop_jump::LoopJump {
55                    r#type: crate::enums::type_compiler::Type::Break,
56                    label: 0,
57                },
58            );
59
60            self.loops.pop();
61        }
62    }
63}