diff --git a/.env b/.env index 0832629f..d5fda3d9 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ -VERSION="3.0.13" +VERSION="3.0.14" MAJOR=3 MINOR=0 -PATCH=13 +PATCH=14 diff --git a/Core/Generators/CSharp/CSharpGenerator.cs b/Core/Generators/CSharp/CSharpGenerator.cs index f59e75b3..514c7a05 100644 --- a/Core/Generators/CSharp/CSharpGenerator.cs +++ b/Core/Generators/CSharp/CSharpGenerator.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.Encodings.Web; @@ -121,7 +122,25 @@ public override ValueTask Compile(BebopSchema schema, GeneratorConfig co _ => string.Empty }; builder.AppendLine(recordAttribute); - builder.AppendLine($"public partial class {definition.ClassName()} : {BebopRecord}, {IDecodable}<{definition.ClassName()}>, global::System.IEquatable<{definition.ClassName()}> {{"); + + var implementedInterfaces = new List + { + BebopRecord, + $"{IDecodable}<{definition.ClassName()}>", + $"global::System.IEquatable<{definition.ClassName()}>" + }; + + // Check if the definition's parent is a UnionDefinition + if (definition.Parent is UnionDefinition ud) + { + // Add the union interface to the list of implemented interfaces + implementedInterfaces.Add($"I{ud.ClassName()}Member"); + } + + // Join the interfaces with commas + var interfaceList = string.Join(", ", implementedInterfaces); + + builder.AppendLine($"public partial class {definition.ClassName()} : {interfaceList} {{"); builder.Indent(indentStep); if (fd is MessageDefinition) @@ -469,17 +488,24 @@ private string CompileDecodeUnion(UnionDefinition definition) /// private void CompileUnionFamily(IndentedStringBuilder builder, UnionDefinition ud) { + + var recordAttribute = "[global::Bebop.Attributes.BebopRecord(global::Bebop.Runtime.BebopKind.Union)]"; var genericPositionalArguments = string.Join(", ", ud.Branches.Select(b => $"T{b.GenericIndex()}")).Trim(); var genericTypeArguments = string.Join(", ", ud.Branches.Select(b => $"{PrefixNamespace(b.Definition.ClassName())}")).Trim(); var genericConstraints = string.Join(' ', ud.Branches.Select(b => $"where T{b.GenericIndex()}: {PrefixNamespace(b.Definition.ClassName())}")).Trim(); var structName = $"{ud.ClassName()}Union"; + var interfaceName = $"I{ud.ClassName()}Member"; + + var nullCheck = LanguageVersion == CSharpNine ? "is null" : "== null"; var notNullCheck = LanguageVersion == CSharpNine ? "is not null" : "!= null"; var isCheck = LanguageVersion == CSharpNine ? "is" : "=="; + + void CompileValueProperty() { builder.AppendLine($"public {BebopRecord} Value => _discriminator switch {{").Indent(4); @@ -573,6 +599,18 @@ void CompileEquals(bool isClass) CompileHashCode(); builder.AppendLine("#endregion"); } + + void CompileUnionInterface() + { + builder.AppendLine("/// "); + builder.AppendLine($"/// Interface for members of the {ud.ClassName()} union"); + builder.AppendLine("/// "); + builder.AppendLine(GeneratedAttribute); + builder.AppendLine($"public partial interface {interfaceName} {{").Indent(indentStep); + + builder.Dedent(indentStep).AppendLine("}").AppendLine(); + } + // Compiles a read-only struct which holds our union. void CompileUnionStruct() { @@ -726,6 +764,7 @@ void CompileUnionConcreteClass() CompileUnionBaseClass(); CompileUnionConcreteClass(); CompileUnionStruct(); + CompileUnionInterface(); } #endregion diff --git a/Laboratory/C#/README.md b/Laboratory/C#/README.md index 82299f7e..15d56bd7 100644 --- a/Laboratory/C#/README.md +++ b/Laboratory/C#/README.md @@ -1,6 +1,5 @@ # C# Bebop Laboratory To run the C# tests, from PowerShell: - - dotnet run --project ..\..\Compiler\ --cs ".\GeneratedTestCode\Output.g.cs" --namespace Bebop.Codegen --files (gci ..\Schemas\Valid\*.bop) + dotnet run --project ../../Compiler/ -i ../Schemas/Valid/*.bop build -g "cs:./GeneratedTestCode/Output.g.cs,namespace=Bebop.Codegen" dotnet test -nowarn:CS0618