示例#1
0
        private SyntaxTree?TryGetSyntaxTree(Uri fileUri, out DiagnosticBuilder.ErrorBuilderDelegate?failureBuilder)
        {
            if (workspace.TryGetSyntaxTree(fileUri, out var syntaxTree))
            {
                failureBuilder       = null;
                syntaxTrees[fileUri] = syntaxTree;
                return(syntaxTree);
            }

            if (syntaxTrees.TryGetValue(fileUri, out syntaxTree))
            {
                failureBuilder = null;
                return(syntaxTree);
            }

            if (syntaxTreeLoadFailures.TryGetValue(fileUri, out failureBuilder))
            {
                return(null);
            }

            if (!fileResolver.TryRead(fileUri, out var fileContents, out failureBuilder))
            {
                syntaxTreeLoadFailures[fileUri] = failureBuilder;
                return(null);
            }

            failureBuilder = null;
            return(AddSyntaxTree(fileUri, fileContents));
        }
        private ISourceFile?TryGetSourceFile(Uri fileUri, ModuleReference?moduleReference, out ErrorBuilderDelegate?failureBuilder)
        {
            if (workspace.TryGetSourceFile(fileUri, out var sourceFile))
            {
                failureBuilder            = null;
                sourceFilesByUri[fileUri] = sourceFile;
                return(sourceFile);
            }

            if (sourceFilesByUri.TryGetValue(fileUri, out sourceFile))
            {
                failureBuilder = null;
                return(sourceFile);
            }

            if (errorBuildersByUri.TryGetValue(fileUri, out failureBuilder))
            {
                return(null);
            }

            if (!fileResolver.TryRead(fileUri, out var fileContents, out failureBuilder))
            {
                errorBuildersByUri[fileUri] = failureBuilder;
                return(null);
            }

            failureBuilder = null;
            return(AddSourceFile(fileUri, fileContents, moduleReference));
        }
        private SyntaxTree?TryGetSyntaxTree(string fullFileName, out DiagnosticBuilder.ErrorBuilderDelegate?failureBuilder)
        {
            var normalizedFileName = fileResolver.GetNormalizedFileName(fullFileName);

            if (syntaxTrees.TryGetValue(normalizedFileName, out var syntaxTree))
            {
                failureBuilder = null;
                return(syntaxTree);
            }

            if (syntaxTreeLoadFailures.TryGetValue(normalizedFileName, out failureBuilder))
            {
                return(null);
            }

            var fileContents = fileResolver.TryRead(normalizedFileName, out var failureMessage);

            if (fileContents == null)
            {
                // TODO: If we upgrade to netstandard2.1, we should be able to use the following to hint to the compiler that failureBuilder is non-null:
                // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/nullable-analysis
                var concreteFailureMessage = failureMessage ?? throw new InvalidOperationException($"Expected {nameof(fileResolver.TryRead)} to provide failure diagnostics");

                failureBuilder = x => x.ErrorOccurredLoadingModule(concreteFailureMessage);
                syntaxTreeLoadFailures[normalizedFileName] = failureBuilder;
                return(null);
            }

            failureBuilder = null;
            return(AddSyntaxTree(normalizedFileName, fileContents));
        }
示例#4
0
        private static TypeSymbol LoadTextContentTypeBuilder(IBinder binder, IFileResolver fileResolver, IDiagnosticWriter diagnostics, ImmutableArray <FunctionArgumentSyntax> arguments, ImmutableArray <TypeSymbol> argumentTypes)
        {
            if (argumentTypes[0] is not StringLiteralType filePathType)
            {
                diagnostics.Write(DiagnosticBuilder.ForPosition(arguments[0]).CompileTimeConstantRequired());
                return(LanguageConstants.String);
            }
            var filePathValue = filePathType.RawStringValue;

            var fileUri = GetFileUriWithDiagnostics(binder, fileResolver, diagnostics, filePathValue, arguments[0]);

            if (fileUri is null)
            {
                return(LanguageConstants.String);
            }
            var fileEncoding = Encoding.UTF8;

            if (argumentTypes.Length > 1)
            {
                if (argumentTypes[1] is not StringLiteralType encodingType)
                {
                    diagnostics.Write(DiagnosticBuilder.ForPosition(arguments[1]).CompileTimeConstantRequired());
                    return(LanguageConstants.String);
                }
                fileEncoding = LanguageConstants.SupportedEncodings.First(x => string.Equals(x.name, encodingType.RawStringValue, LanguageConstants.IdentifierComparison)).encoding;
            }

            if (!fileResolver.TryRead(fileUri, out var fileContent, out var fileReadFailureBuilder, fileEncoding, LanguageConstants.MaxLiteralCharacterLimit, out var detectedEncoding))
            {
                diagnostics.Write(fileReadFailureBuilder.Invoke(DiagnosticBuilder.ForPosition(arguments[0])));
                return(LanguageConstants.String);
            }
            if (arguments.Length > 1 && fileEncoding != detectedEncoding)
            {
                diagnostics.Write(DiagnosticBuilder.ForPosition(arguments[1]).FileEncodingMismatch(detectedEncoding.WebName));
            }
            return(new StringLiteralType(fileContent));
        }
