Esempio n. 1
0
        private void RecomputeWorkspace(TextDocumentItem document)
        {
            var path = document.Uri.ToAbsolutePath(m_pathTable);

            // Need to check if parsedModule is prelude or configuration module.
            // If the parsed module is the configuration module, then full reanalysis is required.
            ParsedModule     parsedModule = m_workspace.TryGetModuleBySpecFileName(path);
            ModuleDefinition moduleDefinition;

            if (parsedModule != null)
            {
                moduleDefinition = parsedModule.Definition;
            }
            else
            {
                // This should never happen: all the new files trigger full workspace reconstruction.
                return;
            }

            try
            {
                var updatedWorkspace = GetUpdatedWorkspace(parsedModule, moduleDefinition, path);
                m_workspace = updatedWorkspace;
            }
            catch (Exception e)
            {
                // TODO: saqadri - log exception, but for now just swallow
                Debug.Fail($"Workspace recomputation threw an exception: {e}");
            }
        }
Esempio n. 2
0
        private void ConvertExportsFile(IModuleRegistry moduleRegistry, ParsedModule module, Package package)
        {
            var exportsFileModule = ModuleLiteral.CreateFileModule(
                m_javaScriptWorkspaceResolver.ExportsFile,
                moduleRegistry,
                package,
                module.Specs[m_javaScriptWorkspaceResolver.ExportsFile].LineMap);

            // For each symbol defined in the resolver settings for exports, add all specified project outputs
            int pos = 1;

            foreach (var export in Exports)
            {
                FrontEndUtilities.AddEvaluationCallbackToFileModule(
                    exportsFileModule,
                    (context, moduleLiteral, evaluationStackFrame) =>
                    CollectProjectOutputsAsync(module.Definition.Specs, moduleLiteral.Qualifier.QualifierId, export, context.EvaluationScheduler),
                    export.FullSymbol,
                    pos);

                pos += 2;
            }

            var moduleInfo = new UninstantiatedModuleInfo(
                // We can register an empty one since we have the module populated properly
                new Script.SourceFile(
                    m_javaScriptWorkspaceResolver.ExportsFile,
                    new Declaration[] { }),
                exportsFileModule,
                Context.QualifierTable.EmptyQualifierSpaceId);

            moduleRegistry.AddUninstantiatedModuleInfo(moduleInfo);
        }
Esempio n. 3
0
        private CodeLens GetModuleReference(ParsedModule module, ISourceFile spec)
        {
            var moduleVersion = string.IsNullOrEmpty(module.Descriptor.Version) ? null : $" (version: {module.Descriptor.Version})";

            // Ideally we want to navigate to the module declaration, but unfortunately we don't keep proper track of that.
            // Therefore we do a quick file existence check, try to find the common name and then fall back to the current spec file.
            var moduleConfigFile = module.Definition.ModuleConfigFile.ToString(PathTable);

            if (!File.Exists(moduleConfigFile))
            {
                moduleConfigFile = Path.Combine(Path.GetDirectoryName(moduleConfigFile), "module.config.dsc");
            }
            else if (!File.Exists(moduleConfigFile))
            {
                // Fall back to the current spec....
                moduleConfigFile = spec.FileName;
            }

            return
                (new CodeLens
            {
                Range = spec.ToRange(),
                Command = new Command
                {
                    Title = FormattableStringEx.I($"Module: {module.Descriptor.Name}{moduleVersion} - {module.Definition.Root.ToString(PathTable)}"),
                    CommandIdentifier = "DScript.openDocument",
                    Arguments = new object[] { UriExtensions.GetUriFromPath(moduleConfigFile) },
                },
            });
        }
