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); }
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); }