Coverage Report

Created: 2025-11-02 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibJS/SourceTextModule.cpp
Line
Count
Source
1
/*
2
 * Copyright (c) 2021-2023, Andreas Kling <kling@serenityos.org>
3
 * Copyright (c) 2022, David Tuin <davidot@serenityos.org>
4
 *
5
 * SPDX-License-Identifier: BSD-2-Clause
6
 */
7
8
#include <AK/Debug.h>
9
#include <AK/QuickSort.h>
10
#include <LibJS/Bytecode/Interpreter.h>
11
#include <LibJS/Parser.h>
12
#include <LibJS/Runtime/AsyncFunctionDriverWrapper.h>
13
#include <LibJS/Runtime/ECMAScriptFunctionObject.h>
14
#include <LibJS/Runtime/GlobalEnvironment.h>
15
#include <LibJS/Runtime/ModuleEnvironment.h>
16
#include <LibJS/Runtime/PromiseCapability.h>
17
#include <LibJS/SourceTextModule.h>
18
19
namespace JS {
20
21
JS_DEFINE_ALLOCATOR(SourceTextModule);
22
23
// 16.2.2.2 Static Semantics: WithClauseToAttributes, https://tc39.es/proposal-import-attributes/#sec-with-clause-to-attributes
24
static Vector<ImportAttribute> with_clause_to_assertions(Vector<ImportAttribute> const& source_attributes)
25
0
{
26
    // WithClause : AttributesKeyword { WithEntries , opt }
27
    // 1. Let attributes be WithClauseToAttributes of WithEntries.
28
0
    Vector<ImportAttribute> attributes;
29
30
    // AssertEntries : AssertionKey : StringLiteral
31
    // AssertEntries : AssertionKey : StringLiteral , WithEntries
32
33
0
    for (auto const& attribute : source_attributes) {
34
        // 1. Let key be the PropName of AttributeKey.
35
        // 2. Let entry be the ImportAttribute Record { [[Key]]: key, [[Value]]: SV of StringLiteral }.
36
        // 3. Return « entry ».
37
0
        attributes.empend(attribute);
38
0
    }
39
40
    // 2. Sort attributes according to the lexicographic order of their [[Key]] fields, treating the value of each such field as a sequence of UTF-16 code unit values. NOTE: This sorting is observable only in that hosts are prohibited from distinguishing among attributes by the order they occur in.
41
    // Note: The sorting is done in construction of the ModuleRequest object.
42
43
    // 3. Return attributes.
44
0
    return attributes;
45
0
}
46
47
// 16.2.1.3 Static Semantics: ModuleRequests, https://tc39.es/ecma262/#sec-static-semantics-modulerequests
48
static Vector<ModuleRequest> module_requests(Program& program)
49
0
{
50
    // A List of all the ModuleSpecifier strings used by the module represented by this record to request the importation of a module.
51
    // Note: The List is source text occurrence ordered!
52
0
    struct RequestedModuleAndSourceIndex {
53
0
        u32 source_offset { 0 };
54
0
        ModuleRequest const* module_request { nullptr };
55
0
    };
56
57
0
    Vector<RequestedModuleAndSourceIndex> requested_modules_with_indices;
58
59
0
    for (auto& import_statement : program.imports())
60
0
        requested_modules_with_indices.empend(import_statement->start_offset(), &import_statement->module_request());
61
62
0
    for (auto& export_statement : program.exports()) {
63
0
        for (auto& export_entry : export_statement->entries()) {
64
0
            if (!export_entry.is_module_request())
65
0
                continue;
66
0
            requested_modules_with_indices.empend(export_statement->start_offset(), &export_statement->module_request());
67
0
        }
68
0
    }
69
70
    // Note: The List is source code occurrence ordered. https://tc39.es/proposal-import-attributes/#table-cyclic-module-fields
71
0
    quick_sort(requested_modules_with_indices, [&](RequestedModuleAndSourceIndex const& lhs, RequestedModuleAndSourceIndex const& rhs) {
72
0
        return lhs.source_offset < rhs.source_offset;
73
0
    });
74
75
0
    Vector<ModuleRequest> requested_modules_in_source_order;
76
0
    requested_modules_in_source_order.ensure_capacity(requested_modules_with_indices.size());
77
0
    for (auto& module : requested_modules_with_indices) {
78
        // 16.2.1.3 Static Semantics: ModuleRequests, https://tc39.es/proposal-import-attributes/#sec-static-semantics-modulerequests
79
0
        if (module.module_request->attributes.is_empty()) {
80
            //  ExportDeclaration : export ExportFromClause FromClause ;
81
            //  ImportDeclaration : import ImportClause FromClause ;
82
83
            // 2. Let specifier be SV of FromClause.
84
            // 3. Return a List whose sole element is the ModuleRequest Record { [[Specifer]]: specifier, [[Attributes]]: « » }.
85
0
            requested_modules_in_source_order.empend(module.module_request->module_specifier);
86
0
        } else {
87
            //  ExportDeclaration : export ExportFromClause FromClause WithClause ;
88
            //  ImportDeclaration : import ImportClause FromClause WithClause ;
89
90
            // 1. Let specifier be the SV of FromClause.
91
            // 2. Let attributes be WithClauseToAttributes of WithClause.
92
0
            auto attributes = with_clause_to_assertions(module.module_request->attributes);
93
            // NOTE: We have to modify the attributes in place because else it might keep unsupported ones.
94
0
            const_cast<ModuleRequest*>(module.module_request)->attributes = move(attributes);
95
96
            // 3. Return a List whose sole element is the ModuleRequest Record { [[Specifer]]: specifier, [[Attributes]]: attributes }.
97
0
            requested_modules_in_source_order.empend(module.module_request->module_specifier, module.module_request->attributes);
98
0
        }
99
0
    }
100
101
0
    return requested_modules_in_source_order;
102
0
}
103
104
SourceTextModule::SourceTextModule(Realm& realm, StringView filename, Script::HostDefined* host_defined, bool has_top_level_await, NonnullRefPtr<Program> body, Vector<ModuleRequest> requested_modules,
105
    Vector<ImportEntry> import_entries, Vector<ExportEntry> local_export_entries,
106
    Vector<ExportEntry> indirect_export_entries, Vector<ExportEntry> star_export_entries,
107
    RefPtr<ExportStatement const> default_export)
108
0
    : CyclicModule(realm, filename, has_top_level_await, move(requested_modules), host_defined)
109
0
    , m_ecmascript_code(move(body))
110
0
    , m_execution_context(ExecutionContext::create())
111
0
    , m_import_entries(move(import_entries))
112
0
    , m_local_export_entries(move(local_export_entries))
113
0
    , m_indirect_export_entries(move(indirect_export_entries))
114
0
    , m_star_export_entries(move(star_export_entries))
115
0
    , m_default_export(move(default_export))
116
0
{
117
0
}
118
119
0
SourceTextModule::~SourceTextModule() = default;
120
121
void SourceTextModule::visit_edges(Cell::Visitor& visitor)
122
0
{
123
0
    Base::visit_edges(visitor);
124
0
    visitor.visit(m_import_meta);
125
0
    m_execution_context->visit_edges(visitor);
126
0
}
127
128
// 16.2.1.6.1 ParseModule ( sourceText, realm, hostDefined ), https://tc39.es/ecma262/#sec-parsemodule
129
Result<NonnullGCPtr<SourceTextModule>, Vector<ParserError>> SourceTextModule::parse(StringView source_text, Realm& realm, StringView filename, Script::HostDefined* host_defined)
130
0
{
131
    // 1. Let body be ParseText(sourceText, Module).
132
0
    auto parser = Parser(Lexer(source_text, filename), Program::Type::Module);
133
0
    auto body = parser.parse_program();
134
135
    // 2. If body is a List of errors, return body.
136
0
    if (parser.has_errors())
137
0
        return parser.errors();
138
139
    // 3. Let requestedModules be the ModuleRequests of body.
140
0
    auto requested_modules = module_requests(*body);
141
142
    // 4. Let importEntries be ImportEntries of body.
143
0
    Vector<ImportEntry> import_entries;
144
0
    for (auto const& import_statement : body->imports())
145
0
        import_entries.extend(import_statement->entries());
146
147
    // 5. Let importedBoundNames be ImportedLocalNames(importEntries).
148
    // Note: Since we have to potentially extract the import entry we just use importEntries
149
    //       In the future it might be an optimization to have a set/map of string to speed up the search.
150
151
    // 6. Let indirectExportEntries be a new empty List.
152
0
    Vector<ExportEntry> indirect_export_entries;
153
154
    // 7. Let localExportEntries be a new empty List.
155
0
    Vector<ExportEntry> local_export_entries;
156
157
    // 8. Let starExportEntries be a new empty List.
158
0
    Vector<ExportEntry> star_export_entries;
159
160
    // Note: Not in the spec but makes it easier to find the default.
161
0
    RefPtr<ExportStatement const> default_export;
162
163
    // 9. Let exportEntries be ExportEntries of body.
164
    // 10. For each ExportEntry Record ee of exportEntries, do
165
0
    for (auto const& export_statement : body->exports()) {
166
167
0
        if (export_statement->is_default_export()) {
168
0
            VERIFY(!default_export);
169
0
            VERIFY(export_statement->entries().size() == 1);
170
0
            VERIFY(export_statement->has_statement());
171
172
0
            auto const& entry = export_statement->entries()[0];
173
0
            VERIFY(entry.kind == ExportEntry::Kind::NamedExport);
174
0
            VERIFY(!entry.is_module_request());
175
0
            VERIFY(import_entries.find_if(
176
0
                                     [&](ImportEntry const& import_entry) {
177
0
                                         return import_entry.local_name == entry.local_or_import_name;
178
0
                                     })
179
0
                    .is_end());
180
0
            default_export = export_statement;
181
0
        }
182
183
0
        for (auto const& export_entry : export_statement->entries()) {
184
185
            // Special case, export {} from "module" should add "module" to
186
            // required_modules but not any import or export so skip here.
187
0
            if (export_entry.kind == ExportEntry::Kind::EmptyNamedExport) {
188
0
                VERIFY(export_statement->entries().size() == 1);
189
0
                break;
190
0
            }
191
192
            // a. If ee.[[ModuleRequest]] is null, then
193
0
            if (!export_entry.is_module_request()) {
194
195
0
                auto in_imported_bound_names = import_entries.find_if(
196
0
                    [&](ImportEntry const& import_entry) {
197
0
                        return import_entry.local_name == export_entry.local_or_import_name;
198
0
                    });
199
200
                // i. If ee.[[LocalName]] is not an element of importedBoundNames, then
201
0
                if (in_imported_bound_names.is_end()) {
202
                    // 1. Append ee to localExportEntries.
203
0
                    local_export_entries.empend(export_entry);
204
0
                }
205
                // ii. Else,
206
0
                else {
207
                    // 1. Let ie be the element of importEntries whose [[LocalName]] is the same as ee.[[LocalName]].
208
0
                    auto& import_entry = *in_imported_bound_names;
209
210
                    // 2. If ie.[[ImportName]] is namespace-object, then
211
0
                    if (import_entry.is_namespace()) {
212
                        // a. NOTE: This is a re-export of an imported module namespace object.
213
                        // b. Append ee to localExportEntries.
214
0
                        local_export_entries.empend(export_entry);
215
0
                    }
216
                    // 3. Else,
217
0
                    else {
218
                        // a. NOTE: This is a re-export of a single name.
219
                        // b. Append the ExportEntry Record { [[ModuleRequest]]: ie.[[ModuleRequest]], [[ImportName]]: ie.[[ImportName]], [[LocalName]]: null, [[ExportName]]: ee.[[ExportName]] } to indirectExportEntries.
220
0
                        indirect_export_entries.empend(ExportEntry::indirect_export_entry(import_entry.module_request(), export_entry.export_name, import_entry.import_name));
221
0
                    }
222
0
                }
223
0
            }
224
            // b. Else if ee.[[ImportName]] is all-but-default, then
225
0
            else if (export_entry.kind == ExportEntry::Kind::ModuleRequestAllButDefault) {
226
                // i. Assert: ee.[[ExportName]] is null.
227
0
                VERIFY(!export_entry.export_name.has_value());
228
                // ii. Append ee to starExportEntries.
229
0
                star_export_entries.empend(export_entry);
230
0
            }
231
            // c. Else,
232
0
            else {
233
                // i. Append ee to indirectExportEntries.
234
0
                indirect_export_entries.empend(export_entry);
235
0
            }
236
0
        }
237
0
    }
238
239
    // 11. Let async be body Contains await.
240
0
    bool async = body->has_top_level_await();
241
242
    // 12. Return Source Text Module Record {
243
    //          [[Realm]]: realm, [[Environment]]: empty, [[Namespace]]: empty, [[CycleRoot]]: empty, [[HasTLA]]: async,
244
    //          [[AsyncEvaluation]]: false, [[TopLevelCapability]]: empty, [[AsyncParentModules]]: « »,
245
    //          [[PendingAsyncDependencies]]: empty, [[Status]]: unlinked, [[EvaluationError]]: empty,
246
    //          [[HostDefined]]: hostDefined, [[ECMAScriptCode]]: body, [[Context]]: empty, [[ImportMeta]]: empty,
247
    //          [[RequestedModules]]: requestedModules, [[ImportEntries]]: importEntries, [[LocalExportEntries]]: localExportEntries,
248
    //          [[IndirectExportEntries]]: indirectExportEntries, [[StarExportEntries]]: starExportEntries, [[DFSIndex]]: empty, [[DFSAncestorIndex]]: empty }.
249
0
    return realm.heap().allocate_without_realm<SourceTextModule>(
250
0
        realm,
251
0
        filename,
252
0
        host_defined,
253
0
        async,
254
0
        move(body),
255
0
        move(requested_modules),
256
0
        move(import_entries),
257
0
        move(local_export_entries),
258
0
        move(indirect_export_entries),
259
0
        move(star_export_entries),
260
0
        move(default_export));
261
0
}
262
263
// 16.2.1.6.2 GetExportedNames ( [ exportStarSet ] ), https://tc39.es/ecma262/#sec-getexportednames
264
ThrowCompletionOr<Vector<DeprecatedFlyString>> SourceTextModule::get_exported_names(VM& vm, Vector<Module*> export_star_set)
265
0
{
266
0
    dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] get_export_names of {}", filename());
267
    // 1. Assert: module.[[Status]] is not new.
268
0
    VERIFY(m_status != ModuleStatus::New);
269
270
    // 2. If exportStarSet is not present, set exportStarSet to a new empty List.
271
    // Note: This is done by default argument
272
273
    // 3. If exportStarSet contains module, then
274
0
    if (export_star_set.contains_slow(this)) {
275
        // a. Assert: We've reached the starting point of an export * circularity.
276
        // FIXME: How do we check that?
277
278
        // b. Return a new empty List.
279
0
        return Vector<DeprecatedFlyString> {};
280
0
    }
281
282
    // 4. Append module to exportStarSet.
283
0
    export_star_set.append(this);
284
285
    // 5. Let exportedNames be a new empty List.
286
0
    Vector<DeprecatedFlyString> exported_names;
287
288
    // 6. For each ExportEntry Record e of module.[[LocalExportEntries]], do
289
0
    for (auto& entry : m_local_export_entries) {
290
        // a. Assert: module provides the direct binding for this export.
291
        // FIXME: How do we check that?
292
293
        // b. Assert: e.[[ExportName]] is not null.
294
0
        VERIFY(entry.export_name.has_value());
295
296
        // c. Append e.[[ExportName]] to exportedNames.
297
0
        exported_names.empend(entry.export_name.value());
298
0
    }
299
300
    // 7. For each ExportEntry Record e of module.[[IndirectExportEntries]], do
301
0
    for (auto& entry : m_indirect_export_entries) {
302
        // a. a. Assert: module imports a specific binding for this export.
303
        // FIXME: How do we check that?
304
305
        // b. Assert: e.[[ExportName]] is not null.
306
0
        VERIFY(entry.export_name.has_value());
307
308
        // c. Append e.[[ExportName]] to exportedNames.
309
0
        exported_names.empend(entry.export_name.value());
310
0
    }
311
312
    // 8. For each ExportEntry Record e of module.[[StarExportEntries]], do
313
0
    for (auto& entry : m_star_export_entries) {
314
        // a. Assert: e.[[ModuleRequest]] is not null.
315
        // b. Let requestedModule be GetImportedModule(module, e.[[ModuleRequest]]).
316
0
        auto requested_module = get_imported_module(entry.module_request());
317
318
        // c. Let starNames be ? requestedModule.GetExportedNames(exportStarSet).
319
0
        auto star_names = TRY(requested_module->get_exported_names(vm, export_star_set));
320
321
        // d. For each element n of starNames, do
322
0
        for (auto& name : star_names) {
323
            // i. If SameValue(n, "default") is false, then
324
0
            if (name != "default"sv) {
325
                // 1. If n is not an element of exportedNames, then
326
0
                if (!exported_names.contains_slow(name)) {
327
                    // a. Append n to exportedNames.
328
0
                    exported_names.empend(name);
329
0
                }
330
0
            }
331
0
        }
332
0
    }
333
334
    // 9. Return exportedNames.
335
0
    return exported_names;
336
0
}
337
338
// 16.2.1.6.4 InitializeEnvironment ( ), https://tc39.es/ecma262/#sec-source-text-module-record-initialize-environment
339
ThrowCompletionOr<void> SourceTextModule::initialize_environment(VM& vm)
340
0
{
341
    // 1. For each ExportEntry Record e of module.[[IndirectExportEntries]], do
342
0
    for (auto& entry : m_indirect_export_entries) {
343
        // a. Let resolution be ? module.ResolveExport(e.[[ExportName]]).
344
0
        auto resolution = TRY(resolve_export(vm, entry.export_name.value()));
345
        // b. If resolution is null or ambiguous, throw a SyntaxError exception.
346
0
        if (!resolution.is_valid())
347
0
            return vm.throw_completion<SyntaxError>(ErrorType::InvalidOrAmbiguousExportEntry, entry.export_name);
348
349
        // c. Assert: resolution is a ResolvedBinding Record.
350
0
        VERIFY(resolution.is_valid());
351
0
    }
352
353
    // 2. Assert: All named exports from module are resolvable.
354
    // Note: We check all the indirect export entries above in step 1 and all
355
    // the local named exports are resolvable by construction.
356
357
    // 3. Let realm be module.[[Realm]].
358
    // 4. Assert: realm is not undefined.
359
    // Note: This must be true because we use a reference.
360
361
    // 5. Let env be NewModuleEnvironment(realm.[[GlobalEnv]]).
362
0
    auto environment = vm.heap().allocate_without_realm<ModuleEnvironment>(&realm().global_environment());
363
364
    // 6. Set module.[[Environment]] to env.
365
0
    set_environment(environment);
366
367
    // 7. For each ImportEntry Record in of module.[[ImportEntries]], do
368
0
    for (auto& import_entry : m_import_entries) {
369
        // a. Let importedModule be GetImportedModule(module, in.[[ModuleRequest]]).
370
0
        auto imported_module = get_imported_module(import_entry.module_request());
371
        // b. NOTE: The above call cannot fail because imported module requests are a subset of module.[[RequestedModules]], and these have been resolved earlier in this algorithm.
372
373
        // c. If in.[[ImportName]] is namespace-object, then
374
0
        if (import_entry.is_namespace()) {
375
            // i. Let namespace be ? GetModuleNamespace(importedModule).
376
0
            auto* namespace_ = TRY(imported_module->get_module_namespace(vm));
377
378
            // ii. Perform ! env.CreateImmutableBinding(in.[[LocalName]], true).
379
0
            MUST(environment->create_immutable_binding(vm, import_entry.local_name, true));
380
381
            // iii. Perform ! env.InitializeBinding(in.[[LocalName]], namespace, normal).
382
0
            MUST(environment->initialize_binding(vm, import_entry.local_name, namespace_, Environment::InitializeBindingHint::Normal));
383
0
        }
384
        // d. Else,
385
0
        else {
386
            // i. Let resolution be ? importedModule.ResolveExport(in.[[ImportName]]).
387
0
            auto resolution = TRY(imported_module->resolve_export(vm, import_entry.import_name.value()));
388
389
            // ii. If resolution is null or ambiguous, throw a SyntaxError exception.
390
0
            if (!resolution.is_valid())
391
0
                return vm.throw_completion<SyntaxError>(ErrorType::InvalidOrAmbiguousExportEntry, import_entry.import_name);
392
393
            // iii. If resolution.[[BindingName]] is namespace, then
394
0
            if (resolution.is_namespace()) {
395
                // 1. Let namespace be ? GetModuleNamespace(resolution.[[Module]]).
396
0
                auto* namespace_ = TRY(resolution.module->get_module_namespace(vm));
397
398
                // 2. Perform ! env.CreateImmutableBinding(in.[[LocalName]], true).
399
0
                MUST(environment->create_immutable_binding(vm, import_entry.local_name, true));
400
401
                // 3. Perform ! env.InitializeBinding(in.[[LocalName]], namespace, normal).
402
0
                MUST(environment->initialize_binding(vm, import_entry.local_name, namespace_, Environment::InitializeBindingHint::Normal));
403
0
            }
404
            // iv. Else,
405
0
            else {
406
                // 1. Perform env.CreateImportBinding(in.[[LocalName]], resolution.[[Module]], resolution.[[BindingName]]).
407
0
                MUST(environment->create_import_binding(import_entry.local_name, resolution.module, resolution.export_name));
408
0
            }
409
0
        }
410
0
    }
411
412
    // 8. Let moduleContext be a new ECMAScript code execution context.
413
    // Note: this has already been created during the construction of this object.
414
415
    // 9. Set the Function of moduleContext to null.
416
417
    // 10. Assert: module.[[Realm]] is not undefined.
418
    // Note: This must be true because we use a reference.
419
420
    // 11. Set the Realm of moduleContext to module.[[Realm]].
421
0
    m_execution_context->realm = &realm();
422
423
    // 12. Set the ScriptOrModule of moduleContext to module.
424
0
    m_execution_context->script_or_module = NonnullGCPtr<Module>(*this);
425
426
    // 13. Set the VariableEnvironment of moduleContext to module.[[Environment]].
427
0
    m_execution_context->variable_environment = environment;
428
429
    // 14. Set the LexicalEnvironment of moduleContext to module.[[Environment]].
430
0
    m_execution_context->lexical_environment = environment;
431
432
    // 15. Set the PrivateEnvironment of moduleContext to null.
433
434
    // 16. Set module.[[Context]] to moduleContext.
435
    // Note: We're already working on that one.
436
437
    // 17. Push moduleContext onto the execution context stack; moduleContext is now the running execution context.
438
0
    TRY(vm.push_execution_context(*m_execution_context, {}));
439
440
    // 18. Let code be module.[[ECMAScriptCode]].
441
442
    // 19. Let varDeclarations be the VarScopedDeclarations of code.
443
    // Note: We just loop through them in step 21.
444
445
    // 20. Let declaredVarNames be a new empty List.
446
0
    Vector<DeprecatedFlyString> declared_var_names;
447
448
    // 21. For each element d of varDeclarations, do
449
    // a. For each element dn of the BoundNames of d, do
450
    // NOTE: Due to the use of MUST with `create_mutable_binding` and `initialize_binding` below,
451
    //       an exception should not result from `for_each_var_declared_identifier`.
452
0
    MUST(m_ecmascript_code->for_each_var_declared_identifier([&](auto const& identifier) {
453
0
        auto const& name = identifier.string();
454
        // i. If dn is not an element of declaredVarNames, then
455
0
        if (!declared_var_names.contains_slow(name)) {
456
            // 1. Perform ! env.CreateMutableBinding(dn, false).
457
0
            MUST(environment->create_mutable_binding(vm, name, false));
458
459
            // 2. Perform ! env.InitializeBinding(dn, undefined, normal).
460
0
            MUST(environment->initialize_binding(vm, name, js_undefined(), Environment::InitializeBindingHint::Normal));
461
462
            // 3. Append dn to declaredVarNames.
463
0
            declared_var_names.empend(name);
464
0
        }
465
0
    }));
466
467
    // 22. Let lexDeclarations be the LexicallyScopedDeclarations of code.
468
    // Note: We only loop through them in step 24.
469
470
    // 23. Let privateEnv be null.
471
0
    PrivateEnvironment* private_environment = nullptr;
472
473
    // 24. For each element d of lexDeclarations, do
474
    // NOTE: Due to the use of MUST in the callback, an exception should not result from `for_each_lexically_scoped_declaration`.
475
0
    MUST(m_ecmascript_code->for_each_lexically_scoped_declaration([&](Declaration const& declaration) {
476
        // a. For each element dn of the BoundNames of d, do
477
        // NOTE: Due to the use of MUST with `create_immutable_binding`, `create_mutable_binding` and `initialize_binding` below,
478
        //       an exception should not result from `for_each_bound_identifier`.
479
0
        MUST(declaration.for_each_bound_identifier([&](auto const& identifier) {
480
0
            auto const& name = identifier.string();
481
            // i. If IsConstantDeclaration of d is true, then
482
0
            if (declaration.is_constant_declaration()) {
483
                // 1. Perform ! env.CreateImmutableBinding(dn, true).
484
0
                MUST(environment->create_immutable_binding(vm, name, true));
485
0
            }
486
            // ii. Else,
487
0
            else {
488
                // 1. Perform ! env.CreateMutableBinding(dn, false).
489
0
                MUST(environment->create_mutable_binding(vm, name, false));
490
0
            }
491
492
            // iii. If d is a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration, then
493
0
            if (declaration.is_function_declaration()) {
494
0
                VERIFY(is<FunctionDeclaration>(declaration));
495
0
                auto const& function_declaration = static_cast<FunctionDeclaration const&>(declaration);
496
497
                // 1. Let fo be InstantiateFunctionObject of d with arguments env and privateEnv.
498
                // NOTE: Special case if the function is a default export of an anonymous function
499
                //       it has name "*default*" but internally should have name "default".
500
0
                DeprecatedFlyString function_name = function_declaration.name();
501
0
                if (function_name == ExportStatement::local_name_for_default)
502
0
                    function_name = "default"sv;
503
0
                auto function = ECMAScriptFunctionObject::create(realm(), function_name, function_declaration.source_text(), function_declaration.body(), function_declaration.parameters(), function_declaration.function_length(), function_declaration.local_variables_names(), environment, private_environment, function_declaration.kind(), function_declaration.is_strict_mode(),
504
0
                    function_declaration.parsing_insights());
505
506
                // 2. Perform ! env.InitializeBinding(dn, fo, normal).
507
0
                MUST(environment->initialize_binding(vm, name, function, Environment::InitializeBindingHint::Normal));
508
0
            }
509
0
        }));
510
0
    }));
511
512
    // Note: The default export name is also part of the local lexical declarations but
513
    //       instead of making that a special case in the parser we just check it here.
514
    //       This is only needed for things which are not declarations.
515
    //       For more info check Parser::parse_export_statement.
516
    //       Furthermore, that declaration is not constant. so we take 24.a.ii
517
0
    if (m_default_export) {
518
0
        VERIFY(m_default_export->has_statement());
519
520
0
        auto const& statement = m_default_export->statement();
521
0
        if (!is<Declaration>(statement)) {
522
0
            auto const& name = m_default_export->entries()[0].local_or_import_name;
523
0
            dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] Adding default export to lexical declarations: local name: {}, Expression: {}", name, statement.class_name());
524
525
            // 1. Perform ! env.CreateMutableBinding(dn, false).
526
0
            MUST(environment->create_mutable_binding(vm, name.value(), false));
527
528
            // Note: Since this is not a function declaration 24.a.iii never applies
529
0
        }
530
0
    }