Esempio n. 4
0
        private static HashSet <string> GetUpStreamModuleNames(ParsedModule parsedModule, ISpecDependencyProvider semanticModel)
        {
            HashSet <string> upStreamDependencies = new HashSet <string>();

            foreach (var spec in parsedModule.Specs)
            {
                upStreamDependencies.AddRange(semanticModel.GetModuleDependenciesOf(spec.Key));
            }

            return(upStreamDependencies);
        }
        private Package CreatePackageForModule(ParsedModule module)
        {
            var path    = module.Definition.Root.Combine(PathTable, "package.config.dsc");
            var package = Package.Create(
                PackageId.Create(StringTable, module.Descriptor.Name),
                path,
                new PackageDescriptor {
                Name = module.Descriptor.Name
            },
                parsedProjects: module.PathToSpecs,
                moduleId: module.Descriptor.Id);

            return(package);
        }
Esempio n. 6
0
        /// <inheritdoc />
        public async Task <bool?> TryConvertModuleToEvaluationAsync(ParsedModule module, IWorkspace workspace)
        {
            Contract.Requires(module != null);
            Contract.Assert(m_resolverState == State.ResolverInitialized);
            Contract.Assert(m_owningModules != null, "Owning modules should not be null if the instance is initialized.");

            if (!m_owningModules.TryGetValue(module.Descriptor.Id, out Package package))
            {
                // Current resolver doesn't own a given module.
                return(null);
            }

            var factory  = CreateRuntimeModelFactory((Workspace)workspace);
            var tasks    = module.Specs.Select(spec => ConvertFileToEvaluationAsync(factory, spec.Key, spec.Value, package)).ToArray();
            var allTasks = await Task.WhenAll(tasks);

            return(allTasks.All(b => b));
        }
Esempio n. 7
0
        public List <ParsedModule> FilterForConversion([NotNull] Workspace workspace, [NotNull] EvaluationFilter evaluationFilter)
        {
            // TODO: need to check that file2file map is available and skip filtering otherwise.
            var spec2SpecMapProvider = new WorkspaceBasedSpecDependencyProvider(workspace, m_pathTable);

            // First, getting all modules, that satisfy the module filter.
            var modulesToInclude = GetModulesToInclude(workspace, spec2SpecMapProvider, evaluationFilter);

            // Second, getting all the specs, that satisfy the spec filter.
            var filesToInclude = GetFilesToInclude(
                modulesToInclude,
                workspace,
                spec2SpecMapProvider,
                evaluationFilter);

            // Third, constructing a new set of modules based on a filtered set of specs.
            var partiallyFilteredModules = new Dictionary <ModuleDefinition, Dictionary <AbsolutePath, ISourceFile> >();

            foreach (var kvp in workspace.SpecSources)
            {
                // File is not part of 'must have' module and is part of 'must have' spec.
                if (!modulesToInclude.Contains(kvp.Value.OwningModule) && filesToInclude.Contains(kvp.Key))
                {
                    var map = partiallyFilteredModules.GetOrAdd(kvp.Value.OwningModule.Definition, k => new Dictionary <AbsolutePath, ISourceFile>());
                    map[kvp.Key] = kvp.Value.SourceFile;
                }
            }

            foreach (var kvp in partiallyFilteredModules)
            {
                // Need to recreate both - module definition and parsed module,
                // because the set of specs is different.
                var moduleDefinition    = kvp.Key.WithSpecs(kvp.Value.Keys.ToReadOnlySet());
                var parsedPartialModule = new ParsedModule(moduleDefinition, kvp.Value, workspace.GetModuleByModuleDescriptor(moduleDefinition.Descriptor).ReferencedModules);
                modulesToInclude.Add(parsedPartialModule);
            }

            return(modulesToInclude.ToList());
        }
