База для нового бэкэнда

This commit is contained in:
2025-03-06 14:10:52 +03:00
parent be6dedaee4
commit c802f337c7
18 changed files with 245 additions and 163 deletions
+48 -61
View File
@@ -17,74 +17,57 @@ namespace mROA.Codegen
[Generator]
public class mROASourceGenerator : ISourceGenerator
{
private const string Namespace = "mROA.Implementation";
private const string AttributeName = "SharedObjectInterafceAttribute";
private const string AttributeSourceCode = $@"// <auto-generated/>
namespace {Namespace}
{{
[System.AttributeUsage(System.AttributeTargets.Class)]
public class {AttributeName} : System.Attribute
{{
}}
}}";
/// <summary>
/// Generate code action.
/// It will be executed on specific nodes (ClassDeclarationSyntax annotated with the [Report] attribute) changed by the user.
/// </summary>
/// <param name="context">Source generation context used to add source files.</param>
/// <param name="compilation">Compilation used to provide access to the Semantic Model.</param>
/// <param name="classes">Nodes annotated with the [Report] attribute that trigger the generate action.</param>
private void GenerateCode(GeneratorExecutionContext context, Compilation compilation,
ImmutableArray<InterfaceDeclarationSyntax> classes)
{
var methods = new List<(string, IMethodSymbol)>();
var frontendContextRepo = new List<string>();
// Go through all filtered class declarations.
var declarations = classes.ToList().OrderBy(i => i.Identifier.Text).ToList();
foreach (var classDeclarationSyntax in declarations)
{
// We need to get semantic model of the class to retrieve metadata.
{
var semanticModel = compilation.GetSemanticModel(classDeclarationSyntax.SyntaxTree);
// Symbols allow us to get the compile-time information.
if (semanticModel.GetDeclaredSymbol(classDeclarationSyntax) is not INamedTypeSymbol classSymbol)
continue;
var namespaceName = classSymbol.ContainingNamespace.ToDisplayString();
// 'Identifier' means the token of the node. Get class name from the syntax node.
var className = classDeclarationSyntax.Identifier.Text;
// Go through all class members with a particular type (property) to generate method lines.
var methodBody = classSymbol.GetMembers()
.OfType<IMethodSymbol>().OrderBy(i => i.Name);
var methodBody = CollectMethods(classSymbol);
var originalName = className;
// Build up the source code
className = className.TrimStart('I') + "RemoteEndpoint";
var methodsText = new List<string>();
foreach (var method in methodBody)
{
var index = methods.Count;
methods.Add((namespaceName + "." + originalName, method));
var sb = new StringBuilder();
bool isParametrized;
bool isAsync = method.ReturnType.Name == "Task";
bool isVoid = method.ReturnType.Name == "Void" ||
method.ReturnType.ToString() == "System.Threading.Tasks.Task";
bool isParametrized = method.Parameters.Length == 1 && !isAsync ||
method.Parameters.Length == 2 && isAsync;
bool isAsync;
bool isVoid;
switch (method.ReturnType)
{
case INamedTypeSymbol namedType:
isAsync = namedType.Name == "Task";
isVoid = isAsync && namedType.TypeParameters.Length == 0 || namedType.Name == "Void";
isParametrized = method.Parameters.Length == 1 && !isAsync ||
method.Parameters.Length == 2 && isAsync;
break;
case IArrayTypeSymbol:
isAsync = false;
isVoid = false;
isParametrized = method.Parameters.Length != 0;
break;
default:
continue;
}
//Creating signature
sb.AppendLine("public" + (isAsync
@@ -140,7 +123,7 @@ namespace {namespaceName}
// Add the source code to the compilation.
context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8));
// context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8));
frontendContextRepo.Add(
$"{{ typeof({classSymbol.ToDisplayString()}), typeof({namespaceName}.{className}) }}");
@@ -148,31 +131,27 @@ namespace {namespaceName}
if (methods.Count != 0)
{
// var methodsStringed = methods.Select(i =>
// $"typeof({i.Item1}).GetMethod(\"{i.Item2.Name}\", new Type[] {{{string.Join(", ", i.Item2.Parameters.Select(p => $"typeof({p.Type.ToDisplayString()})"))}}})")
// .ToList();
var methodsStringed = methods.Select(i =>
$"typeof({i.Item1}).GetMethod(\"{i.Item2.Name}\")")
.ToList();
var methodsStringed = Array.Empty<string>();
var coCodegenRepoCode = @$"// <auto-generated/>
using System.Collections.Generic;
using System.Reflection;
using mROA.Abstract;
using mROA.Implementation;
using System;
namespace mROA.Codegen
{{
public class CoCodegenMethodRepository : IMethodRepository
{{
private readonly List<MethodInfo> _methods = new () {{
private readonly List<IMethodInvoker> _methods = new () {{
{string.Join(",\r\n\t\t\t", methodsStringed)}
}};
public MethodInfo GetMethod(int id)
public IMethodInvoker GetMethod(int id)
{{
if (id == -1)
return typeof(IDisposable).GetMethod(""Dispose"");
return mROA.Implementation.MethodInvoker.Dispose;
if (_methods.Count <= id)
return null;
@@ -186,7 +165,7 @@ namespace mROA.Codegen
}}
}}
";
context.AddSource($"CoCodegenMethodRepository.g.cs", SourceText.From(coCodegenRepoCode, Encoding.UTF8));
context.AddSource("CoCodegenMethodRepository.g.cs", SourceText.From(coCodegenRepoCode, Encoding.UTF8));
}
if (frontendContextRepo.Count != 0)
@@ -209,7 +188,7 @@ namespace mROA.Codegen
}}
}}
";
context.AddSource("RemoteTypeBinder.g.cs", SourceText.From(fronendRepoCode, Encoding.UTF8));
// context.AddSource("RemoteTypeBinder.g.cs", SourceText.From(fronendRepoCode, Encoding.UTF8));
}
}
@@ -225,9 +204,7 @@ namespace mROA.Codegen
private string ExtractTaskType(ITypeSymbol taskType)
{
var type = taskType.ToString();
type = type.Substring(type.IndexOf('<') + 1);
return type.Substring(0, type.Length - 1);
return (taskType as INamedTypeSymbol).TypeParameters[0].ToDisplayString();
}
public void Initialize(GeneratorInitializationContext context)
@@ -266,8 +243,7 @@ namespace mROA.Codegen
private bool ContainsSOIAttribute(SyntaxList<AttributeListSyntax> attributes, GeneratorExecutionContext context,
InterfaceDeclarationSyntax interfaceDeclarationSyntax)
{
foreach (AttributeListSyntax attributeListSyntax in attributes)
foreach (AttributeSyntax attributeSyntax in attributeListSyntax.Attributes)
foreach (var attributeSyntax in attributes.SelectMany(attributeListSyntax => attributeListSyntax.Attributes))
{
if (context.Compilation.GetSemanticModel(interfaceDeclarationSyntax.SyntaxTree)
.GetSymbolInfo(attributeSyntax).Symbol is not IMethodSymbol attributeSymbol)
@@ -282,5 +258,16 @@ namespace mROA.Codegen
return false;
}
private List<IMethodSymbol> CollectMethods(INamedTypeSymbol type)
{
var methods = type.GetMembers().OfType<IMethodSymbol>().ToList();
foreach (var inner in type.AllInterfaces)
{
methods.AddRange(inner.GetMembers().OfType<IMethodSymbol>());
}
return methods.OrderBy(i => i.Name).ToList();
}
}
}