531
532
    // 25. Remove moduleContext from the execution context stack.
533
0
    vm.pop_execution_context();
534
535
    // 26. Return unused.
536
0
    return {};
537
0
}
538
539
// 16.2.1.6.3 ResolveExport ( exportName [ , resolveSet ] ), https://tc39.es/ecma262/#sec-resolveexport
540
ThrowCompletionOr<ResolvedBinding> SourceTextModule::resolve_export(VM& vm, DeprecatedFlyString const& export_name, Vector<ResolvedBinding> resolve_set)
541
0
{
542
    // 1. Assert: module.[[Status]] is not new.
543
0
    VERIFY(m_status != ModuleStatus::New);
544
545
    // 2. If resolveSet is not present, set resolveSet to a new empty List.
546
    // Note: This is done by the default argument.
547
548
    // 3. For each Record { [[Module]], [[ExportName]] } r of resolveSet, do
549
0
    for (auto& [type, module, exported_name] : resolve_set) {
550
        // a. If module and r.[[Module]] are the same Module Record and SameValue(exportName, r.[[ExportName]]) is true, then
551
0
        if (module == this && exported_name == export_name) {
552
            // i. Assert: This is a circular import request.
553
554
            // ii. Return null.
555
0
            return ResolvedBinding::null();
556
0
        }
557
0
    }
558
559
    // 4. Append the Record { [[Module]]: module, [[ExportName]]: exportName } to resolveSet.
560
0
    resolve_set.append({ ResolvedBinding::Type::BindingName, this, export_name });
561
562
    // 5. For each ExportEntry Record e of module.[[LocalExportEntries]], do
563
0
    for (auto& entry : m_local_export_entries) {
564
        // a. If SameValue(exportName, e.[[ExportName]]) is true, then
565
0
        if (export_name != entry.export_name)
566
0
            continue;
567
568
        // i. Assert: module provides the direct binding for this export.
569
        // FIXME: What does this mean?
570
571
        // ii. Return ResolvedBinding Record { [[Module]]: module, [[BindingName]]: e.[[LocalName]] }.
572
0
        return ResolvedBinding {
573
0
            ResolvedBinding::Type::BindingName,
574
0
            this,
575
0
            entry.local_or_import_name.value(),
576
0
        };
577
0
    }
578
579
    // 5. For each ExportEntry Record e of module.[[IndirectExportEntries]], do
580
0
    for (auto& entry : m_indirect_export_entries) {
581
        // a. If SameValue(exportName, e.[[ExportName]]) is true, then
582
0
        if (export_name != entry.export_name)
583
0
            continue;
584
585
        // i. Assert: e.[[ModuleRequest]] is not null.
586
        // ii. Let importedModule be GetImportedModule(module, e.[[ModuleRequest]]).
587
0
        auto imported_module = get_imported_module(entry.module_request());
588
589
        // iii. If e.[[ImportName]] is all, then
590
0
        if (entry.kind == ExportEntry::Kind::ModuleRequestAll) {
591
            // 1. Assert: module does not provide the direct binding for this export.
592
            // FIXME: What does this mean? / How do we check this
593
594
            // 2. Return ResolvedBinding Record { [[Module]]: importedModule, [[BindingName]]: namespace }.
595
0
            return ResolvedBinding {
596
0
                ResolvedBinding::Type::Namespace,
597
0
                imported_module.ptr(),
598
0
                {}
599
0
            };
600
0
        }
601
        // iv. Else,
602
0
        else {
603
            // 1. Assert: module imports a specific binding for this export.
604
            // FIXME: What does this mean? / How do we check this
605
606
            // 2. Return ? importedModule.ResolveExport(e.[[ImportName]], resolveSet).
607
0
            return imported_module->resolve_export(vm, entry.local_or_import_name.value(), resolve_set);
608
0
        }
609
0
    }
610
611
    // 7. If SameValue(exportName, "default") is true, then
612
0
    if (export_name == "default"sv) {
613
        // a. Assert: A default export was not explicitly defined by this module.
614
        // FIXME: What does this mean? / How do we check this
615
616
        // b. Return null.
617
0
        return ResolvedBinding::null();
618
        // c. NOTE: A default export cannot be provided by an export * from "mod" declaration.
619
0
    }
620
621
    // 8. Let starResolution be null.
622
0
    ResolvedBinding star_resolution = ResolvedBinding::null();
623
624
    // 9. For each ExportEntry Record e of module.[[StarExportEntries]], do
625
0
    for (auto& entry : m_star_export_entries) {
626
        // a. Assert: e.[[ModuleRequest]] is not null.
627
        // b. Let importedModule be GetImportedModule(module, e.[[ModuleRequest]]).
628
0
        auto imported_module = get_imported_module(entry.module_request());
629
630
        // c. Let resolution be ? importedModule.ResolveExport(exportName, resolveSet).
631
0
        auto resolution = TRY(imported_module->resolve_export(vm, export_name, resolve_set));
632
633
        // d. If resolution is ambiguous, return ambiguous.
634
0
        if (resolution.is_ambiguous())
635
0
            return ResolvedBinding::ambiguous();
636
637
        // e. If resolution is not null, then
638
0
        if (resolution.type == ResolvedBinding::Null)
639
0
            continue;
640
641
        // i. Assert: resolution is a ResolvedBinding Record.
642
0
        VERIFY(resolution.is_valid());
643
644
        // ii. If starResolution is null, set starResolution to resolution.
645
0
        if (star_resolution.type == ResolvedBinding::Null) {
646
0
            star_resolution = resolution;
647
0
        }
648
        // iii. Else,
649
0
        else {
650
            // 1. Assert: There is more than one * import that includes the requested name.
651
            // FIXME: Assert this
652
653
            // 2. If resolution.[[Module]] and starResolution.[[Module]] are not the same Module Record, return ambiguous.
654
0
            if (resolution.module != star_resolution.module)
655
0
                return ResolvedBinding::ambiguous();
656
657
            // 3. If resolution.[[BindingName]] is namespace and starResolution.[[BindingName]] is not namespace, or if resolution.[[BindingName]] is not namespace and starResolution.[[BindingName]] is namespace, return ambiguous.
658
0
            if (resolution.is_namespace() != star_resolution.is_namespace())
659
0
                return ResolvedBinding::ambiguous();
660
661
            // 4. If resolution.[[BindingName]] is a String, starResolution.[[BindingName]] is a String, and SameValue(resolution.[[BindingName]], starResolution.[[BindingName]]) is false, return ambiguous.
662
0
            if (!resolution.is_namespace() && resolution.export_name != star_resolution.export_name) {
663
                // Note: Because we know from the previous if that either both are namespaces or both are string we can check just one
664
0
                return ResolvedBinding::ambiguous();
665
0
            }
666
0
        }
667
0
    }
668
669
    // 10. Return starResolution.
670
0
    return star_resolution;
671
0
}
672
673
// 16.2.1.6.5 ExecuteModule ( [ capability ] ), https://tc39.es/ecma262/#sec-source-text-module-record-execute-module
674
ThrowCompletionOr<void> SourceTextModule::execute_module(VM& vm, GCPtr<PromiseCapability> capability)
675
0
{
676
0
    dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] SourceTextModule::execute_module({}, PromiseCapability @ {})", filename(), capability.ptr());
