Skip to main content

luaur_compiler/methods/
compiler_compile_class_declaration.rs

1use crate::records::compiler::Compiler;
2use alloc::vec::Vec;
3use luaur_ast::records::ast_stat_class::AstStatClass;
4use luaur_common::enums::luau_opcode::LuauOpcode;
5use luaur_common::macros::luau_assert::LUAU_ASSERT;
6use luaur_common::records::variant::Variant2;
7
8impl Compiler {
9    pub fn compile_class_declaration(&mut self, decl: *mut AstStatClass) {
10        let dest = self.alloc_reg(decl as *mut _, 1);
11        self.push_local(unsafe { (*decl).name }, dest, !0u32);
12        // C++ `RegScope _(this)` after pushLocal: reclaims the transient `temp` register on
13        // scope exit so it doesn't leak past the declaration (the port had dropped this).
14        let _rs = self.reg_scope_compiler();
15        unsafe {
16            (*self.bytecode).emit_ad(LuauOpcode::LOP_LOADKX, dest, 0);
17            let aux_offset = (*self.bytecode).emit_label();
18            (*self.bytecode).emit_aux(0xDEADBEEF);
19            // C++ builds `shape.className`/`propertyNames`/`methodNames` directly; the port
20            // collected names into throwaway vecs and stored an empty default shape, so every
21            // class constant dumped `(props: 0, methods: 0)`.
22            let mut shape = luaur_bytecode::records::class_shape::ClassShape::default();
23            let class_name = (*(*decl).name).name;
24            let class_name_cid = (*self.bytecode)
25                .add_constant_string(crate::functions::sref_compiler::sref_ast_name(class_name));
26            self.check_constant(class_name_cid, &(*(*decl).name).location);
27            shape.className = class_name_cid;
28            let temp = self.alloc_reg(decl as *mut _, 1);
29            for member in (*decl).members.as_slice() {
30                match member {
31                    Variant2::V0(prop) => {
32                        let cid = (*self.bytecode).add_constant_string(
33                            crate::functions::sref_compiler::sref_ast_name(prop.name),
34                        );
35                        self.check_constant(cid, &prop.name_location);
36                        shape.propertyNames.push(cid);
37                    }
38                    Variant2::V1(method) => {
39                        self.compile_expr_function(method.function, temp);
40                        let cid = (*self.bytecode).add_constant_string(
41                            crate::functions::sref_compiler::sref_ast_name(method.function_name),
42                        );
43                        self.check_constant(cid, &(*method.function).base.base.location);
44                        shape.methodNames.push(cid);
45                        (*self.bytecode).emit_abc(LuauOpcode::LOP_NEWCLASSMEMBER, dest, 0, temp);
46                        (*self.bytecode).emit_aux(cid as u32);
47                    }
48                }
49            }
50            let class_const = (*self.bytecode).add_class_shape(shape);
51            self.check_constant(class_const, &(*decl).base.base.location);
52            (*self.bytecode).patch_aux(aux_offset, class_const);
53            if luaur_common::FFlag::LuauExportValueSyntax.get() && (*decl).exported {
54                self.exported_classes.push((class_name, dest));
55            }
56        }
57    }
58}