add: Patchable items and frames
This commit is contained in:
@@ -86,6 +86,33 @@ public abstract class AssetProcessGenerator : ISourceGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected IEnumerable<InterfaceInfo> GetInterfacesWithAttribute(GeneratorExecutionContext context,
|
||||||
|
INamedTypeSymbol? attribute)
|
||||||
|
{
|
||||||
|
if(context.SyntaxReceiver is not ClassSyntaxReceiver receiver)
|
||||||
|
yield break;
|
||||||
|
Compilation compilation = context.Compilation;
|
||||||
|
foreach (InterfaceDeclarationSyntax ifc in receiver.Interfaces)
|
||||||
|
{
|
||||||
|
SemanticModel model = compilation.GetSemanticModel(ifc.SyntaxTree);
|
||||||
|
INamedTypeSymbol? interfaceSymbol = model.GetDeclaredSymbol(ifc) as INamedTypeSymbol;
|
||||||
|
string filePath = ifc.SyntaxTree.FilePath;
|
||||||
|
string interfaceName = Path.GetFileNameWithoutExtension(filePath);
|
||||||
|
if(interfaceSymbol is null)
|
||||||
|
continue;
|
||||||
|
if (HasAttribute(interfaceSymbol, attribute))
|
||||||
|
yield return new InterfaceInfo
|
||||||
|
{
|
||||||
|
DeclarationSyntax = ifc,
|
||||||
|
InterfaceName = interfaceName,
|
||||||
|
InterfaceFillName = interfaceSymbol.ToDisplayString(),
|
||||||
|
Path = filePath,
|
||||||
|
Symbol = interfaceSymbol,
|
||||||
|
Namespace = interfaceSymbol.ContainingNamespace.ToDisplayString()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected IEnumerable<ClassInfo> GetClassesWithAttribute(GeneratorExecutionContext context,
|
protected IEnumerable<ClassInfo> GetClassesWithAttribute(GeneratorExecutionContext context,
|
||||||
INamedTypeSymbol? attribute)
|
INamedTypeSymbol? attribute)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,13 +6,14 @@ namespace Polonium.Generators;
|
|||||||
|
|
||||||
public class ClassSyntaxReceiver : ISyntaxReceiver
|
public class ClassSyntaxReceiver : ISyntaxReceiver
|
||||||
{
|
{
|
||||||
public List<ClassDeclarationSyntax> Classes { get; set; } = new ();
|
public List<ClassDeclarationSyntax> Classes { get; } = new ();
|
||||||
|
public List<InterfaceDeclarationSyntax> Interfaces { get; } = new ();
|
||||||
|
|
||||||
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
|
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
|
||||||
{
|
{
|
||||||
if (syntaxNode is ClassDeclarationSyntax classDeclaration)
|
if (syntaxNode is ClassDeclarationSyntax classDeclaration)
|
||||||
{
|
|
||||||
Classes.Add(classDeclaration);
|
Classes.Add(classDeclaration);
|
||||||
}
|
if(syntaxNode is InterfaceDeclarationSyntax interfaceDeclaration)
|
||||||
|
Interfaces.Add(interfaceDeclaration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
131
src/Generators/FramePatchGenerator.cs
Normal file
131
src/Generators/FramePatchGenerator.cs
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
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());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/InterfaceInfo.cs
Normal file
14
src/InterfaceInfo.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
|
|
||||||
|
namespace Polonium.Generators;
|
||||||
|
|
||||||
|
public class InterfaceInfo
|
||||||
|
{
|
||||||
|
public INamedTypeSymbol Symbol { get; set; }
|
||||||
|
public InterfaceDeclarationSyntax DeclarationSyntax { get; set; }
|
||||||
|
public string InterfaceName { get; set; }
|
||||||
|
public string InterfaceFillName { get; set; }
|
||||||
|
public string Namespace { get; set; }
|
||||||
|
public string Path { get; set; }
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user