From be9dcc78bd56c33a44c92f813fcaf3b3c4706b0d Mon Sep 17 00:00:00 2001 From: Ivan Murashka Date: Sat, 6 Sep 2025 14:18:04 +0200 Subject: [PATCH] generate match method for union --- .../Union/Parts/UnionMatchPart.cs | 51 ++++++++++++++++++ .../Union/UnionAttributeGenerator.cs | 1 + .../Union/UnionAttributePartInput.cs | 1 + .../Utilities/CodeWriterExtensions.cs | 8 ++- .../Utilities/DisposableIndent.cs | 24 +++++++++ .../Utilities/SyntaxTreeExtensions.cs | 14 ++++- Runtime/Appegy.Union.Generator.dll | 4 +- Runtime/Appegy.Union.Generator.pdb | Bin 27124 -> 27944 bytes 8 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 Appegy.Union.Generator~/Appegy.Union.Generator/Union/Parts/UnionMatchPart.cs create mode 100644 Appegy.Union.Generator~/Appegy.Union.Generator/Utilities/DisposableIndent.cs diff --git a/Appegy.Union.Generator~/Appegy.Union.Generator/Union/Parts/UnionMatchPart.cs b/Appegy.Union.Generator~/Appegy.Union.Generator/Union/Parts/UnionMatchPart.cs new file mode 100644 index 0000000..6e64654 --- /dev/null +++ b/Appegy.Union.Generator~/Appegy.Union.Generator/Union/Parts/UnionMatchPart.cs @@ -0,0 +1,51 @@ +using System.CodeDom.Compiler; + +namespace Appegy.Union.Generator; + +public class UnionMatchPart : GeneratorPart +{ + public override void Generate(IndentedTextWriter codeWriter, UnionAttributePartInput input) + { + var types = input.Types; + + codeWriter.WriteLine("public void Match("); + + using (codeWriter.IndentScope()) + { + for (var i = 0; i < types.Count; i++) + { + var type = types[i]; + codeWriter.Write("global::System.Action<"); + codeWriter.Write(type.FullName); + codeWriter.Write('>'); + codeWriter.Write(' '); + codeWriter.Write(type.ParamName); + codeWriter.WriteLine(i != types.Count - 1 ? "," : ")"); + } + } + + codeWriter.WriteLine("{"); + using (codeWriter.IndentScope()) + { + codeWriter.WriteLine("switch (Type)"); + codeWriter.WriteLine("{"); + using (codeWriter.IndentScope()) + { + foreach (var type in types) + { + codeWriter.Write("case Kind."); + codeWriter.Write(type.Name); + codeWriter.Write(": "); + codeWriter.Write(type.ParamName); + codeWriter.Write("("); + codeWriter.Write(type.FieldName); + codeWriter.Write("); break;"); + codeWriter.WriteLine(); + } + codeWriter.WriteLine("default: throw new global::System.InvalidOperationException($\"Unknown type of union: {_type}\");"); + } + codeWriter.WriteLine("}"); + } + codeWriter.WriteLine("}"); + } +} \ No newline at end of file diff --git a/Appegy.Union.Generator~/Appegy.Union.Generator/Union/UnionAttributeGenerator.cs b/Appegy.Union.Generator~/Appegy.Union.Generator/Union/UnionAttributeGenerator.cs index f50fc7c..509ebee 100644 --- a/Appegy.Union.Generator~/Appegy.Union.Generator/Union/UnionAttributeGenerator.cs +++ b/Appegy.Union.Generator~/Appegy.Union.Generator/Union/UnionAttributeGenerator.cs @@ -25,6 +25,7 @@ public class UnionAttributeGenerator : IIncrementalGenerator new UnionFieldsPart(), new UnionPropertiesPart(), new UnionConstructorsPart(), + new UnionMatchPart(), new UnionToStringPart(), new UnionGetHashCodePart(), new UnionEqualsPart(), diff --git a/Appegy.Union.Generator~/Appegy.Union.Generator/Union/UnionAttributePartInput.cs b/Appegy.Union.Generator~/Appegy.Union.Generator/Union/UnionAttributePartInput.cs index b7f3681..e614190 100644 --- a/Appegy.Union.Generator~/Appegy.Union.Generator/Union/UnionAttributePartInput.cs +++ b/Appegy.Union.Generator~/Appegy.Union.Generator/Union/UnionAttributePartInput.cs @@ -12,4 +12,5 @@ public readonly struct UnionTypeInfo(INamedTypeSymbol symbol) public readonly INamedTypeSymbol Symbol = symbol; public readonly string FullName = symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); public readonly string FieldName = symbol.GetFieldName(); + public readonly string ParamName = symbol.GetParamName(); } \ No newline at end of file diff --git a/Appegy.Union.Generator~/Appegy.Union.Generator/Utilities/CodeWriterExtensions.cs b/Appegy.Union.Generator~/Appegy.Union.Generator/Utilities/CodeWriterExtensions.cs index 8e5bf13..8308df6 100644 --- a/Appegy.Union.Generator~/Appegy.Union.Generator/Utilities/CodeWriterExtensions.cs +++ b/Appegy.Union.Generator~/Appegy.Union.Generator/Utilities/CodeWriterExtensions.cs @@ -1,4 +1,5 @@ -using System.CodeDom.Compiler; +using System; +using System.CodeDom.Compiler; using System.Collections.Generic; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -23,6 +24,11 @@ public static void AppendParts(this IndentedTextWriter codeWriter, IReadOnlyL } } + public static IDisposable IndentScope(this IndentedTextWriter codeWriter) + { + return new DisposableIndent(codeWriter); + } + public static void WriteFieldName(this IndentedTextWriter codeWriter, ISymbol symbol) { var name = symbol.Name; diff --git a/Appegy.Union.Generator~/Appegy.Union.Generator/Utilities/DisposableIndent.cs b/Appegy.Union.Generator~/Appegy.Union.Generator/Utilities/DisposableIndent.cs new file mode 100644 index 0000000..f032b1d --- /dev/null +++ b/Appegy.Union.Generator~/Appegy.Union.Generator/Utilities/DisposableIndent.cs @@ -0,0 +1,24 @@ +using System; +using System.CodeDom.Compiler; + +namespace Appegy.Union.Generator; + +public struct DisposableIndent : IDisposable +{ + private readonly IndentedTextWriter _codeWriter; + private bool _isDisposed; + + public DisposableIndent(IndentedTextWriter codeWriter) + { + _isDisposed = false; + _codeWriter = codeWriter; + _codeWriter.Indent++; + } + + public void Dispose() + { + if (_isDisposed) return; + _codeWriter.Indent--; + _isDisposed = true; + } +} \ No newline at end of file diff --git a/Appegy.Union.Generator~/Appegy.Union.Generator/Utilities/SyntaxTreeExtensions.cs b/Appegy.Union.Generator~/Appegy.Union.Generator/Utilities/SyntaxTreeExtensions.cs index ce45943..5089380 100644 --- a/Appegy.Union.Generator~/Appegy.Union.Generator/Utilities/SyntaxTreeExtensions.cs +++ b/Appegy.Union.Generator~/Appegy.Union.Generator/Utilities/SyntaxTreeExtensions.cs @@ -28,13 +28,23 @@ public static ImmutableList GetTypesFromConstructor(this Attri } public static string GetFieldName(this INamedTypeSymbol symbol) + { + var name = symbol.Name; + var param = symbol.GetParamName(); + + if (string.IsNullOrEmpty(param)) return string.Empty; + + return "_" + param; + } + + public static string GetParamName(this INamedTypeSymbol symbol) { var name = symbol.Name; if (string.IsNullOrEmpty(name)) return string.Empty; return name.Length > 1 - ? "_" + char.ToLower(name[0]) + name.Substring(1) - : "_" + char.ToLower(name[0]); + ? char.ToLower(name[0]) + name.Substring(1) + : name.ToLower(); } } \ No newline at end of file diff --git a/Runtime/Appegy.Union.Generator.dll b/Runtime/Appegy.Union.Generator.dll index 7ccddaf..225a4ac 100644 --- a/Runtime/Appegy.Union.Generator.dll +++ b/Runtime/Appegy.Union.Generator.dll @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dfb6f14913fc4a5224b91604329dc26ddb6aceda20efd5c0f6b1d3cc263316c6 -size 55296 +oid sha256:f2005c0ac57cd3ba43df4e6216d5d0eef2f777890f2db89bf942dd7d9737d7bb +size 56832 diff --git a/Runtime/Appegy.Union.Generator.pdb b/Runtime/Appegy.Union.Generator.pdb index aeedcdf1408a9a8894b94a5f0e61b0ff60100f20..686aa9330f7bad138d771452b35355488a1d8c24 100644 GIT binary patch delta 4708 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