luaur-compiler 0.1.3

Luau source-to-bytecode compiler (Rust).
Documentation
use crate::enums::type_constant_folding::Type;
use crate::functions::sref_compiler::sref_ast_name;
use crate::functions::sref_compiler_alt_c::sref_ast_array_c_char;
use crate::records::compile_error::CompileError;
use crate::records::compiler::Compiler;
use luaur_ast::records::ast_expr::AstExpr;
use luaur_ast::records::ast_expr_binary::AstExprBinary;
use luaur_ast::records::ast_expr_call::AstExprCall;
use luaur_ast::records::ast_expr_constant_bool::AstExprConstantBool;
use luaur_ast::records::ast_expr_constant_integer::AstExprConstantInteger;
use luaur_ast::records::ast_expr_constant_nil::AstExprConstantNil;
use luaur_ast::records::ast_expr_constant_number::AstExprConstantNumber;
use luaur_ast::records::ast_expr_constant_string::AstExprConstantString;
use luaur_ast::records::ast_expr_function::AstExprFunction;
use luaur_ast::records::ast_expr_global::AstExprGlobal;
use luaur_ast::records::ast_expr_group::AstExprGroup;
use luaur_ast::records::ast_expr_if_else::AstExprIfElse;
use luaur_ast::records::ast_expr_index_expr::AstExprIndexExpr;
use luaur_ast::records::ast_expr_index_name::AstExprIndexName;
use luaur_ast::records::ast_expr_instantiate::AstExprInstantiate;
use luaur_ast::records::ast_expr_interp_string::AstExprInterpString;
use luaur_ast::records::ast_expr_local::AstExprLocal;
use luaur_ast::records::ast_expr_table::AstExprTable;
use luaur_ast::records::ast_expr_type_assertion::AstExprTypeAssertion;
use luaur_ast::records::ast_expr_unary::AstExprUnary;
use luaur_ast::records::ast_expr_varargs::AstExprVarargs;
use luaur_ast::records::ast_node::AstNode;
use luaur_bytecode::methods::bytecode_builder_get_string_hash::bytecode_builder_get_string_hash;
use luaur_common::enums::luau_opcode::LuauOpcode;
use luaur_common::macros::luau_assert::LUAU_ASSERT;

