diff options
Diffstat (limited to 'js/src/builtin/Module.js')
-rw-r--r-- | js/src/builtin/Module.js | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/js/src/builtin/Module.js b/js/src/builtin/Module.js new file mode 100644 index 000000000..7b70a7fe8 --- /dev/null +++ b/js/src/builtin/Module.js @@ -0,0 +1,328 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +function CallModuleResolveHook(module, specifier, expectedMinimumState) +{ + let requestedModule = HostResolveImportedModule(module, specifier); + if (requestedModule.state < expectedMinimumState) + ThrowInternalError(JSMSG_BAD_MODULE_STATE); + + return requestedModule; +} + +// 15.2.1.16.2 GetExportedNames(exportStarSet) +function ModuleGetExportedNames(exportStarSet = []) +{ + if (!IsObject(this) || !IsModule(this)) { + return callFunction(CallModuleMethodIfWrapped, this, exportStarSet, + "ModuleGetExportedNames"); + } + + // Step 1 + let module = this; + + // Step 2 + if (callFunction(ArrayIncludes, exportStarSet, module)) + return []; + + // Step 3 + _DefineDataProperty(exportStarSet, exportStarSet.length, module); + + // Step 4 + let exportedNames = []; + let namesCount = 0; + + // Step 5 + let localExportEntries = module.localExportEntries; + for (let i = 0; i < localExportEntries.length; i++) { + let e = localExportEntries[i]; + _DefineDataProperty(exportedNames, namesCount++, e.exportName); + } + + // Step 6 + let indirectExportEntries = module.indirectExportEntries; + for (let i = 0; i < indirectExportEntries.length; i++) { + let e = indirectExportEntries[i]; + _DefineDataProperty(exportedNames, namesCount++, e.exportName); + } + + // Step 7 + let starExportEntries = module.starExportEntries; + for (let i = 0; i < starExportEntries.length; i++) { + let e = starExportEntries[i]; + let requestedModule = CallModuleResolveHook(module, e.moduleRequest, + MODULE_STATE_INSTANTIATED); + let starNames = callFunction(requestedModule.getExportedNames, requestedModule, + exportStarSet); + for (let j = 0; j < starNames.length; j++) { + let n = starNames[j]; + if (n !== "default" && !callFunction(ArrayIncludes, exportedNames, n)) + _DefineDataProperty(exportedNames, namesCount++, n); + } + } + + return exportedNames; +} + +// 15.2.1.16.3 ResolveExport(exportName, resolveSet, exportStarSet) +function ModuleResolveExport(exportName, resolveSet = [], exportStarSet = []) +{ + if (!IsObject(this) || !IsModule(this)) { + return callFunction(CallModuleMethodIfWrapped, this, exportName, resolveSet, + exportStarSet, "ModuleResolveExport"); + } + + // Step 1 + let module = this; + + // Step 2 + for (let i = 0; i < resolveSet.length; i++) { + let r = resolveSet[i]; + if (r.module === module && r.exportName === exportName) + return null; + } + + // Step 3 + _DefineDataProperty(resolveSet, resolveSet.length, {module: module, exportName: exportName}); + + // Step 4 + let localExportEntries = module.localExportEntries; + for (let i = 0; i < localExportEntries.length; i++) { + let e = localExportEntries[i]; + if (exportName === e.exportName) + return {module: module, bindingName: e.localName}; + } + + // Step 5 + let indirectExportEntries = module.indirectExportEntries; + for (let i = 0; i < indirectExportEntries.length; i++) { + let e = indirectExportEntries[i]; + if (exportName === e.exportName) { + let importedModule = CallModuleResolveHook(module, e.moduleRequest, + MODULE_STATE_INSTANTIATED); + let indirectResolution = callFunction(importedModule.resolveExport, importedModule, + e.importName, resolveSet, exportStarSet); + if (indirectResolution !== null) + return indirectResolution; + } + } + + // Step 6 + if (exportName === "default") { + // A default export cannot be provided by an export *. + ThrowSyntaxError(JSMSG_BAD_DEFAULT_EXPORT); + } + + // Step 7 + if (callFunction(ArrayIncludes, exportStarSet, module)) + return null; + + // Step 8 + _DefineDataProperty(exportStarSet, exportStarSet.length, module); + + // Step 9 + let starResolution = null; + + // Step 10 + let starExportEntries = module.starExportEntries; + for (let i = 0; i < starExportEntries.length; i++) { + let e = starExportEntries[i]; + let importedModule = CallModuleResolveHook(module, e.moduleRequest, + MODULE_STATE_INSTANTIATED); + let resolution = callFunction(importedModule.resolveExport, importedModule, + exportName, resolveSet, exportStarSet); + if (resolution === "ambiguous") + return resolution; + + if (resolution !== null) { + if (starResolution === null) { + starResolution = resolution; + } else { + if (resolution.module !== starResolution.module || + resolution.exportName !== starResolution.exportName) + { + return "ambiguous"; + } + } + } + } + + return starResolution; +} + +// 15.2.1.18 GetModuleNamespace(module) +function GetModuleNamespace(module) +{ + // Step 2 + let namespace = module.namespace; + + // Step 3 + if (typeof namespace === "undefined") { + let exportedNames = callFunction(module.getExportedNames, module); + let unambiguousNames = []; + for (let i = 0; i < exportedNames.length; i++) { + let name = exportedNames[i]; + let resolution = callFunction(module.resolveExport, module, name); + if (resolution === null) + ThrowSyntaxError(JSMSG_MISSING_NAMESPACE_EXPORT); + if (resolution !== "ambiguous") + _DefineDataProperty(unambiguousNames, unambiguousNames.length, name); + } + namespace = ModuleNamespaceCreate(module, unambiguousNames); + } + + // Step 4 + return namespace; +} + +// 9.4.6.13 ModuleNamespaceCreate(module, exports) +function ModuleNamespaceCreate(module, exports) +{ + callFunction(std_Array_sort, exports); + + let ns = NewModuleNamespace(module, exports); + + // Pre-compute all bindings now rather than calling ResolveExport() on every + // access. + for (let i = 0; i < exports.length; i++) { + let name = exports[i]; + let binding = callFunction(module.resolveExport, module, name); + assert(binding !== null && binding !== "ambiguous", "Failed to resolve binding"); + AddModuleNamespaceBinding(ns, name, binding.module, binding.bindingName); + } + + return ns; +} + +function GetModuleEnvironment(module) +{ + assert(IsModule(module), "Non-module passed to GetModuleEnvironment"); + + // Check for a previous failed attempt to instantiate this module. This can + // only happen due to a bug in the module loader. + if (module.state == MODULE_STATE_FAILED) + ThrowInternalError(JSMSG_MODULE_INSTANTIATE_FAILED); + + let env = UnsafeGetReservedSlot(module, MODULE_OBJECT_ENVIRONMENT_SLOT); + assert(env === undefined || IsModuleEnvironment(env), + "Module environment slot contains unexpected value"); + + return env; +} + +function RecordInstantationFailure(module) +{ + // Set the module's environment slot to 'null' to indicate a failed module + // instantiation. + assert(IsModule(module), "Non-module passed to RecordInstantationFailure"); + SetModuleState(module, MODULE_STATE_FAILED); + UnsafeSetReservedSlot(module, MODULE_OBJECT_ENVIRONMENT_SLOT, undefined); +} + +// 15.2.1.16.4 ModuleDeclarationInstantiation() +function ModuleDeclarationInstantiation() +{ + if (!IsObject(this) || !IsModule(this)) + return callFunction(CallModuleMethodIfWrapped, this, "ModuleDeclarationInstantiation"); + + // Step 1 + let module = this; + + // Step 5 + if (GetModuleEnvironment(module) !== undefined) + return; + + // Step 7 + CreateModuleEnvironment(module); + let env = GetModuleEnvironment(module); + + SetModuleState(this, MODULE_STATE_INSTANTIATED); + + try { + // Step 8 + let requestedModules = module.requestedModules; + for (let i = 0; i < requestedModules.length; i++) { + let required = requestedModules[i]; + let requiredModule = CallModuleResolveHook(module, required, MODULE_STATE_PARSED); + callFunction(requiredModule.declarationInstantiation, requiredModule); + } + + // Step 9 + let indirectExportEntries = module.indirectExportEntries; + for (let i = 0; i < indirectExportEntries.length; i++) { + let e = indirectExportEntries[i]; + let resolution = callFunction(module.resolveExport, module, e.exportName); + if (resolution === null) + ThrowSyntaxError(JSMSG_MISSING_INDIRECT_EXPORT, e.exportName); + if (resolution === "ambiguous") + ThrowSyntaxError(JSMSG_AMBIGUOUS_INDIRECT_EXPORT, e.exportName); + } + + // Step 12 + let importEntries = module.importEntries; + for (let i = 0; i < importEntries.length; i++) { + let imp = importEntries[i]; + let importedModule = CallModuleResolveHook(module, imp.moduleRequest, + MODULE_STATE_INSTANTIATED); + if (imp.importName === "*") { + let namespace = GetModuleNamespace(importedModule); + CreateNamespaceBinding(env, imp.localName, namespace); + } else { + let resolution = callFunction(importedModule.resolveExport, importedModule, + imp.importName); + if (resolution === null) + ThrowSyntaxError(JSMSG_MISSING_IMPORT, imp.importName); + if (resolution === "ambiguous") + ThrowSyntaxError(JSMSG_AMBIGUOUS_IMPORT, imp.importName); + CreateImportBinding(env, imp.localName, resolution.module, resolution.bindingName); + } + } + + // Step 16.iv + InstantiateModuleFunctionDeclarations(module); + } catch (e) { + RecordInstantationFailure(module); + throw e; + } +} +_SetCanonicalName(ModuleDeclarationInstantiation, "ModuleDeclarationInstantiation"); + +// 15.2.1.16.5 ModuleEvaluation() +function ModuleEvaluation() +{ + if (!IsObject(this) || !IsModule(this)) + return callFunction(CallModuleMethodIfWrapped, this, "ModuleEvaluation"); + + // Step 1 + let module = this; + + if (module.state < MODULE_STATE_INSTANTIATED) + ThrowInternalError(JSMSG_BAD_MODULE_STATE); + + // Step 4 + if (module.state == MODULE_STATE_EVALUATED) + return undefined; + + // Step 5 + SetModuleState(this, MODULE_STATE_EVALUATED); + + // Step 6 + let requestedModules = module.requestedModules; + for (let i = 0; i < requestedModules.length; i++) { + let required = requestedModules[i]; + let requiredModule = CallModuleResolveHook(module, required, MODULE_STATE_INSTANTIATED); + callFunction(requiredModule.evaluation, requiredModule); + } + + return EvaluateModule(module); +} +_SetCanonicalName(ModuleEvaluation, "ModuleEvaluation"); + +function ModuleNamespaceEnumerate() +{ + if (!IsObject(this) || !IsModuleNamespace(this)) + return callFunction(CallModuleMethodIfWrapped, this, "ModuleNamespaceEnumerate"); + + return CreateListIterator(ModuleNamespaceExports(this)); +} |