123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914 |
- using System;
- using Esprima.Ast;
- using System.Collections.Generic;
- using System.Linq;
- using Jint.Native;
- using Jint.Native.Object;
- using Jint.Native.Promise;
- using Jint.Runtime.Descriptors;
- using Jint.Runtime.Environments;
- using Jint.Runtime.Interop;
- using Jint.Runtime.Interpreter;
- namespace Jint.Runtime.Modules;
- #pragma warning disable CS0649 // never assigned to, waiting for new functionalities in spec
- internal sealed record ResolvedBinding(JsModule Module, string BindingName)
- {
- internal static ResolvedBinding Ambiguous => new(null, "ambiguous");
- }
- internal sealed record ImportEntry(
- string ModuleRequest,
- string ImportName,
- string LocalName
- );
- internal sealed record ExportEntry(
- string ExportName,
- string ModuleRequest,
- string ImportName,
- string LocalName
- );
- internal sealed record ExportResolveSetItem(
- JsModule Module,
- string ExportName
- );
- /// <summary>
- /// Represents a module record
- /// https://tc39.es/ecma262/#sec-abstract-module-records
- /// https://tc39.es/ecma262/#sec-cyclic-module-records
- /// https://tc39.es/ecma262/#sec-source-text-module-records
- /// </summary>
- public sealed class JsModule : JsValue
- {
- private readonly Engine _engine;
- private readonly Realm _realm;
- internal ModuleEnvironmentRecord _environment;
- private ObjectInstance _namespace;
- private Completion? _evalError;
- private int _dfsIndex;
- private int _dfsAncestorIndex;
- private readonly HashSet<string> _requestedModules;
- private JsModule _cycleRoot;
- private bool _hasTLA;
- private bool _asyncEvaluation;
- private PromiseCapability _topLevelCapability;
- private List<JsModule> _asyncParentModules;
- private int _asyncEvalOrder;
- private int _pendingAsyncDependencies;
- private readonly Module _source;
- private ExecutionContext _context;
- private readonly ObjectInstance _importMeta;
- private readonly List<ImportEntry> _importEntries;
- private readonly List<ExportEntry> _localExportEntries;
- private readonly List<ExportEntry> _indirectExportEntries;
- private readonly List<ExportEntry> _starExportEntries;
- internal readonly string _location;
- internal JsValue _evalResult;
- internal JsModule(Engine engine, Realm realm, Module source, string location, bool async) : base(InternalTypes.Module)
- {
- _engine = engine;
- _realm = realm;
- _source = source;
- _location = location;
- _importMeta = _realm.Intrinsics.Object.Construct(1);
- _importMeta.DefineOwnProperty("url", new PropertyDescriptor(location, PropertyFlag.ConfigurableEnumerableWritable));
- HoistingScope.GetImportsAndExports(
- _source,
- out _requestedModules,
- out _importEntries,
- out _localExportEntries,
- out _indirectExportEntries,
- out _starExportEntries);
- //ToDo async modules
- }
- internal ModuleStatus Status { get; private set; }
- /// <summary>
- /// https://tc39.es/ecma262/#sec-getmodulenamespace
- /// </summary>
- public static ObjectInstance GetModuleNamespace(JsModule module)
- {
- var ns = module._namespace;
- if(ns is null)
- {
- var exportedNames = module.GetExportedNames();
- var unambiguousNames = new List<string>();
- for (var i = 0; i < exportedNames.Count; i++)
- {
- var name = exportedNames[i];
- var resolution = module.ResolveExport(name);
- if(resolution is not null)
- {
- unambiguousNames.Add(name);
- }
- }
- ns = CreateModuleNamespace(module, unambiguousNames);
- }
- return ns;
- }
- /// <summary>
- /// https://tc39.es/ecma262/#sec-modulenamespacecreate
- /// </summary>
- private static ObjectInstance CreateModuleNamespace(JsModule module, List<string> unambiguousNames)
- {
- var m = new ModuleNamespace(module._engine, module, unambiguousNames);
- module._namespace = m;
- return m;
- }
- /// <summary>
- /// https://tc39.es/ecma262/#sec-getexportednames
- /// </summary>
- public List<string> GetExportedNames(List<JsModule> exportStarSet = null)
- {
- exportStarSet ??= new();
- if (exportStarSet.Contains(this))
- {
- //Reached the starting point of an export * circularity
- return new();
- }
- exportStarSet.Add(this);
- var exportedNames = new List<string>();
- for (var i = 0; i < _localExportEntries.Count; i++)
- {
- var e = _localExportEntries[i];
- exportedNames.Add(e.ExportName);
- }
- for (var i = 0; i < _indirectExportEntries.Count; i++)
- {
- var e = _indirectExportEntries[i];
- exportedNames.Add(e.ExportName);
- }
- for(var i = 0; i < _starExportEntries.Count; i++)
- {
- var e = _starExportEntries[i];
- var requestedModule = _engine._host.ResolveImportedModule(this, e.ModuleRequest);
- var starNames = requestedModule.GetExportedNames(exportStarSet);
- for (var j = 0; j < starNames.Count; j++)
- {
- var n = starNames[i];
- if (!"default".Equals(n) && !exportedNames.Contains(n))
- {
- exportedNames.Add(n);
- }
- }
- }
- return exportedNames;
- }
- /// <summary>
- /// https://tc39.es/ecma262/#sec-resolveexport
- /// </summary>
- internal ResolvedBinding ResolveExport(string exportName, List<ExportResolveSetItem> resolveSet = null)
- {
- resolveSet ??= new();
- for(var i = 0; i < resolveSet.Count; i++)
- {
- var r = resolveSet[i];
- if(this == r.Module && exportName == r.ExportName)
- {
- //circular import request
- return null;
- }
- }
- resolveSet.Add(new(this, exportName));
- for(var i = 0; i < _localExportEntries.Count; i++)
- {
- var e = _localExportEntries[i];
- if (exportName == e.ExportName)
- {
- return new ResolvedBinding(this, e.LocalName);
- }
- }
- for(var i = 0; i < _indirectExportEntries.Count; i++)
- {
- var e = _localExportEntries[i];
- if (exportName.Equals(e.ExportName))
- {
- var importedModule = _engine._host.ResolveImportedModule(this, e.ModuleRequest);
- if(e.ImportName == "*")
- {
- return new ResolvedBinding(importedModule, "*namespace*");
- }
- else
- {
- return importedModule.ResolveExport(e.ImportName, resolveSet);
- }
- }
- }
- if ("default".Equals(exportName))
- {
- return null;
- }
- ResolvedBinding starResolution = null;
- for(var i = 0; i < _starExportEntries.Count; i++)
- {
- var e = _starExportEntries[i];
- var importedModule = _engine._host.ResolveImportedModule(this, e.ModuleRequest);
- var resolution = importedModule.ResolveExport(exportName, resolveSet);
- if(resolution == ResolvedBinding.Ambiguous)
- {
- return resolution;
- }
- if(resolution is not null)
- {
- if(starResolution is null)
- {
- starResolution = resolution;
- }
- else
- {
- if(resolution.Module != starResolution.Module || resolution.BindingName != starResolution.BindingName)
- {
- return ResolvedBinding.Ambiguous;
- }
- }
- }
- }
- return starResolution;
- }
- /// <summary>
- /// https://tc39.es/ecma262/#sec-moduledeclarationlinking
- /// </summary>
- public void Link()
- {
- if (Status == ModuleStatus.Linking || Status == ModuleStatus.Evaluating)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while linking module: Module is already either linking or evaluating");
- }
- var stack = new Stack<JsModule>();
- try
- {
- Link(this, stack, 0);
- }
- catch
- {
- foreach (var m in stack)
- {
- m.Status = ModuleStatus.Unlinked;
- m._environment = null;
- m._dfsIndex = -1;
- m._dfsAncestorIndex = -1;
- }
- Status = ModuleStatus.Unlinked;
- throw;
- }
- if (Status != ModuleStatus.Linked && Status != ModuleStatus.Unlinked)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while linking module: Module is neither linked or unlinked");
- }
- if(stack.Any())
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while linking module: One or more modules were not linked");
- }
- }
- /// <summary>
- /// https://tc39.es/ecma262/#sec-moduleevaluation
- /// </summary>
- public JsValue Evaluate()
- {
- var module = this;
- if (module.Status != ModuleStatus.Linked &&
- module.Status != ModuleStatus.EvaluatingAsync &&
- module.Status != ModuleStatus.Evaluated)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while evaluating module: Module is in an invalid state");
- }
- if (module.Status == ModuleStatus.EvaluatingAsync || module.Status == ModuleStatus.Evaluated)
- {
- module = module._cycleRoot;
- }
- if (module._topLevelCapability is not null)
- {
- return module._topLevelCapability.PromiseInstance;
- }
- var stack = new Stack<JsModule>();
- var capability = PromiseConstructor.NewPromiseCapability(_engine, _realm.Intrinsics.Promise);
- int asyncEvalOrder = 0;
- module._topLevelCapability = capability;
- var result = Evaluate(module, stack, 0, ref asyncEvalOrder);
- if(result.Type != CompletionType.Normal)
- {
- foreach(var m in stack)
- {
- m.Status = ModuleStatus.Evaluated;
- m._evalError = result;
- }
- capability.Reject.Call(Undefined, new [] { result.Value });
- }
- else
- {
- if (module.Status != ModuleStatus.EvaluatingAsync && module.Status != ModuleStatus.Evaluated)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while evaluating module: Module is in an invalid state");
- }
- if (module._evalError is not null)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while evaluating module: Module is in an invalid state");
- }
- if (!module._asyncEvaluation)
- {
- if(module.Status != ModuleStatus.Evaluated)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while evaluating module: Module is in an invalid state");
- }
- capability.Resolve.Call(Undefined, Array.Empty<JsValue>());
- }
- if (stack.Any())
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while evaluating module: Module is in an invalid state");
- }
- }
- return capability.PromiseInstance;
- }
- /// <summary>
- /// https://tc39.es/ecma262/#sec-InnerModuleLinking
- /// </summary>
- private int Link(JsModule module, Stack<JsModule> stack, int index)
- {
- if(module.Status is ModuleStatus.Linking or
- ModuleStatus.Linked or
- ModuleStatus.EvaluatingAsync or
- ModuleStatus.Evaluating)
- {
- return index;
- }
- if(module.Status != ModuleStatus.Unlinked)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while linking module: Module in an invalid state");
- }
- module.Status = ModuleStatus.Linking;
- module._dfsIndex = index;
- module._dfsAncestorIndex = index;
- index++;
- stack.Push(module);
- var requestedModules = module._requestedModules;
- foreach (var moduleSpecifier in requestedModules)
- {
- var requiredModule = _engine._host.ResolveImportedModule(module, moduleSpecifier);
- if (requiredModule.Status != ModuleStatus.Linking &&
- requiredModule.Status != ModuleStatus.Linked &&
- requiredModule.Status != ModuleStatus.Evaluated)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while linking module: Required module is in an invalid state");
- }
- if(requiredModule.Status == ModuleStatus.Linking && !stack.Contains(requiredModule))
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while linking module: Required module is in an invalid state");
- }
- if (requiredModule.Status == ModuleStatus.Linking)
- {
- module._dfsAncestorIndex = System.Math.Min(module._dfsAncestorIndex, requiredModule._dfsAncestorIndex);
- }
- }
- module.InitializeEnvironment();
- if (stack.Count(m => m == module) != 1)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while linking module: Recursive dependency detected");
- }
- if (module._dfsIndex > module._dfsAncestorIndex)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while linking module: Recursive dependency detected");
- }
- if (module._dfsIndex == module._dfsAncestorIndex)
- {
- while (true)
- {
- var requiredModule = stack.Pop();
- requiredModule.Status = ModuleStatus.Linked;
- if (requiredModule == module)
- {
- break;
- }
- }
- }
- return index;
- }
- /// <summary>
- /// https://tc39.es/ecma262/#sec-innermoduleevaluation
- /// </summary>
- private Completion Evaluate(JsModule module, Stack<JsModule> stack, int index, ref int asyncEvalOrder)
- {
- if(module.Status == ModuleStatus.EvaluatingAsync || module.Status == ModuleStatus.Evaluated)
- {
- if(module._evalError is null)
- {
- return new Completion(CompletionType.Normal, index, null, default);
- }
- return module._evalError.Value;
- }
- if(module.Status == ModuleStatus.Evaluating)
- {
- return new Completion(CompletionType.Normal, index, null, default);
- }
- if (module.Status != ModuleStatus.Linked)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while evaluating module: Module is in an invalid state");
- }
- module.Status = ModuleStatus.Evaluating;
- module._dfsIndex = index;
- module._dfsAncestorIndex = index;
- module._pendingAsyncDependencies = 0;
- index++;
- stack.Push(module);
- var requestedModules = module._requestedModules;
- foreach (var moduleSpecifier in requestedModules)
- {
- var requiredModule = _engine._host.ResolveImportedModule(module, moduleSpecifier);
- var result = Evaluate(module, stack, index, ref asyncEvalOrder);
- if(result.Type != CompletionType.Normal)
- {
- return result;
- }
- index = TypeConverter.ToInt32(result.Value);
- if (requiredModule.Status != ModuleStatus.Evaluating &&
- requiredModule.Status != ModuleStatus.EvaluatingAsync &&
- requiredModule.Status != ModuleStatus.Evaluated)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while evaluating module: Module is in an invalid state");
- }
- if (requiredModule.Status == ModuleStatus.Evaluating && !stack.Contains(requiredModule))
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while evaluating module: Module is in an invalid state");
- }
- if(requiredModule.Status == ModuleStatus.Evaluating)
- {
- module._dfsAncestorIndex = System.Math.Min(module._dfsAncestorIndex, requiredModule._dfsAncestorIndex);
- }
- else
- {
- requiredModule = requiredModule._cycleRoot;
- if(requiredModule.Status != ModuleStatus.EvaluatingAsync && requiredModule.Status != ModuleStatus.Evaluated)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while evaluating module: Module is in an invalid state");
- }
- }
- if (requiredModule._asyncEvaluation)
- {
- module._pendingAsyncDependencies++;
- requiredModule._asyncParentModules.Add(module);
- }
- }
- if(module._pendingAsyncDependencies > 0 || module._hasTLA)
- {
- if (module._asyncEvaluation)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while evaluating module: Module is in an invalid state");
- }
- module._asyncEvaluation = true;
- module._asyncEvalOrder = asyncEvalOrder++;
- if (module._pendingAsyncDependencies == 0)
- {
- module.ExecuteAsync();
- }
- else
- {
- module.Execute();
- }
- }
- else
- {
- module.Execute();
- }
- if(stack.Count(x => x == module) != 1)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while evaluating module: Module is in an invalid state");
- }
- if (module._dfsAncestorIndex > module._dfsIndex)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while evaluating module: Module is in an invalid state");
- }
- if(module._dfsIndex == module._dfsAncestorIndex)
- {
- bool done = false;
- while (!done)
- {
- var requiredModule = stack.Pop();
- if (!requiredModule._asyncEvaluation)
- {
- requiredModule.Status = ModuleStatus.Evaluated;
- }
- else
- {
- requiredModule.Status = ModuleStatus.EvaluatingAsync;
- }
- done = requiredModule == module;
- requiredModule._cycleRoot = module;
- }
- }
- return new Completion(CompletionType.Normal, index, null, default);
- }
- /// <summary>
- /// https://tc39.es/ecma262/#sec-source-text-module-record-initialize-environment
- /// </summary>
- private void InitializeEnvironment()
- {
- for(var i = 0; i < _indirectExportEntries.Count; i++)
- {
- var e = _indirectExportEntries[i];
- var resolution = ResolveExport(e.ExportName);
- if (resolution is null || resolution == ResolvedBinding.Ambiguous)
- {
- ExceptionHelper.ThrowSyntaxError(_realm, "Ambiguous import statement for identifier: " + e.ExportName);
- }
- }
- var realm = _realm;
- var env = JintEnvironment.NewModuleEnvironment(_engine, realm.GlobalEnv);
- _environment = env;
- for (var i = 0; i < _importEntries.Count; i++)
- {
- var ie = _importEntries[i];
- var importedModule = _engine._host.ResolveImportedModule(this, ie.ModuleRequest);
- if(ie.ImportName == "*")
- {
- var ns = GetModuleNamespace(importedModule);
- env.CreateImmutableBinding(ie.LocalName, true);
- env.InitializeBinding(ie.LocalName, ns);
- }
- else
- {
- var resolution = importedModule.ResolveExport(ie.ImportName);
- if(resolution is null || resolution == ResolvedBinding.Ambiguous)
- {
- ExceptionHelper.ThrowSyntaxError(_realm, "Ambigous import statement for identifier " + ie.ImportName);
- }
- if (resolution.BindingName == "*namespace*")
- {
- var ns = GetModuleNamespace(resolution.Module);
- env.CreateImmutableBinding(ie.LocalName, true);
- env.InitializeBinding(ie.LocalName, ns);
- }
- else
- {
- env.CreateImportBinding(ie.LocalName, resolution.Module, resolution.BindingName);
- }
- }
- }
- var moduleContext = new ExecutionContext(_environment, _environment, null, realm, null);
- _context = moduleContext;
- _engine.EnterExecutionContext(_context);
- var hoistingScope = HoistingScope.GetModuleLevelDeclarations(_source);
- var varDeclarations = hoistingScope._variablesDeclarations;
- var declaredVarNames = new List<string>();
- if(varDeclarations != null)
- {
- var boundNames = new List<string>();
- for(var i = 0; i < varDeclarations.Count; i++)
- {
- var d = varDeclarations[i];
- boundNames.Clear();
- d.GetBoundNames(boundNames);
- for(var j = 0; j < boundNames.Count; j++)
- {
- var dn = boundNames[j];
- if (!declaredVarNames.Contains(dn))
- {
- env.CreateMutableBinding(dn, false);
- env.InitializeBinding(dn, Undefined);
- declaredVarNames.Add(dn);
- }
- }
- }
- }
- var lexDeclarations = hoistingScope._lexicalDeclarations;
- if(lexDeclarations != null)
- {
- var boundNames = new List<string>();
- for(var i = 0; i < lexDeclarations.Count; i++)
- {
- var d = lexDeclarations[i];
- boundNames.Clear();
- d.GetBoundNames(boundNames);
- for (var j = 0; j < boundNames.Count; j++)
- {
- var dn = boundNames[j];
- if(d.Kind == VariableDeclarationKind.Const)
- {
- env.CreateImmutableBinding(dn, true);
- }
- else
- {
- env.CreateMutableBinding(dn, false);
- }
- }
- }
- }
- var functionDeclarations = hoistingScope._functionDeclarations;
- if(functionDeclarations != null)
- {
- for(var i = 0; i < functionDeclarations.Count; i++)
- {
- var d = functionDeclarations[i];
- var fn = d.Id.Name;
- var fd = new JintFunctionDefinition(_engine, d);
- env.CreateImmutableBinding(fn, true);
- var fo = realm.Intrinsics.Function.InstantiateFunctionObject(fd, env);
- env.InitializeBinding(fn, fo);
- }
- }
- _engine.LeaveExecutionContext();
- }
- /// <summary>
- /// https://tc39.es/ecma262/#sec-source-text-module-record-execute-module
- /// </summary>
- private Completion Execute(PromiseCapability capability = null)
- {
- var moduleContext = new ExecutionContext(_environment, _environment, null, _realm);
- if (!_hasTLA)
- {
- using (new StrictModeScope(strict: true))
- {
- _engine.EnterExecutionContext(moduleContext);
- var statementList = new JintStatementList(null, _source.Body);
- var result = statementList.Execute(_engine._activeEvaluationContext ?? new EvaluationContext(_engine)); //Create new evaluation context when called from e.g. module tests
- _engine.LeaveExecutionContext();
- return result;
- }
- }
- else
- {
- //ToDo async modules
- return default;
- }
- }
- /// <summary>
- /// https://tc39.es/ecma262/#sec-execute-async-module
- /// </summary>
- private Completion ExecuteAsync()
- {
- if((Status != ModuleStatus.Evaluating && Status != ModuleStatus.EvaluatingAsync) || !_hasTLA)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while evaluating module: Module is in an invalid state");
- }
- var capability = PromiseConstructor.NewPromiseCapability(_engine, _realm.Intrinsics.Promise);
- var onFullfilled = new ClrFunctionInstance(_engine, "fulfilled", AsyncModuleExecutionFulfilled, 1, PropertyFlag.Configurable);
- var onRejected = new ClrFunctionInstance(_engine, "rejected", AsyncModuleExecutionRejected, 1, PropertyFlag.Configurable);
- PromiseOperations.PerformPromiseThen(_engine, (PromiseInstance)capability.PromiseInstance, onFullfilled, onRejected, null);
- return Execute(capability);
- }
- /// <summary>
- /// https://tc39.es/ecma262/#sec-gather-available-ancestors
- /// </summary>
- private void GatherAvailableAncestors(List<JsModule> execList)
- {
- foreach(var m in _asyncParentModules)
- {
- if(!execList.Contains(m) && m._cycleRoot._evalError is null)
- {
- if(m.Status != ModuleStatus.EvaluatingAsync ||
- m._evalError is not null ||
- !m._asyncEvaluation ||
- m._pendingAsyncDependencies <= 0)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while evaluating module: Module is in an invalid state");
- }
- if(--m._pendingAsyncDependencies == 0)
- {
- execList.Add(m);
- if (!m._hasTLA)
- {
- m.GatherAvailableAncestors(execList);
- }
- }
- }
- }
- }
- /// <summary>
- /// https://tc39.es/ecma262/#sec-async-module-execution-fulfilled
- /// </summary>
- private JsValue AsyncModuleExecutionFulfilled(JsValue thisObj, JsValue[] arguments)
- {
- var module = (JsModule)arguments.At(0);
- if (module.Status == ModuleStatus.Evaluated)
- {
- if(module._evalError is not null)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while evaluating module: Module is in an invalid state");
- }
- return Undefined;
- }
- if (module.Status != ModuleStatus.EvaluatingAsync ||
- !module._asyncEvaluation ||
- module._evalError is not null)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while evaluating module: Module is in an invalid state");
- }
- if (module._topLevelCapability is not null)
- {
- if(module._cycleRoot is null)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while evaluating module: Module is in an invalid state");
- }
- module._topLevelCapability.Resolve.Call(Undefined, Array.Empty<JsValue>());
- }
- var execList = new List<JsModule>();
- module.GatherAvailableAncestors(execList);
- execList.Sort((x, y) => x._asyncEvalOrder - y._asyncEvalOrder);
- for(var i = 0; i < execList.Count; i++)
- {
- var m = execList[i];
- if (m.Status == ModuleStatus.Evaluated && m._evalError is null)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while evaluating module: Module is in an invalid state");
- }
- else if (m._hasTLA)
- {
- m.ExecuteAsync();
- }
- else
- {
- var result = m.Execute();
- if(result.Type != CompletionType.Normal)
- {
- AsyncModuleExecutionRejected(Undefined, new[] { m, result.Value });
- }
- else
- {
- m.Status = ModuleStatus.Evaluated;
- if(m._topLevelCapability is not null)
- {
- if (m._cycleRoot is null)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while evaluating module: Module is in an invalid state");
- }
- m._topLevelCapability.Resolve.Call(Undefined, Array.Empty<JsValue>());
- }
- }
- }
- }
- return Undefined;
- }
- /// <summary>
- /// https://tc39.es/ecma262/#sec-async-module-execution-rejected
- /// </summary>
- private JsValue AsyncModuleExecutionRejected(JsValue thisObj, JsValue[] arguments)
- {
- JsModule module = (JsModule)arguments.At(0);
- JsValue error = arguments.At(1);
- if (module.Status == ModuleStatus.Evaluated)
- {
- if(module._evalError is null)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while evaluating module: Module is in an invalid state");
- }
- return Undefined;
- }
- if (module.Status != ModuleStatus.EvaluatingAsync ||
- !module._asyncEvaluation ||
- module._evalError is not null)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while evaluating module: Module is in an invalid state");
- }
- module._evalError = new Completion(CompletionType.Throw, error, null, default);
- module.Status = ModuleStatus.Evaluated;
- var asyncParentModules = module._asyncParentModules;
- for (var i = 0; i < asyncParentModules.Count; i++)
- {
- var m = asyncParentModules[i];
- AsyncModuleExecutionRejected(thisObj, new[] { m, error });
- }
- if (module._topLevelCapability is not null)
- {
- if (module._cycleRoot is null)
- {
- ExceptionHelper.ThrowInvalidOperationException("Error while evaluating module: Module is in an invalid state");
- }
- module._topLevelCapability.Reject.Call(Undefined, new [] { error });
- }
- return Undefined;
- }
- public override bool Equals(JsValue other)
- {
- return false;
- }
- public override object ToObject()
- {
- ExceptionHelper.ThrowNotSupportedException();
- return null;
- }
- }
|