Skip to main content

luaur_compiler/methods/
compiler_compile_stat_repeat.rs

1use crate::enums::type_compiler::Type;
2use crate::records::compiler::Compiler;
3use crate::records::loop_jump::LoopJump;
4use crate::records::reg_scope::RegScope;
5use luaur_ast::records::ast_expr::AstExpr;
6use luaur_ast::records::ast_node::AstNode;
7use luaur_ast::records::ast_stat::AstStat;
8use luaur_ast::records::ast_stat_block::AstStatBlock;
9use luaur_ast::records::ast_stat_repeat::AstStatRepeat;
10use luaur_bytecode::records::bytecode_builder::BytecodeBuilder;
11use luaur_common::enums::luau_opcode::LuauOpcode;
12
13impl Compiler {
14    pub fn compile_stat_repeat(&mut self, stat: *mut AstStatRepeat) {
15        unsafe {
16            let stat_ref = &*stat;
17
18            let old_jumps = self.loop_jumps.len();
19            let old_locals = self.local_stack.len();
20
21            self.loops.push(crate::records::r#loop::Loop {
22                local_offset: old_locals,
23                local_offset_continue: old_locals,
24                continue_used: core::ptr::null_mut(),
25            });
26            self.has_loops = true;
27
28            let loop_label = (*self.bytecode).emit_label();
29
30            let body = stat_ref.body;
31
32            let mut rs = RegScope {
33                self_: self as *mut Compiler,
34                old_top: self.reg_top,
35            };
36
37            let mut continue_validated = false;
38            let mut condition_locals = 0;
39
40            for i in 0..(*body).body.size {
41                self.compile_stat(unsafe { *(*body).body.data.add(i as usize) });
42
43                self.loops.last_mut().unwrap().local_offset_continue = self.local_stack.len();
44
45                if !self.loops.last().unwrap().continue_used.is_null() && !continue_validated {
46                    self.validate_continue_until(
47                        self.loops.last().unwrap().continue_used as *mut AstStat,
48                        stat_ref.condition,
49                        body,
50                        (i + 1) as usize,
51                    );
52                    continue_validated = true;
53                    condition_locals = self.local_stack.len();
54                }
55            }
56
57            if continue_validated {
58                self.set_debug_line_end(unsafe {
59                    *(*body).body.data.add(((*body).body.size - 1) as usize) as *mut AstNode
60                });
61
62                self.close_locals(condition_locals);
63                self.pop_locals(condition_locals);
64            }
65
66            let cont_label = (*self.bytecode).emit_label();
67
68            let end_label;
69
70            self.set_debug_line_ast_node(stat_ref.condition as *mut AstNode);
71
72            if self.is_constant_true(stat_ref.condition) {
73                self.close_locals(old_locals);
74
75                end_label = (*self.bytecode).emit_label();
76            } else {
77                let mut skip_jump = Vec::new();
78                self.compile_condition_value(
79                    stat_ref.condition,
80                    core::ptr::null(),
81                    &mut skip_jump,
82                    true,
83                );
84
85                self.close_locals(old_locals);
86
87                let back_label = (*self.bytecode).emit_label();
88
89                (*self.bytecode).emit_ad(LuauOpcode::LOP_JUMPBACK, 0, 0);
90
91                let skip_label = (*self.bytecode).emit_label();
92
93                self.close_locals(old_locals);
94
95                end_label = (*self.bytecode).emit_label();
96
97                self.patch_jump(stat as *mut AstNode, back_label, loop_label);
98                self.patch_jumps(stat as *mut AstNode, &mut skip_jump, skip_label);
99            }
100
101            self.pop_locals(old_locals);
102
103            self.patch_loop_jumps(stat as *mut AstNode, old_jumps, end_label, cont_label);
104            self.loop_jumps.resize(
105                old_jumps,
106                LoopJump {
107                    r#type: Type::Break,
108                    label: 0,
109                },
110            );
111
112            self.loops.pop();
113        }
114    }
115}