131 lines
7.4 KiB
C#
131 lines
7.4 KiB
C#
using System.Linq;
|
|
using System.Text;
|
|
using Microsoft.CodeAnalysis;
|
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
|
|
namespace Polonium.Generators.Generators;
|
|
[Generator]
|
|
public class FramePatchGenerator : AssetProcessGenerator
|
|
{
|
|
public override void Execute(GeneratorExecutionContext context)
|
|
{
|
|
if(context.SyntaxReceiver is not ClassSyntaxReceiver receiver)
|
|
return;
|
|
Compilation compilation = context.Compilation;
|
|
INamedTypeSymbol? autoPatch = compilation.GetTypeByMetadataName("Polonium.Attributes.AutoPatch");
|
|
INamedTypeSymbol? patchableProperty = compilation.GetTypeByMetadataName("Polonium.Attributes.PatchableProperty");
|
|
foreach (InterfaceInfo inf in GetInterfacesWithAttribute(context, autoPatch))
|
|
{
|
|
|
|
PropertyDeclarationSyntax? underlying = inf.DeclarationSyntax.Members
|
|
.OfType<PropertyDeclarationSyntax>()
|
|
.FirstOrDefault(m => m.AttributeLists
|
|
.SelectMany(a => a.Attributes)
|
|
.Any(a =>
|
|
{
|
|
SemanticModel model = compilation.GetSemanticModel(a.SyntaxTree);
|
|
INamedTypeSymbol? attributeSymbol = model.GetSymbolInfo(a).Symbol?.ContainingType;
|
|
return SymbolEqualityComparer.Default.Equals(attributeSymbol, patchableProperty);
|
|
}));
|
|
if (underlying is null)
|
|
continue;
|
|
SemanticModel model = compilation.GetSemanticModel(underlying.SyntaxTree);
|
|
ITypeSymbol? underlyingType = model.GetTypeInfo(underlying.Type).Type;
|
|
ITypeSymbol? hashSet = compilation
|
|
.GetTypeByMetadataName("Polonium.DataStructures.PatchableItems.PatchableHashSet`1");
|
|
ITypeSymbol? dictionary = compilation
|
|
.GetTypeByMetadataName("Polonium.DataStructures.PatchableItems.PatchableDictionary`2");
|
|
string typeString = "";
|
|
StringBuilder sb = new();
|
|
sb
|
|
.AppendLine("using System;")
|
|
.AppendLine("using System.Collections.Generic;")
|
|
.AppendLine("using System.Linq;")
|
|
.AppendLine("using Polonium.Interfaces;")
|
|
.AppendLine("using Polonium.DataStructures.PatchableItems;")
|
|
.AppendLine("using Polonium.Resources.FramePatches;")
|
|
.AppendLine("using Polonium.Resources.FramePatches.Generic;")
|
|
.AppendLine($"namespace {inf.Namespace};");
|
|
|
|
string lName = inf.InterfaceName[0] == 'I' ? inf.InterfaceName.Substring(1) : inf.InterfaceName;
|
|
if (SymbolEqualityComparer.Default.Equals(underlyingType?.OriginalDefinition, hashSet))
|
|
{
|
|
ITypeSymbol? x1 = (underlyingType as INamedTypeSymbol)?.TypeArguments[0];
|
|
sb
|
|
.AppendLine($"public partial class {lName}Patch : HashSetFramePatch<{x1?.ToDisplayString()}>")
|
|
.AppendLine("{")
|
|
.AppendLine($" public override void Patch(IPatchableFrame frame)")
|
|
.AppendLine(" {")
|
|
.AppendLine($" if(frame is not {inf.InterfaceFillName} sFrame)")
|
|
.AppendLine(" return;")
|
|
.AppendLine($" switch (sFrame.{underlying.Identifier.ToString()}.UpdateMethod )")
|
|
.AppendLine(" {")
|
|
.AppendLine(" case UpdateMethods.None:")
|
|
.AppendLine(" return;")
|
|
.AppendLine(" case UpdateMethods.Update:")
|
|
.AppendLine($" foreach({x1?.ToDisplayString()} x in Updates)")
|
|
.AppendLine($" sFrame.{underlying.Identifier.ToString()}.Add(x);")
|
|
.AppendLine(" return;")
|
|
.AppendLine(" case UpdateMethods.Replace:")
|
|
.AppendLine($" sFrame.{underlying.Identifier.ToString()}.Data = Updates;")
|
|
.AppendLine(" return;")
|
|
.AppendLine(" case UpdateMethods.Custom:")
|
|
.AppendLine($" sFrame.{underlying.Identifier.ToString()}.CustomUpdate(Updates);")
|
|
.AppendLine(" return;")
|
|
.AppendLine(" default:")
|
|
.AppendLine(" return;")
|
|
.AppendLine(" }")
|
|
.AppendLine(" }")
|
|
.AppendLine("}");
|
|
}
|
|
else if (SymbolEqualityComparer.Default.Equals(underlyingType?.OriginalDefinition, dictionary))
|
|
{
|
|
ITypeSymbol? x1 = (underlyingType as INamedTypeSymbol)?.TypeArguments[0];
|
|
ITypeSymbol? x2 = (underlyingType as INamedTypeSymbol)?.TypeArguments[1];
|
|
sb
|
|
.AppendLine($"public partial class {lName}Patch : DictionaryFramePatch<{x1?.ToDisplayString()}, {x2?.ToDisplayString()}>")
|
|
.AppendLine("{")
|
|
.AppendLine(" public override void Patch(IPatchableFrame frame)")
|
|
.AppendLine(" {")
|
|
.AppendLine($" if(frame is not {inf.InterfaceFillName} sFrame)")
|
|
.AppendLine(" return;")
|
|
.AppendLine($" switch (sFrame.{underlying.Identifier.ToString()}.UpdateMethod )")
|
|
.AppendLine(" {")
|
|
.AppendLine(" case UpdateMethods.None:")
|
|
.AppendLine(" return;")
|
|
.AppendLine(" case UpdateMethods.Update:")
|
|
.AppendLine($" foreach({x1?.ToDisplayString()} x in Updates.Keys)")
|
|
.AppendLine($" sFrame.{underlying.Identifier.ToString()}[x] = Updates[x];")
|
|
.AppendLine(" return;")
|
|
.AppendLine(" case UpdateMethods.Replace:")
|
|
.AppendLine($" sFrame.{underlying.Identifier.ToString()}.Data = Updates;")
|
|
.AppendLine(" return;")
|
|
.AppendLine(" case UpdateMethods.Custom:")
|
|
.AppendLine($" sFrame.{underlying.Identifier.ToString()}.CustomUpdate(Updates);")
|
|
.AppendLine(" return;")
|
|
.AppendLine(" default:")
|
|
.AppendLine(" return;")
|
|
.AppendLine(" }")
|
|
.AppendLine(" }")
|
|
.AppendLine("}");
|
|
}
|
|
|
|
else
|
|
{
|
|
sb
|
|
|
|
.AppendLine($"public partial class {lName}Patch : FramePatch<{underlyingType?.ToDisplayString()}>")
|
|
.AppendLine("{")
|
|
.AppendLine(" public override void Patch(IPatchableFrame frame)")
|
|
.AppendLine(" {")
|
|
.AppendLine($" if(frame is not {inf.InterfaceFillName} sFrame)")
|
|
.AppendLine(" return;")
|
|
.AppendLine($" sFrame.{underlying.Identifier.ToString()} = Updates;")
|
|
.AppendLine(" }")
|
|
.AppendLine("}");
|
|
}
|
|
context.AddSource($"{lName}Patch.g.cs", sb.ToString());
|
|
|
|
}
|
|
}
|
|
} |