Практически доделанный кодген, но не работает демка
This commit is contained in:
@@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
|
||||
|
||||
namespace mROA.Codegen
|
||||
{
|
||||
/// <summary>
|
||||
@@ -19,6 +18,45 @@ namespace mROA.Codegen
|
||||
[Generator]
|
||||
public class mROASourceGenerator : ISourceGenerator
|
||||
{
|
||||
private static Predicate<IParameterSymbol> ParameterFilter =
|
||||
i => i.Type.Name is "CancellationToken" or "RequestContext";
|
||||
|
||||
private static Predicate<ITypeSymbol> ParameterFilterForType =
|
||||
i => i.Name is "CancellationToken" or "RequestContext";
|
||||
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
{
|
||||
}
|
||||
|
||||
public void Execute(GeneratorExecutionContext context)
|
||||
{
|
||||
var trees = context.Compilation.SyntaxTrees;
|
||||
|
||||
var interfaces = new List<InterfaceDeclarationSyntax>();
|
||||
foreach (var tree in trees)
|
||||
{
|
||||
var node = tree.GetRoot() as CompilationUnitSyntax;
|
||||
|
||||
foreach (var member in node.Members)
|
||||
{
|
||||
if (member is InterfaceDeclarationSyntax ids)
|
||||
{
|
||||
interfaces.Add(ids);
|
||||
}
|
||||
else if (member is NamespaceDeclarationSyntax nds)
|
||||
{
|
||||
foreach (var inside in nds.Members)
|
||||
|
||||
if (inside is InterfaceDeclarationSyntax ids2)
|
||||
if (ContainsSOIAttribute(ids2.AttributeLists, context, ids2))
|
||||
interfaces.Add(ids2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GenerateCode(context, context.Compilation, interfaces.ToImmutableArray());
|
||||
}
|
||||
|
||||
private void GenerateCode(GeneratorExecutionContext context, Compilation compilation,
|
||||
ImmutableArray<InterfaceDeclarationSyntax> classes)
|
||||
{
|
||||
@@ -31,6 +69,7 @@ namespace mROA.Codegen
|
||||
var frontendContextRepo = new List<string>();
|
||||
List<IMethodSymbol> totalMethods = new List<IMethodSymbol>();
|
||||
|
||||
|
||||
List<string> invokers = new List<string>();
|
||||
var declarations = classes.ToList().OrderBy(i => i.Identifier.Text).ToList();
|
||||
foreach (var classDeclarationSyntax in declarations)
|
||||
@@ -52,7 +91,7 @@ namespace mROA.Codegen
|
||||
.ToList();
|
||||
|
||||
totalMethods.AddRange(innerMethods);
|
||||
|
||||
|
||||
var originalName = className;
|
||||
|
||||
className = className.TrimStart('I') + "RemoteEndpoint";
|
||||
@@ -66,10 +105,11 @@ namespace mROA.Codegen
|
||||
switch (method.MethodKind)
|
||||
{
|
||||
case MethodKind.PropertyGet or MethodKind.PropertySet:
|
||||
GeneratePropertyMethod(method, totalMethods, propertiesAccessMethods, invokers);
|
||||
GeneratePropertyMethod(method, propertiesAccessMethods, invokers,
|
||||
classSymbol);
|
||||
continue;
|
||||
default:
|
||||
GenerateDeclaredMethod(method, declaredMethods, totalMethods, invokers);
|
||||
GenerateDeclaredMethod(method, declaredMethods, invokers, classSymbol);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -105,6 +145,8 @@ namespace mROA.Codegen
|
||||
}
|
||||
}
|
||||
|
||||
GenerateEventImplementation(classSymbol, invokers, declaredMethods, context);
|
||||
|
||||
var code = $@"// <auto-generated/>
|
||||
|
||||
using mROA;
|
||||
@@ -138,7 +180,7 @@ namespace {namespaceName}
|
||||
if (totalMethods.Count != 0)
|
||||
{
|
||||
var methodsStringed = invokers;
|
||||
|
||||
|
||||
var coCodegenRepoCode = @$"// <auto-generated/>
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
@@ -203,7 +245,61 @@ namespace mROA.Codegen
|
||||
}
|
||||
}
|
||||
|
||||
public static string Caster(ITypeSymbol type, string inner)
|
||||
private void GenerateEventImplementation(INamedTypeSymbol classSymbol, List<string> invokers,
|
||||
List<string> declaredMethods, GeneratorExecutionContext context)
|
||||
{
|
||||
var events = classSymbol.AllInterfaces.Add(classSymbol).SelectMany(i => i.GetMembers())
|
||||
.OfType<IEventSymbol>().ToList();
|
||||
if (events.Count == 0)
|
||||
return;
|
||||
|
||||
var additionalSignatures = new List<string>(events.Count);
|
||||
var namespaceName = classSymbol.ContainingNamespace.ToDisplayString();
|
||||
|
||||
for (int i = 0; i < events.Count; i++)
|
||||
{
|
||||
var currentEvent = events[i];
|
||||
|
||||
var additionalMethod = GenerateMethodExternalCaller(currentEvent, out var signature);
|
||||
declaredMethods.Add(additionalMethod);
|
||||
additionalSignatures.Add(signature);
|
||||
GenerateEventCode(currentEvent, invokers, classSymbol);
|
||||
}
|
||||
|
||||
var partialInterface = $@"
|
||||
namespace {classSymbol.ContainingNamespace.ToDisplayString()}
|
||||
{{
|
||||
public partial interface {classSymbol.Name}
|
||||
{{
|
||||
{string.Join("\r\n", additionalSignatures)}
|
||||
}}
|
||||
}}
|
||||
";
|
||||
#if !DONT_ADD
|
||||
context.AddSource($"{classSymbol.Name}.g.cs", SourceText.From(partialInterface, Encoding.UTF8));
|
||||
#endif
|
||||
}
|
||||
|
||||
private string GenerateMethodExternalCaller(IEventSymbol eventSymbol, out string interfaceSignature)
|
||||
{
|
||||
var level = "\t\t";
|
||||
var parameters = (eventSymbol.Type as INamedTypeSymbol).TypeArguments;
|
||||
var parameterIndex = 0;
|
||||
var parametersDeclaration =
|
||||
string.Join(", ", parameters.Select(i => $"{i.ToDisplayString()} p{parameterIndex++}"));
|
||||
var signature = $@"public void {EventExternalName(eventSymbol)}({parametersDeclaration})";
|
||||
interfaceSignature = level + signature + ";";
|
||||
var caller = $@"{signature}
|
||||
{level}{{
|
||||
{level} {eventSymbol.Name}?.Invoke({string.Join(", ", Enumerable.Range(0, parameterIndex).Select(i => "p" + i))});
|
||||
{level}}}
|
||||
";
|
||||
return caller;
|
||||
}
|
||||
|
||||
public static string EventExternalName(IEventSymbol eventSymbol) => $"{eventSymbol.Name}External";
|
||||
|
||||
private static string Caster(ITypeSymbol type, string inner)
|
||||
{
|
||||
if (!type.IsValueType)
|
||||
return inner +
|
||||
@@ -212,10 +308,10 @@ namespace mROA.Codegen
|
||||
return $"({type.ToDisplayString()})" + inner;
|
||||
}
|
||||
|
||||
private void GenerateDeclaredMethod(IMethodSymbol method, List<string> declaredMethods,
|
||||
List<IMethodSymbol> methods, List<string> invokers)
|
||||
private void GenerateDeclaredMethod(IMethodSymbol method, List<string> declaredMethods, List<string> invokers,
|
||||
INamedTypeSymbol baseInterace)
|
||||
{
|
||||
var index = methods.IndexOf(method);
|
||||
var index = invokers.Count;
|
||||
var sb = new StringBuilder();
|
||||
|
||||
bool isParametrized;
|
||||
@@ -327,7 +423,7 @@ namespace mROA.Codegen
|
||||
{level} IsVoid = {isVoid.ToString().ToLower()},
|
||||
{(isVoid ? String.Empty : (level + "\t" + "ReturnType = typeof(" + ExtractTaskType(method.ReturnType)) + "),")}
|
||||
{level} ParameterTypes = new Type[] {{ {parameterTypes} }},
|
||||
{level} SuitableType = typeof({method.ContainingType.ToDisplayString()}),
|
||||
{level} SuitableType = typeof({baseInterace.ToDisplayString()}),
|
||||
{level} Invoking = (i, parameters, special, post) => {funcInvoking},
|
||||
{level}}}";
|
||||
else
|
||||
@@ -336,21 +432,62 @@ namespace mROA.Codegen
|
||||
{level} IsVoid = {isVoid.ToString().ToLower()},
|
||||
{level} ReturnType = typeof({method.ReturnType.ToDisplayString()}),
|
||||
{level} ParameterTypes = new Type[] {{ {parameterTypes} }},
|
||||
{level} SuitableType = typeof({method.ContainingType.ToDisplayString()}),
|
||||
{level} SuitableType = typeof({baseInterace.ToDisplayString()}),
|
||||
{level} Invoking = (i, parameters, special) => {funcInvoking}
|
||||
{level}}}";
|
||||
|
||||
invokers.Add(backend);
|
||||
}
|
||||
|
||||
private static Predicate<IParameterSymbol> ParameterFilter =
|
||||
i => i.Type.Name is "CancellationToken" or "RequestContext";
|
||||
|
||||
public void GeneratePropertyMethod(IMethodSymbol method, List<IMethodSymbol> methods,
|
||||
List<(string, IMethodSymbol)> propsCollection, List<string> invokers)
|
||||
private void GenerateEventCode(IEventSymbol eventSymbol, List<string> invokers, ITypeSymbol baseInterface)
|
||||
{
|
||||
var level = "\t\t\t";
|
||||
var index = methods.IndexOf(method);
|
||||
|
||||
var parameters = (eventSymbol.Type as INamedTypeSymbol).TypeArguments;
|
||||
var parsingParameters = parameters.RemoveAll(ParameterFilterForType).ToList();
|
||||
var parameterTypes = string.Join(", ",
|
||||
$"{string.Join(", ", parsingParameters.Select(p => $"typeof({p.ToDisplayString()})"))}");
|
||||
|
||||
var parametersInsertList = new List<string>();
|
||||
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
var parameter = parameters[i];
|
||||
switch (parameter.Name)
|
||||
{
|
||||
case "CancellationToken":
|
||||
parametersInsertList.Add("(CancellationToken)special[1]");
|
||||
break;
|
||||
case "RequestContext":
|
||||
parametersInsertList.Add("special[1] as RequestContext");
|
||||
break;
|
||||
default:
|
||||
parametersInsertList.Add(Caster(parameter,
|
||||
$"parameters[{parameters.IndexOf(parameter)}]"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var parametersInsert = string.Join(", ", parametersInsertList);
|
||||
var backend = $@"new mROA.Implementation.MethodInvoker
|
||||
{level}{{
|
||||
{level} IsVoid = true,
|
||||
{level} ReturnType = typeof(void),
|
||||
{level} ParameterTypes = new Type[] {{ {parameterTypes} }},
|
||||
{level} SuitableType = typeof({baseInterface.ToDisplayString()}),
|
||||
{level} Invoking = (i, parameters, special) => {{
|
||||
{level} (i as {baseInterface.ToDisplayString()}).{EventExternalName(eventSymbol)}({parametersInsert});
|
||||
{level} return null;
|
||||
{level} }}
|
||||
{level}}}";
|
||||
invokers.Add(backend);
|
||||
}
|
||||
|
||||
private void GeneratePropertyMethod(IMethodSymbol method,
|
||||
List<(string, IMethodSymbol)> propsCollection, List<string> invokers, INamedTypeSymbol baseInterace)
|
||||
{
|
||||
var level = "\t\t\t";
|
||||
var index = invokers.Count;
|
||||
string frontend;
|
||||
string backend = string.Empty;
|
||||
if (method.MethodKind == MethodKind.PropertyGet)
|
||||
@@ -363,21 +500,14 @@ namespace mROA.Codegen
|
||||
var parameterTypes = string.Join(", ",
|
||||
$"{string.Join(", ", method.Parameters.Select(p => "typeof(" + p.Type.ToDisplayString() + ")"))}");
|
||||
var parameterInserts = string.Join(", ",
|
||||
method.Parameters.Select(p =>
|
||||
{
|
||||
return Caster(p.Type, "parameters[" + method.Parameters.IndexOf(p) + "]");
|
||||
// if (!p.Type.IsValueType)
|
||||
// return "parameters[" + method.Parameters.IndexOf(p) + "] as " +
|
||||
// p.Type.ToDisplayString();
|
||||
// return $"({p.Type.ToDisplayString()})parameters[{method.Parameters.IndexOf(p)}]";
|
||||
}
|
||||
));
|
||||
method.Parameters.Select(
|
||||
p => Caster(p.Type, "parameters[" + method.Parameters.IndexOf(p) + "]")));
|
||||
backend = $@"new mROA.Implementation.MethodInvoker
|
||||
{level}{{
|
||||
{level} IsVoid = false,
|
||||
{level} ReturnType = typeof({method.ReturnType.ToDisplayString()}),
|
||||
{level} ParameterTypes = new Type[] {{ {parameterTypes} }},
|
||||
{level} SuitableType = typeof({method.ContainingType.ToDisplayString()}),
|
||||
{level} SuitableType = typeof({baseInterace.ToDisplayString()}),
|
||||
{level} Invoking = (i, parameters, _) => (i as {method.ContainingType.ToDisplayString()})[{parameterInserts}],
|
||||
{level}}}";
|
||||
}
|
||||
@@ -387,7 +517,7 @@ namespace mROA.Codegen
|
||||
{level}{{
|
||||
{level} IsVoid = false,
|
||||
{level} ReturnType = typeof({method.ReturnType.ToDisplayString()}),
|
||||
{level} SuitableType = typeof({method.ContainingType.ToDisplayString()}),
|
||||
{level} SuitableType = typeof({baseInterace.ToDisplayString()}),
|
||||
{level} Invoking = (i, _, _) => (i as {method.ContainingType.ToDisplayString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name},
|
||||
{level}}}";
|
||||
}
|
||||
@@ -426,7 +556,7 @@ namespace mROA.Codegen
|
||||
{level} IsVoid = true,
|
||||
{level} ReturnType = typeof({method.ReturnType.ToDisplayString()}),
|
||||
{level} ParameterTypes = new Type[] {{ {parameterTypes} }},
|
||||
{level} SuitableType = typeof({method.ContainingType.ToDisplayString()}),
|
||||
{level} SuitableType = typeof({baseInterace.ToDisplayString()}),
|
||||
{level} Invoking = (i, parameters, _) => (i as {method.ContainingType.ToDisplayString()})[{parameterInserts}] = {valueInsert},
|
||||
{level}}}";
|
||||
}
|
||||
@@ -437,7 +567,7 @@ namespace mROA.Codegen
|
||||
{level} IsVoid = true,
|
||||
{level} ReturnType = typeof({method.ReturnType.ToDisplayString()}),
|
||||
{level} ParameterTypes = new Type[] {{ typeof({method.Parameters.First().Type.ToDisplayString()}) }},
|
||||
{level} SuitableType = typeof({method.ContainingType.ToDisplayString()}),
|
||||
{level} SuitableType = typeof({baseInterace.ToDisplayString()}),
|
||||
{level} Invoking = (i, parameters, _) => (i as {method.ContainingType.ToDisplayString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name} = {Caster((method.AssociatedSymbol as IPropertySymbol)!.Type, "parameters[0]")},
|
||||
{level}}}";
|
||||
}
|
||||
@@ -464,39 +594,6 @@ namespace mROA.Codegen
|
||||
return (taskType as INamedTypeSymbol).TypeArguments[0].ToDisplayString();
|
||||
}
|
||||
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
{
|
||||
}
|
||||
|
||||
public void Execute(GeneratorExecutionContext context)
|
||||
{
|
||||
var trees = context.Compilation.SyntaxTrees;
|
||||
|
||||
var interfaces = new List<InterfaceDeclarationSyntax>();
|
||||
foreach (var tree in trees)
|
||||
{
|
||||
var node = tree.GetRoot() as CompilationUnitSyntax;
|
||||
|
||||
foreach (var member in node.Members)
|
||||
{
|
||||
if (member is InterfaceDeclarationSyntax ids)
|
||||
{
|
||||
interfaces.Add(ids);
|
||||
}
|
||||
else if (member is NamespaceDeclarationSyntax nds)
|
||||
{
|
||||
foreach (var inside in nds.Members)
|
||||
|
||||
if (inside is InterfaceDeclarationSyntax ids2)
|
||||
if (ContainsSOIAttribute(ids2.AttributeLists, context, ids2))
|
||||
interfaces.Add(ids2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GenerateCode(context, context.Compilation, interfaces.ToImmutableArray());
|
||||
}
|
||||
|
||||
private bool ContainsSOIAttribute(SyntaxList<AttributeListSyntax> attributes, GeneratorExecutionContext context,
|
||||
InterfaceDeclarationSyntax interfaceDeclarationSyntax)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user