Esempio n. 1
0
        public void Initialize(IncrementalGeneratorInitializationContext context)
        {
            var errorCodeType = context.CompilationProvider.Select((comp, _) =>
                                                                   comp.GetTypeByMetadataName("Loretta.CodeAnalysis.Lua.ErrorCode"));

            var errorCodeFields = errorCodeType.SelectMany((type, _) =>
                                                           type?.GetMembers().OfType <IFieldSymbol>() ?? Enumerable.Empty <IFieldSymbol>())
                                  .Collect();

            context.RegisterSourceOutput(errorCodeFields, (context, codes) =>
            {
                if (codes.IsEmpty)
                {
                    return;
                }
                else
                {
                    using var writer = new SourceWriter();
                    using (writer.CurlyIndenter("namespace Loretta.CodeAnalysis.Lua"))
                        using (writer.CurlyIndenter("internal static partial class ErrorFacts"))
                        {
                            using (writer.CurlyIndenter("public static partial bool IsWarning(ErrorCode code)"))
                                using (writer.CurlyIndenter("switch(code)"))
                                {
                                    var warnings = codes.Where(field => field.Name.StartsWith("WRN_", StringComparison.OrdinalIgnoreCase));
                                    if (warnings.Any())
                                    {
                                        foreach (var code in warnings)
                                        {
                                            writer.WriteLine($"case ErrorCode.{code.Name}:");
                                        }
                                        using (writer.Indenter())
                                            writer.WriteLine("return true;");
                                    }
                                    writer.WriteLine("default:");
                                    using (writer.Indenter())
                                        writer.WriteLine("return false;");
                                }
                            writer.WriteLine();
                            using (writer.CurlyIndenter("public static partial bool IsFatal(ErrorCode code)"))
                                using (writer.CurlyIndenter("switch(code)"))
                                {
                                    var fatals = codes.Where(field => field.Name.StartsWith("FTL_", StringComparison.OrdinalIgnoreCase));
                                    if (fatals.Any())
                                    {
                                        foreach (var code in fatals)
                                        {
                                            writer.WriteLine($"case ErrorCode.{code.Name}:");
                                        }
                                        using (writer.Indenter())
                                            writer.WriteLine("return true;");
                                    }
                                    writer.WriteLine("default:");
                                    using (writer.Indenter())
                                        writer.WriteLine("return false;");
                                }
                            writer.WriteLine();
                            using (writer.CurlyIndenter("public static partial bool IsInfo(ErrorCode code)"))
                                using (writer.CurlyIndenter("switch(code)"))
                                {
                                    var infos = codes.Where(field => field.Name.StartsWith("INF_", StringComparison.OrdinalIgnoreCase));
                                    if (infos.Any())
                                    {
                                        foreach (var code in infos)
                                        {
                                            writer.WriteLine($"case ErrorCode.{code.Name}:");
                                        }
                                        using (writer.Indenter())
                                            writer.WriteLine("return true;");
                                    }
                                    writer.WriteLine("default:");
                                    using (writer.Indenter())
                                        writer.WriteLine("return false;");
                                }
                            writer.WriteLine();
                            using (writer.CurlyIndenter("public static partial bool IsHidden(ErrorCode code)"))
                                using (writer.CurlyIndenter("switch(code)"))
                                {
                                    var hidden = codes.Where(field => field.Name.StartsWith("HDN_", StringComparison.OrdinalIgnoreCase));
                                    if (hidden.Any())
                                    {
                                        foreach (var code in hidden)
                                        {
                                            writer.WriteLine($"case ErrorCode.{code.Name}:");
                                        }
                                        using (writer.Indenter())
                                            writer.WriteLine("return true;");
                                    }
                                    writer.WriteLine("default:");
                                    using (writer.Indenter())
                                        writer.WriteLine("return false;");
                                }
                        }

                    context.AddSource("ErrorFacts.g.cs", writer.GetText());
                }
            });
        }
        private static void GenerateSyntaxFacts(GeneratorExecutionContext context, KindList kinds)
        {
            SourceText sourceText;

            using (var writer = new SourceWriter())
            {
                writer.WriteLine("// <auto-generated />");
                writer.WriteLine();
                writer.WriteLine("using System;");
                writer.WriteLine("using System.Collections.Generic;");
                writer.WriteLine("using System.Collections.Immutable;");
                writer.WriteLine("using System.Diagnostics.CodeAnalysis;");
                writer.WriteLine("using Tsu;");
                writer.WriteLine();
                writer.WriteLine("#nullable enable");
                writer.WriteLine();

                using (writer.CurlyIndenter("namespace Loretta.CodeAnalysis.Lua"))
                    using (writer.CurlyIndenter("public static partial class SyntaxFacts"))
                    {
                        GenerateMinMaxLength(kinds.Tokens.Concat(kinds.Keywords), writer, "Token");
                        GenerateMinMaxLength(kinds.Tokens, writer, "NonKeywordToken");
                        GenerateMinMaxLength(kinds.Keywords, writer, "Keyword");
                        GenerateMinMaxLength(kinds.UnaryOperators, writer, "UnaryOperator");
                        GenerateMinMaxLength(kinds.BinaryOperators, writer, "BinaryOperator");

                        writer.WriteLineNoTabs("");

                        GenerateGetUnaryOperatorPrecedence(kinds, writer);

                        writer.WriteLineNoTabs("");

                        GenerateGetUnaryExpression(kinds, writer);

                        writer.WriteLineNoTabs("");

                        GenerateGetBinaryOperatorPrecedence(kinds, writer);

                        writer.WriteLineNoTabs("");

                        GenerateGetBinaryExpression(kinds, writer);

                        writer.WriteLineNoTabs("");

                        GenerateGetKeywordKind(kinds, writer);

                        writer.WriteLineNoTabs("");

                        GenerateGetUnaryOperatorKinds(kinds, writer);

                        writer.WriteLineNoTabs("");

                        GenerateGetBinaryOperatorKinds(kinds, writer);

                        writer.WriteLineNoTabs("");

                        GenerateGetText(kinds, writer);

                        var properties =
                            kinds.SelectMany(kind => kind.Properties.Select(kv => (kind, key: kv.Key, value: kv.Value)))
                            .GroupBy(t => t.key, t => (t.kind, t.value));
                        foreach (var propertyGroup in properties)
                        {
                            var possibleTypes = propertyGroup.Select(t => t.value.Type)
                                                .Where(t => t is not null)
                                                .Distinct(SymbolEqualityComparer.Default)
                                                .ToImmutableArray();

                            string type;
                            if (possibleTypes.Length > 1)
                            {
                                type = context.Compilation.GetSpecialType(SpecialType.System_Object) + "?";
                            }
                            else
                            {
                                type = possibleTypes.Single() !.ToString();
                            }

                            writer.WriteLineNoTabs("");
                            using (new CurlyIndenter(writer, $"public static partial Option<{type}> Get{propertyGroup.Key}(SyntaxKind kind)"))
                            {
                                var values = propertyGroup.GroupBy(t => t.value, t => t.kind);
                                writer.WriteLine("return kind switch");
                                writer.WriteLine("{");
                                using (new Indenter(writer))
                                {
                                    foreach (var value in values)
                                    {
                                        writer.Write(string.Join(" or ", value.Select(k => $"SyntaxKind.{k.Field.Name}")));
                                        writer.Write(" => ");
                                        writer.Write(value.Key.ToCSharpString());
                                        writer.WriteLine(",");
                                    }
                                    writer.WriteLine("_ => default,");
                                }
                                writer.WriteLine("};");
                            }
                        }

                        writer.WriteLineNoTabs("");

                        // Generate IsTrivia
                        GenerateIsX(kinds, writer, "Trivia", kind => kind.IsTrivia);

                        writer.WriteLineNoTabs("");

                        // Generate IsKeyword
                        GenerateIsX(kinds, writer, "Keyword", kind => kind.TokenInfo?.IsKeyword is true);

                        writer.WriteLineNoTabs("");

                        // Generate IsToken
                        GenerateIsX(kinds, writer, "Token", kind => kind.TokenInfo is not null);

                        // Generate Is(Unary|Binary)Operator
                        GenerateIsX(kinds, writer, "OperatorToken", kind => kind.UnaryOperatorInfo is not null || kind.BinaryOperatorInfo is not null);
                        GenerateIsX(kinds, writer, "UnaryOperatorToken", kind => kind.UnaryOperatorInfo is not null);
                        GenerateIsX(kinds, writer, "BinaryOperatorToken", kind => kind.BinaryOperatorInfo is not null);

                        writer.WriteLineNoTabs("");

                        // Extra Categories
                        var extraCategories = kinds.SelectMany(kind => kind.ExtraCategories.Select(cat => (cat, kind)))
                                              .GroupBy(t => t.cat, t => t.kind);
                        foreach (var group in extraCategories)
                        {
                            writer.WriteLineNoTabs("");

                            var groupKinds = new KindList(group.ToImmutableArray());
                            GenerateIsX(groupKinds, writer, group.Key, k => true);

                            writer.WriteLineNoTabs("");
                            writer.WriteLine("/// <summary>");
                            writer.WriteLine($"/// Returns all <see cref=\"SyntaxKind\"/>s that are in the {group.Key} category.");
                            writer.WriteLine("/// </summary>");
                            writer.WriteLine("/// <returns></returns>");
                            using (writer.CurlyIndenter($"public static IEnumerable<SyntaxKind> Get{group.Key}Kinds() => ImmutableArray.Create(new[]", ");"))
                            {
                                foreach (var kind in group)
                                {
                                    writer.WriteLine($"SyntaxKind.{kind.Field.Name},");
                                }
                            }
                        }
                    }

                sourceText = writer.GetText();
            }

            context.AddSource("SyntaxFacts.g.cs", sourceText);
        }
