Skip to main content

luaur_compiler/methods/
compiler_compile_l_value_use.rs

1use crate::enums::kind::Kind;
2use crate::records::compile_error::CompileError;
3use crate::records::compiler::Compiler;
4use crate::records::l_value::LValue;
5use luaur_ast::records::ast_expr::AstExpr;
6use luaur_ast::records::ast_expr_index_expr::AstExprIndexExpr;
7use luaur_ast::records::ast_expr_index_name::AstExprIndexName;
8use luaur_ast::records::ast_node::AstNode;
9use luaur_bytecode::methods::bytecode_builder_get_string_hash::bytecode_builder_get_string_hash;
10use luaur_common::enums::luau_bytecode_type::LBC_TYPE_TABLE;
11use luaur_common::enums::luau_opcode::LuauOpcode;
12use luaur_common::macros::luau_assert::LUAU_ASSERT;
13
14impl Compiler {
15    pub fn compile_l_value_use(
16        &mut self,
17        lv: &LValue,
18        reg: u8,
19        set: bool,
20        target_expr: *mut AstExpr,
21    ) {
22        // C++ `compileLValueUse` opens with `setDebugLine(lv.location)` so the store/load
23        // instruction is attributed to the index's own location (e.g. the `["d"]` line of
24        // `a["b"]["c"]["d"] = 4`), not whatever line was set while compiling the lvalue base.
25        self.set_debug_line_location(&lv.location);
26        unsafe {
27            match lv.kind {
28                Kind::Kind_Local => {
29                    if set {
30                        (*self.bytecode).emit_abc(LuauOpcode::LOP_MOVE, lv.reg, reg, 0);
31                    } else {
32                        (*self.bytecode).emit_abc(LuauOpcode::LOP_MOVE, reg, lv.reg, 0);
33                    }
34                }
35                Kind::Kind_Upvalue => {
36                    if set {
37                        (*self.bytecode).emit_abc(LuauOpcode::LOP_SETUPVAL, reg, lv.upval, 0);
38                    } else {
39                        (*self.bytecode).emit_abc(LuauOpcode::LOP_GETUPVAL, reg, lv.upval, 0);
40                    }
41                }
42                Kind::Kind_Global => {
43                    let cid = (*self.bytecode).add_constant_string(lv.name);
44                    if cid < 0 {
45                        CompileError::raise(
46                            &lv.location,
47                            format_args!("Exceeded constant limit; simplify the code to compile"),
48                        );
49                    }
50
51                    let hash = bytecode_builder_get_string_hash(lv.name) as u8;
52                    if set {
53                        (*self.bytecode).emit_abc(LuauOpcode::LOP_SETGLOBAL, reg, 0, hash);
54                    } else {
55                        (*self.bytecode).emit_abc(LuauOpcode::LOP_GETGLOBAL, reg, 0, hash);
56                    }
57                    (*self.bytecode).emit_aux(cid as u32);
58                }
59                Kind::Kind_IndexName => {
60                    let cid = (*self.bytecode).add_constant_string(lv.name);
61                    if cid < 0 {
62                        CompileError::raise(
63                            &lv.location,
64                            format_args!("Exceeded constant limit; simplify the code to compile"),
65                        );
66                    }
67
68                    let hash = bytecode_builder_get_string_hash(lv.name) as u8;
69                    if set {
70                        (*self.bytecode).emit_abc(LuauOpcode::LOP_SETTABLEKS, reg, lv.reg, hash);
71                    } else {
72                        (*self.bytecode).emit_abc(LuauOpcode::LOP_GETTABLEKS, reg, lv.reg, hash);
73                    }
74                    (*self.bytecode).emit_aux(cid as u32);
75
76                    if !target_expr.is_null() {
77                        let target_expr_index_name = luaur_ast::rtti::ast_node_as::<AstExprIndexName>(
78                            target_expr as *mut AstNode,
79                        );
80                        if !target_expr_index_name.is_null() {
81                            self.hint_temporary_expr_reg_type(
82                                (*target_expr_index_name).expr,
83                                lv.reg as i32,
84                                LBC_TYPE_TABLE,
85                                2,
86                            );
87                        }
88                    }
89                }
90                Kind::Kind_IndexNumber => {
91                    if set {
92                        (*self.bytecode).emit_abc(
93                            LuauOpcode::LOP_SETTABLEN,
94                            reg,
95                            lv.reg,
96                            lv.number,
97                        );
98                    } else {
99                        (*self.bytecode).emit_abc(
100                            LuauOpcode::LOP_GETTABLEN,
101                            reg,
102                            lv.reg,
103                            lv.number,
104                        );
105                    }
106
107                    if !target_expr.is_null() {
108                        let target_expr_index_expr = luaur_ast::rtti::ast_node_as::<AstExprIndexExpr>(
109                            target_expr as *mut AstNode,
110                        );
111                        if !target_expr_index_expr.is_null() {
112                            self.hint_temporary_expr_reg_type(
113                                (*target_expr_index_expr).expr,
114                                lv.reg as i32,
115                                LBC_TYPE_TABLE,
116                                1,
117                            );
118                        }
119                    }
120                }
121                Kind::Kind_IndexExpr => {
122                    if set {
123                        (*self.bytecode).emit_abc(LuauOpcode::LOP_SETTABLE, reg, lv.reg, lv.index);
124                    } else {
125                        (*self.bytecode).emit_abc(LuauOpcode::LOP_GETTABLE, reg, lv.reg, lv.index);
126                    }
127
128                    if !target_expr.is_null() {
129                        let target_expr_index_expr = luaur_ast::rtti::ast_node_as::<AstExprIndexExpr>(
130                            target_expr as *mut AstNode,
131                        );
132                        if !target_expr_index_expr.is_null() {
133                            self.hint_temporary_expr_reg_type(
134                                (*target_expr_index_expr).expr,
135                                lv.reg as i32,
136                                LBC_TYPE_TABLE,
137                                1,
138                            );
139                            self.hint_temporary_expr_reg_type(
140                                (*target_expr_index_expr).index,
141                                lv.index as i32,
142                                luaur_common::enums::luau_bytecode_type::LBC_TYPE_NUMBER,
143                                1,
144                            );
145                        }
146                    }
147                }
148                _ => LUAU_ASSERT!(false),
149            }
150        }
151    }
152}