677
678
    // 1. Let moduleContext be a new ECMAScript code execution context.
679
0
    auto module_context = ExecutionContext::create();
680
681
    // Note: This is not in the spec but we require it.
682
0
    module_context->is_strict_mode = true;
683
684
    // 2. Set the Function of moduleContext to null.
685
686
    // 3. Set the Realm of moduleContext to module.[[Realm]].
687
0
    module_context->realm = &realm();
688
689
    // 4. Set the ScriptOrModule of moduleContext to module.
690
0
    module_context->script_or_module = NonnullGCPtr<Module>(*this);
691
692
    // 5. Assert: module has been linked and declarations in its module environment have been instantiated.
693
0
    VERIFY(m_status != ModuleStatus::New);
694
0
    VERIFY(m_status != ModuleStatus::Unlinked);
695
0
    VERIFY(m_status != ModuleStatus::Linking);
696
0
    VERIFY(environment());
697
698
    // 6. Set the VariableEnvironment of moduleContext to module.[[Environment]].
699
0
    module_context->variable_environment = environment();
700
701
    // 7. Set the LexicalEnvironment of moduleContext to module.[[Environment]].
702
0
    module_context->lexical_environment = environment();
703
704
    // 8. Suspend the currently running execution context.
705
    // FIXME: We don't have suspend yet
