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}"); } }
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); }
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) }, }, }); }
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); }
/// <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)); }
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()); }
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)); }
/// <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)); }
/// <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); }
/// <inheritdoc/> public Task <bool?> TryConvertModuleToEvaluationAsync(IModuleRegistry moduleRegistry, ParsedModule module, IWorkspace workspace) { // No conversion needed. return(Task.FromResult <bool?>(true)); }
/// <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)); }
/// <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)); }
/// <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)); }
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); }
/// <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); }
public Task <bool?> TryConvertModuleToEvaluationAsync(IModuleRegistry moduleRegistry, ParsedModule module, IWorkspace workspace) { Contract.Requires(module != null); Contract.Requires(workspace != null); throw new System.NotImplementedException(); }