summaryrefslogtreecommitdiffstats
path: root/js/src/builtin/Module.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/builtin/Module.js')
-rw-r--r--js/src/builtin/Module.js328
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));
+}