/// <summary>
        /// From an initial set of requested <param name="moduleDefinitions"/> returns a workspace that contains the set
        /// of corresponding modules closed under dependencies (if A is in the workspace and A imports B,
        /// then B is in the workspace).
        /// </summary>
        /// <remarks>
        /// For each module definition, it parses all its specs and builds a module out of it. Only specs successfully parsed are
        /// added to the module. Any failures are reported as part of the returned workspace instance.
        /// If <param name="computeBindingFingerprint"/> is true, then the binding fingerprint for all file would be computed after the parsing phase.
        /// </remarks>
        private async Task <Workspace> CreateWorkspaceFromModuleDefinitionsAsync(HashSet <ModuleDefinition> moduleDefinitions, bool computeBindingFingerprint)
        {
            var possiblePreludeDefinition = await TryGetPreludeModuleDefinitionAsync();

            if (!possiblePreludeDefinition.Succeeded)
            {
                return(Workspace.Failure(this, Configuration, possiblePreludeDefinition.Failure));
            }

            if (possiblePreludeDefinition.Result != null)
            {
                moduleDefinitions.Add(possiblePreludeDefinition.Result);
            }

            if (!WorkspaceValidator.ValidateModuleDefinitions(moduleDefinitions, PathTable, out var failures))
            {
                return(Workspace.Failure(this, Configuration, failures));
            }

            var queue = ModuleParsingQueue.Create(
                this,
                Configuration.WithComputeBindingFingerprint(computeBindingFingerprint),
                m_moduleReferenceResolver,
                possiblePreludeDefinition.Result,
                GetConfigurationModule());

            return(await queue.ProcessAsync(moduleDefinitions));
        }
        /// <summary>
        /// Creates a workspace from all known modules in an incremental way
        /// </summary>
        /// <remarks>
        /// It reuses already parsed modules so they don't get recomputed again
        /// </remarks>
        public async Task <Workspace> CreateIncrementalWorkspaceForAllKnownModulesAsync(
            IEnumerable <ParsedModule> parsedModules,
            ModuleUnderConstruction moduleUnderConstruction,
            IEnumerable <Failure> failures,
            [CanBeNull] ParsedModule preludeModule)
        {
            var maybeModuleDefinitions = await GetModuleDefinitionsForAllResolversAsync();

            if (!maybeModuleDefinitions.Succeeded)
            {
                return(Failure(maybeModuleDefinitions.Failure));
            }

            var moduleDefinitions = maybeModuleDefinitions.Result;

            ModuleDefinition preludeDefinition;

            if (preludeModule != null)
            {
                // Need to add prelude to a list of parsed modules if awailable
                var parsedModuleList = parsedModules.ToList();
                parsedModuleList.Add(preludeModule);
                parsedModules     = parsedModuleList;
                preludeDefinition = preludeModule.Definition;
            }
            else
            {
                var possiblePreludeDefinition = await TryGetPreludeModuleDefinitionAsync();

                if (!possiblePreludeDefinition.Succeeded)
                {
                    return(Failure(possiblePreludeDefinition.Failure));
                }

                preludeDefinition = possiblePreludeDefinition.Result;
                moduleDefinitions.Add(preludeDefinition);
            }

            if (!WorkspaceValidator.ValidateModuleDefinitions(moduleDefinitions, PathTable, out var validationFailures))
            {
                return(Failure(validationFailures));
            }

            var queue = ModuleParsingQueue.CreateIncrementalQueue(
                this,
                Configuration,
                m_moduleReferenceResolver,
                preludeDefinition,
                GetConfigurationModule(),
                parsedModules,
                failures);

            return(await queue.ProcessIncrementalAsync(moduleUnderConstruction));
        }
Exemple #3
0
        private async Task <Workspace> EnqueuingFinishedAndWaitForCompletion()
        {
            // No more new module definition may be added for processing
            EnqueuingCompleted();

            try
            {
                await m_parseQueue.Completion;
            }
            catch (TaskCanceledException)
            {
                // Expected. This means that at least one task failed parsing
            }

            // Parsing is complete. Just need to wait for pending items to finish binding.
            m_bindQueue.Complete();

            try
            {
                await m_bindQueue.Completion;
            }
            catch (TaskCanceledException)
            {
                // Expected. This means that at least one task failed binding
            }

            // Need to check if the queue reparsed prelude or configuration module.
            ParsedModule prelude             = GetProcessedPreludeOrDefault();
            ParsedModule configurationModule = GetProcessedConfigurationModuleOrDefault();

            // The workspace is ready to be constructed. So at this point we can run some workspace-level validations.
            var workspaceFailures = WorkspaceValidator.ValidateParsedModules(m_modulesAlreadyParsed.Values, m_workspaceProvider.PathTable);

            // Create the result. Observe that if the task is cancelled, we don't propagate it
            // but reflect it in the result.
            return(new Workspace(
                       m_workspaceProvider,
                       m_workspaceConfiguration,
                       GetAllSourceModules(prelude, configurationModule),
                       m_failures.Union(workspaceFailures),
                       preludeModule: prelude,
                       configurationModule: configurationModule));
        }