706
707
    // 9. If module.[[HasTLA]] is false, then
708
0
    if (!m_has_top_level_await) {
709
        // a. Assert: capability is not present.
710
0
        VERIFY(capability == nullptr);
711
        // b. Push moduleContext onto the execution context stack; moduleContext is now the running execution context.
712
0
        TRY(vm.push_execution_context(*module_context, {}));
713
714
        // c. Let result be the result of evaluating module.[[ECMAScriptCode]].
715
0
        Completion result;
716
717
0
        auto maybe_executable = Bytecode::compile(vm, m_ecmascript_code, FunctionKind::Normal, "ShadowRealmEval"sv);
718
0
        if (maybe_executable.is_error())
719
0
            result = maybe_executable.release_error();
720
0
        else {
721
0
            auto executable = maybe_executable.release_value();
722
723
0
            auto result_and_return_register = vm.bytecode_interpreter().run_executable(*executable, {});
724
0
            if (result_and_return_register.value.is_error()) {
725
0
                result = result_and_return_register.value.release_error();
726
0
            } else {
727
                // Resulting value is in the accumulator.
728
0
                result = result_and_return_register.return_register_value.value_or(js_undefined());
729
0
            }
730
0
        }
731
732
        // d. Let env be moduleContext's LexicalEnvironment.
733
0
        auto env = module_context->lexical_environment;
734
0
        VERIFY(is<DeclarativeEnvironment>(*env));
735
736
        // e. Set result to DisposeResources(env, result).
737
0
        result = dispose_resources(vm, static_cast<DeclarativeEnvironment*>(env.ptr()), result);
738
739
        // f. Suspend moduleContext and remove it from the execution context stack.
740
0
        vm.pop_execution_context();
741
742
        // g. Resume the context that is now on the top of the execution context stack as the running execution context.
743
        // FIXME: We don't have resume yet.
744
745
        // h. If result is an abrupt completion, then
746
0
        if (result.is_error()) {
747
            // i. Return ? result.
748
0
            return result.release_error();
749
0
        }
750
0
    }
