Skip to main content

luaur_compiler/methods/
compiler_compile_expr_select_vararg.rs

1use crate::records::compile_error::CompileError;
2use crate::records::compiler::Compiler;
3use luaur_ast::records::ast_expr::AstExpr;
4use luaur_ast::records::ast_expr_call::AstExprCall;
5use luaur_ast::records::ast_expr_varargs::AstExprVarargs;
6use luaur_ast::records::ast_node::AstNode;
7use luaur_ast::rtti;
8use luaur_common::enums::luau_opcode::LuauOpcode;
9use luaur_common::macros::luau_assert::LUAU_ASSERT;
10
11impl Compiler {
12    pub fn compile_expr_select_vararg(
13        &mut self,
14        expr: *mut AstExprCall,
15        target: u8,
16        target_count: u8,
17        target_top: bool,
18        mult_ret: bool,
19        regs: u8,
20    ) {
21        LUAU_ASSERT!(target_count == 1);
22        let expr_ref = unsafe { &*expr };
23        LUAU_ASSERT!(!expr_ref.self_);
24        LUAU_ASSERT!(expr_ref.args.size == 2);
25        let arg = unsafe { *expr_ref.args.data.add(0) };
26        let arg_varargs = unsafe { *expr_ref.args.data.add(1) };
27        LUAU_ASSERT!(
28            !unsafe { rtti::ast_node_as::<AstExprVarargs>(arg_varargs as *mut AstNode) }.is_null()
29        );
30
31        let argreg: u8;
32        let reg = self.get_expr_local_reg(arg);
33        if reg >= 0 {
34            argreg = reg as u8;
35        } else {
36            argreg = regs + 1;
37            self.compile_expr_temp_top(arg, argreg);
38        }
39
40        let fastcall_label = unsafe { (*self.bytecode).emit_label() };
41
42        unsafe {
43            (*self.bytecode).emit_abc(
44                LuauOpcode::LOP_FASTCALL1,
45                luaur_common::enums::luau_builtin_function::LuauBuiltinFunction::LBF_SELECT_VARARG
46                    as u8,
47                argreg,
48                0,
49            );
50        }
51
52        self.compile_expr_temp(expr_ref.func, regs);
53
54        if argreg != regs + 1 {
55            unsafe {
56                (*self.bytecode).emit_abc(LuauOpcode::LOP_MOVE, regs + 1, argreg, 0);
57            }
58        }
59
60        unsafe {
61            (*self.bytecode).emit_abc(LuauOpcode::LOP_GETVARARGS, regs + 2, 0, 0);
62        }
63
64        let call_label = unsafe { (*self.bytecode).emit_label() };
65        if !unsafe { (*self.bytecode).patch_skip_c(fastcall_label, call_label) } {
66            CompileError::raise(
67                unsafe { &(*expr_ref.func).base.location },
68                core::format_args!("Exceeded jump distance limit; simplify the code to compile"),
69            );
70        }
71
72        unsafe {
73            (*self.bytecode).emit_abc(
74                LuauOpcode::LOP_CALL,
75                regs,
76                0,
77                if mult_ret { 0 } else { target_count + 1 },
78            );
79        }
80
81        if !target_top {
82            for i in 0..target_count {
83                unsafe {
84                    (*self.bytecode).emit_abc(LuauOpcode::LOP_MOVE, target + i, regs + i, 0);
85                }
86            }
87        }
88    }
89}