示例#5
0
        public static (Uri entrypointUri, ImmutableDictionary <Uri, string> filesToSave) DecompileFileWithModules(IResourceTypeProvider resourceTypeProvider, IFileResolver fileResolver, Uri jsonUri)
        {
            var decompileQueue = new Queue <Uri>();

            var entryUri  = ChangeExtension(jsonUri, "bicep");
            var workspace = new Workspace();

            decompileQueue.Enqueue(entryUri);

            while (decompileQueue.Any())
            {
                var bicepUri = decompileQueue.Dequeue();
                if (!bicepUri.AbsolutePath.EndsWith(".bicep", StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                var currentJsonUri = ChangeExtension(bicepUri, "json");

                if (workspace.TryGetSyntaxTree(bicepUri, out _))
                {
                    continue;
                }

                if (!fileResolver.TryRead(currentJsonUri, out var jsonInput, out _))
                {
                    throw new InvalidOperationException($"Failed to read {currentJsonUri}");
                }

                var program    = TemplateConverter.DecompileTemplate(workspace, fileResolver, currentJsonUri, jsonInput);
                var syntaxTree = new SyntaxTree(bicepUri, ImmutableArray <int> .Empty, program);
                workspace.UpsertSyntaxTrees(syntaxTree.AsEnumerable());

                foreach (var module in program.Children.OfType <ModuleDeclarationSyntax>())
                {
                    var moduleRelativePath = SyntaxHelper.TryGetModulePath(module, out _);
                    if (moduleRelativePath == null ||
                        !SyntaxTreeGroupingBuilder.ValidateModulePath(moduleRelativePath, out _) ||
                        !Uri.TryCreate(bicepUri, moduleRelativePath, out var moduleUri))
                    {
                        // Do our best, but keep going if we fail to resolve a module file
                        continue;
                    }

                    if (!workspace.TryGetSyntaxTree(moduleUri, out _))
                    {
                        decompileQueue.Enqueue(moduleUri);
                    }
                }
            }

            RewriteSyntax(resourceTypeProvider, workspace, entryUri, semanticModel => new ParentChildResourceNameRewriter(semanticModel));
            RewriteSyntax(resourceTypeProvider, workspace, entryUri, semanticModel => new DependsOnRemovalRewriter(semanticModel));
            RewriteSyntax(resourceTypeProvider, workspace, entryUri, semanticModel => new ForExpressionSimplifierRewriter(semanticModel));
            for (var i = 0; i < 5; i++)
            {
                // This is a little weird. If there are casing issues nested inside casing issues (e.g. in an object), then the inner casing issue will have no type information
                // available, as the compilation will not have associated a type with it (since there was no match on the outer object). So we need to correct the outer issue first,
                // and then move to the inner one. We need to recompute the entire compilation to do this. It feels simpler to just do this in passes over the file, rather than on demand.
                if (!RewriteSyntax(resourceTypeProvider, workspace, entryUri, semanticModel => new TypeCasingFixerRewriter(semanticModel)))
                {
                    break;
                }
            }

            return(entryUri, PrintFiles(workspace));
        }
示例#6
0
        public static (Uri entrypointUri, ImmutableDictionary <Uri, string> filesToSave) DecompileFileWithModules(IFileResolver fileResolver, Uri jsonUri)
        {
            var decompiled     = new Dictionary <Uri, ProgramSyntax>();
            var decompileQueue = new Queue <Uri>();

            var entryUri = ChangeExtension(jsonUri, "bicep");

            decompileQueue.Enqueue(entryUri);

            while (decompileQueue.Any())
            {
                var bicepUri = decompileQueue.Dequeue();
                if (!bicepUri.AbsolutePath.EndsWith(".bicep", StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                var currentJsonUri = ChangeExtension(bicepUri, "json");

                if (decompiled.ContainsKey(bicepUri))
                {
                    continue;
                }

                if (!fileResolver.TryRead(currentJsonUri, out var jsonInput, out _))
                {
                    throw new InvalidOperationException($"Failed to read {currentJsonUri}");
                }

                var program = TemplateConverter.DecompileTemplate(fileResolver, currentJsonUri, jsonInput);
                decompiled[bicepUri] = program;

                foreach (var module in program.Children.OfType <ModuleDeclarationSyntax>())
                {
                    var moduleRelativePath = SyntaxHelper.TryGetModulePath(module, out _);

                    if (moduleRelativePath == null || !Uri.TryCreate(bicepUri, moduleRelativePath, out var moduleUri))
                    {
                        throw new ArgumentException($"Failed to resolve {moduleRelativePath} relative to {bicepUri}");
                    }

                    if (!decompiled.ContainsKey(moduleUri))
                    {
                        decompileQueue.Enqueue(moduleUri);
                    }
                }
            }

            var filesToSave = new Dictionary <Uri, string>();

            foreach (var(fileUri, program) in decompiled)
            {
                var bicepOutput = PrettyPrinter.PrintProgram(program, new PrettyPrintOptions(NewlineOption.Auto, IndentKindOption.Space, 2, false));

                if (bicepOutput == null)
                {
                    throw new ArgumentException($"Failed to pring bicep file {fileUri}");
                }

                filesToSave[fileUri] = bicepOutput;
            }

            return(entryUri, filesToSave.ToImmutableDictionary());
        }
示例#7
0
        public (Uri entrypointUri, ImmutableDictionary <Uri, string> filesToSave) DecompileFileWithModules(Uri entryJsonUri, Uri entryBicepUri)
        {
            var workspace      = new Workspace();
            var decompileQueue = new Queue <(Uri, Uri)>();

            decompileQueue.Enqueue((entryJsonUri, entryBicepUri));

            while (decompileQueue.Count > 0)
            {
                var(jsonUri, bicepUri) = decompileQueue.Dequeue();

                if (PathHelper.HasBicepExtension(jsonUri))
                {
                    throw new InvalidOperationException($"Cannot decompile the file with .bicep extension: {jsonUri}.");
                }

                if (workspace.TryGetSourceFile(bicepUri, out _))
                {
                    continue;
                }

                if (!fileResolver.TryRead(jsonUri, out var jsonInput, out _))
                {
                    throw new InvalidOperationException($"Failed to read {jsonUri}");
                }

                var(program, jsonTemplateUrisByModule) = TemplateConverter.DecompileTemplate(workspace, fileResolver, bicepUri, jsonInput);
                var bicepFile = SourceFileFactory.CreateBicepFile(bicepUri, program.ToText());
                workspace.UpsertSourceFile(bicepFile);

                foreach (var module in program.Children.OfType <ModuleDeclarationSyntax>())
                {
                    var moduleRelativePath = SyntaxHelper.TryGetModulePath(module, out _);
                    if (moduleRelativePath == null ||
                        !LocalModuleReference.Validate(moduleRelativePath, out _) ||
                        !Uri.TryCreate(bicepUri, moduleRelativePath, out var moduleUri))
                    {
                        // Do our best, but keep going if we fail to resolve a module file
                        continue;
                    }

                    if (!workspace.TryGetSourceFile(moduleUri, out _) && jsonTemplateUrisByModule.TryGetValue(module, out var linkedTemplateUri))
                    {
                        decompileQueue.Enqueue((linkedTemplateUri, moduleUri));
                    }
                }
            }

            RewriteSyntax(workspace, entryBicepUri, semanticModel => new ParentChildResourceNameRewriter(semanticModel));
            RewriteSyntax(workspace, entryBicepUri, semanticModel => new DependsOnRemovalRewriter(semanticModel));
            RewriteSyntax(workspace, entryBicepUri, semanticModel => new ForExpressionSimplifierRewriter(semanticModel));
            for (var i = 0; i < 5; i++)
            {
                // This is a little weird. If there are casing issues nested inside casing issues (e.g. in an object), then the inner casing issue will have no type information
                // available, as the compilation will not have associated a type with it (since there was no match on the outer object). So we need to correct the outer issue first,
                // and then move to the inner one. We need to recompute the entire compilation to do this. It feels simpler to just do this in passes over the file, rather than on demand.
                if (!RewriteSyntax(workspace, entryBicepUri, semanticModel => new TypeCasingFixerRewriter(semanticModel)))
                {
                    break;
                }
            }

            return(entryBicepUri, PrintFiles(workspace));
        }