Skip to main content

boa_engine/bytecompiler/
module.rs

1use super::{ByteCompiler, Literal, ToJsString};
2use crate::vm::opcode::BindingOpcode;
3use boa_ast::{ModuleItem, ModuleItemList, declaration::ExportDeclaration};
4use boa_interner::Sym;
5
6impl ByteCompiler<'_> {
7    /// Compiles a [`ModuleItemList`].
8    #[inline]
9    pub fn compile_module_item_list(&mut self, list: &ModuleItemList) {
10        for node in list.items() {
11            self.compile_module_item(node);
12        }
13    }
14
15    /// Compiles a [`ModuleItem`].
16    #[inline]
17    pub fn compile_module_item(&mut self, item: &ModuleItem) {
18        match item {
19            ModuleItem::StatementListItem(stmt) => {
20                self.compile_stmt_list_item(stmt, false, false);
21            }
22            ModuleItem::ImportDeclaration(_) => {
23                // ModuleItem : ImportDeclaration
24
25                // 1. Return empty.
26            }
27            ModuleItem::ExportDeclaration(export) => {
28                #[allow(clippy::match_same_arms)]
29                match export.as_ref() {
30                    ExportDeclaration::ReExport { .. } | ExportDeclaration::List(_) => {
31                        // ExportDeclaration :
32                        //    export ExportFromClause FromClause ;
33                        //    export NamedExports ;
34                        //        1. Return empty.
35                    }
36                    ExportDeclaration::DefaultFunctionDeclaration(_)
37                    | ExportDeclaration::DefaultGeneratorDeclaration(_)
38                    | ExportDeclaration::DefaultAsyncFunctionDeclaration(_)
39                    | ExportDeclaration::DefaultAsyncGeneratorDeclaration(_) => {
40                        // Already instantiated in `initialize_environment`.
41                    }
42                    ExportDeclaration::VarStatement(var) => self.compile_var_decl(var),
43                    ExportDeclaration::Declaration(decl) => self.compile_decl(decl, false),
44                    ExportDeclaration::DefaultClassDeclaration(cl) => {
45                        // 2. Let className be the sole element of BoundNames of ClassDeclaration.
46                        // 3. If className is "*default*", then
47                        if cl.name().sym() == Sym::DEFAULT_EXPORT {
48                            let class = self.register_allocator.alloc();
49
50                            // 1. Let value be ? BindingClassDeclarationEvaluation of ClassDeclaration.
51                            self.compile_class(cl.as_ref().into(), Some(&class));
52
53                            // a. Let env be the running execution context's LexicalEnvironment.
54                            // b. Perform ? InitializeBoundName("*default*", value, env).
55                            let default_export = self
56                                .interner()
57                                .resolve_expect(Sym::DEFAULT_EXPORT)
58                                .into_common(false);
59                            self.emit_binding(BindingOpcode::InitLexical, default_export, &class);
60
61                            self.register_allocator.dealloc(class);
62                        } else {
63                            // 1. Let value be ? BindingClassDeclarationEvaluation of ClassDeclaration.
64                            self.compile_class(cl.as_ref().into(), None);
65                        }
66                    }
67                    ExportDeclaration::DefaultAssignmentExpression(expr) => {
68                        let function = self.register_allocator.alloc();
69                        self.compile_expr(expr, &function);
70
71                        if expr.is_anonymous_function_definition() {
72                            let default = self
73                                .interner()
74                                .resolve_expect(Sym::DEFAULT)
75                                .into_common(false);
76                            let key = self.register_allocator.alloc();
77                            self.emit_store_literal(Literal::String(default), &key);
78                            self.bytecode.emit_set_function_name(
79                                function.variable(),
80                                key.variable(),
81                                0u32.into(),
82                            );
83                            self.register_allocator.dealloc(key);
84                        }
85
86                        let name = Sym::DEFAULT_EXPORT.to_js_string(self.interner());
87                        self.emit_binding(BindingOpcode::InitLexical, name, &function);
88                        self.register_allocator.dealloc(function);
89                    }
90                }
91            }
92        }
93    }
94}