luaur_compiler/methods/
compiler_compile_stat_repeat.rs1use 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}