Esempio n. 8
0
        private async Task <Workspace> CreateWorkspaceAsync(AbsolutePath configPath, IReadOnlyDictionary <AbsolutePath, ISourceFile> specFileMap, bool typecheck)
        {
            var moduleDefinition = ModuleDefinition.CreateConfigModuleDefinition(Context.PathTable, configPath, specFileMap.Keys);
            var parsedModule     = new ParsedModule(moduleDefinition, specFileMap);

            // if type checking is not requested --> directly create a workspace from the given source file map
            if (!typecheck)
            {
                return(Workspace.CreateConfigurationWorkspace(WorkspaceConfiguration, parsedModule, preludeModule: null));
            }

            // otherwise, request a prelude module from the PreludeManager and proceed to type checking
            var maybePrelude = await GetPreludeParsedModule(configPath);

            if (!maybePrelude.Succeeded)
            {
                return(Workspace.Failure(null, WorkspaceConfiguration, maybePrelude.Failure));
            }

            var preludeModule = (ParsedModule)maybePrelude.Result;
            var workspace     = Workspace.CreateConfigurationWorkspace(WorkspaceConfiguration, parsedModule, preludeModule);

            return(await TypeCheckWorkspaceAsync(workspace));
        }
Esempio n. 9
0
 /// <summary>
 /// Returns true if the <paramref name="module"/> is a prelude or a special configuration module that contains all configuration files.
 /// </summary>
 public static bool IsPreludeOrConfigurationModule(this Workspace workspace, ParsedModule module)
 {
     return(module != null && (module == workspace.PreludeModule || module == workspace.ConfigurationModule));
 }
Esempio n. 10
0
        /// <inheritdoc/>
        public async Task <bool?> TryConvertModuleToEvaluationAsync(IModuleRegistry moduleRegistry, ParsedModule module, IWorkspace workspace)
        {
            // This resolver owns only one module.
            if (!module.Definition.Equals(ModuleDefinition))
            {
                return(null);
            }

            var package = FrontEndUtilities.CreatePackage(module.Definition, Context.StringTable);

            ConvertExportsFile(moduleRegistry, module, package);
            await ConvertImportsFileAsync(package);

            return(true);
        }
Esempio n. 11
0
 /// <inheritdoc/>
 public Task <bool?> TryConvertModuleToEvaluationAsync(IModuleRegistry moduleRegistry, ParsedModule module, IWorkspace workspace)
 {
     // No conversion needed.
     return(Task.FromResult <bool?>(true));
 }
Esempio n. 12
0
        /// <inheritdoc/>
        public Task <bool?> TryConvertModuleToEvaluationAsync(IModuleRegistry moduleRegistry, ParsedModule module, IWorkspace workspace)
        {
            // This resolver owns only one module.
            if (!module.Definition.Equals(ModuleDefinition))
            {
                return(Task.FromResult <bool?>(null));
            }

            var exportsFileModule = ModuleLiteral.CreateFileModule(
                m_javaScriptWorkspaceResolver.ExportsFile,
                moduleRegistry,
                FrontEndUtilities.CreatePackage(module.Definition, Context.StringTable),
                module.Specs[m_javaScriptWorkspaceResolver.ExportsFile].LineMap);

            // For each symbol defined in the resolver settings for exports, add all specified project outputs
            int pos = 1;

            foreach (var export in Exports)
            {
                FrontEndUtilities.AddEvaluationCallbackToFileModule(
                    exportsFileModule,
                    (context, moduleLiteral, evaluationStackFrame) =>
                    CollectProjectOutputsAsync(module.Definition.Specs, moduleLiteral.Qualifier.QualifierId, export),
                    export.FullSymbol,
                    pos);

                pos += 2;
            }

            var moduleInfo = new UninstantiatedModuleInfo(
                // We can register an empty one since we have the module populated properly
                new SourceFile(
                    m_javaScriptWorkspaceResolver.ExportsFile,
                    new Declaration[] {}),
                exportsFileModule,
                Context.QualifierTable.EmptyQualifierSpaceId);

            moduleRegistry.AddUninstantiatedModuleInfo(moduleInfo);

            return(Task.FromResult <bool?>(true));
        }
