luaur_compiler/methods/
compiler_compile_condition_value.rs1use 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}