add: Template Define
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
"profiles": {
|
||||
"DebugRoslynSourceGenerator": {
|
||||
"commandName": "DebugRoslynComponent",
|
||||
"targetProject": "../Polonium.Generators.Test/Polonium.Generators.Test.csproj"
|
||||
"targetProject": "../Polonium.Workspace/Polonium.Test/Polonium.Test.csproj"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace Polonium.Generators;
|
||||
|
||||
@@ -10,7 +12,7 @@ public abstract class AssetProcessGenerator : ISourceGenerator
|
||||
{
|
||||
context.RegisterForSyntaxNotifications(() => new ClassSyntaxReceiver());
|
||||
}
|
||||
|
||||
|
||||
public abstract void Execute(GeneratorExecutionContext context);
|
||||
|
||||
protected IEnumerable<AssetInfo> GetAssetsOfType(GeneratorExecutionContext context, INamedTypeSymbol? t)
|
||||
@@ -75,6 +77,14 @@ public abstract class AssetProcessGenerator : ISourceGenerator
|
||||
|
||||
return false;
|
||||
}
|
||||
protected static string Format(string template, string data)
|
||||
{
|
||||
string[] dataParts = data.Split(':');
|
||||
for(int i = 0; i < dataParts.Length; i++)
|
||||
template = template.Replace($"/*{i}*/", dataParts[i]);
|
||||
return template;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
34
src/ContextExtensions.cs
Normal file
34
src/ContextExtensions.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace Polonium.Generators;
|
||||
|
||||
public static class ContextExtensions
|
||||
{
|
||||
public static IEnumerable<ClassDeclarationSyntax> GetClassesWithAttribute(this GeneratorExecutionContext context, ClassSyntaxReceiver receiver, INamedTypeSymbol? t)
|
||||
{
|
||||
Compilation compilation = context.Compilation;
|
||||
foreach (ClassDeclarationSyntax? cls in receiver.Classes)
|
||||
{
|
||||
SemanticModel model = compilation.GetSemanticModel(cls.SyntaxTree);
|
||||
if (
|
||||
model.GetDeclaredSymbol(cls) is INamedTypeSymbol symbol &&
|
||||
symbol.GetAttributes().Any(x => SymbolEqualityComparer.Default.Equals(x.AttributeClass, t))
|
||||
)
|
||||
yield return cls;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<AttributeData> GetAttributes(this GeneratorExecutionContext context, ClassDeclarationSyntax cls, INamedTypeSymbol? t)
|
||||
{
|
||||
Compilation compilation = context.Compilation;
|
||||
SemanticModel model = compilation.GetSemanticModel(cls.SyntaxTree);
|
||||
return model
|
||||
.GetDeclaredSymbol(cls)!
|
||||
.GetAttributes()
|
||||
.Where(x => SymbolEqualityComparer.Default.Equals(x.AttributeClass, t));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace Polonium.Generators.Generators;
|
||||
[Generator]
|
||||
@@ -12,7 +13,7 @@ public class RegistryEntityGenerator : AssetProcessGenerator
|
||||
return;
|
||||
Compilation compilation = context.Compilation;
|
||||
INamedTypeSymbol? regEntity = compilation.GetTypeByMetadataName("Polonium.Attributes.RegistryEntity");
|
||||
foreach (var derivedClassDeclaration in receiver.Classes)
|
||||
foreach (ClassDeclarationSyntax? derivedClassDeclaration in receiver.Classes)
|
||||
{
|
||||
SemanticModel model = compilation.GetSemanticModel(derivedClassDeclaration.SyntaxTree);
|
||||
if (
|
||||
|
||||
69
src/Generators/TemplateBlockGenerator.cs
Normal file
69
src/Generators/TemplateBlockGenerator.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace Polonium.Generators.Generators;
|
||||
[Generator]
|
||||
public class TemplateBlockGenerator : AssetProcessGenerator
|
||||
{
|
||||
public override void Execute(GeneratorExecutionContext context)
|
||||
{
|
||||
if (!(context.SyntaxReceiver is ClassSyntaxReceiver receiver))
|
||||
return;
|
||||
Compilation compilation = context.Compilation;
|
||||
INamedTypeSymbol? templateDefine = compilation.GetTypeByMetadataName("Polonium.Attributes.TemplateDefines.TemplateBlock");
|
||||
|
||||
foreach (ClassDeclarationSyntax? cls in context.GetClassesWithAttribute(receiver, templateDefine))
|
||||
{
|
||||
if(!cls.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword)))
|
||||
continue;
|
||||
string isStatic = "";
|
||||
if(cls.Modifiers.Any(m => m.IsKind(SyntaxKind.StaticKeyword)))
|
||||
isStatic = "static";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb
|
||||
.AppendLine($"public {isStatic} partial class {cls.Identifier.ToString()}")
|
||||
.AppendLine("{");
|
||||
HashSet<string> headers = new();
|
||||
foreach (AttributeData attr in context.GetAttributes(cls, templateDefine))
|
||||
{
|
||||
string signature = attr.ConstructorArguments[0].Value?.ToString()??string.Empty;
|
||||
string template = attr.ConstructorArguments[1].Value?.ToString()??string.Empty;
|
||||
string dataFile = attr.ConstructorArguments[2].Value?.ToString()??string.Empty;
|
||||
string depsStr = attr.ConstructorArguments[3].Value?.ToString()??string.Empty;
|
||||
string[] deps = depsStr.Split(';');
|
||||
foreach (string dep in deps)
|
||||
headers.Add(dep);
|
||||
sb
|
||||
.AppendLine($" {signature}")
|
||||
.AppendLine(" {");
|
||||
AdditionalText? df = context.AdditionalFiles.FirstOrDefault(f => f.Path.EndsWith(dataFile));
|
||||
string[] data =(df?.GetText()?.ToString() ?? "").Split('\n');
|
||||
foreach (string d in data)
|
||||
{
|
||||
if(d.Trim().Equals(""))
|
||||
continue;
|
||||
sb.AppendLine($" {Format(template, d)}");
|
||||
}
|
||||
sb.AppendLine(" }");
|
||||
}
|
||||
|
||||
sb.AppendLine("}");
|
||||
StringBuilder hb = new StringBuilder();
|
||||
foreach (string header in headers)
|
||||
{
|
||||
if(header.Trim().Equals(""))
|
||||
continue;
|
||||
hb.AppendLine($"using {header};");
|
||||
}
|
||||
hb.Append(sb);
|
||||
context.AddSource($"{cls.Identifier.ToString()}_TemplateDefine.g.cs", hb.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
63
src/Generators/TemplateInlineGenerator.cs
Normal file
63
src/Generators/TemplateInlineGenerator.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace Polonium.Generators.Generators;
|
||||
[Generator]
|
||||
public class TemplateInlineGenerator : AssetProcessGenerator
|
||||
{
|
||||
public override void Execute(GeneratorExecutionContext context)
|
||||
{
|
||||
if (!(context.SyntaxReceiver is ClassSyntaxReceiver receiver))
|
||||
return;
|
||||
Compilation compilation = context.Compilation;
|
||||
INamedTypeSymbol? templateDefine = compilation.GetTypeByMetadataName("Polonium.Attributes.TemplateDefines.TemplateInline");
|
||||
|
||||
foreach (ClassDeclarationSyntax? cls in context.GetClassesWithAttribute(receiver, templateDefine))
|
||||
{
|
||||
if(!cls.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword)))
|
||||
continue;
|
||||
string isStatic = "";
|
||||
if(cls.Modifiers.Any(m => m.IsKind(SyntaxKind.StaticKeyword)))
|
||||
isStatic = "static";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb
|
||||
.AppendLine($"public {isStatic} partial class {cls.Identifier.ToString()}")
|
||||
.AppendLine("{");
|
||||
HashSet<string> headers = new();
|
||||
foreach (AttributeData attr in context.GetAttributes(cls, templateDefine))
|
||||
{
|
||||
string template = attr.ConstructorArguments[0].Value?.ToString()??string.Empty;
|
||||
string dataFile = attr.ConstructorArguments[1].Value?.ToString()??string.Empty;
|
||||
string depsString = attr.ConstructorArguments[2].Value?.ToString()??string.Empty;
|
||||
string[] deps = depsString.Split(';');
|
||||
foreach (string dep in deps)
|
||||
headers.Add(dep);
|
||||
AdditionalText? df = context.AdditionalFiles.FirstOrDefault(f => f.Path.EndsWith(dataFile));
|
||||
string[] data =(df?.GetText()?.ToString() ?? "").Split('\n');
|
||||
foreach (string d in data)
|
||||
{
|
||||
if(d.Trim().Equals(""))
|
||||
continue;
|
||||
sb.AppendLine($" {Format(template, d)}");
|
||||
}
|
||||
}
|
||||
|
||||
sb.AppendLine("}");
|
||||
StringBuilder hb = new();
|
||||
foreach(string header in headers)
|
||||
{
|
||||
if(header.Trim().Equals(""))
|
||||
continue;
|
||||
hb.AppendLine($"using {header};");
|
||||
}
|
||||
hb.Append(sb);
|
||||
Console.WriteLine(hb.ToString());
|
||||
context.AddSource($"{cls.Identifier.ToString()}_TemplateInline.g.cs", hb.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user