Skip to main content

luaur_compiler/methods/
compiler_compile_compare_jump.rs

1use crate::enums::type_constant_folding::Type;
2use crate::functions::sref_compiler::sref_ast_name;
3use crate::records::compile_error::CompileError;
4use crate::records::compiler::Compiler;
5use crate::records::constant::Constant;
6use luaur_ast::records::ast_expr_binary::{AstExprBinary, AstExprBinaryOp};
7use luaur_common::enums::luau_opcode::LuauOpcode;
8use luaur_common::macros::luau_assert::LUAU_ASSERT;
9
10impl Compiler {
11    pub fn compile_compare_jump(&mut self, expr: *mut AstExprBinary, not_: bool) -> usize {
12        unsafe {
13            let expr_ref = &*expr;
14            let mut left = expr_ref.left;
15            let mut right = expr_ref.right;
16            let is_eq = expr_ref.op == AstExprBinaryOp::CompareEq
17                || expr_ref.op == AstExprBinaryOp::CompareNe;
18
19            let mut operand_is_constant = self.is_constant(right);
20            if is_eq && !operand_is_constant {
21                operand_is_constant = self.is_constant(left);
22                if operand_is_constant {
23                    core::mem::swap(&mut left, &mut right);
24                }
25            }
26
27            if operand_is_constant
28                && (self.is_constant_vector(right) || self.is_constant_integer(right))
29            {
30                operand_is_constant = false;
31            }
32
33            let mut rs = self.reg_scope_compiler();
34            let rl = self.compile_expr_auto(left, &mut rs);
35
36            if is_eq && operand_is_constant {
37                let cv = self.get_constant(right);
38                LUAU_ASSERT!(cv.r#type != Type::Type_Unknown);
39
40                let (opc, cid_val) = match cv.r#type {
41                    Type::Type_Nil => (LuauOpcode::LOP_JUMPXEQKNIL, 0),
42                    Type::Type_Boolean => (LuauOpcode::LOP_JUMPXEQKB, cv.data.value_boolean as i32),
43                    Type::Type_Number => {
44                        (LuauOpcode::LOP_JUMPXEQKN, self.get_constant_index(right))
45                    }
46                    Type::Type_String => {
47                        (LuauOpcode::LOP_JUMPXEQKS, self.get_constant_index(right))
48                    }
49                    _ => {
50                        LUAU_ASSERT!(false);
51                        (LuauOpcode::LOP_NOP, 0)
52                    }
53                };
54
55                if cid_val < 0 {
56                    CompileError::raise(
57                        &expr_ref.base.base.location,
58                        format_args!("Exceeded constant limit; simplify the code to compile"),
59                    );
60                }
61
62                let jump_label = (*self.bytecode).emit_label();
63                let flip = if (expr_ref.op == AstExprBinaryOp::CompareEq) == not_ {
64                    0x80000000
65                } else {
66                    0
67                };
68
69                (*self.bytecode).emit_ad(opc, rl, 0);
70                (*self.bytecode).emit_aux((cid_val as u32) | flip);
71
72                jump_label
73            } else {
74                let opc = self.get_jump_op_compare(expr_ref.op, not_);
75                let rr = self.compile_expr_auto(right, &mut rs);
76                let jump_label = (*self.bytecode).emit_label();
77
78                if expr_ref.op == AstExprBinaryOp::CompareGt
79                    || expr_ref.op == AstExprBinaryOp::CompareGe
80                {
81                    (*self.bytecode).emit_ad(opc, rr, 0);
82                    (*self.bytecode).emit_aux(rl as u32);
83                } else {
84                    (*self.bytecode).emit_ad(opc, rl, 0);
85                    (*self.bytecode).emit_aux(rr as u32);
86                }
87                jump_label
88            }
89        }
90    }
91}