From 5f2cfd781e31b595256023541771482c6457cf85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Boh=C3=A1=C4=8Dek?= Date: Sun, 2 Jan 2022 21:11:07 +0100 Subject: [PATCH] feat: add inline list converter --- .../BasicInlineConverterGenerator.cs | 2 +- .../EnumInlineConverterGenerator.cs | 2 +- .../FallbackInlineConverterGenerator.cs | 9 +- .../ListInlineConverterGenerator.cs | 162 ++++++++++++++++++ .../InlineTypeConverterGenerator.cs | 66 ++++++- ...osSmooth.PacketSerializersGenerator.csproj | 4 - .../PacketConverterGenerator.cs | 1 + .../SourceGenerator.cs | 14 +- 8 files changed, 238 insertions(+), 22 deletions(-) create mode 100644 Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/ListInlineConverterGenerator.cs diff --git a/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/BasicInlineConverterGenerator.cs b/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/BasicInlineConverterGenerator.cs index 51ea414..364e7aa 100644 --- a/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/BasicInlineConverterGenerator.cs +++ b/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/BasicInlineConverterGenerator.cs @@ -57,7 +57,7 @@ public class BasicInlineConverterGenerator : IInlineConverterGenerator throw new Exception("TypeSyntax or TypeSymbol has to be non null."); } - textWriter.WriteLine($"{Constants.HelperClass}.ParseBasic{type}(this, stringEnumerator);"); + textWriter.WriteLine($"{Constants.HelperClass}.ParseBasic{type}(typeConverter, stringEnumerator);"); return null; } diff --git a/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/EnumInlineConverterGenerator.cs b/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/EnumInlineConverterGenerator.cs index 421e678..5f163a1 100644 --- a/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/EnumInlineConverterGenerator.cs +++ b/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/EnumInlineConverterGenerator.cs @@ -66,7 +66,7 @@ public class EnumInlineConverterGenerator : IInlineConverterGenerator textWriter.WriteLine ( - $"{Constants.HelperClass}.ParseEnum{typeSymbol?.ToString().TrimEnd('?').Replace('.', '_')}(this, stringEnumerator);" + $"{Constants.HelperClass}.ParseEnum{typeSymbol?.ToString().TrimEnd('?').Replace('.', '_')}(typeConverter, stringEnumerator);" ); return null; } diff --git a/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/FallbackInlineConverterGenerator.cs b/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/FallbackInlineConverterGenerator.cs index 694b827..32856dc 100644 --- a/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/FallbackInlineConverterGenerator.cs +++ b/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/FallbackInlineConverterGenerator.cs @@ -29,10 +29,17 @@ public class FallbackInlineConverterGenerator : IInlineConverterGenerator ITypeSymbol? typeSymbol ) { + var resultName = $"{variableName.Replace(".", string.Empty)}Result"; textWriter.WriteLine ( - $"_typeConverterRepository.Serialize<{(typeSyntax?.ToString() ?? typeSymbol!.ToString()).TrimEnd('?')}?>({variableName}, builder);" + $"var {resultName} = _typeConverterRepository.Serialize<{(typeSyntax?.ToString() ?? typeSymbol!.ToString()).TrimEnd('?')}?>({variableName}, builder);" ); + textWriter.WriteLine($"if (!{resultName}.IsSuccess)"); + textWriter.WriteLine("{"); + textWriter.Indent++; + textWriter.WriteLine($"return Result.FromError(new PacketParameterSerializerError(this, \"{variableName}\", {resultName}), {resultName});"); + textWriter.Indent--; + textWriter.WriteLine("}"); return null; } diff --git a/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/ListInlineConverterGenerator.cs b/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/ListInlineConverterGenerator.cs new file mode 100644 index 0000000..b8b6e56 --- /dev/null +++ b/Core/NosSmooth.PacketSerializersGenerator/InlineConverterGenerators/ListInlineConverterGenerator.cs @@ -0,0 +1,162 @@ +// +// ListInlineConverterGenerator.cs +// +// Copyright (c) František Boháček. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.CodeDom.Compiler; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using NosSmooth.PacketSerializersGenerator.Errors; +using NosSmooth.PacketSerializersGenerator.Extensions; + +namespace NosSmooth.PacketSerializersGenerator.InlineConverterGenerators; + +/// +public class ListInlineConverterGenerator : IInlineConverterGenerator +{ + private readonly InlineTypeConverterGenerator _inlineConverters; + private readonly List _listTypes; + + /// + /// Initializes a new instance of the class. + /// + /// The inline converter that is used for converting the values of the list. + public ListInlineConverterGenerator(InlineTypeConverterGenerator inlineConverters) + { + _inlineConverters = inlineConverters; + _listTypes = new List(); + } + + /// + public bool ShouldHandle(TypeSyntax? typeSyntax, ITypeSymbol? typeSymbol) + => typeSymbol?.Name == "IReadOnlyList"; + + /// + public IError? GenerateSerializerPart + ( + IndentedTextWriter textWriter, + string variableName, + TypeSyntax? typeSyntax, + ITypeSymbol? typeSymbol + ) + { + ITypeSymbol genericArgument = ((INamedTypeSymbol)typeSymbol!).TypeArguments[0]; + textWriter.WriteMultiline + ( + @$" + if ({variableName} is null) + {{ + builder.Append('-'); + }} + else + {{ + foreach (var item in {variableName}) + {{ + if (!builder.PushPreparedLevel()) + {{ + return new ArgumentInvalidError(nameof(builder), ""The string builder has to have a prepared level for all lists.""); + }} + +" + ); + var error = _inlineConverters.Serialize(textWriter, "item", null, genericArgument); + if (error is not null) + { + return error; + } + + textWriter.WriteMultiline(@" + builder.PopLevel(); + } + } +" + ); + return null; + } + + /// + public IError? CallDeserialize(IndentedTextWriter textWriter, TypeSyntax? typeSyntax, ITypeSymbol? typeSymbol) + { + ITypeSymbol genericArgument = ((INamedTypeSymbol)typeSymbol!).TypeArguments[0]; + if (_listTypes.All + ( + x => x.ToString() != genericArgument!.ToString() + || ((x.IsNullable() ?? false) && (!genericArgument.IsNullable() ?? false)) + )) + { + _listTypes.Add(genericArgument!); + } + + textWriter.WriteLine + ($"{Constants.HelperClass}.{GetMethodName(genericArgument)}(typeConverter, _typeConverterRepository, stringEnumerator);"); + return null; + } + + private string GetMethodName(ITypeSymbol genericArgumentType) + { + return + $"ParseList{genericArgumentType.ToString().Replace('.', '_')}{((genericArgumentType.IsNullable() ?? false) ? "Nullable" : string.Empty)}"; + } + + /// + public void GenerateHelperMethods(IndentedTextWriter textWriter) + { + foreach (var type in _listTypes) + { + textWriter.WriteLine + ( + @$" +public static Result> {GetMethodName(type)}(ITypeConverter typeConverter, ITypeConverterRepository _typeConverterRepository, PacketStringEnumerator stringEnumerator) +{{ + var data = new List<{type.GetActualType()}>(); + + while (!(stringEnumerator.IsOnLastToken() ?? false)) + {{ + if (!stringEnumerator.PushPreparedLevel()) + {{ + return new ArgumentInvalidError(nameof(stringEnumerator), ""The string enumerator has to have a prepared level for all lists.""); + }} + + var result = " + ); + /*var error = */_inlineConverters.CallDeserialize(textWriter, null, type); // TODO handle error + + textWriter.WriteMultiline(@$" + + // If we know that we are not on the last token in the item level, just skip to the end of the item. + // Note that if this is the case, then that means the converter is either corrupted + // or the packet has more fields. + while (stringEnumerator.IsOnLastToken() == false) + {{ + stringEnumerator.GetNextToken(); + }} + + stringEnumerator.PopLevel(); + if (!result.IsSuccess) + {{ + return Result>.FromError(new ListSerializerError(result, data.Count), result); + }} + +" + ); + + if (!(type.IsNullable() ?? false)) + { + textWriter.WriteMultiline + ( + $@" +if (result.Entity is null) +{{ + return new DeserializedValueNullError(typeof({type.ToString().TrimEnd('?')})); +}} +" + ); + } + textWriter.WriteLine($"data.Add(({type.GetActualType()})result.Entity);"); + textWriter.WriteLine("}"); + textWriter.WriteLine("return data;"); + textWriter.WriteLine("}"); + } + } +} \ No newline at end of file diff --git a/Core/NosSmooth.PacketSerializersGenerator/InlineTypeConverterGenerator.cs b/Core/NosSmooth.PacketSerializersGenerator/InlineTypeConverterGenerator.cs index 2c8e45c..8e612fa 100644 --- a/Core/NosSmooth.PacketSerializersGenerator/InlineTypeConverterGenerator.cs +++ b/Core/NosSmooth.PacketSerializersGenerator/InlineTypeConverterGenerator.cs @@ -5,6 +5,8 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.CodeDom.Compiler; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; using NosSmooth.PacketSerializersGenerator.Data; using NosSmooth.PacketSerializersGenerator.Errors; using NosSmooth.PacketSerializersGenerator.Extensions; @@ -32,7 +34,7 @@ public class InlineTypeConverterGenerator } /// - /// Generates deserialize and check code. + /// Generates deserialize call. /// /// The text writer. /// The packet. @@ -56,7 +58,32 @@ public class InlineTypeConverterGenerator } /// - /// Generates serialize and check code. + /// Generates deserialize call. + /// + /// The text writer. + /// The type syntax. + /// The type symbol. + /// An error, if any. + public IError? CallDeserialize + ( + IndentedTextWriter textWriter, + TypeSyntax? typeSyntax, + ITypeSymbol? typeSymbol + ) + { + foreach (var generator in _typeGenerators) + { + if (generator.ShouldHandle(typeSyntax, typeSymbol)) + { + return generator.CallDeserialize(textWriter, typeSyntax, typeSymbol); + } + } + + return _fallbackInlineConverterGenerator.CallDeserialize(textWriter, typeSyntax, typeSymbol); + } + + /// + /// Generates serialize code. /// /// The text writer. /// The packet. @@ -72,11 +99,42 @@ public class InlineTypeConverterGenerator { if (generator.ShouldHandle(parameter.Parameter.Type, parameter.Type)) { - return generator.GenerateSerializerPart(textWriter, variableName, parameter.Parameter.Type, parameter.Type); + return generator.GenerateSerializerPart + (textWriter, variableName, parameter.Parameter.Type, parameter.Type); } } } - return _fallbackInlineConverterGenerator.GenerateSerializerPart(textWriter, variableName, parameter.Parameter.Type, parameter.Type); + return _fallbackInlineConverterGenerator.GenerateSerializerPart + (textWriter, variableName, parameter.Parameter.Type, parameter.Type); + } + + /// + /// Generates serialize code. + /// + /// The text writer. + /// The name of the variable. + /// The type syntax. + /// The type symbol. + /// An error, if any. + public IError? Serialize + ( + IndentedTextWriter textWriter, + string variableName, + TypeSyntax? typeSyntax, + ITypeSymbol? typeSymbol + ) + { + foreach (var generator in _typeGenerators) + { + if (generator.ShouldHandle(typeSyntax, typeSymbol)) + { + return generator.GenerateSerializerPart + (textWriter, variableName, typeSyntax, typeSymbol); + } + } + + return _fallbackInlineConverterGenerator.GenerateSerializerPart + (textWriter, variableName, typeSyntax, typeSymbol); } } \ No newline at end of file diff --git a/Core/NosSmooth.PacketSerializersGenerator/NosSmooth.PacketSerializersGenerator.csproj b/Core/NosSmooth.PacketSerializersGenerator/NosSmooth.PacketSerializersGenerator.csproj index cf63b88..2c152d4 100644 --- a/Core/NosSmooth.PacketSerializersGenerator/NosSmooth.PacketSerializersGenerator.csproj +++ b/Core/NosSmooth.PacketSerializersGenerator/NosSmooth.PacketSerializersGenerator.csproj @@ -19,8 +19,4 @@ - - - - diff --git a/Core/NosSmooth.PacketSerializersGenerator/PacketConverterGenerator.cs b/Core/NosSmooth.PacketSerializersGenerator/PacketConverterGenerator.cs index 5e70051..eb2aeee 100644 --- a/Core/NosSmooth.PacketSerializersGenerator/PacketConverterGenerator.cs +++ b/Core/NosSmooth.PacketSerializersGenerator/PacketConverterGenerator.cs @@ -97,6 +97,7 @@ public override Result Serialize({_packetInfo.Name}? obj, PacketStringBuilder bu /// public override Result<{_packetInfo.Name}?> Deserialize(PacketStringEnumerator stringEnumerator) {{ + var typeConverter = this; " ); diff --git a/Core/NosSmooth.PacketSerializersGenerator/SourceGenerator.cs b/Core/NosSmooth.PacketSerializersGenerator/SourceGenerator.cs index 2faf476..b48933f 100644 --- a/Core/NosSmooth.PacketSerializersGenerator/SourceGenerator.cs +++ b/Core/NosSmooth.PacketSerializersGenerator/SourceGenerator.cs @@ -42,8 +42,8 @@ public class SourceGenerator : ISourceGenerator new BoolInlineConverterGenerator(), } ); - var inlineTypeConverter = new InlineTypeConverterGenerator(_typeConverterGenerator); + _typeConverterGenerator.Add(new ListInlineConverterGenerator(inlineTypeConverter)); _generators = new List ( @@ -130,11 +130,6 @@ public class SourceGenerator : ISourceGenerator $"{packetRecord.GetPrefix()}.{packetRecord.Identifier.NormalizeWhitespace().ToFullString()}Converter.g.cs", stringWriter.GetStringBuilder().ToString() ); - File.WriteAllText - ( - $"/tmp/{packetRecord.GetPrefix()}.{packetRecord.Identifier.NormalizeWhitespace().ToFullString()}Converter.g.cs", - stringWriter.GetStringBuilder().ToString() - ); } } @@ -144,11 +139,6 @@ public class SourceGenerator : ISourceGenerator $"HelperClass.g.cs", helperClass ); - File.WriteAllText - ( - $"/tmp/HelperClass.g.cs", - helperClass - ); } private string GenerateHelperMethods() @@ -159,6 +149,8 @@ public class SourceGenerator : ISourceGenerator #nullable enable #pragma warning disable 1591 +using System.Collections; +using System.Collections.Generic; using NosSmooth.Packets.Converters; using NosSmooth.Packets.Errors; using NosSmooth.Packets; -- 2.48.1