Skip to main content

luaur_compiler/methods/
compiler_compile_expr.rs

1use crate::enums::type_constant_folding::Type;
2use crate::functions::sref_compiler::sref_ast_name;
3use crate::functions::sref_compiler_alt_c::sref_ast_array_c_char;
4use crate::records::compile_error::CompileError;
5use crate::records::compiler::Compiler;
6use luaur_ast::records::ast_expr::AstExpr;
7use luaur_ast::records::ast_expr_binary::AstExprBinary;
8use luaur_ast::records::ast_expr_call::AstExprCall;
9use luaur_ast::records::ast_expr_constant_bool::AstExprConstantBool;
10use luaur_ast::records::ast_expr_constant_integer::AstExprConstantInteger;
11use luaur_ast::records::ast_expr_constant_nil::AstExprConstantNil;
12use luaur_ast::records::ast_expr_constant_number::AstExprConstantNumber;
13use luaur_ast::records::ast_expr_constant_string::AstExprConstantString;
14use luaur_ast::records::ast_expr_function::AstExprFunction;
15use luaur_ast::records::ast_expr_global::AstExprGlobal;
16use luaur_ast::records::ast_expr_group::AstExprGroup;
17use luaur_ast::records::ast_expr_if_else::AstExprIfElse;
18use luaur_ast::records::ast_expr_index_expr::AstExprIndexExpr;
19use luaur_ast::records::ast_expr_index_name::AstExprIndexName;
20use luaur_ast::records::ast_expr_instantiate::AstExprInstantiate;
21use luaur_ast::records::ast_expr_interp_string::AstExprInterpString;
22use luaur_ast::records::ast_expr_local::AstExprLocal;
23use luaur_ast::records::ast_expr_table::AstExprTable;
24use luaur_ast::records::ast_expr_type_assertion::AstExprTypeAssertion;
25use luaur_ast::records::ast_expr_unary::AstExprUnary;
26use luaur_ast::records::ast_expr_varargs::AstExprVarargs;
27use luaur_ast::records::ast_node::AstNode;
28use luaur_bytecode::methods::bytecode_builder_get_string_hash::bytecode_builder_get_string_hash;
29use luaur_common::enums::luau_opcode::LuauOpcode;
30use luaur_common::macros::luau_assert::LUAU_ASSERT;
31
32impl Compiler {
33    pub fn compile_expr(&mut self, node: *mut AstExpr, target: u8, target_temp: bool) {
34        self.set_debug_line_ast_node(node as *mut AstNode);
35
36        unsafe {
37            if self.options.coverage_level >= 2 && self.needs_coverage(node as *mut AstNode) {
38                (*self.bytecode).emit_abc(LuauOpcode::LOP_COVERAGE, 0, 0, 0);
39            }
40
41            if let Some(cv) = self.constants.find(&node) {
42                if cv.r#type != Type::Type_Unknown {
43                    let cv = *cv;
44                    self.compile_expr_constant(node, &cv, target);
45                    return;
46                }
47            }
48
49            let expr_group = luaur_ast::rtti::ast_node_as::<AstExprGroup>(node as *mut AstNode);
50            if !expr_group.is_null() {
51                self.compile_expr((*expr_group).expr, target, target_temp);
52                return;
53            }
54
55            if luaur_ast::rtti::ast_node_is::<AstExprConstantNil>(&*(node as *mut AstNode)) {
56                (*self.bytecode).emit_abc(LuauOpcode::LOP_LOADNIL, target, 0, 0);
57                return;
58            }
59
60            let expr_bool =
61                luaur_ast::rtti::ast_node_as::<AstExprConstantBool>(node as *mut AstNode);
62            if !expr_bool.is_null() {
63                (*self.bytecode).emit_abc(
64                    LuauOpcode::LOP_LOADB,
65                    target,
66                    (*expr_bool).value as u8,
67                    0,
68                );
69                return;
70            }
71
72            let expr_number =
73                luaur_ast::rtti::ast_node_as::<AstExprConstantNumber>(node as *mut AstNode);
74            if !expr_number.is_null() {
75                let cid = (*self.bytecode).add_constant_number((*expr_number).value);
76                if cid < 0 {
77                    CompileError::raise(
78                        &(*expr_number).base.base.location,
79                        format_args!("Exceeded constant limit; simplify the code to compile"),
80                    );
81                }
82                self.emit_load_k(target, cid);
83                return;
84            }
85
86            let expr_integer =
87                luaur_ast::rtti::ast_node_as::<AstExprConstantInteger>(node as *mut AstNode);
88            if !expr_integer.is_null() {
89                let cid = (*self.bytecode).add_constant_integer((*expr_integer).value);
90                if cid < 0 {
91                    CompileError::raise(
92                        &(*expr_integer).base.base.location,
93                        format_args!("Exceeded constant limit; simplify the code to compile"),
94                    );
95                }
96                self.emit_load_k(target, cid);
97                return;
98            }
99
100            let expr_string =
101                luaur_ast::rtti::ast_node_as::<AstExprConstantString>(node as *mut AstNode);
102            if !expr_string.is_null() {
103                let cid = (*self.bytecode)
104                    .add_constant_string(sref_ast_array_c_char((*expr_string).value));
105                if cid < 0 {
106                    CompileError::raise(
107                        &(*expr_string).base.base.location,
108                        format_args!("Exceeded constant limit; simplify the code to compile"),
109                    );
110                }
111                self.emit_load_k(target, cid);
112                return;
113            }
114
115            let expr_local = luaur_ast::rtti::ast_node_as::<AstExprLocal>(node as *mut AstNode);
116            if !expr_local.is_null() {
117                if luaur_common::FFlag::LuauExportValueSyntax.get()
118                    && (*(*expr_local).local).is_exported
119                {
120                    let table_reg = self.get_export_table_reg(node as *mut AstNode);
121                    let name = sref_ast_name((*(*expr_local).local).name);
122                    let cid = (*self.bytecode).add_constant_string(name);
123                    if cid < 0 {
124                        CompileError::raise(
125                            &(*expr_local).base.base.location,
126                            format_args!("Exceeded constant limit; simplify the code to compile"),
127                        );
128                    }
129                    (*self.bytecode).emit_abc(
130                        LuauOpcode::LOP_GETTABLEKS,
131                        target,
132                        table_reg,
133                        bytecode_builder_get_string_hash(name) as u8,
134                    );
135                    (*self.bytecode).emit_aux(cid as u32);
136                } else {
137                    let reg = self.get_expr_local_reg(node);
138                    if reg >= 0 {
139                        if self.options.optimization_level == 0 || target != reg as u8 {
140                            (*self.bytecode).emit_abc(LuauOpcode::LOP_MOVE, target, reg as u8, 0);
141                        }
142                    } else {
143                        LUAU_ASSERT!((*expr_local).upvalue);
144                        let uid = self.get_upval((*expr_local).local);
145                        (*self.bytecode).emit_abc(LuauOpcode::LOP_GETUPVAL, target, uid, 0);
146                    }
147                }
148                return;
149            }
150
151            let expr_global = luaur_ast::rtti::ast_node_as::<AstExprGlobal>(node as *mut AstNode);
152            if !expr_global.is_null() {
153                self.compile_expr_global(expr_global, target);
154                return;
155            }
156
157            let expr_varargs = luaur_ast::rtti::ast_node_as::<AstExprVarargs>(node as *mut AstNode);
158            if !expr_varargs.is_null() {
159                self.compile_expr_varargs(expr_varargs, target, 1, false);
160                return;
161            }
162
163            let expr_call = luaur_ast::rtti::ast_node_as::<AstExprCall>(node as *mut AstNode);
164            if !expr_call.is_null() {
165                if target_temp && self.reg_top != 0 && u32::from(target) == self.reg_top - 1 {
166                    self.compile_expr_call(expr_call, target, 1, true, false);
167                } else {
168                    self.compile_expr_call(expr_call, target, 1, false, false);
169                }
170                return;
171            }
172
173            let expr_index_name =
174                luaur_ast::rtti::ast_node_as::<AstExprIndexName>(node as *mut AstNode);
175            if !expr_index_name.is_null() {
176                self.compile_expr_index_name(expr_index_name, target, target_temp);
177                return;
178            }
179
180            let expr_index_expr =
181                luaur_ast::rtti::ast_node_as::<AstExprIndexExpr>(node as *mut AstNode);
182            if !expr_index_expr.is_null() {
183                self.compile_expr_index_expr(expr_index_expr, target);
184                return;
185            }
186
187            let expr_function =
188                luaur_ast::rtti::ast_node_as::<AstExprFunction>(node as *mut AstNode);
189            if !expr_function.is_null() {
190                self.compile_expr_function(expr_function, target);
191                return;
192            }
193
194            let expr_table = luaur_ast::rtti::ast_node_as::<AstExprTable>(node as *mut AstNode);
195            if !expr_table.is_null() {
196                self.compile_expr_table(expr_table, target, target_temp);
197                return;
198            }
199
200            let expr_unary = luaur_ast::rtti::ast_node_as::<AstExprUnary>(node as *mut AstNode);
201            if !expr_unary.is_null() {
202                self.compile_expr_unary(expr_unary, target);
203                return;
204            }
205
206            let expr_binary = luaur_ast::rtti::ast_node_as::<AstExprBinary>(node as *mut AstNode);
207            if !expr_binary.is_null() {
208                self.compile_expr_binary(expr_binary, target, target_temp);
209                return;
210            }
211
212            let expr_assertion =
213                luaur_ast::rtti::ast_node_as::<AstExprTypeAssertion>(node as *mut AstNode);
214            if !expr_assertion.is_null() {
215                self.compile_expr((*expr_assertion).expr, target, target_temp);
216                return;
217            }
218
219            let expr_if_else = luaur_ast::rtti::ast_node_as::<AstExprIfElse>(node as *mut AstNode);
220            if !expr_if_else.is_null() {
221                self.compile_expr_if_else(expr_if_else, target, target_temp);
222                return;
223            }
224
225            let interp_string =
226                luaur_ast::rtti::ast_node_as::<AstExprInterpString>(node as *mut AstNode);
227            if !interp_string.is_null() {
228                self.compile_expr_interp_string(interp_string, target, target_temp);
229                return;
230            }
231
232            let expr_instantiate =
233                luaur_ast::rtti::ast_node_as::<AstExprInstantiate>(node as *mut AstNode);
234            if !expr_instantiate.is_null() {
235                self.compile_expr((*expr_instantiate).expr, target, target_temp);
236                return;
237            }
238        }
239
240        LUAU_ASSERT!(false);
241    }
242}