Esempio n. 13
0
        /// <inheritdoc />
        public Task <bool?> TryConvertModuleToEvaluationAsync(IModuleRegistry moduleRegistry, ParsedModule module, IWorkspace workspace)
        {
            if (!string.Equals(module.Descriptor.ResolverName, Name, StringComparison.Ordinal))
            {
                return(Task.FromResult <bool?>(null));
            }

            var downloadData = m_workspaceResolver.Downloads[module.Descriptor.Name];

            var package = CreatePackage(module.Definition);

            Contract.Assert(module.Specs.Count == 1, "This resolver generated the module, so we expect a single spec.");
            var sourceKv = module.Specs.First();

            var sourceFilePath = sourceKv.Key;
            var sourceFile     = sourceKv.Value;

            var currentFileModule = ModuleLiteral.CreateFileModule(
                sourceFilePath,
                moduleRegistry,
                package,
                sourceFile.LineMap);

            // Download
            var downloadSymbol        = FullSymbol.Create(m_context.SymbolTable, "download");
            var downloadResolvedEntry = new ResolvedEntry(
                downloadSymbol,
                (Context context, ModuleLiteral env, EvaluationStackFrame args) => DownloadFile(downloadData),
                // The following position is a contract right now iwtht he generated ast in the workspace resolver
                // we have to find a nicer way to handle and register these.
                TypeScript.Net.Utilities.LineInfo.FromLineAndPosition(0, 1)
                );

            currentFileModule.AddResolvedEntry(downloadSymbol, downloadResolvedEntry);
            currentFileModule.AddResolvedEntry(new FilePosition(1, sourceFilePath), downloadResolvedEntry);

            // Contents.All
            var extractedSymbol       = FullSymbol.Create(m_context.SymbolTable, "extracted");
            var contentsResolvedEntry = new ResolvedEntry(
                extractedSymbol,
                (Context context, ModuleLiteral env, EvaluationStackFrame args) => ExtractFile(downloadData),
                // The following position is a contract right now iwtht he generated ast in the workspace resolver
                // we have to find a nicer way to handle and register these.
                TypeScript.Net.Utilities.LineInfo.FromLineAndPosition(0, 3)
                );

            currentFileModule.AddResolvedEntry(extractedSymbol, contentsResolvedEntry);
            currentFileModule.AddResolvedEntry(new FilePosition(3, sourceFilePath), contentsResolvedEntry);

            var moduleInfo = new UninstantiatedModuleInfo(
                // We can register an empty one since we have the module populated properly
                new SourceFile(
                    sourceFilePath,
                    new Declaration[]
            {
            }),
                currentFileModule,
                m_context.QualifierTable.EmptyQualifierSpaceId);

            moduleRegistry.AddUninstantiatedModuleInfo(moduleInfo);

            return(Task.FromResult <bool?>(true));
        }
Esempio n. 14
0
        /// <inheritdoc/>
        public Task <bool?> TryConvertModuleToEvaluationAsync(IModuleRegistry moduleRegistry, ParsedModule module, IWorkspace workspace)
        {
            // This resolver owns only one module.
            if (!module.Definition.Equals(ModuleDefinition))
            {
                return(Task.FromResult <bool?>(null));
            }

            return(Task.FromResult <bool?>(true));
        }