Esempio n. 3
0
        protected override void GenerateFiles(GeneratorExecutionContext context, CSharpCompilation compilation)
        {
            var errorCodeType =
                compilation.GetTypeByMetadataName("Loretta.CodeAnalysis.Lua.ErrorCode");

            if (errorCodeType is null)
            {
                return;
            }

            var codes = errorCodeType.GetMembers().OfType <IFieldSymbol>().ToImmutableArray();

            SourceText sourceText;

            using (var writer = new SourceWriter())
            {
                using (writer.CurlyIndenter("namespace Loretta.CodeAnalysis.Lua"))
                    using (writer.CurlyIndenter("internal static partial class ErrorFacts"))
                    {
                        using (writer.CurlyIndenter("public static partial bool IsWarning(ErrorCode code)"))
                            using (writer.CurlyIndenter("switch(code)"))
                            {
                                var warnings = codes.Where(field => field.Name.StartsWith("WRN_", StringComparison.OrdinalIgnoreCase));
                                if (warnings.Any())
                                {
                                    foreach (var code in warnings)
                                    {
                                        writer.WriteLine($"case ErrorCode.{code.Name}:");
                                    }
                                    using (writer.Indenter())
                                        writer.WriteLine("return true;");
                                }
                                writer.WriteLine("default:");
                                using (writer.Indenter())
                                    writer.WriteLine("return false;");
                            }
                        writer.WriteLine();
                        using (writer.CurlyIndenter("public static partial bool IsFatal(ErrorCode code)"))
                            using (writer.CurlyIndenter("switch(code)"))
                            {
                                var fatals = codes.Where(field => field.Name.StartsWith("FTL_", StringComparison.OrdinalIgnoreCase));
                                if (fatals.Any())
                                {
                                    foreach (var code in fatals)
                                    {
                                        writer.WriteLine($"case ErrorCode.{code.Name}:");
                                    }
                                    using (writer.Indenter())
                                        writer.WriteLine("return true;");
                                }
                                writer.WriteLine("default:");
                                using (writer.Indenter())
                                    writer.WriteLine("return false;");
                            }
                        writer.WriteLine();
                        using (writer.CurlyIndenter("public static partial bool IsInfo(ErrorCode code)"))
                            using (writer.CurlyIndenter("switch(code)"))
                            {
                                var infos = codes.Where(field => field.Name.StartsWith("INF_", StringComparison.OrdinalIgnoreCase));
                                if (infos.Any())
                                {
                                    foreach (var code in infos)
                                    {
                                        writer.WriteLine($"case ErrorCode.{code.Name}:");
                                    }
                                    using (writer.Indenter())
                                        writer.WriteLine("return true;");
                                }
                                writer.WriteLine("default:");
                                using (writer.Indenter())
                                    writer.WriteLine("return false;");
                            }
                        writer.WriteLine();
                        using (writer.CurlyIndenter("public static partial bool IsHidden(ErrorCode code)"))
                            using (writer.CurlyIndenter("switch(code)"))
                            {
                                var hidden = codes.Where(field => field.Name.StartsWith("HDN_", StringComparison.OrdinalIgnoreCase));
                                if (hidden.Any())
                                {
                                    foreach (var code in hidden)
                                    {
                                        writer.WriteLine($"case ErrorCode.{code.Name}:");
                                    }
                                    using (writer.Indenter())
                                        writer.WriteLine("return true;");
                                }
                                writer.WriteLine("default:");
                                using (writer.Indenter())
                                    writer.WriteLine("return false;");
                            }
                    }

                sourceText = writer.GetText();
            }

            context.AddSource("ErrorFacts.g.cs", sourceText);
            Utilities.DoVsCodeHack(errorCodeType, "ErrorFacts.g.cs", sourceText);
        }