Skip to main content

luaur_compiler/methods/
compiler_compile_stat.rs

1use crate::records::compiler::Compiler;
2use luaur_ast::records::ast_node::AstNode;
3use luaur_ast::records::ast_stat::AstStat;
4use luaur_ast::records::ast_stat_assign::AstStatAssign;
5use luaur_ast::records::ast_stat_block::AstStatBlock;
6use luaur_ast::records::ast_stat_break::AstStatBreak;
7use luaur_ast::records::ast_stat_class::AstStatClass;
8use luaur_ast::records::ast_stat_compound_assign::AstStatCompoundAssign;
9use luaur_ast::records::ast_stat_continue::AstStatContinue;
10use luaur_ast::records::ast_stat_for::AstStatFor;
11use luaur_ast::records::ast_stat_for_in::AstStatForIn;
12use luaur_ast::records::ast_stat_function::AstStatFunction;
13use luaur_ast::records::ast_stat_if::AstStatIf;
14use luaur_ast::records::ast_stat_local::AstStatLocal;
15use luaur_ast::records::ast_stat_local_function::AstStatLocalFunction;
16use luaur_ast::records::ast_stat_repeat::AstStatRepeat;
17use luaur_ast::records::ast_stat_return::AstStatReturn;
18use luaur_ast::records::ast_stat_while::AstStatWhile;
19use luaur_ast::rtti;
20use luaur_common::enums::luau_opcode::LuauOpcode;
21use luaur_common::macros::luau_assert::LUAU_ASSERT;
22
23impl Compiler {
24    pub fn compile_stat(&mut self, node: *mut AstStat) {
25        unsafe {
26            self.set_debug_line_ast_node(node as *mut AstNode);
27            if self.options.coverage_level >= 1 && self.needs_coverage(node as *mut AstNode) {
28                (*self.bytecode).emit_abc(LuauOpcode::LOP_COVERAGE, 0, 0, 0);
29            }
30
31            let stat = rtti::ast_node_as::<AstStatBlock>(node as *mut AstNode);
32            if !stat.is_null() {
33                let _rs = self.reg_scope_compiler();
34                let old_locals = self.local_stack.len();
35                if luaur_common::FFlag::LuauExportValueSyntax.get() {
36                    self.block_depth += 1;
37                }
38                for i in 0..(*stat).body.size {
39                    let body_stat = *(*stat).body.data.add(i);
40                    self.compile_stat(body_stat);
41                    if self.always_terminates(body_stat) {
42                        break;
43                    }
44                }
45                if luaur_common::FFlag::LuauExportValueSyntax.get() {
46                    self.block_depth -= 1;
47                }
48                self.close_locals(old_locals);
49                self.pop_locals(old_locals);
50                return;
51            }
52
53            let stat = rtti::ast_node_as::<AstStatIf>(node as *mut AstNode);
54            if !stat.is_null() {
55                self.compile_stat_if(stat);
56                return;
57            }
58
59            let stat = rtti::ast_node_as::<AstStatWhile>(node as *mut AstNode);
60            if !stat.is_null() {
61                self.compile_stat_while(stat);
62                return;
63            }
64
65            let stat = rtti::ast_node_as::<AstStatRepeat>(node as *mut AstNode);
66            if !stat.is_null() {
67                self.compile_stat_repeat(stat);
68                return;
69            }
70
71            if rtti::ast_node_is::<AstStatBreak>(&*(node as *mut AstNode)) {
72                LUAU_ASSERT!(!self.loops.is_empty());
73                self.close_locals(self.loops.last().unwrap().local_offset);
74                let label = (*self.bytecode).emit_label();
75                (*self.bytecode).emit_ad(LuauOpcode::LOP_JUMP, 0, 0);
76                self.loop_jumps.push(crate::records::loop_jump::LoopJump {
77                    r#type: crate::enums::type_compiler::Type::Break,
78                    label,
79                });
80                return;
81            }
82
83            let stat = rtti::ast_node_as::<AstStatContinue>(node as *mut AstNode);
84            if !stat.is_null() {
85                LUAU_ASSERT!(!self.loops.is_empty());
86                if self.loops.last().unwrap().continue_used.is_null() {
87                    self.loops.last_mut().unwrap().continue_used = stat as *mut _;
88                }
89                self.close_locals(self.loops.last().unwrap().local_offset_continue);
90                let label = (*self.bytecode).emit_label();
91                (*self.bytecode).emit_ad(LuauOpcode::LOP_JUMP, 0, 0);
92                self.loop_jumps.push(crate::records::loop_jump::LoopJump {
93                    r#type: crate::enums::type_compiler::Type::Continue,
94                    label,
95                });
96                return;
97            }
98
99            let stat = rtti::ast_node_as::<AstStatReturn>(node as *mut AstNode);
100            if !stat.is_null() {
101                if self.options.optimization_level >= 2 && !self.inline_frames.is_empty() {
102                    self.compile_inline_return(stat, false);
103                } else {
104                    self.compile_stat_return(stat);
105                }
106                return;
107            }
108
109            let stat = rtti::ast_node_as::<luaur_ast::records::ast_stat_expr::AstStatExpr>(
110                node as *mut AstNode,
111            );
112            if !stat.is_null() {
113                let expr = rtti::ast_node_as::<luaur_ast::records::ast_expr_call::AstExprCall>(
114                    (*stat).expr as *mut AstNode,
115                );
116                if !expr.is_null() {
117                    self.compile_expr_call(expr, self.reg_top as u8, 0, false, false);
118                } else {
119                    self.compile_expr_side((*stat).expr);
120                }
121                return;
122            }
123
124            let stat = rtti::ast_node_as::<AstStatLocal>(node as *mut AstNode);
125            if !stat.is_null() {
126                if luaur_common::FFlag::LuauExportValueSyntax.get() {
127                    for i in 0..(*stat).vars.size {
128                        self.check_exported_local(
129                            *(*stat).vars.data.add(i),
130                            &(*stat).base.base.location,
131                        );
132                    }
133                }
134                self.compile_stat_local(stat);
135                return;
136            }
137
138            let stat = rtti::ast_node_as::<AstStatFor>(node as *mut AstNode);
139            if !stat.is_null() {
140                self.compile_stat_for(stat);
141                return;
142            }
143
144            let stat = rtti::ast_node_as::<AstStatForIn>(node as *mut AstNode);
145            if !stat.is_null() {
146                self.compile_stat_for_in(stat);
147                return;
148            }
149
150            let stat = rtti::ast_node_as::<AstStatAssign>(node as *mut AstNode);
151            if !stat.is_null() {
152                self.compile_stat_assign(stat);
153                return;
154            }
155
156            let stat = rtti::ast_node_as::<AstStatCompoundAssign>(node as *mut AstNode);
157            if !stat.is_null() {
158                self.compile_stat_compound_assign(stat);
159                return;
160            }
161
162            let stat = rtti::ast_node_as::<AstStatFunction>(node as *mut AstNode);
163            if !stat.is_null() {
164                self.compile_stat_function(stat);
165                return;
166            }
167
168            let stat = rtti::ast_node_as::<AstStatLocalFunction>(node as *mut AstNode);
169            if !stat.is_null() {
170                if luaur_common::FFlag::LuauExportValueSyntax.get() && (*(*stat).name).is_exported {
171                    self.check_exported_local((*stat).name, &(*stat).base.base.location);
172
173                    self.ensure_export_table(stat as *mut AstNode);
174
175                    let _rs = self.reg_scope_compiler();
176                    let var = self.alloc_reg(stat as *mut AstNode, 1);
177                    self.compile_expr_function((*stat).func, var);
178
179                    let name_ref =
180                        crate::functions::sref_compiler::sref_ast_name((*(*stat).name).name);
181                    let cid = (*self.bytecode).add_constant_string(name_ref);
182                    if cid < 0 {
183                        crate::records::compile_error::CompileError::raise(
184                            &(*(*stat).name).location,
185                            format_args!("Exceeded constant limit; simplify the code to compile"),
186                        );
187                    }
188
189                    let table_reg = self.get_export_table_reg(stat as *mut AstNode);
190                    (*self.bytecode).emit_abc(
191                        LuauOpcode::LOP_SETTABLEKS,
192                        var,
193                        table_reg,
194                        luaur_bytecode::methods::bytecode_builder_get_string_hash::bytecode_builder_get_string_hash(name_ref) as u8,
195                    );
196                    (*self.bytecode).emit_aux(cid as u32);
197                } else {
198                    // kDefaultAllocPc sentinel (push_local treats !0 as "use debugpc").
199                    let var = self.alloc_reg(stat as *mut AstNode, 1);
200
201                    self.push_local((*stat).name, var, !0u32);
202                    if luaur_common::FFlag::LuauExportValueSyntax.get() {
203                        self.check_exported_local((*stat).name, &(*stat).base.base.location);
204                    }
205                    self.compile_expr_function((*stat).func, var);
206
207                    // We *have* to pushLocal before compiling the function (it may refer
208                    // to the local as an upvalue), but that means the local's debugpc is
209                    // an instruction before its value is established; fix it up afterwards.
210                    let debugpc = (*self.bytecode).get_debug_pc();
211                    self.locals.get_or_insert((*stat).name).debugpc = debugpc;
212                }
213                return;
214            }
215
216            if luaur_common::FFlag::DebugLuauUserDefinedClasses.get() {
217                let stat = rtti::ast_node_as::<AstStatClass>(node as *mut AstNode);
218                if !stat.is_null() {
219                    self.compile_class_declaration(stat);
220                }
221            }
222        }
223    }
224}