mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-10 02:51:55 +00:00
LibJS: Update spec steps / links for the import-assertions proposal
This proposal has reached stage 4 and been merged into the main ECMA-262
spec. See:
4e3450e
This commit is contained in:
parent
c1a3b95176
commit
3867a192a1
Notes:
github-actions[bot]
2025-04-29 11:35:05 +00:00
Author: https://github.com/trflynn89
Commit: 3867a192a1
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4514
17 changed files with 223 additions and 225 deletions
|
@ -20,10 +20,10 @@ namespace JS {
|
|||
|
||||
GC_DEFINE_ALLOCATOR(SourceTextModule);
|
||||
|
||||
// 16.2.2.2 Static Semantics: WithClauseToAttributes, https://tc39.es/proposal-import-attributes/#sec-with-clause-to-attributes
|
||||
// 16.2.2.4 Static Semantics: WithClauseToAttributes, https://tc39.es/ecma262/#sec-withclausetoattributes
|
||||
static Vector<ImportAttribute> with_clause_to_assertions(Vector<ImportAttribute> const& source_attributes)
|
||||
{
|
||||
// WithClause : AttributesKeyword { WithEntries , opt }
|
||||
// WithClause : with { WithEntries ,opt }
|
||||
// 1. Let attributes be WithClauseToAttributes of WithEntries.
|
||||
Vector<ImportAttribute> attributes;
|
||||
|
||||
|
@ -37,18 +37,20 @@ static Vector<ImportAttribute> with_clause_to_assertions(Vector<ImportAttribute>
|
|||
attributes.empend(attribute);
|
||||
}
|
||||
|
||||
// 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.
|
||||
// Note: The sorting is done in construction of the ModuleRequest object.
|
||||
// 2. Sort attributes according to the lexicographic order of their [[Key]] field, 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 changing behaviour based on the order in which attributes are enumerated.
|
||||
// NOTE: The sorting is done in construction of the ModuleRequest object.
|
||||
|
||||
// 3. Return attributes.
|
||||
return attributes;
|
||||
}
|
||||
|
||||
// 16.2.1.3 Static Semantics: ModuleRequests, https://tc39.es/ecma262/#sec-static-semantics-modulerequests
|
||||
// 16.2.1.4 Static Semantics: ModuleRequests, https://tc39.es/ecma262/#sec-static-semantics-modulerequests
|
||||
static Vector<ModuleRequest> module_requests(Program& program)
|
||||
{
|
||||
// A List of all the ModuleSpecifier strings used by the module represented by this record to request the importation of a module.
|
||||
// Note: The List is source text occurrence ordered!
|
||||
// NOTE: The List is source text occurrence ordered!
|
||||
struct RequestedModuleAndSourceIndex {
|
||||
u32 source_offset { 0 };
|
||||
ModuleRequest const* module_request { nullptr };
|
||||
|
@ -56,44 +58,45 @@ static Vector<ModuleRequest> module_requests(Program& program)
|
|||
|
||||
Vector<RequestedModuleAndSourceIndex> requested_modules_with_indices;
|
||||
|
||||
for (auto& import_statement : program.imports())
|
||||
for (auto const& import_statement : program.imports())
|
||||
requested_modules_with_indices.empend(import_statement->start_offset(), &import_statement->module_request());
|
||||
|
||||
for (auto& export_statement : program.exports()) {
|
||||
for (auto& export_entry : export_statement->entries()) {
|
||||
for (auto const& export_statement : program.exports()) {
|
||||
for (auto const& export_entry : export_statement->entries()) {
|
||||
if (!export_entry.is_module_request())
|
||||
continue;
|
||||
requested_modules_with_indices.empend(export_statement->start_offset(), &export_statement->module_request());
|
||||
}
|
||||
}
|
||||
|
||||
// Note: The List is source code occurrence ordered. https://tc39.es/proposal-import-attributes/#table-cyclic-module-fields
|
||||
// NOTE: The List is source code occurrence ordered. https://tc39.es/ecma262/#table-cyclic-module-fields
|
||||
quick_sort(requested_modules_with_indices, [&](RequestedModuleAndSourceIndex const& lhs, RequestedModuleAndSourceIndex const& rhs) {
|
||||
return lhs.source_offset < rhs.source_offset;
|
||||
});
|
||||
|
||||
Vector<ModuleRequest> requested_modules_in_source_order;
|
||||
requested_modules_in_source_order.ensure_capacity(requested_modules_with_indices.size());
|
||||
for (auto& module : requested_modules_with_indices) {
|
||||
// 16.2.1.3 Static Semantics: ModuleRequests, https://tc39.es/proposal-import-attributes/#sec-static-semantics-modulerequests
|
||||
if (module.module_request->attributes.is_empty()) {
|
||||
// ExportDeclaration : export ExportFromClause FromClause ;
|
||||
// ImportDeclaration : import ImportClause FromClause ;
|
||||
|
||||
// 2. Let specifier be SV of FromClause.
|
||||
// 3. Return a List whose sole element is the ModuleRequest Record { [[Specifer]]: specifier, [[Attributes]]: « » }.
|
||||
for (auto const& module : requested_modules_with_indices) {
|
||||
if (module.module_request->attributes.is_empty()) {
|
||||
// ImportDeclaration : import ImportClause FromClause ;
|
||||
// ExportDeclaration : export ExportFromClause FromClause ;
|
||||
|
||||
// 1. Let specifier be SV of FromClause.
|
||||
// 2. Return a List whose sole element is the ModuleRequest Record { [[Specifer]]: specifier, [[Attributes]]: « » }.
|
||||
requested_modules_in_source_order.empend(module.module_request->module_specifier);
|
||||
} else {
|
||||
// ExportDeclaration : export ExportFromClause FromClause WithClause ;
|
||||
// ImportDeclaration : import ImportClause FromClause WithClause ;
|
||||
// ImportDeclaration : import ImportClause FromClause WithClause ;
|
||||
// ExportDeclaration : export ExportFromClause FromClause WithClause ;
|
||||
|
||||
// 1. Let specifier be the SV of FromClause.
|
||||
// 2. Let attributes be WithClauseToAttributes of WithClause.
|
||||
auto attributes = with_clause_to_assertions(module.module_request->attributes);
|
||||
|
||||
// NOTE: We have to modify the attributes in place because else it might keep unsupported ones.
|
||||
const_cast<ModuleRequest*>(module.module_request)->attributes = move(attributes);
|
||||
|
||||
// 3. Return a List whose sole element is the ModuleRequest Record { [[Specifer]]: specifier, [[Attributes]]: attributes }.
|
||||
// 3. Return a List whose sole element is the ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: attributes }.
|
||||
requested_modules_in_source_order.empend(module.module_request->module_specifier, module.module_request->attributes);
|
||||
}
|
||||
}
|
||||
|
@ -125,7 +128,7 @@ void SourceTextModule::visit_edges(Cell::Visitor& visitor)
|
|||
m_execution_context->visit_edges(visitor);
|
||||
}
|
||||
|
||||
// 16.2.1.6.1 ParseModule ( sourceText, realm, hostDefined ), https://tc39.es/ecma262/#sec-parsemodule
|
||||
// 16.2.1.7.1 ParseModule ( sourceText, realm, hostDefined ), https://tc39.es/ecma262/#sec-parsemodule
|
||||
Result<GC::Ref<SourceTextModule>, Vector<ParserError>> SourceTextModule::parse(StringView source_text, Realm& realm, StringView filename, Script::HostDefined* host_defined)
|
||||
{
|
||||
// 1. Let body be ParseText(sourceText, Module).
|
||||
|
@ -145,7 +148,7 @@ Result<GC::Ref<SourceTextModule>, Vector<ParserError>> SourceTextModule::parse(S
|
|||
import_entries.extend(import_statement->entries());
|
||||
|
||||
// 5. Let importedBoundNames be ImportedLocalNames(importEntries).
|
||||
// Note: Since we have to potentially extract the import entry we just use importEntries
|
||||
// NOTE: Since we have to potentially extract the import entry we just use importEntries
|
||||
// In the future it might be an optimization to have a set/map of string to speed up the search.
|
||||
|
||||
// 6. Let indirectExportEntries be a new empty List.
|
||||
|
@ -157,13 +160,12 @@ Result<GC::Ref<SourceTextModule>, Vector<ParserError>> SourceTextModule::parse(S
|
|||
// 8. Let starExportEntries be a new empty List.
|
||||
Vector<ExportEntry> star_export_entries;
|
||||
|
||||
// Note: Not in the spec but makes it easier to find the default.
|
||||
// NOTE: Not in the spec but makes it easier to find the default.
|
||||
RefPtr<ExportStatement const> default_export;
|
||||
|
||||
// 9. Let exportEntries be ExportEntries of body.
|
||||
// 10. For each ExportEntry Record ee of exportEntries, do
|
||||
for (auto const& export_statement : body->exports()) {
|
||||
|
||||
if (export_statement->is_default_export()) {
|
||||
VERIFY(!default_export);
|
||||
VERIFY(export_statement->entries().size() == 1);
|
||||
|
@ -181,7 +183,6 @@ Result<GC::Ref<SourceTextModule>, Vector<ParserError>> SourceTextModule::parse(S
|
|||
}
|
||||
|
||||
for (auto const& export_entry : export_statement->entries()) {
|
||||
|
||||
// Special case, export {} from "module" should add "module" to
|
||||
// required_modules but not any import or export so skip here.
|
||||
if (export_entry.kind == ExportEntry::Kind::EmptyNamedExport) {
|
||||
|
@ -207,7 +208,7 @@ Result<GC::Ref<SourceTextModule>, Vector<ParserError>> SourceTextModule::parse(S
|
|||
// 1. Let ie be the element of importEntries whose [[LocalName]] is the same as ee.[[LocalName]].
|
||||
auto& import_entry = *in_imported_bound_names;
|
||||
|
||||
// 2. If ie.[[ImportName]] is namespace-object, then
|
||||
// 2. If ie.[[ImportName]] is NAMESPACE-OBJECT, then
|
||||
if (import_entry.is_namespace()) {
|
||||
// a. NOTE: This is a re-export of an imported module namespace object.
|
||||
// b. Append ee to localExportEntries.
|
||||
|
@ -260,33 +261,34 @@ Result<GC::Ref<SourceTextModule>, Vector<ParserError>> SourceTextModule::parse(S
|
|||
move(default_export));
|
||||
}
|
||||
|
||||
// 16.2.1.6.2 GetExportedNames ( [ exportStarSet ] ), https://tc39.es/ecma262/#sec-getexportednames
|
||||
ThrowCompletionOr<Vector<FlyString>> SourceTextModule::get_exported_names(VM& vm, Vector<Module*> export_star_set)
|
||||
// 16.2.1.7.2.1 GetExportedNames ( [ exportStarSet ] ), https://tc39.es/ecma262/#sec-getexportednames
|
||||
Vector<FlyString> SourceTextModule::get_exported_names(VM& vm, HashTable<Module const*>& export_star_set)
|
||||
{
|
||||
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] get_export_names of {}", filename());
|
||||
// 1. Assert: module.[[Status]] is not new.
|
||||
|
||||
// 1. Assert: module.[[Status]] is not NEW.
|
||||
VERIFY(m_status != ModuleStatus::New);
|
||||
|
||||
// 2. If exportStarSet is not present, set exportStarSet to a new empty List.
|
||||
// Note: This is done by default argument
|
||||
// NOTE: This is done by Module.
|
||||
|
||||
// 3. If exportStarSet contains module, then
|
||||
if (export_star_set.contains_slow(this)) {
|
||||
if (export_star_set.contains(this)) {
|
||||
// a. Assert: We've reached the starting point of an export * circularity.
|
||||
// FIXME: How do we check that?
|
||||
|
||||
// b. Return a new empty List.
|
||||
return Vector<FlyString> {};
|
||||
return {};
|
||||
}
|
||||
|
||||
// 4. Append module to exportStarSet.
|
||||
export_star_set.append(this);
|
||||
export_star_set.set(this);
|
||||
|
||||
// 5. Let exportedNames be a new empty List.
|
||||
Vector<FlyString> exported_names;
|
||||
|
||||
// 6. For each ExportEntry Record e of module.[[LocalExportEntries]], do
|
||||
for (auto& entry : m_local_export_entries) {
|
||||
for (auto const& entry : m_local_export_entries) {
|
||||
// a. Assert: module provides the direct binding for this export.
|
||||
// FIXME: How do we check that?
|
||||
|
||||
|
@ -298,7 +300,7 @@ ThrowCompletionOr<Vector<FlyString>> SourceTextModule::get_exported_names(VM& vm
|
|||
}
|
||||
|
||||
// 7. For each ExportEntry Record e of module.[[IndirectExportEntries]], do
|
||||
for (auto& entry : m_indirect_export_entries) {
|
||||
for (auto const& entry : m_indirect_export_entries) {
|
||||
// a. a. Assert: module imports a specific binding for this export.
|
||||
// FIXME: How do we check that?
|
||||
|
||||
|
@ -310,19 +312,19 @@ ThrowCompletionOr<Vector<FlyString>> SourceTextModule::get_exported_names(VM& vm
|
|||
}
|
||||
|
||||
// 8. For each ExportEntry Record e of module.[[StarExportEntries]], do
|
||||
for (auto& entry : m_star_export_entries) {
|
||||
for (auto const& entry : m_star_export_entries) {
|
||||
// a. Assert: e.[[ModuleRequest]] is not null.
|
||||
// b. Let requestedModule be GetImportedModule(module, e.[[ModuleRequest]]).
|
||||
auto requested_module = get_imported_module(entry.module_request());
|
||||
|
||||
// c. Let starNames be ? requestedModule.GetExportedNames(exportStarSet).
|
||||
auto star_names = TRY(requested_module->get_exported_names(vm, export_star_set));
|
||||
// c. Let starNames be requestedModule.GetExportedNames(exportStarSet).
|
||||
auto star_names = requested_module->get_exported_names(vm, export_star_set);
|
||||
|
||||
// d. For each element n of starNames, do
|
||||
for (auto& name : star_names) {
|
||||
// i. If SameValue(n, "default") is false, then
|
||||
for (auto const& name : star_names) {
|
||||
// i. If n is not "default", then
|
||||
if (name != "default"sv) {
|
||||
// 1. If n is not an element of exportedNames, then
|
||||
// 1. If exportedNames does not contain n, then
|
||||
if (!exported_names.contains_slow(name)) {
|
||||
// a. Append n to exportedNames.
|
||||
exported_names.empend(name);
|
||||
|
@ -335,14 +337,18 @@ ThrowCompletionOr<Vector<FlyString>> SourceTextModule::get_exported_names(VM& vm
|
|||
return exported_names;
|
||||
}
|
||||
|
||||
// 16.2.1.6.4 InitializeEnvironment ( ), https://tc39.es/ecma262/#sec-source-text-module-record-initialize-environment
|
||||
// 16.2.1.7.3.1 InitializeEnvironment ( ), https://tc39.es/ecma262/#sec-source-text-module-record-initialize-environment
|
||||
ThrowCompletionOr<void> SourceTextModule::initialize_environment(VM& vm)
|
||||
{
|
||||
// 1. For each ExportEntry Record e of module.[[IndirectExportEntries]], do
|
||||
for (auto& entry : m_indirect_export_entries) {
|
||||
// a. Let resolution be ? module.ResolveExport(e.[[ExportName]]).
|
||||
auto resolution = TRY(resolve_export(vm, entry.export_name.value()));
|
||||
// b. If resolution is null or ambiguous, throw a SyntaxError exception.
|
||||
for (auto const& entry : m_indirect_export_entries) {
|
||||
// a. Assert: e.[[ExportName]] is not null.
|
||||
VERIFY(entry.export_name.has_value());
|
||||
|
||||
// a. Let resolution be module.ResolveExport(e.[[ExportName]]).
|
||||
auto resolution = resolve_export(vm, entry.export_name.value());
|
||||
|
||||
// b. If resolution is either null or AMBIGUOUS, throw a SyntaxError exception.
|
||||
if (!resolution.is_valid())
|
||||
return vm.throw_completion<SyntaxError>(ErrorType::InvalidOrAmbiguousExportEntry, entry.export_name);
|
||||
|
||||
|
@ -351,29 +357,27 @@ ThrowCompletionOr<void> SourceTextModule::initialize_environment(VM& vm)
|
|||
}
|
||||
|
||||
// 2. Assert: All named exports from module are resolvable.
|
||||
// Note: We check all the indirect export entries above in step 1 and all
|
||||
// the local named exports are resolvable by construction.
|
||||
// NOTE: We check all the indirect export entries above in step 1 and all the local named exports are resolvable by construction.
|
||||
|
||||
// 3. Let realm be module.[[Realm]].
|
||||
// 4. Assert: realm is not undefined.
|
||||
// Note: This must be true because we use a reference.
|
||||
auto& realm = this->realm();
|
||||
|
||||
// 5. Let env be NewModuleEnvironment(realm.[[GlobalEnv]]).
|
||||
auto environment = vm.heap().allocate<ModuleEnvironment>(&realm().global_environment());
|
||||
auto environment = vm.heap().allocate<ModuleEnvironment>(&realm.global_environment());
|
||||
|
||||
// 6. Set module.[[Environment]] to env.
|
||||
set_environment(environment);
|
||||
|
||||
// 7. For each ImportEntry Record in of module.[[ImportEntries]], do
|
||||
for (auto& import_entry : m_import_entries) {
|
||||
for (auto const& import_entry : m_import_entries) {
|
||||
// a. Let importedModule be GetImportedModule(module, in.[[ModuleRequest]]).
|
||||
auto imported_module = get_imported_module(import_entry.module_request());
|
||||
// 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.
|
||||
|
||||
// c. If in.[[ImportName]] is namespace-object, then
|
||||
// b. If in.[[ImportName]] is NAMESPACE-OBJECT, then
|
||||
if (import_entry.is_namespace()) {
|
||||
// i. Let namespace be ? GetModuleNamespace(importedModule).
|
||||
auto* namespace_ = TRY(imported_module->get_module_namespace(vm));
|
||||
// i. Let namespace be GetModuleNamespace(importedModule).
|
||||
auto namespace_ = imported_module->get_module_namespace(vm);
|
||||
|
||||
// ii. Perform ! env.CreateImmutableBinding(in.[[LocalName]], true).
|
||||
MUST(environment->create_immutable_binding(vm, import_entry.local_name, true));
|
||||
|
@ -381,19 +385,19 @@ ThrowCompletionOr<void> SourceTextModule::initialize_environment(VM& vm)
|
|||
// iii. Perform ! env.InitializeBinding(in.[[LocalName]], namespace, normal).
|
||||
MUST(environment->initialize_binding(vm, import_entry.local_name, namespace_, Environment::InitializeBindingHint::Normal));
|
||||
}
|
||||
// d. Else,
|
||||
// c. Else,
|
||||
else {
|
||||
// i. Let resolution be ? importedModule.ResolveExport(in.[[ImportName]]).
|
||||
auto resolution = TRY(imported_module->resolve_export(vm, import_entry.import_name.value()));
|
||||
// i. Let resolution be importedModule.ResolveExport(in.[[ImportName]]).
|
||||
auto resolution = imported_module->resolve_export(vm, import_entry.import_name.value());
|
||||
|
||||
// ii. If resolution is null or ambiguous, throw a SyntaxError exception.
|
||||
// ii. If resolution is either null or AMBIGUOUS, throw a SyntaxError exception.
|
||||
if (!resolution.is_valid())
|
||||
return vm.throw_completion<SyntaxError>(ErrorType::InvalidOrAmbiguousExportEntry, import_entry.import_name);
|
||||
|
||||
// iii. If resolution.[[BindingName]] is namespace, then
|
||||
// iii. If resolution.[[BindingName]] is NAMESPACE, then
|
||||
if (resolution.is_namespace()) {
|
||||
// 1. Let namespace be ? GetModuleNamespace(resolution.[[Module]]).
|
||||
auto* namespace_ = TRY(resolution.module->get_module_namespace(vm));
|
||||
// 1. Let namespace be GetModuleNamespace(resolution.[[Module]]).
|
||||
auto namespace_ = resolution.module->get_module_namespace(vm);
|
||||
|
||||
// 2. Perform ! env.CreateImmutableBinding(in.[[LocalName]], true).
|
||||
MUST(environment->create_immutable_binding(vm, import_entry.local_name, true));
|
||||
|
@ -410,15 +414,15 @@ ThrowCompletionOr<void> SourceTextModule::initialize_environment(VM& vm)
|
|||
}
|
||||
|
||||
// 8. Let moduleContext be a new ECMAScript code execution context.
|
||||
// Note: this has already been created during the construction of this object.
|
||||
// NOTE: this has already been created during the construction of this object.
|
||||
|
||||
// 9. Set the Function of moduleContext to null.
|
||||
|
||||
// 10. Assert: module.[[Realm]] is not undefined.
|
||||
// Note: This must be true because we use a reference.
|
||||
// NOTE: This must be true because we use a reference.
|
||||
|
||||
// 11. Set the Realm of moduleContext to module.[[Realm]].
|
||||
m_execution_context->realm = &realm();
|
||||
m_execution_context->realm = &this->realm();
|
||||
|
||||
// 12. Set the ScriptOrModule of moduleContext to module.
|
||||
m_execution_context->script_or_module = GC::Ref<Module>(*this);
|
||||
|
@ -432,7 +436,7 @@ ThrowCompletionOr<void> SourceTextModule::initialize_environment(VM& vm)
|
|||
// 15. Set the PrivateEnvironment of moduleContext to null.
|
||||
|
||||
// 16. Set module.[[Context]] to moduleContext.
|
||||
// Note: We're already working on that one.
|
||||
// NOTE: We're already working on that one.
|
||||
|
||||
// 17. Push moduleContext onto the execution context stack; moduleContext is now the running execution context.
|
||||
TRY(vm.push_execution_context(*m_execution_context, {}));
|
||||
|
@ -440,7 +444,7 @@ ThrowCompletionOr<void> SourceTextModule::initialize_environment(VM& vm)
|
|||
// 18. Let code be module.[[ECMAScriptCode]].
|
||||
|
||||
// 19. Let varDeclarations be the VarScopedDeclarations of code.
|
||||
// Note: We just loop through them in step 21.
|
||||
// NOTE: We just loop through them in step 21.
|
||||
|
||||
// 20. Let declaredVarNames be a new empty List.
|
||||
Vector<FlyString> declared_var_names;
|
||||
|
@ -465,7 +469,7 @@ ThrowCompletionOr<void> SourceTextModule::initialize_environment(VM& vm)
|
|||
}));
|
||||
|
||||
// 22. Let lexDeclarations be the LexicallyScopedDeclarations of code.
|
||||
// Note: We only loop through them in step 24.
|
||||
// NOTE: We only loop through them in step 24.
|
||||
|
||||
// 23. Let privateEnv be null.
|
||||
PrivateEnvironment* private_environment = nullptr;
|
||||
|
@ -474,8 +478,6 @@ ThrowCompletionOr<void> SourceTextModule::initialize_environment(VM& vm)
|
|||
// NOTE: Due to the use of MUST in the callback, an exception should not result from `for_each_lexically_scoped_declaration`.
|
||||
MUST(m_ecmascript_code->for_each_lexically_scoped_declaration([&](Declaration const& declaration) {
|
||||
// a. For each element dn of the BoundNames of d, do
|
||||
// NOTE: Due to the use of MUST with `create_immutable_binding`, `create_mutable_binding` and `initialize_binding` below,
|
||||
// an exception should not result from `for_each_bound_identifier`.
|
||||
MUST(declaration.for_each_bound_identifier([&](auto const& identifier) {
|
||||
auto const& name = identifier.string();
|
||||
// i. If IsConstantDeclaration of d is true, then
|
||||
|
@ -503,7 +505,7 @@ ThrowCompletionOr<void> SourceTextModule::initialize_environment(VM& vm)
|
|||
auto function = ECMAScriptFunctionObject::create_from_function_node(
|
||||
function_declaration,
|
||||
function_name,
|
||||
realm(),
|
||||
realm,
|
||||
environment,
|
||||
private_environment);
|
||||
|
||||
|
@ -513,23 +515,20 @@ ThrowCompletionOr<void> SourceTextModule::initialize_environment(VM& vm)
|
|||
}));
|
||||
}));
|
||||
|
||||
// Note: The default export name is also part of the local lexical declarations but
|
||||
// instead of making that a special case in the parser we just check it here.
|
||||
// This is only needed for things which are not declarations.
|
||||
// For more info check Parser::parse_export_statement.
|
||||
// Furthermore, that declaration is not constant. so we take 24.a.ii
|
||||
// NOTE: The default export name is also part of the local lexical declarations but instead of making that a special
|
||||
// case in the parser we just check it here. This is only needed for things which are not declarations. For more
|
||||
// info check Parser::parse_export_statement. Furthermore, that declaration is not constant. so we take 24.a.ii.
|
||||
if (m_default_export) {
|
||||
VERIFY(m_default_export->has_statement());
|
||||
|
||||
auto const& statement = m_default_export->statement();
|
||||
if (!is<Declaration>(statement)) {
|
||||
if (auto const& statement = m_default_export->statement(); !is<Declaration>(statement)) {
|
||||
auto const& name = m_default_export->entries()[0].local_or_import_name;
|
||||
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] Adding default export to lexical declarations: local name: {}, Expression: {}", name, statement.class_name());
|
||||
|
||||
// 1. Perform ! env.CreateMutableBinding(dn, false).
|
||||
MUST(environment->create_mutable_binding(vm, name.value(), false));
|
||||
|
||||
// Note: Since this is not a function declaration 24.a.iii never applies
|
||||
// NOTE: Since this is not a function declaration 24.a.iii never applies
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -540,18 +539,18 @@ ThrowCompletionOr<void> SourceTextModule::initialize_environment(VM& vm)
|
|||
return {};
|
||||
}
|
||||
|
||||
// 16.2.1.6.3 ResolveExport ( exportName [ , resolveSet ] ), https://tc39.es/ecma262/#sec-resolveexport
|
||||
ThrowCompletionOr<ResolvedBinding> SourceTextModule::resolve_export(VM& vm, FlyString const& export_name, Vector<ResolvedBinding> resolve_set)
|
||||
// 16.2.1.7.2.2 ResolveExport ( exportName [ , resolveSet ] ), https://tc39.es/ecma262/#sec-resolveexport
|
||||
ResolvedBinding SourceTextModule::resolve_export(VM& vm, FlyString const& export_name, Vector<ResolvedBinding> resolve_set)
|
||||
{
|
||||
// 1. Assert: module.[[Status]] is not new.
|
||||
// 1. Assert: module.[[Status]] is not NEW.
|
||||
VERIFY(m_status != ModuleStatus::New);
|
||||
|
||||
// 2. If resolveSet is not present, set resolveSet to a new empty List.
|
||||
// Note: This is done by the default argument.
|
||||
// NOTE: This is done by the default argument.
|
||||
|
||||
// 3. For each Record { [[Module]], [[ExportName]] } r of resolveSet, do
|
||||
for (auto& [type, module, exported_name] : resolve_set) {
|
||||
// a. If module and r.[[Module]] are the same Module Record and SameValue(exportName, r.[[ExportName]]) is true, then
|
||||
for (auto const& [type, module, exported_name] : resolve_set) {
|
||||
// a. If module and r.[[Module]] are the same Module Record and exportName is r.[[ExportName]], then
|
||||
if (module == this && exported_name == export_name) {
|
||||
// i. Assert: This is a circular import request.
|
||||
|
||||
|
@ -564,8 +563,8 @@ ThrowCompletionOr<ResolvedBinding> SourceTextModule::resolve_export(VM& vm, FlyS
|
|||
resolve_set.append({ ResolvedBinding::Type::BindingName, this, export_name });
|
||||
|
||||
// 5. For each ExportEntry Record e of module.[[LocalExportEntries]], do
|
||||
for (auto& entry : m_local_export_entries) {
|
||||
// a. If SameValue(exportName, e.[[ExportName]]) is true, then
|
||||
for (auto const& entry : m_local_export_entries) {
|
||||
// a. If e.[[ExportName]] is exportName, then
|
||||
if (export_name != entry.export_name)
|
||||
continue;
|
||||
|
||||
|
@ -581,8 +580,8 @@ ThrowCompletionOr<ResolvedBinding> SourceTextModule::resolve_export(VM& vm, FlyS
|
|||
}
|
||||
|
||||
// 5. For each ExportEntry Record e of module.[[IndirectExportEntries]], do
|
||||
for (auto& entry : m_indirect_export_entries) {
|
||||
// a. If SameValue(exportName, e.[[ExportName]]) is true, then
|
||||
for (auto const& entry : m_indirect_export_entries) {
|
||||
// a. If e.[[ExportName]] is exportName, then
|
||||
if (export_name != entry.export_name)
|
||||
continue;
|
||||
|
||||
|
@ -595,7 +594,7 @@ ThrowCompletionOr<ResolvedBinding> SourceTextModule::resolve_export(VM& vm, FlyS
|
|||
// 1. Assert: module does not provide the direct binding for this export.
|
||||
// FIXME: What does this mean? / How do we check this
|
||||
|
||||
// 2. Return ResolvedBinding Record { [[Module]]: importedModule, [[BindingName]]: namespace }.
|
||||
// 2. Return ResolvedBinding Record { [[Module]]: importedModule, [[BindingName]]: NAMESPACE }.
|
||||
return ResolvedBinding {
|
||||
ResolvedBinding::Type::Namespace,
|
||||
imported_module.ptr(),
|
||||
|
@ -607,34 +606,35 @@ ThrowCompletionOr<ResolvedBinding> SourceTextModule::resolve_export(VM& vm, FlyS
|
|||
// 1. Assert: module imports a specific binding for this export.
|
||||
// FIXME: What does this mean? / How do we check this
|
||||
|
||||
// 2. Return ? importedModule.ResolveExport(e.[[ImportName]], resolveSet).
|
||||
// 2. Return importedModule.ResolveExport(e.[[ImportName]], resolveSet).
|
||||
return imported_module->resolve_export(vm, entry.local_or_import_name.value(), resolve_set);
|
||||
}
|
||||
}
|
||||
|
||||
// 7. If SameValue(exportName, "default") is true, then
|
||||
// 7. If exportName is "default", then
|
||||
if (export_name == "default"sv) {
|
||||
// a. Assert: A default export was not explicitly defined by this module.
|
||||
// FIXME: What does this mean? / How do we check this
|
||||
|
||||
// b. Return null.
|
||||
return ResolvedBinding::null();
|
||||
|
||||
// c. NOTE: A default export cannot be provided by an export * from "mod" declaration.
|
||||
}
|
||||
|
||||
// 8. Let starResolution be null.
|
||||
ResolvedBinding star_resolution = ResolvedBinding::null();
|
||||
auto star_resolution = ResolvedBinding::null();
|
||||
|
||||
// 9. For each ExportEntry Record e of module.[[StarExportEntries]], do
|
||||
for (auto& entry : m_star_export_entries) {
|
||||
for (auto const& entry : m_star_export_entries) {
|
||||
// a. Assert: e.[[ModuleRequest]] is not null.
|
||||
// b. Let importedModule be GetImportedModule(module, e.[[ModuleRequest]]).
|
||||
auto imported_module = get_imported_module(entry.module_request());
|
||||
|
||||
// c. Let resolution be ? importedModule.ResolveExport(exportName, resolveSet).
|
||||
auto resolution = TRY(imported_module->resolve_export(vm, export_name, resolve_set));
|
||||
// c. Let resolution be importedModule.ResolveExport(exportName, resolveSet).
|
||||
auto resolution = imported_module->resolve_export(vm, export_name, resolve_set);
|
||||
|
||||
// d. If resolution is ambiguous, return ambiguous.
|
||||
// d. If resolution is AMBIGUOUS, return AMBIGUOUS.
|
||||
if (resolution.is_ambiguous())
|
||||
return ResolvedBinding::ambiguous();
|
||||
|
||||
|
@ -654,19 +654,20 @@ ThrowCompletionOr<ResolvedBinding> SourceTextModule::resolve_export(VM& vm, FlyS
|
|||
// 1. Assert: There is more than one * import that includes the requested name.
|
||||
// FIXME: Assert this
|
||||
|
||||
// 2. If resolution.[[Module]] and starResolution.[[Module]] are not the same Module Record, return ambiguous.
|
||||
// 2. If resolution.[[Module]] and starResolution.[[Module]] are not the same Module Record, return AMBIGUOUS.
|
||||
if (resolution.module != star_resolution.module)
|
||||
return ResolvedBinding::ambiguous();
|
||||
|
||||
// 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.
|
||||
// 3. If resolution.[[BindingName]] is not starResolution.[[BindingName]] and either resolution.[[BindingName]]
|
||||
// or starResolution.[[BindingName]] is NAMESPACE, return AMBIGUOUS.
|
||||
if (resolution.is_namespace() != star_resolution.is_namespace())
|
||||
return ResolvedBinding::ambiguous();
|
||||
|
||||
// 4. If resolution.[[BindingName]] is a String, starResolution.[[BindingName]] is a String, and SameValue(resolution.[[BindingName]], starResolution.[[BindingName]]) is false, return ambiguous.
|
||||
if (!resolution.is_namespace() && resolution.export_name != star_resolution.export_name) {
|
||||
// Note: Because we know from the previous if that either both are namespaces or both are string we can check just one
|
||||
// 4. If resolution.[[BindingName]] is a String, starResolution.[[BindingName]] is a String, and
|
||||
// resolution.[[BindingName]] is not starResolution.[[BindingName]], return ambiguous.
|
||||
// NOTE: We know from the previous step that either both are namespaces or both are string, so we can check just one.
|
||||
if (!resolution.is_namespace() && resolution.export_name != star_resolution.export_name)
|
||||
return ResolvedBinding::ambiguous();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -704,7 +705,7 @@ ThrowCompletionOr<void> SourceTextModule::execute_module(VM& vm, GC::Ptr<Promise
|
|||
ExecutionContext* module_context = nullptr;
|
||||
ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(module_context, registers_and_constants_and_locals_count, 0);
|
||||
|
||||
// Note: This is not in the spec but we require it.
|
||||
// NOTE: This is not in the spec but we require it.
|
||||
module_context->is_strict_mode = true;
|
||||
|
||||
// 2. Set the Function of moduleContext to null.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue