luaur_compiler/methods/
compiler_compile_stat_if.rs1use crate::enums::type_compiler::Type;
2use crate::records::compiler::Compiler;
3use crate::records::loop_jump::LoopJump;
4use luaur_ast::records::ast_expr_binary::AstExprBinary;
5use luaur_ast::records::ast_expr_binary::AstExprBinary_Op;
6use luaur_ast::records::ast_stat::AstStat;
7use luaur_ast::records::ast_stat_block::AstStatBlock;
8use luaur_ast::records::ast_stat_continue::AstStatContinue;
9use luaur_ast::records::ast_stat_if::AstStatIf;
10use luaur_ast::rtti::ast_node_as;
11use luaur_common::enums::luau_opcode::LuauOpcode;
12
13impl Compiler {
14 pub fn compile_stat_if(&mut self, stat: *mut AstStatIf) {
15 unsafe {
16 let stat = &*stat;
17
18 if self.is_constant_false(stat.condition) {
19 if !stat.elsebody.is_null() {
20 self.compile_stat(stat.elsebody);
21 }
22 return;
23 }
24
25 let cand = ast_node_as::<AstExprBinary>(
26 stat.condition as *mut luaur_ast::records::ast_node::AstNode,
27 );
28 if !cand.is_null() {
29 let cand = &*cand;
30 if cand.op == AstExprBinary_Op::And && self.is_constant_false(cand.right) {
31 self.compile_expr_side(cand.left);
32 if !stat.elsebody.is_null() {
33 self.compile_stat(stat.elsebody);
34 }
35 return;
36 }
37 }
38
39 if stat.elsebody.is_null()
40 && self.is_stat_break(stat.thenbody as *mut AstStat)
41 && !self.are_locals_captured(self.loops.last().unwrap().local_offset)
42 {
43 let mut else_jump = Vec::new();
44 self.compile_condition_value(
45 stat.condition,
46 core::ptr::null(),
47 &mut else_jump,
48 true,
49 );
50 for jump in else_jump {
51 self.loop_jumps.push(LoopJump {
52 r#type: Type::Break,
53 label: jump,
54 });
55 }
56 return;
57 }
58
59 let continue_statement = self.extract_stat_continue(stat.thenbody as *mut AstStatBlock);
60 if stat.elsebody.is_null()
61 && !continue_statement.is_null()
62 && !self.are_locals_captured(self.loops.last().unwrap().local_offset_continue)
63 {
64 if self.loops.last().unwrap().continue_used.is_null() {
65 self.loops.last_mut().unwrap().continue_used = continue_statement;
66 }
67 let mut else_jump = Vec::new();
68 self.compile_condition_value(
69 stat.condition,
70 core::ptr::null(),
71 &mut else_jump,
72 true,
73 );
74 for jump in else_jump {
75 self.loop_jumps.push(LoopJump {
76 r#type: Type::Continue,
77 label: jump,
78 });
79 }
80 return;
81 }
82
83 let mut else_jump = Vec::new();
84 self.compile_condition_value(stat.condition, core::ptr::null(), &mut else_jump, false);
85 self.compile_stat(stat.thenbody as *mut AstStat);
86
87 if !stat.elsebody.is_null() && !else_jump.is_empty() {
88 if self.always_terminates(stat.thenbody as *mut AstStat) {
89 let else_label = unsafe { (*self.bytecode).emit_label() };
90 self.compile_stat(stat.elsebody);
91 self.patch_jumps(
92 stat as *const AstStatIf as *mut luaur_ast::records::ast_node::AstNode,
93 &mut else_jump,
94 else_label,
95 );
96 } else {
97 let then_label = unsafe { (*self.bytecode).emit_label() };
98 unsafe { (*self.bytecode).emit_ad(LuauOpcode::LOP_JUMP, 0, 0) };
99 let else_label = unsafe { (*self.bytecode).emit_label() };
100 self.compile_stat(stat.elsebody);
101 let end_label = unsafe { (*self.bytecode).emit_label() };
102 self.patch_jumps(
103 stat as *const AstStatIf as *mut luaur_ast::records::ast_node::AstNode,
104 &mut else_jump,
105 else_label,
106 );
107 self.patch_jump(
108 stat as *const AstStatIf as *mut luaur_ast::records::ast_node::AstNode,
109 then_label,
110 end_label,
111 );
112 }
113 } else {
114 let end_label = unsafe { (*self.bytecode).emit_label() };
115 self.patch_jumps(
116 stat as *const AstStatIf as *mut luaur_ast::records::ast_node::AstNode,
117 &mut else_jump,
118 end_label,
119 );
120 }
121 }
122 }
123}