| File: DocumentCompiler.cs | Web Access |
| Project: src\runtime\src\tools\ilasm\src\ILAssembler\ILAssembler.csproj (ILAssembler) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.Collections.Immutable; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Metadata.Ecma335; using System.Reflection.PortableExecutable; using Antlr4.Runtime; namespace ILAssembler; public sealed class DocumentCompiler { public (ImmutableArray<Diagnostic>, PEBuilder?) Compile(SourceText document, Func<string, SourceText> includedDocumentLoader, Func<string, byte[]> resourceLocator, Options options) { var inputSource = new AntlrInputStream(document.Text) { name = document.Path }; CILLexer lexer = new(inputSource); Dictionary<string, SourceText> loadedDocuments = new() { {document.Path!, document } }; PreprocessedTokenSource preprocessor = new(lexer, path => { var includedDocument = includedDocumentLoader(path); var includedSource = new AntlrInputStream(includedDocument.Text) { name = includedDocument.Path }; loadedDocuments.Add(includedDocument.Path, includedDocument); return new CILLexer(includedSource); }); ImmutableArray<Diagnostic>.Builder diagnostics = ImmutableArray.CreateBuilder<Diagnostic>(); preprocessor.OnPreprocessorSyntaxError += (source, start, length, msg) => { diagnostics.Add(new Diagnostic("Preprocessor", DiagnosticSeverity.Error, msg, new Location(new(start, length), loadedDocuments[source]))); }; // Note: Parser must use the preprocessor token stream (not the raw lexer) // to properly handle #include, #define, and other preprocessor directives. CILParser parser = new(new CommonTokenStream(preprocessor)); var result = parser.decls(); GrammarVisitor visitor = new GrammarVisitor(loadedDocuments, options, resourceLocator); _ = result.Accept(visitor); var image = visitor.BuildImage(); bool anyErrors = diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Error); anyErrors |= image.Diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Error); diagnostics.AddRange(image.Diagnostics); // In error-tolerant mode, return image even with errors bool returnImage = !anyErrors || options.ErrorTolerant; return (diagnostics.ToImmutable(), returnImage ? image.Image : null); } }