luaur-compiler 0.1.3

Luau source-to-bytecode compiler (Rust).
Documentation
use crate::enums::type_compiler::Type;
use crate::records::compiler::Compiler;
use crate::records::loop_jump::LoopJump;
use crate::records::reg_scope::RegScope;
use luaur_ast::records::ast_expr::AstExpr;
use luaur_ast::records::ast_node::AstNode;
use luaur_ast::records::ast_stat::AstStat;
use luaur_ast::records::ast_stat_block::AstStatBlock;
use luaur_ast::records::ast_stat_repeat::AstStatRepeat;
use luaur_bytecode::records::bytecode_builder::BytecodeBuilder;
use luaur_common::enums::luau_opcode::LuauOpcode;

impl Compiler {
    pub fn compile_stat_repeat(&mut self, stat: *mut AstStatRepeat) {
        unsafe {
            let stat_ref = &*stat;

            let old_jumps = self.loop_jumps.len();
            let old_locals = self.local_stack.len();

            self.loops.push(crate::records::r#loop::Loop {
                local_offset: old_locals,
                local_offset_continue: old_locals,
                continue_used: core::ptr::null_mut(),
            });
            self.has_loops = true;

            let loop_label = (*self.bytecode).emit_label();

            let body = stat_ref.body;

            let mut rs = RegScope {
                self_: self as *mut Compiler,
                old_top: self.reg_top,
            };

            let mut continue_validated = false;
            let mut condition_locals = 0;

            for i in 0..(*body).body.size {
                self.compile_stat(unsafe { *(*body).body.data.add(i as usize) });

                self.loops.last_mut().unwrap().local_offset_continue = self.local_stack.len();

                if !self.loops.last().unwrap().continue_used.is_null() && !continue_validated {
                    self.validate_continue_until(
                        self.loops.last().unwrap().continue_used as *mut AstStat,
                        stat_ref.condition,
                        body,
                        (i + 1) as usize,
                    );
                    continue_validated = true;
                    condition_locals = self.local_stack.len();
                }
            }

            if continue_validated {
                self.set_debug_line_end(unsafe {
                    *(*body).body.data.add(((*body).body.size - 1) as usize) as *mut AstNode
                });

                self.close_locals(condition_locals);
                self.pop_locals(condition_locals);
            }

            let cont_label = (*self.bytecode).emit_label();

            let end_label;

            self.set_debug_line_ast_node(stat_ref.condition as *mut AstNode);

            if self.is_constant_true(stat_ref.condition) {
                self.close_locals(old_locals);

                end_label = (*self.bytecode).emit_label();
            } else {
                let mut skip_jump = Vec::new();
                self.compile_condition_value(
                    stat_ref.condition,
                    core::ptr::null(),
                    &mut skip_jump,
                    true,
                );

                self.close_locals(old_locals);

                let back_label = (*self.bytecode).emit_label();

                (*self.bytecode).emit_ad(LuauOpcode::LOP_JUMPBACK, 0, 0);

                let skip_label = (*self.bytecode).emit_label();

                self.close_locals(old_locals);

                end_label = (*self.bytecode).emit_label();

                self.patch_jump(stat as *mut AstNode, back_label, loop_label);
                self.patch_jumps(stat as *mut AstNode, &mut skip_jump, skip_label);
            }

            self.pop_locals(old_locals);

            self.patch_loop_jumps(stat as *mut AstNode, old_jumps, end_label, cont_label);
            self.loop_jumps.resize(
                old_jumps,
                LoopJump {
                    r#type: Type::Break,
                    label: 0,
                },
            );

            self.loops.pop();
        }
    }
}