boa_engine 0.21.1

Boa is a Javascript lexer, parser and compiler written in Rust. Currently, it has support for some of the language.
Documentation
use crate::bytecompiler::{Access, ByteCompiler, FunctionSpec, MethodKind, Register};
use boa_ast::{
    Expression,
    expression::literal::{ObjectLiteral, PropertyDefinition},
    property::{MethodDefinitionKind, PropertyName},
};
use boa_interner::Sym;
use thin_vec::ThinVec;

impl ByteCompiler<'_> {
    pub(crate) fn compile_object_literal(&mut self, literal: &ObjectLiteral, dst: &Register) {
        self.bytecode.emit_push_empty_object(dst.variable());

        for property in literal.properties() {
            match property {
                PropertyDefinition::IdentifierReference(ident) => {
                    let value = self.register_allocator.alloc();
                    self.access_get(Access::Variable { name: *ident }, &value);
                    let index = self.get_or_insert_name(ident.sym());
                    self.bytecode.emit_define_own_property_by_name(
                        dst.variable(),
                        value.variable(),
                        index.into(),
                    );
                    self.register_allocator.dealloc(value);
                }
                PropertyDefinition::Property(name, expr) => match name {
                    PropertyName::Literal(name) => {
                        let value = self.register_allocator.alloc();
                        self.compile_expr(expr, &value);
                        if *name == Sym::__PROTO__ && !self.json_parse {
                            self.bytecode
                                .emit_set_prototype(dst.variable(), value.variable());
                        } else {
                            let index = self.get_or_insert_name(name.sym());
                            self.bytecode.emit_define_own_property_by_name(
                                dst.variable(),
                                value.variable(),
                                index.into(),
                            );
                        }
                        self.register_allocator.dealloc(value);
                    }
                    PropertyName::Computed(name_node) => {
                        let key = self.register_allocator.alloc();
                        self.compile_expr(name_node, &key);
                        self.bytecode
                            .emit_to_property_key(key.variable(), key.variable());
                        let function = self.register_allocator.alloc();
                        self.compile_expr(expr, &function);
                        if expr.is_anonymous_function_definition() {
                            self.bytecode.emit_set_function_name(
                                function.variable(),
                                key.variable(),
                                0u32.into(),
                            );
                        }
                        self.bytecode.emit_define_own_property_by_value(
                            function.variable(),
                            key.variable(),
                            dst.variable(),
                        );
                        self.register_allocator.dealloc(key);
                        self.register_allocator.dealloc(function);
                    }
                },
                PropertyDefinition::MethodDefinition(m) => {
                    let kind = match m.kind() {
                        MethodDefinitionKind::Get => MethodKind::Get,
                        MethodDefinitionKind::Set => MethodKind::Set,
                        _ => MethodKind::Ordinary,
                    };
                    match m.name() {
                        PropertyName::Literal(name) => {
                            let method = self.object_method(m.into(), kind);
                            self.bytecode
                                .emit_set_home_object(method.variable(), dst.variable());
                            let index = self.get_or_insert_name(name.sym());
                            match kind {
                                MethodKind::Get => self.bytecode.emit_set_property_getter_by_name(
                                    dst.variable(),
                                    method.variable(),
                                    index.into(),
                                ),
                                MethodKind::Set => self.bytecode.emit_set_property_setter_by_name(
                                    dst.variable(),
                                    method.variable(),
                                    index.into(),
                                ),
                                MethodKind::Ordinary => {
                                    self.bytecode.emit_define_own_property_by_name(
                                        dst.variable(),
                                        method.variable(),
                                        index.into(),
                                    );
                                }
                            }
                            self.register_allocator.dealloc(method);
                        }
                        PropertyName::Computed(name_node) => {
                            self.compile_object_literal_computed_method(
                                name_node,
                                m.into(),
                                kind,
                                dst,
                            );
                        }
                    }
                }
                PropertyDefinition::SpreadObject(expr) => {
                    let source = self.register_allocator.alloc();
                    self.compile_expr(expr, &source);
                    self.bytecode.emit_copy_data_properties(
                        dst.variable(),
                        source.variable(),
                        ThinVec::new(),
                    );
                    self.register_allocator.dealloc(source);
                }
                PropertyDefinition::CoverInitializedName(_, _) => {
                    unreachable!("invalid assignment pattern in object literal")
                }
            }
        }
    }

    fn compile_object_literal_computed_method(
        &mut self,
        expr: &Expression,
        function: FunctionSpec<'_>,
        kind: MethodKind,
        object: &Register,
    ) {
        let key = self.register_allocator.alloc();
        self.compile_expr(expr, &key);

        self.bytecode
            .emit_to_property_key(key.variable(), key.variable());

        let method = self.object_method(function, kind);
        let value: u32 = match kind {
            MethodKind::Get => 1,
            MethodKind::Set => 2,
            MethodKind::Ordinary => 0,
        };

        self.bytecode
            .emit_set_function_name(method.variable(), key.variable(), value.into());
        self.bytecode
            .emit_set_home_object(method.variable(), object.variable());

        match kind {
            MethodKind::Get => self.bytecode.emit_set_property_getter_by_value(
                method.variable(),
                key.variable(),
                object.variable(),
            ),
            MethodKind::Set => self.bytecode.emit_set_property_setter_by_value(
                method.variable(),
                key.variable(),
                object.variable(),
            ),
            MethodKind::Ordinary => self.bytecode.emit_define_own_property_by_value(
                method.variable(),
                key.variable(),
                object.variable(),
            ),
        }

        self.register_allocator.dealloc(key);
        self.register_allocator.dealloc(method);
    }
}