751
    // 10. Else,
752
0
    else {
753
        // a. Assert: capability is a PromiseCapability Record.
754
0
        VERIFY(capability != nullptr);
755
756
        // b. Perform AsyncBlockStart(capability, module.[[ECMAScriptCode]], moduleContext).
757
758
        // AD-HOC: We implement asynchronous execution via synthetic generator functions,
759
        //         so we fake "AsyncBlockStart" here by creating an async function to wrap
760
        //         the top-level module code.
761
        // FIXME: Improve this situation, so we can match the spec better.
762
763
        // AD-HOC: We push/pop the moduleContext around the function construction to ensure that the async execution context
764
        //         captures the module execution context.
765
0
        vm.push_execution_context(*module_context);
766
767
0
        FunctionParsingInsights parsing_insights;
768
0
        parsing_insights.uses_this_from_environment = true;
769
0
        parsing_insights.uses_this = true;
770
0
        auto module_wrapper_function = ECMAScriptFunctionObject::create(
771
0
            realm(), "module code with top-level await", StringView {}, this->m_ecmascript_code,
772
0
            {}, 0, {}, environment(), nullptr, FunctionKind::Async, true, parsing_insights);
773
0
        module_wrapper_function->set_is_module_wrapper(true);
774
775
0
        vm.pop_execution_context();
776
777
0
        auto result = call(vm, Value { module_wrapper_function }, js_undefined(), ReadonlySpan<Value> {});
778
779
        // AD-HOC: This is basically analogous to what AsyncBlockStart would do.
780
0
        if (result.is_throw_completion()) {
781
0
            MUST(call(vm, *capability->reject(), js_undefined(), result.throw_completion().value().value()));
782
0
        } else {
783
0
            MUST(call(vm, *capability->resolve(), js_undefined(), result.value()));
784
0
        }
785
0
    }
786
787
    // 11. Return unused.
788
0
    return {};
789
0
}
790
791
}