2021-09-14 18:51:16 +00:00
/*
* Copyright ( c ) 2021 , Andreas Kling < kling @ serenityos . org >
2022-01-18 18:29:17 +00:00
* Copyright ( c ) 2022 , David Tuin < davidot @ serenityos . org >
2021-09-14 18:51:16 +00:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2023-01-02 20:07:18 +00:00
# include <AK/Debug.h>
2022-01-18 18:29:17 +00:00
# include <AK/QuickSort.h>
# include <LibJS/Interpreter.h>
2022-11-23 12:28:01 +00:00
# include <LibJS/Parser.h>
2022-01-18 18:29:17 +00:00
# include <LibJS/Runtime/ECMAScriptFunctionObject.h>
# include <LibJS/Runtime/ModuleEnvironment.h>
2021-09-14 18:51:16 +00:00
# include <LibJS/SourceTextModule.h>
namespace JS {
2022-01-27 01:44:03 +00:00
// 2.7 Static Semantics: AssertClauseToAssertions, https://tc39.es/proposal-import-assertions/#sec-assert-clause-to-assertions
2022-12-04 18:02:33 +00:00
static Vector < ModuleRequest : : Assertion > assert_clause_to_assertions ( Vector < ModuleRequest : : Assertion > const & source_assertions , Vector < DeprecatedString > const & supported_import_assertions )
2022-01-27 01:44:03 +00:00
{
// AssertClause : assert { AssertEntries ,opt }
// 1. Let assertions be AssertClauseToAssertions of AssertEntries.
Vector < ModuleRequest : : Assertion > assertions ;
// AssertEntries : AssertionKey : StringLiteral
// AssertEntries : AssertionKey : StringLiteral , AssertEntries
// 1. Let supportedAssertions be !HostGetSupportedImportAssertions().
for ( auto & assertion : source_assertions ) {
// 2. Let key be StringValue of AssertionKey.
// 3. If supportedAssertions contains key,
if ( supported_import_assertions . contains_slow ( assertion . key ) ) {
// a. Let entry be a Record { [[Key]]: key, [[Value]]: StringValue of StringLiteral }.
assertions . empend ( assertion ) ;
}
}
// 2. Sort assertions by the code point order of the [[Key]] of each element. NOTE: This sorting is observable only in that hosts are prohibited from distinguishing among assertions by the order they occur in.
// Note: The sorting is done in construction of the ModuleRequest object.
// 3. Return assertions.
return assertions ;
}
2022-01-18 18:29:17 +00:00
// 16.2.1.3 Static Semantics: ModuleRequests, https://tc39.es/ecma262/#sec-static-semantics-modulerequests
2022-12-04 18:02:33 +00:00
static Vector < ModuleRequest > module_requests ( Program & program , Vector < DeprecatedString > const & supported_import_assertions )
2022-01-18 18:29:17 +00:00
{
// 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!
struct RequestedModuleAndSourceIndex {
2022-11-27 00:15:37 +00:00
u32 source_offset { 0 } ;
2022-01-27 01:44:03 +00:00
ModuleRequest * module_request { nullptr } ;
2022-01-18 18:29:17 +00:00
} ;
Vector < RequestedModuleAndSourceIndex > requested_modules_with_indices ;
2022-11-27 00:15:37 +00:00
for ( auto & import_statement : program . imports ( ) )
requested_modules_with_indices . empend ( import_statement . start_offset ( ) , & import_statement . module_request ( ) ) ;
2022-01-18 18:29:17 +00:00
2022-01-27 01:44:03 +00:00
for ( auto & export_statement : program . exports ( ) ) {
for ( auto & export_entry : export_statement . entries ( ) ) {
2022-01-27 00:54:47 +00:00
if ( ! export_entry . is_module_request ( ) )
2022-01-18 18:29:17 +00:00
continue ;
2022-11-27 00:15:37 +00:00
requested_modules_with_indices . empend ( export_statement . start_offset ( ) , & export_statement . module_request ( ) ) ;
2022-01-18 18:29:17 +00:00
}
}
2022-01-27 01:44:03 +00:00
// Note: The List is source code occurrence ordered. https://tc39.es/proposal-import-assertions/#table-cyclic-module-fields
quick_sort ( requested_modules_with_indices , [ & ] ( RequestedModuleAndSourceIndex const & lhs , RequestedModuleAndSourceIndex const & rhs ) {
2022-11-27 00:15:37 +00:00
return lhs . source_offset < rhs . source_offset ;
2022-01-27 01:44:03 +00:00
} ) ;
2022-01-18 18:29:17 +00:00
2022-01-27 01:44:03 +00:00
Vector < ModuleRequest > requested_modules_in_source_order ;
2022-01-18 18:29:17 +00:00
requested_modules_in_source_order . ensure_capacity ( requested_modules_with_indices . size ( ) ) ;
for ( auto & module : requested_modules_with_indices ) {
2022-01-27 01:44:03 +00:00
// 2.10 Static Semantics: ModuleRequests https://tc39.es/proposal-import-assertions/#sec-static-semantics-modulerequests
if ( module . module_request - > assertions . is_empty ( ) ) {
// ExportDeclaration : export ExportFromClause FromClause ;
// ImportDeclaration : import ImportClause FromClause ;
// 1. Let specifier be StringValue of the StringLiteral contained in FromClause.
// 2. Return a ModuleRequest Record { [[Specifer]]: specifier, [[Assertions]]: an empty List }.
requested_modules_in_source_order . empend ( module . module_request - > module_specifier ) ;
} else {
// ExportDeclaration : export ExportFromClause FromClause AssertClause ;
// ImportDeclaration : import ImportClause FromClause AssertClause ;
// 1. Let specifier be StringValue of the StringLiteral contained in FromClause.
// 2. Let assertions be AssertClauseToAssertions of AssertClause.
auto assertions = assert_clause_to_assertions ( module . module_request - > assertions , supported_import_assertions ) ;
// Note: We have to modify the assertions in place because else it might keep non supported ones
module . module_request - > assertions = move ( assertions ) ;
// 3. Return a ModuleRequest Record { [[Specifer]]: specifier, [[Assertions]]: assertions }.
requested_modules_in_source_order . empend ( module . module_request - > module_specifier , module . module_request - > assertions ) ;
}
2022-01-18 18:29:17 +00:00
}
return requested_modules_in_source_order ;
}
2022-10-02 19:18:33 +00:00
SourceTextModule : : SourceTextModule ( Realm & realm , StringView filename , Script : : HostDefined * host_defined , bool has_top_level_await , NonnullRefPtr < Program > body , Vector < ModuleRequest > requested_modules ,
2022-01-18 18:29:17 +00:00
Vector < ImportEntry > import_entries , Vector < ExportEntry > local_export_entries ,
Vector < ExportEntry > indirect_export_entries , Vector < ExportEntry > star_export_entries ,
RefPtr < ExportStatement > default_export )
2022-10-02 19:18:33 +00:00
: CyclicModule ( realm , filename , has_top_level_await , move ( requested_modules ) , host_defined )
2022-01-18 18:29:17 +00:00
, m_ecmascript_code ( move ( body ) )
, m_execution_context ( realm . heap ( ) )
, m_import_entries ( move ( import_entries ) )
, m_local_export_entries ( move ( local_export_entries ) )
, m_indirect_export_entries ( move ( indirect_export_entries ) )
, m_star_export_entries ( move ( star_export_entries ) )
, m_default_export ( move ( default_export ) )
{
}
2022-09-05 12:31:25 +00:00
void SourceTextModule : : visit_edges ( Cell : : Visitor & visitor )
{
Base : : visit_edges ( visitor ) ;
visitor . visit ( m_import_meta ) ;
}
2021-09-14 18:51:16 +00:00
// 16.2.1.6.1 ParseModule ( sourceText, realm, hostDefined ), https://tc39.es/ecma262/#sec-parsemodule
2022-11-23 11:39:23 +00:00
Result < NonnullGCPtr < SourceTextModule > , Vector < ParserError > > SourceTextModule : : parse ( StringView source_text , Realm & realm , StringView filename , Script : : HostDefined * host_defined )
2021-09-14 18:51:16 +00:00
{
// 1. Let body be ParseText(sourceText, Module).
auto parser = Parser ( Lexer ( source_text , filename ) , Program : : Type : : Module ) ;
auto body = parser . parse_program ( ) ;
// 2. If body is a List of errors, return body.
if ( parser . has_errors ( ) )
return parser . errors ( ) ;
2022-01-27 01:44:03 +00:00
// Needed for 2.7 Static Semantics: AssertClauseToAssertions, https://tc39.es/proposal-import-assertions/#sec-assert-clause-to-assertions
// 1. Let supportedAssertions be !HostGetSupportedImportAssertions().
auto supported_assertions = realm . vm ( ) . host_get_supported_import_assertions ( ) ;
2022-01-18 18:29:17 +00:00
// 3. Let requestedModules be the ModuleRequests of body.
2022-01-27 01:44:03 +00:00
auto requested_modules = module_requests ( * body , supported_assertions ) ;
2022-01-18 18:29:17 +00:00
// 4. Let importEntries be ImportEntries of body.
Vector < ImportEntry > import_entries ;
for ( auto const & import_statement : body - > imports ( ) )
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
// 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.
Vector < ExportEntry > indirect_export_entries ;
// 7. Let localExportEntries be a new empty List.
Vector < ExportEntry > local_export_entries ;
// 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.
RefPtr < ExportStatement > 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 ) ;
VERIFY ( export_statement . has_statement ( ) ) ;
auto const & entry = export_statement . entries ( ) [ 0 ] ;
2022-11-23 11:16:51 +00:00
VERIFY ( entry . kind = = ExportEntry : : Kind : : NamedExport ) ;
2022-01-27 00:54:47 +00:00
VERIFY ( ! entry . is_module_request ( ) ) ;
2022-01-18 18:29:17 +00:00
VERIFY ( import_entries . find_if (
[ & ] ( ImportEntry const & import_entry ) {
return import_entry . local_name = = entry . local_or_import_name ;
} )
. is_end ( ) ) ;
default_export = export_statement ;
}
for ( auto const & export_entry : export_statement . entries ( ) ) {
2022-08-29 20:12:25 +00:00
// Special case, export {} from "module" should add "module" to
// required_modules but not any import or export so skip here.
2022-11-23 11:16:51 +00:00
if ( export_entry . kind = = ExportEntry : : Kind : : EmptyNamedExport ) {
2022-08-29 20:12:25 +00:00
VERIFY ( export_statement . entries ( ) . size ( ) = = 1 ) ;
break ;
}
2022-01-18 18:29:17 +00:00
// a. If ee.[[ModuleRequest]] is null, then
2022-01-27 00:54:47 +00:00
if ( ! export_entry . is_module_request ( ) ) {
2022-01-18 18:29:17 +00:00
auto in_imported_bound_names = import_entries . find_if (
[ & ] ( ImportEntry const & import_entry ) {
return import_entry . local_name = = export_entry . local_or_import_name ;
} ) ;
// i. If ee.[[LocalName]] is not an element of importedBoundNames, then
if ( in_imported_bound_names . is_end ( ) ) {
// 1. Append ee to localExportEntries.
local_export_entries . empend ( export_entry ) ;
}
// ii. Else,
else {
// 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
2022-01-27 00:54:47 +00:00
if ( import_entry . is_namespace ) {
2022-01-18 18:29:17 +00:00
// a. NOTE: This is a re-export of an imported module namespace object.
// b. Append ee to localExportEntries.
local_export_entries . empend ( export_entry ) ;
}
// 3. Else,
else {
// a. NOTE: This is a re-export of a single name.
// b. Append the ExportEntry Record { [[ModuleRequest]]: ie.[[ModuleRequest]], [[ImportName]]: ie.[[ImportName]], [[LocalName]]: null, [[ExportName]]: ee.[[ExportName]] } to indirectExportEntries.
2022-01-27 00:54:47 +00:00
indirect_export_entries . empend ( ExportEntry : : indirect_export_entry ( import_entry . module_request ( ) , import_entry . import_name , export_entry . export_name ) ) ;
2022-01-18 18:29:17 +00:00
}
}
}
// b. Else if ee.[[ImportName]] is all-but-default, then
2022-11-23 11:16:51 +00:00
else if ( export_entry . kind = = ExportEntry : : Kind : : ModuleRequestAllButDefault ) {
2022-01-18 18:29:17 +00:00
// i. Assert: ee.[[ExportName]] is null.
VERIFY ( export_entry . export_name . is_null ( ) ) ;
// ii. Append ee to starExportEntries.
star_export_entries . empend ( export_entry ) ;
}
// c. Else,
else {
// i. Append ee to indirectExportEntries.
indirect_export_entries . empend ( export_entry ) ;
}
}
}
// 11. Let async be body Contains await.
bool async = body - > has_top_level_await ( ) ;
// 12. Return Source Text Module Record {
// [[Realm]]: realm, [[Environment]]: empty, [[Namespace]]: empty, [[CycleRoot]]: empty, [[HasTLA]]: async,
// [[AsyncEvaluation]]: false, [[TopLevelCapability]]: empty, [[AsyncParentModules]]: « »,
// [[PendingAsyncDependencies]]: empty, [[Status]]: unlinked, [[EvaluationError]]: empty,
// [[HostDefined]]: hostDefined, [[ECMAScriptCode]]: body, [[Context]]: empty, [[ImportMeta]]: empty,
// [[RequestedModules]]: requestedModules, [[ImportEntries]]: importEntries, [[LocalExportEntries]]: localExportEntries,
// [[IndirectExportEntries]]: indirectExportEntries, [[StarExportEntries]]: starExportEntries, [[DFSIndex]]: empty, [[DFSAncestorIndex]]: empty }.
2022-12-14 17:40:33 +00:00
return realm . heap ( ) . allocate_without_realm < SourceTextModule > (
2022-09-05 12:31:25 +00:00
realm ,
filename ,
2022-10-02 19:18:33 +00:00
host_defined ,
2022-09-05 12:31:25 +00:00
async ,
move ( body ) ,
move ( requested_modules ) ,
move ( import_entries ) ,
move ( local_export_entries ) ,
move ( indirect_export_entries ) ,
move ( star_export_entries ) ,
2022-12-14 17:40:33 +00:00
move ( default_export ) ) ;
2021-09-14 18:51:16 +00:00
}
2022-01-18 18:29:17 +00:00
// 16.2.1.6.2 GetExportedNames ( [ exportStarSet ] ), https://tc39.es/ecma262/#sec-getexportednames
2023-01-09 00:23:00 +00:00
ThrowCompletionOr < Vector < DeprecatedFlyString > > SourceTextModule : : get_exported_names ( VM & vm , Vector < Module * > export_star_set )
2021-09-14 18:51:16 +00:00
{
2022-01-18 18:29:17 +00:00
dbgln_if ( JS_MODULE_DEBUG , " [JS MODULE] get_export_names of {} " , filename ( ) ) ;
// 1. If exportStarSet is not present, set exportStarSet to a new empty List.
// Note: This is done by default argument
// 2. If exportStarSet contains module, then
if ( export_star_set . contains_slow ( 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.
2023-01-09 00:23:00 +00:00
return Vector < DeprecatedFlyString > { } ;
2022-01-18 18:29:17 +00:00
}
// 3. Append module to exportStarSet.
export_star_set . append ( this ) ;
// 4. Let exportedNames be a new empty List.
2023-01-09 00:23:00 +00:00
Vector < DeprecatedFlyString > exported_names ;
2022-01-18 18:29:17 +00:00
// 5. For each ExportEntry Record e of module.[[LocalExportEntries]], do
for ( auto & entry : m_local_export_entries ) {
// a. Assert: module provides the direct binding for this export.
// FIXME: How do we check that?
// b. Append e.[[ExportName]] to exportedNames.
exported_names . empend ( entry . export_name ) ;
}
// 6. For each ExportEntry Record e of module.[[IndirectExportEntries]], do
for ( auto & entry : m_indirect_export_entries ) {
// a. Assert: module provides the direct binding for this export.
// FIXME: How do we check that?
// b. Append e.[[ExportName]] to exportedNames.
exported_names . empend ( entry . export_name ) ;
}
// 7. For each ExportEntry Record e of module.[[StarExportEntries]], do
for ( auto & entry : m_star_export_entries ) {
// a. Let requestedModule be ? HostResolveImportedModule(module, e.[[ModuleRequest]]).
2022-09-05 12:31:25 +00:00
auto requested_module = TRY ( vm . host_resolve_imported_module ( NonnullGCPtr < Module > ( * this ) , entry . module_request ( ) ) ) ;
2022-01-18 18:29:17 +00:00
// b. Let starNames be ? requestedModule.GetExportedNames(exportStarSet).
auto star_names = TRY ( requested_module - > get_exported_names ( vm , export_star_set ) ) ;
// c. For each element n of starNames, do
for ( auto & name : star_names ) {
// i. If SameValue(n, "default") is false, then
if ( name ! = " default " sv ) {
// 1. If n is not an element of exportedNames, then
if ( ! exported_names . contains_slow ( name ) ) {
// a. Append n to exportedNames.
exported_names . empend ( name ) ;
}
}
}
}
// 8. Return exportedNames.
return exported_names ;
2021-09-14 18:51:16 +00:00
}
2022-01-18 18:29:17 +00:00
// 16.2.1.6.4 InitializeEnvironment ( ), https://tc39.es/ecma262/#sec-source-text-module-record-initialize-environment
2022-05-02 18:54:39 +00:00
ThrowCompletionOr < void > SourceTextModule : : initialize_environment ( VM & vm )
2021-09-14 18:51:16 +00:00
{
2022-01-18 18:29:17 +00:00
// 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 ) ) ;
// b. If resolution is null or ambiguous, throw a SyntaxError exception.
if ( ! resolution . is_valid ( ) )
2022-08-16 19:33:17 +00:00
return vm . throw_completion < SyntaxError > ( ErrorType : : InvalidOrAmbiguousExportEntry , entry . export_name ) ;
2022-01-18 18:29:17 +00:00
// c. Assert: resolution is a ResolvedBinding Record.
VERIFY ( resolution . is_valid ( ) ) ;
}
// 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.
// 3. Let realm be module.[[Realm]].
// 4. Assert: realm is not undefined.
// Note: This must be true because we use a reference.
// 5. Let env be NewModuleEnvironment(realm.[[GlobalEnv]]).
2022-12-14 17:40:33 +00:00
auto environment = vm . heap ( ) . allocate_without_realm < ModuleEnvironment > ( & realm ( ) . global_environment ( ) ) ;
2022-01-18 18:29:17 +00:00
// 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 ) {
// a. Let importedModule be ! HostResolveImportedModule(module, in.[[ModuleRequest]]).
2022-09-05 12:31:25 +00:00
auto imported_module = MUST ( vm . host_resolve_imported_module ( NonnullGCPtr < Module > ( * this ) , import_entry . module_request ( ) ) ) ;
2022-01-18 18:29:17 +00:00
// 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
2022-01-27 00:54:47 +00:00
if ( import_entry . is_namespace ) {
2022-01-18 18:29:17 +00:00
// i. Let namespace be ? GetModuleNamespace(importedModule).
auto * namespace_ = TRY ( imported_module - > get_module_namespace ( vm ) ) ;
// ii. Perform ! env.CreateImmutableBinding(in.[[LocalName]], true).
2022-08-21 14:12:43 +00:00
MUST ( environment - > create_immutable_binding ( vm , import_entry . local_name , true ) ) ;
2022-01-18 18:29:17 +00:00
2022-05-02 18:54:39 +00:00
// iii. Perform ! env.InitializeBinding(in.[[LocalName]], namespace).
2022-08-21 14:12:43 +00:00
MUST ( environment - > initialize_binding ( vm , import_entry . local_name , namespace_ ) ) ;
2022-01-18 18:29:17 +00:00
}
// d. Else,
else {
// i. Let resolution be ? importedModule.ResolveExport(in.[[ImportName]]).
auto resolution = TRY ( imported_module - > resolve_export ( vm , import_entry . import_name ) ) ;
// ii. If resolution is null or ambiguous, throw a SyntaxError exception.
if ( ! resolution . is_valid ( ) )
2022-08-16 19:33:17 +00:00
return vm . throw_completion < SyntaxError > ( ErrorType : : InvalidOrAmbiguousExportEntry , import_entry . import_name ) ;
2022-01-18 18:29:17 +00:00
// 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 ) ) ;
// 2. Perform ! env.CreateImmutableBinding(in.[[LocalName]], true).
2022-08-21 14:12:43 +00:00
MUST ( environment - > create_immutable_binding ( vm , import_entry . local_name , true ) ) ;
2022-01-18 18:29:17 +00:00
2022-05-02 18:54:39 +00:00
// 3. Perform ! env.InitializeBinding(in.[[LocalName]], namespace).
2022-08-21 14:12:43 +00:00
MUST ( environment - > initialize_binding ( vm , import_entry . local_name , namespace_ ) ) ;
2022-01-18 18:29:17 +00:00
}
// iv. Else,
else {
2022-05-02 18:54:39 +00:00
// 1. Perform env.CreateImportBinding(in.[[LocalName]], resolution.[[Module]], resolution.[[BindingName]]).
2022-01-18 18:29:17 +00:00
MUST ( environment - > create_import_binding ( import_entry . local_name , resolution . module , resolution . export_name ) ) ;
}
}
}
// 8. Let moduleContext be a new ECMAScript code execution context.
// 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.
// 11. Set the Realm of moduleContext to module.[[Realm]].
m_execution_context . realm = & realm ( ) ;
// 12. Set the ScriptOrModule of moduleContext to module.
2022-09-05 12:31:25 +00:00
m_execution_context . script_or_module = NonnullGCPtr < Module > ( * this ) ;
2022-01-18 18:29:17 +00:00
// 13. Set the VariableEnvironment of moduleContext to module.[[Environment]].
m_execution_context . variable_environment = environment ;
// 14. Set the LexicalEnvironment of moduleContext to module.[[Environment]].
m_execution_context . lexical_environment = environment ;
// 15. Set the PrivateEnvironment of moduleContext to null.
// 16. Set module.[[Context]] to moduleContext.
// Note: We're already working on that one.
// 17. Push moduleContext onto the execution context stack; moduleContext is now the running execution context.
2022-08-21 19:38:35 +00:00
TRY ( vm . push_execution_context ( m_execution_context , { } ) ) ;
2022-01-18 18:29:17 +00:00
// 18. Let code be module.[[ECMAScriptCode]].
// 19. Let varDeclarations be the VarScopedDeclarations of code.
// Note: We just loop through them in step 21.
// 20. Let declaredVarNames be a new empty List.
2023-01-09 00:23:00 +00:00
Vector < DeprecatedFlyString > declared_var_names ;
2022-01-18 18:29:17 +00:00
// 21. For each element d of varDeclarations, do
// a. For each element dn of the BoundNames of d, do
m_ecmascript_code - > for_each_var_declared_name ( [ & ] ( auto const & name ) {
// i. If dn is not an element of declaredVarNames, then
if ( ! declared_var_names . contains_slow ( name ) ) {
// 1. Perform ! env.CreateMutableBinding(dn, false).
2022-08-21 14:12:43 +00:00
MUST ( environment - > create_mutable_binding ( vm , name , false ) ) ;
2022-01-18 18:29:17 +00:00
2022-05-02 18:54:39 +00:00
// 2. Perform ! env.InitializeBinding(dn, undefined).
2022-08-21 14:12:43 +00:00
MUST ( environment - > initialize_binding ( vm , name , js_undefined ( ) ) ) ;
2022-01-18 18:29:17 +00:00
// 3. Append dn to declaredVarNames.
declared_var_names . empend ( name ) ;
}
} ) ;
// 22. Let lexDeclarations be the LexicallyScopedDeclarations of code.
// Note: We only loop through them in step 24.
// 23. Let privateEnv be null.
PrivateEnvironment * private_environment = nullptr ;
// 24. For each element d of lexDeclarations, do
m_ecmascript_code - > for_each_lexically_scoped_declaration ( [ & ] ( Declaration const & declaration ) {
// a. For each element dn of the BoundNames of d, do
2023-01-09 00:23:00 +00:00
declaration . for_each_bound_name ( [ & ] ( DeprecatedFlyString const & name ) {
2022-01-18 18:29:17 +00:00
// i. If IsConstantDeclaration of d is true, then
if ( declaration . is_constant_declaration ( ) ) {
// 1. Perform ! env.CreateImmutableBinding(dn, true).
2022-08-21 14:12:43 +00:00
MUST ( environment - > create_immutable_binding ( vm , name , true ) ) ;
2022-01-18 18:29:17 +00:00
}
// ii. Else,
else {
// 1. Perform ! env.CreateMutableBinding(dn, false).
2022-08-21 14:12:43 +00:00
MUST ( environment - > create_mutable_binding ( vm , name , false ) ) ;
2022-01-18 18:29:17 +00:00
}
// iii. If d is a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration, then
if ( declaration . is_function_declaration ( ) ) {
VERIFY ( is < FunctionDeclaration > ( declaration ) ) ;
auto const & function_declaration = static_cast < FunctionDeclaration const & > ( declaration ) ;
// 1. Let fo be InstantiateFunctionObject of d with arguments env and privateEnv.
2022-09-01 22:46:37 +00:00
// NOTE: Special case if the function is a default export of an anonymous function
// it has name "*default*" but internally should have name "default".
2023-01-09 00:23:00 +00:00
DeprecatedFlyString function_name = function_declaration . name ( ) ;
2022-09-01 22:46:37 +00:00
if ( function_name = = ExportStatement : : local_name_for_default )
function_name = " default " sv ;
2022-12-13 20:49:50 +00:00
auto function = ECMAScriptFunctionObject : : create ( realm ( ) , function_name , function_declaration . source_text ( ) , function_declaration . body ( ) , function_declaration . parameters ( ) , function_declaration . function_length ( ) , environment , private_environment , function_declaration . kind ( ) , function_declaration . is_strict_mode ( ) , function_declaration . might_need_arguments_object ( ) , function_declaration . contains_direct_call_to_eval ( ) ) ;
2022-01-18 18:29:17 +00:00
2022-05-02 18:54:39 +00:00
// 2. Perform ! env.InitializeBinding(dn, fo).
2022-08-21 14:12:43 +00:00
MUST ( environment - > initialize_binding ( vm , name , function ) ) ;
2022-01-18 18:29:17 +00:00
}
} ) ;
} ) ;
// 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 ) ) {
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).
2022-08-21 14:12:43 +00:00
MUST ( environment - > create_mutable_binding ( vm , name , false ) ) ;
2022-01-18 18:29:17 +00:00
// Note: Since this is not a function declaration 24.a.iii never applies
}
}
// 25. Remove moduleContext from the execution context stack.
vm . pop_execution_context ( ) ;
2022-05-02 18:54:39 +00:00
// 26. Return unused.
return { } ;
2022-01-18 18:29:17 +00:00
}
// 16.2.1.6.3 ResolveExport ( exportName [ , resolveSet ] ), https://tc39.es/ecma262/#sec-resolveexport
2023-01-09 00:23:00 +00:00
ThrowCompletionOr < ResolvedBinding > SourceTextModule : : resolve_export ( VM & vm , DeprecatedFlyString const & export_name , Vector < ResolvedBinding > resolve_set )
2022-01-18 18:29:17 +00:00
{
// 1. If resolveSet is not present, set resolveSet to a new empty List.
// Note: This is done by the default argument.
// 2. 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
if ( module = = this & & exported_name = = export_name ) {
// i. Assert: This is a circular import request.
// ii. Return null.
return ResolvedBinding : : null ( ) ;
}
}
// 3. Append the Record { [[Module]]: module, [[ExportName]]: exportName } to resolveSet.
resolve_set . append ( { ResolvedBinding : : Type : : BindingName , this , export_name } ) ;
// 4. 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
if ( export_name ! = entry . export_name )
continue ;
// i. Assert: module provides the direct binding for this export.
// FIXME: What does this mean?
// ii. Return ResolvedBinding Record { [[Module]]: module, [[BindingName]]: e.[[LocalName]] }.
return ResolvedBinding {
ResolvedBinding : : Type : : BindingName ,
this ,
entry . local_or_import_name ,
} ;
}
// 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
if ( export_name ! = entry . export_name )
continue ;
// i. Let importedModule be ? HostResolveImportedModule(module, e.[[ModuleRequest]]).
2022-09-05 12:31:25 +00:00
auto imported_module = TRY ( vm . host_resolve_imported_module ( NonnullGCPtr < Module > ( * this ) , entry . module_request ( ) ) ) ;
2022-01-18 18:29:17 +00:00
// ii. If e.[[ImportName]] is all, then
2022-11-23 11:16:51 +00:00
if ( entry . kind = = ExportEntry : : Kind : : ModuleRequestAll ) {
2022-01-18 18:29:17 +00:00
// 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 }.
return ResolvedBinding {
ResolvedBinding : : Type : : Namespace ,
imported_module . ptr ( ) ,
{ }
} ;
}
// iii. Else,
else {
// 1. Assert: module imports a specific binding for this export.
// FIXME: What does this mean? / How do we check this
2022-05-02 18:54:39 +00:00
// 2. Return ? importedModule.ResolveExport(e.[[ImportName]], resolveSet).
2022-01-18 18:29:17 +00:00
return imported_module - > resolve_export ( vm , entry . local_or_import_name , resolve_set ) ;
}
}
// 6. If SameValue(exportName, "default") is true, 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.
}
// 7. Let starResolution be null.
ResolvedBinding star_resolution = ResolvedBinding : : null ( ) ;
// 8. For each ExportEntry Record e of module.[[StarExportEntries]], do
for ( auto & entry : m_star_export_entries ) {
// a. Let importedModule be ? HostResolveImportedModule(module, e.[[ModuleRequest]]).
2022-09-05 12:31:25 +00:00
auto imported_module = TRY ( vm . host_resolve_imported_module ( NonnullGCPtr < Module > ( * this ) , entry . module_request ( ) ) ) ;
2022-01-18 18:29:17 +00:00
// b. Let resolution be ? importedModule.ResolveExport(exportName, resolveSet).
auto resolution = TRY ( imported_module - > resolve_export ( vm , export_name , resolve_set ) ) ;
// c. If resolution is ambiguous, return ambiguous.
if ( resolution . is_ambiguous ( ) )
return ResolvedBinding : : ambiguous ( ) ;
// d. If resolution is not null, then
if ( resolution . type = = ResolvedBinding : : Null )
continue ;
// i. Assert: resolution is a ResolvedBinding Record.
VERIFY ( resolution . is_valid ( ) ) ;
// ii. If starResolution is null, set starResolution to resolution.
if ( star_resolution . type = = ResolvedBinding : : Null ) {
star_resolution = resolution ;
}
// iii. Else,
else {
// 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.
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.
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
return ResolvedBinding : : ambiguous ( ) ;
}
}
}
// 9. Return starResolution.
return star_resolution ;
}
// 16.2.1.6.5 ExecuteModule ( [ capability ] ), https://tc39.es/ecma262/#sec-source-text-module-record-execute-module
2022-10-02 11:11:30 +00:00
ThrowCompletionOr < void > SourceTextModule : : execute_module ( VM & vm , GCPtr < PromiseCapability > capability )
2022-01-18 18:29:17 +00:00
{
2022-10-02 11:11:30 +00:00
dbgln_if ( JS_MODULE_DEBUG , " [JS MODULE] SourceTextModule::execute_module({}, PromiseCapability @ {}) " , filename ( ) , capability . ptr ( ) ) ;
2022-01-18 18:29:17 +00:00
// 1. Let moduleContext be a new ECMAScript code execution context.
ExecutionContext module_context { vm . heap ( ) } ;
// 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.
// 3. Set the Realm of moduleContext to module.[[Realm]].
module_context . realm = & realm ( ) ;
// 4. Set the ScriptOrModule of moduleContext to module.
2022-09-05 12:31:25 +00:00
module_context . script_or_module = NonnullGCPtr < Module > ( * this ) ;
2022-01-18 18:29:17 +00:00
// 5. Assert: module has been linked and declarations in its module environment have been instantiated.
VERIFY ( m_status ! = ModuleStatus : : Unlinked & & m_status ! = ModuleStatus : : Linking & & environment ( ) ) ;
// 6. Set the VariableEnvironment of moduleContext to module.[[Environment]].
module_context . variable_environment = environment ( ) ;
// 7. Set the LexicalEnvironment of moduleContext to module.[[Environment]].
module_context . lexical_environment = environment ( ) ;
// 8. Suspend the currently running execution context.
// FIXME: We don't have suspend yet
// 9. If module.[[HasTLA]] is false, then
if ( ! m_has_top_level_await ) {
// a. Assert: capability is not present.
2022-10-02 11:11:30 +00:00
VERIFY ( capability = = nullptr ) ;
2022-01-18 18:29:17 +00:00
// b. Push moduleContext onto the execution context stack; moduleContext is now the running execution context.
2022-08-21 19:38:35 +00:00
TRY ( vm . push_execution_context ( module_context , { } ) ) ;
2022-01-18 18:29:17 +00:00
// c. Let result be the result of evaluating module.[[ECMAScriptCode]].
2022-08-16 18:28:17 +00:00
auto result = m_ecmascript_code - > execute ( vm . interpreter ( ) ) ;
2022-01-18 18:29:17 +00:00
// d. Suspend moduleContext and remove it from the execution context stack.
vm . pop_execution_context ( ) ;
// e. Resume the context that is now on the top of the execution context stack as the running execution context.
// FIXME: We don't have resume yet.
2022-05-02 18:54:39 +00:00
// f. If result is an abrupt completion, then
if ( result . is_error ( ) ) {
// i. Return ? result.
2022-01-18 18:29:17 +00:00
return result ;
2022-05-02 18:54:39 +00:00
}
2022-01-18 18:29:17 +00:00
}
// 10. Else,
2022-05-02 18:54:39 +00:00
else {
// a. Assert: capability is a PromiseCapability Record.
2022-10-02 11:11:30 +00:00
VERIFY ( capability ! = nullptr ) ;
2022-01-18 18:29:17 +00:00
2022-05-02 18:54:39 +00:00
// b. Perform AsyncBlockStart(capability, module.[[ECMAScriptCode]], moduleContext).
2022-10-02 11:11:30 +00:00
async_block_start ( vm , m_ecmascript_code , * capability , module_context ) ;
2022-05-02 18:54:39 +00:00
}
2022-01-18 18:29:17 +00:00
2022-05-02 18:54:39 +00:00
// 11. Return unused.
return { } ;
2021-09-14 18:51:16 +00:00
}
}