Esempio n. 15
0
        private Workspace GetUpdatedWorkspace(ParsedModule parsedModule, ModuleDefinition moduleDefinition, AbsolutePath path)
        {
            // Need to use both 'ParsedModule' and 'ModuleDefinition' in case if the 'path' is newly added
            // file and was not parsed yet.

            // All already parsed modules are good to go
            var unchangedModules = m_workspace.SpecModules;

            // We build a module under construction that has all specs but the one that changed
            var moduleUnderConstruction = new ModuleUnderConstruction(moduleDefinition);

            foreach (var spec in parsedModule.Specs)
            {
                if (spec.Key != path)
                {
                    moduleUnderConstruction.AddParsedSpec(spec.Key, spec.Value);
                }
            }

            // Update parsing failures so the ones coming from the changed spec are removed
            var filteredFailures = m_workspace.Failures.Where(
                failure => (failure is ParsingFailure parsingFailure && parsingFailure.SourceFile.Path.AbsolutePath != path.ToString(m_pathTable)));

            var updatedWorkspace =
                m_workspace.WorkspaceProvider.CreateIncrementalWorkspaceForAllKnownModulesAsync(
                    unchangedModules,
                    moduleUnderConstruction,
                    filteredFailures,
                    m_workspace.PreludeModule)
                .GetAwaiter()
                .GetResult();

            var semanticWorkspaceProvider = new SemanticWorkspaceProvider(new WorkspaceStatistics(), m_workspace.WorkspaceConfiguration);
            var semanticWorkspace         =
                semanticWorkspaceProvider.ComputeSemanticWorkspaceAsync(m_pathTable, updatedWorkspace, m_workspace.GetSemanticModel(), incrementalMode: true)
                .GetAwaiter()
                .GetResult();

            // Get all the potentially new specs. Old ones, besides the one that changed, were aready linted
            var newPathToSpecs =
                updatedWorkspace.GetAllSpecFiles()
                .Except(m_workspace.GetAllSpecFiles())
                .Concat(new[] { path });

            // The changed spec always needs linting. Plus all the new ones the changed spec may have introduced.
            var preludeModule = updatedWorkspace.PreludeModule;
            var specsToLint   = new HashSet <ISourceFile>();

            foreach (var pathToSpec in newPathToSpecs)
            {
                // Need to exclude prelude files from liinting.
                // Need to keep config files. They should be linted.
                if (preludeModule == null || !preludeModule.Specs.ContainsKey(pathToSpec))
                {
                    specsToLint.Add(updatedWorkspace.GetSourceFile(pathToSpec));
                }
            }

            var lintedWorkspace = WorkspaceBuilder.CreateLintedWorkspaceForChangedSpecs(
                semanticWorkspace,
                specsToLint,
                m_controller.FrontEndContext.LoggingContext,
                m_controller.FrontEndConfiguration,
                m_controller.FrontEndContext.PathTable);

            return(lintedWorkspace);
        }
Esempio n. 16
0
        /// <inheritdoc />
        public async Task <bool?> TryConvertModuleToEvaluationAsync(IModuleRegistry moduleRegistry, ParsedModule module, IWorkspace workspace)
        {
            if (!string.Equals(module.Descriptor.ResolverName, Name, StringComparison.Ordinal))
            {
                return(null);
            }

            var package = CreatePackage(module.Definition);

            Contract.Assert(module.Specs.Count == 1, "This resolver generated the module, so we expect a single spec.");
            var sourceKv = module.Specs.First();

            // The in-memory generated spec is a regular DScript one, so run regular AST conversion
            var result = await FrontEndUtilities.RunAstConversionAsync(m_frontEndHost, m_context, m_logger, m_frontEndStatistics, package, sourceKv.Key);

            if (!result.Success)
            {
                return(false);
            }

            // Register the uninstantiated module
            var moduleData = new UninstantiatedModuleInfo(
                result.SourceFile,
                result.Module,
                result.QualifierSpaceId.IsValid ? result.QualifierSpaceId : m_context.QualifierTable.EmptyQualifierSpaceId);

            m_frontEndHost.ModuleRegistry.AddUninstantiatedModuleInfo(moduleData);

            return(true);
        }
Esempio n. 17
0
 public Task <bool?> TryConvertModuleToEvaluationAsync(IModuleRegistry moduleRegistry, ParsedModule module, IWorkspace workspace)
 {
     Contract.Requires(module != null);
     Contract.Requires(workspace != null);
     throw new System.NotImplementedException();
 }