impl Compiler {
    pub fn compile_expr(&mut self, node: *mut AstExpr, target: u8, target_temp: bool) {
        self.set_debug_line_ast_node(node as *mut AstNode);

        unsafe {
            if self.options.coverage_level >= 2 && self.needs_coverage(node as *mut AstNode) {
                (*self.bytecode).emit_abc(LuauOpcode::LOP_COVERAGE, 0, 0, 0);
            }

            if let Some(cv) = self.constants.find(&node) {
                if cv.r#type != Type::Type_Unknown {
                    let cv = *cv;
                    self.compile_expr_constant(node, &cv, target);
                    return;
                }
            }

            let expr_group = luaur_ast::rtti::ast_node_as::<AstExprGroup>(node as *mut AstNode);
            if !expr_group.is_null() {
                self.compile_expr((*expr_group).expr, target, target_temp);
                return;
            }

            if luaur_ast::rtti::ast_node_is::<AstExprConstantNil>(&*(node as *mut AstNode)) {
                (*self.bytecode).emit_abc(LuauOpcode::LOP_LOADNIL, target, 0, 0);
                return;
            }

            let expr_bool =
                luaur_ast::rtti::ast_node_as::<AstExprConstantBool>(node as *mut AstNode);
            if !expr_bool.is_null() {
                (*self.bytecode).emit_abc(
                    LuauOpcode::LOP_LOADB,
                    target,
                    (*expr_bool).value as u8,
                    0,
                );
                return;
            }

            let expr_number =
                luaur_ast::rtti::ast_node_as::<AstExprConstantNumber>(node as *mut AstNode);
            if !expr_number.is_null() {
                let cid = (*self.bytecode).add_constant_number((*expr_number).value);
                if cid < 0 {
                    CompileError::raise(
                        &(*expr_number).base.base.location,
                        format_args!("Exceeded constant limit; simplify the code to compile"),
                    );
                }
                self.emit_load_k(target, cid);
                return;
            }

            let expr_integer =
                luaur_ast::rtti::ast_node_as::<AstExprConstantInteger>(node as *mut AstNode);
            if !expr_integer.is_null() {
                let cid = (*self.bytecode).add_constant_integer((*expr_integer).value);
                if cid < 0 {
                    CompileError::raise(
                        &(*expr_integer).base.base.location,
                        format_args!("Exceeded constant limit; simplify the code to compile"),
                    );
                }
                self.emit_load_k(target, cid);
                return;
            }

            let expr_string =
                luaur_ast::rtti::ast_node_as::<AstExprConstantString>(node as *mut AstNode);
            if !expr_string.is_null() {
                let cid = (*self.bytecode)
                    .add_constant_string(sref_ast_array_c_char((*expr_string).value));
                if cid < 0 {
                    CompileError::raise(
                        &(*expr_string).base.base.location,
                        format_args!("Exceeded constant limit; simplify the code to compile"),
                    );
                }
                self.emit_load_k(target, cid);
                return;
            }

            let expr_local = luaur_ast::rtti::ast_node_as::<AstExprLocal>(node as *mut AstNode);
            if !expr_local.is_null() {
                if luaur_common::FFlag::LuauExportValueSyntax.get()
                    && (*(*expr_local).local).is_exported
                {
                    let table_reg = self.get_export_table_reg(node as *mut AstNode);
                    let name = sref_ast_name((*(*expr_local).local).name);
                    let cid = (*self.bytecode).add_constant_string(name);
                    if cid < 0 {
                        CompileError::raise(
                            &(*expr_local).base.base.location,
                            format_args!("Exceeded constant limit; simplify the code to compile"),
                        );
                    }
                    (*self.bytecode).emit_abc(
                        LuauOpcode::LOP_GETTABLEKS,
                        target,
                        table_reg,
                        bytecode_builder_get_string_hash(name) as u8,
                    );
                    (*self.bytecode).emit_aux(cid as u32);
                } else {
                    let reg = self.get_expr_local_reg(node);
                    if reg >= 0 {
                        if self.options.optimization_level == 0 || target != reg as u8 {
                            (*self.bytecode).emit_abc(LuauOpcode::LOP_MOVE, target, reg as u8, 0);
                        }
                    } else {
                        LUAU_ASSERT!((*expr_local).upvalue);
                        let uid = self.get_upval((*expr_local).local);
                        (*self.bytecode).emit_abc(LuauOpcode::LOP_GETUPVAL, target, uid, 0);
                    }
                }
                return;
            }

            let expr_global = luaur_ast::rtti::ast_node_as::<AstExprGlobal>(node as *mut AstNode);
            if !expr_global.is_null() {
                self.compile_expr_global(expr_global, target);
                return;
            }

            let expr_varargs = luaur_ast::rtti::ast_node_as::<AstExprVarargs>(node as *mut AstNode);
            if !expr_varargs.is_null() {
                self.compile_expr_varargs(expr_varargs, target, 1, false);
                return;
            }

            let expr_call = luaur_ast::rtti::ast_node_as::<AstExprCall>(node as *mut AstNode);
            if !expr_call.is_null() {
                if target_temp && self.reg_top != 0 && u32::from(target) == self.reg_top - 1 {
                    self.compile_expr_call(expr_call, target, 1, true, false);
                } else {
                    self.compile_expr_call(expr_call, target, 1, false, false);
                }
                return;
            }

            let expr_index_name =
                luaur_ast::rtti::ast_node_as::<AstExprIndexName>(node as *mut AstNode);
            if !expr_index_name.is_null() {
                self.compile_expr_index_name(expr_index_name, target, target_temp);
                return;
            }

            let expr_index_expr =
                luaur_ast::rtti::ast_node_as::<AstExprIndexExpr>(node as *mut AstNode);
            if !expr_index_expr.is_null() {
                self.compile_expr_index_expr(expr_index_expr, target);
                return;
            }

            let expr_function =
                luaur_ast::rtti::ast_node_as::<AstExprFunction>(node as *mut AstNode);
            if !expr_function.is_null() {
                self.compile_expr_function(expr_function, target);
                return;
            }

            let expr_table = luaur_ast::rtti::ast_node_as::<AstExprTable>(node as *mut AstNode);
            if !expr_table.is_null() {
                self.compile_expr_table(expr_table, target, target_temp);
                return;
            }

            let expr_unary = luaur_ast::rtti::ast_node_as::<AstExprUnary>(node as *mut AstNode);
            if !expr_unary.is_null() {
                self.compile_expr_unary(expr_unary, target);
                return;
            }

            let expr_binary = luaur_ast::rtti::ast_node_as::<AstExprBinary>(node as *mut AstNode);
            if !expr_binary.is_null() {
                self.compile_expr_binary(expr_binary, target, target_temp);
                return;
            }

            let expr_assertion =
                luaur_ast::rtti::ast_node_as::<AstExprTypeAssertion>(node as *mut AstNode);
            if !expr_assertion.is_null() {
                self.compile_expr((*expr_assertion).expr, target, target_temp);
                return;
            }

            let expr_if_else = luaur_ast::rtti::ast_node_as::<AstExprIfElse>(node as *mut AstNode);
            if !expr_if_else.is_null() {
                self.compile_expr_if_else(expr_if_else, target, target_temp);
                return;
            }

            let interp_string =
                luaur_ast::rtti::ast_node_as::<AstExprInterpString>(node as *mut AstNode);
            if !interp_string.is_null() {
                self.compile_expr_interp_string(interp_string, target, target_temp);
                return;
            }

            let expr_instantiate =
                luaur_ast::rtti::ast_node_as::<AstExprInstantiate>(node as *mut AstNode);
            if !expr_instantiate.is_null() {
                self.compile_expr((*expr_instantiate).expr, target, target_temp);
                return;
            }
        }

        LUAU_ASSERT!(false);
    }
}