Skip to main content

luaur_compiler/methods/
compiler_compile_stat_if.rs

1use 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}