Skip to main content

luaur_compiler/methods/
compiler_compile_condition_value.rs

1use crate::enums::type_constant_folding::Type;
2use crate::records::compiler::Compiler;
3use crate::records::constant::Constant;
4use crate::records::reg_scope::RegScope;
5use luaur_ast::records::ast_expr::AstExpr;
6use luaur_ast::records::ast_expr_binary::{AstExprBinary, AstExprBinaryOp};
7use luaur_ast::records::ast_expr_group::AstExprGroup;
8use luaur_ast::records::ast_expr_unary::{AstExprUnary, AstExprUnaryOp};
9use luaur_ast::rtti;
10use luaur_common::enums::luau_opcode::LuauOpcode;
11
12impl Compiler {
13    pub fn compile_condition_value(
14        &mut self,
15        node: *mut AstExpr,
16        target: *const u8,
17        skip_jump: &mut Vec<usize>,
18        only_truth: bool,
19    ) {
20        if let Some(cv) = self.constants.find(&node) {
21            if cv.r#type != Type::Type_Unknown {
22                if cv.is_truthful() == only_truth {
23                    if !target.is_null() {
24                        self.compile_expr_temp(node, unsafe { *target });
25                    }
26                    skip_jump.push(unsafe { (*self.bytecode).emit_label() });
27                    unsafe {
28                        (*self.bytecode).emit_ad(LuauOpcode::LOP_JUMP, 0, 0);
29                    }
30                }
31                return;
32            }
33        }
34
35        let expr = unsafe { rtti::ast_node_as::<AstExprBinary>(node as *mut _) };
36        if !expr.is_null() {
37            match unsafe { (*expr).op } {
38                AstExprBinaryOp::And | AstExprBinaryOp::Or => {
39                    if only_truth == (unsafe { (*expr).op } == AstExprBinaryOp::And) {
40                        let mut else_jump = Vec::new();
41                        self.compile_condition_value(
42                            unsafe { (*expr).left },
43                            core::ptr::null(),
44                            &mut else_jump,
45                            !only_truth,
46                        );
47                        self.compile_condition_value(
48                            unsafe { (*expr).right },
49                            target,
50                            skip_jump,
51                            only_truth,
52                        );
53                        let else_label = unsafe { (*self.bytecode).emit_label() };
54                        self.patch_jumps(node as *mut _, &mut else_jump, else_label);
55                    } else {
56                        self.compile_condition_value(
57                            unsafe { (*expr).left },
58                            target,
59                            skip_jump,
60                            only_truth,
61                        );
62                        self.compile_condition_value(
63                            unsafe { (*expr).right },
64                            target,
65                            skip_jump,
66                            only_truth,
67                        );
68                    }
69                    return;
70                }
71                AstExprBinaryOp::CompareNe
72                | AstExprBinaryOp::CompareEq
73                | AstExprBinaryOp::CompareLt
74                | AstExprBinaryOp::CompareLe
75                | AstExprBinaryOp::CompareGt
76                | AstExprBinaryOp::CompareGe => {
77                    if !target.is_null() {
78                        unsafe {
79                            (*self.bytecode).emit_abc(
80                                LuauOpcode::LOP_LOADB,
81                                *target,
82                                if only_truth { 1 } else { 0 },
83                                0,
84                            );
85                        }
86                    }
87                    let jump_label = self.compile_compare_jump(expr, !only_truth);
88                    skip_jump.push(jump_label);
89                    return;
90                }
91                _ => {}
92            }
93        }
94
95        let expr = unsafe { rtti::ast_node_as::<AstExprUnary>(node as *mut _) };
96        if !expr.is_null() {
97            if target.is_null() && unsafe { (*expr).op } == AstExprUnaryOp::Not {
98                self.compile_condition_value(
99                    unsafe { (*expr).expr },
100                    target,
101                    skip_jump,
102                    !only_truth,
103                );
104                return;
105            }
106        }
107
108        let expr = unsafe { rtti::ast_node_as::<AstExprGroup>(node as *mut _) };
109        if !expr.is_null() {
110            self.compile_condition_value(unsafe { (*expr).expr }, target, skip_jump, only_truth);
111            return;
112        }
113
114        let mut rs = self.reg_scope_compiler();
115        let reg = if !target.is_null() {
116            unsafe {
117                self.compile_expr_temp(node, *target);
118                *target
119            }
120        } else {
121            self.compile_expr_auto(node, &mut rs)
122        };
123
124        skip_jump.push(unsafe { (*self.bytecode).emit_label() });
125        unsafe {
126            (*self.bytecode).emit_ad(
127                if only_truth {
128                    LuauOpcode::LOP_JUMPIF
129                } else {
130                    LuauOpcode::LOP_JUMPIFNOT
131                },
132                reg,
133                0,
134            );
135        }
136    }
137}