From 9262fafad50507331a1f4b6daa0f1517da0e3092 Mon Sep 17 00:00:00 2001 From: Ivan Ansimov Date: Mon, 14 Jul 2025 19:11:54 +0300 Subject: [PATCH 1/6] move static methods from main logic --- mROA.Codegen/mROASourceGenerator.cs | 157 ++++++++++++++-------------- 1 file changed, 76 insertions(+), 81 deletions(-) diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index 95ef5b1..2b791be 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -41,6 +41,22 @@ namespace mROA.Codegen private int _currentInternalCallIndex; + public void Initialize(IncrementalGeneratorInitializationContext context) + { + _methodRepoTemplate = TemplateReader.FromEmbeddedResource("MethodRepo.cstmpl"); + _methodInvokerOriginal = + ((InnerTemplateSection)_methodRepoTemplate["syncInvoker"]!).InnerTemplate; + _classTemplateOriginal = TemplateReader.FromEmbeddedResource("Proxy.cstmpl"); + _binderTemplate = TemplateReader.FromEmbeddedResource("RemoteTypeBinder.cstmpl"); + _interfaceTemplateOriginal = TemplateReader.FromEmbeddedResource("PartialInterface.cstmpl"); + _indexerTemplate = TemplateReader.FromEmbeddedResource("IndexProvider.cstmpl"); + + var syntaxes = context.SyntaxProvider.CreateSyntaxProvider( + (static (node, _) => node is InterfaceDeclarationSyntax), static (node, _) => CodegenUtilities.ContainsSoiAttribute(node)).Where(i => i.usefull).Select((node, _) => node.node); + + context.RegisterSourceOutput(context.CompilationProvider.Combine(syntaxes.Collect()), (productionContext, pair) => GenerateCode(productionContext, pair.Left, pair.Right)); + } + private void GenerateCode(SourceProductionContext context, Compilation compilation, ImmutableArray classes) { @@ -60,7 +76,7 @@ namespace mROA.Codegen var namespaceName = classSymbol.ContainingNamespace.ToDisplayString(); var className = classDeclarationSyntax.Identifier.Text; - var innerMethods = CollectMembers(classSymbol); + var innerMethods = CodegenUtilities.CollectMembers(classSymbol); var associated = innerMethods.Select(i => i.AssociatedSymbol).Where(i => i != null) .Distinct(SymbolEqualityComparer.Default).Cast().ToList(); @@ -120,7 +136,7 @@ namespace mROA.Codegen GenerateEventImplementation(classSymbol, invokers, context); var endInvokers = invokers.Count; - _indexerTemplate.Insert("indexSpan", $"{{ typeof({originalName}), new[] {{ {JoinWithComa(Enumerable.Range(startInvokers, endInvokers - startInvokers).Select(i => i.ToString()))} }} }},"); + _indexerTemplate.Insert("indexSpan", $"{{ typeof({originalName}), new[] {{ {CodegenUtilities.JoinWithComa(Enumerable.Range(startInvokers, endInvokers - startInvokers).Select(i => i.ToString()))} }} }},"); _classTemplate.AddDefine("className", className); _classTemplate.AddDefine("originalName", originalName); _classTemplate.AddDefine("namespaceName", namespaceName); @@ -181,7 +197,7 @@ namespace mROA.Codegen // declaredMethods.Add(additionalMethod); _interfaceTemplate.Insert("signature", signature); GenerateEventCode(currentEvent, invokers, classSymbol); - GenerateBinderCode(currentEvent, invokers, classSymbol, objectBinderTemplate); + GenerateBinderCode(currentEvent, classSymbol, objectBinderTemplate); } objectBinderTemplate.AddDefine("type", classSymbol.ToUnityString()); @@ -196,12 +212,12 @@ namespace mROA.Codegen private string GenerateMethodExternalCaller(IEventSymbol eventSymbol, out string interfaceSignature) { - var level = "\t\t"; + const string level = "\t\t"; var parameters = ((INamedTypeSymbol)eventSymbol.Type).TypeArguments; var parameterIndex = 0; var parametersDeclaration = string.Join(", ", parameters.Select(i => $"{i.ToUnityString()} p{parameterIndex++}")); - var signature = $@"public void {EventExternalName(eventSymbol)}({parametersDeclaration})"; + var signature = $"public void {CodegenUtilities.EventExternalName(eventSymbol)}({parametersDeclaration})"; interfaceSignature = signature + ";"; var caller = $@"{signature} {level}{{ @@ -211,22 +227,7 @@ namespace mROA.Codegen return caller; } - private static string EventExternalName(IEventSymbol eventSymbol) - { - return $"{eventSymbol.Name}External"; - } - - private static string Caster(ITypeSymbol type, string inner) - { - if (!type.IsValueType) - return inner + - " as " + - type.ToUnityString(); - return $"({type.ToUnityString()})" + inner; - } - - private void GenerateDeclaredMethod(IMethodSymbol method, List invokers, - INamedTypeSymbol baseInterace) + private void GenerateDeclaredMethod(IMethodSymbol method, List invokers, INamedTypeSymbol baseInterface) { var sb = new StringBuilder(); @@ -260,9 +261,9 @@ namespace mROA.Codegen sb.AppendLine("public" + (isAsync ? " async " : " ") + - $"{method.ReturnType.ToUnityString()} {method.Name}({string.Join(", ", method.Parameters.Select(ToFullString))}){{"); + $"{method.ReturnType.ToUnityString()} {method.Name}({string.Join(", ", method.Parameters.Select(CodegenUtilities.ToFullString))}){{"); - var isUntrusted = method.GetAttributes().Any(i => i.AttributeClass.Name == "UntrustedAttribute"); + var isUntrusted = method.GetAttributes().Any(i => i.AttributeClass?.Name == "UntrustedAttribute"); var prefix = isAsync ? "await " : ""; var postfix = !isAsync ? isVoid ? ".Wait()" : ".GetAwaiter().GetResult()" : ""; @@ -287,8 +288,8 @@ namespace mROA.Codegen caller = isVoid ? $"CallAsync(CallIndices[{_currentInternalCallIndex++}]{parameterLink}{tokenInsert})" : isAsync - ? $"GetResultAsync<{ExtractTaskType(method.ReturnType)}>(CallIndices[{_currentInternalCallIndex++}]{parameterLink}{tokenInsert})" - : $"GetResultAsync<{ToFullString(method.ReturnType)}>(CallIndices[{_currentInternalCallIndex++}]{parameterLink}{tokenInsert})"; + ? $"GetResultAsync<{CodegenUtilities.ExtractTaskType(method.ReturnType)}>(CallIndices[{_currentInternalCallIndex++}]{parameterLink}{tokenInsert})" + : $"GetResultAsync<{CodegenUtilities.ToFullString(method.ReturnType)}>(CallIndices[{_currentInternalCallIndex++}]{parameterLink}{tokenInsert})"; if (!isVoid) prefix = "return " + prefix; @@ -317,7 +318,7 @@ namespace mROA.Codegen parametersInsertList.Add("special[0] as RequestContext"); break; default: - parametersInsertList.Add(Caster(parameter.Type, + parametersInsertList.Add(CodegenUtilities.Caster(parameter.Type, $"parameters[{parameters.IndexOf(parameter)}]")); break; } @@ -347,9 +348,9 @@ namespace mROA.Codegen (TemplateDocument)((InnerTemplateSection)_methodRepoTemplate["asyncInvoker"]!).InnerTemplate .Clone(); invokerTemplate.AddDefine("isVoid", isVoid.ToString().ToLower()); - invokerTemplate.AddDefine("returnType", ExtractTaskType(method.ReturnType)); + invokerTemplate.AddDefine("returnType", CodegenUtilities.ExtractTaskType(method.ReturnType)); invokerTemplate.AddDefine("parametersType", parameterTypes); - invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString()); + invokerTemplate.AddDefine("suitableType", baseInterface.ToUnityString()); invokerTemplate.AddDefine("funcInvoking", funcInvoking); invokerTemplate.AddDefine("isTrusted", (!isUntrusted).ToString().ToLower()); backend = invokerTemplate.Compile(); @@ -360,7 +361,7 @@ namespace mROA.Codegen invokerTemplate.AddDefine("isVoid", isVoid.ToString().ToLower()); invokerTemplate.AddDefine("returnType", isVoid ? "void" : method.ReturnType.ToUnityString()); invokerTemplate.AddDefine("parametersType", parameterTypes); - invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString()); + invokerTemplate.AddDefine("suitableType", baseInterface.ToUnityString()); invokerTemplate.AddDefine("funcInvoking", funcInvoking); invokerTemplate.AddDefine("isTrusted", (!isUntrusted).ToString().ToLower()); backend = invokerTemplate.Compile(); @@ -371,21 +372,18 @@ namespace mROA.Codegen invokers.Add(backend); } - private void GenerateBinderCode(IEventSymbol eventSymbol, List invokers, INamedTypeSymbol baseType, - TemplateDocument document) + private void GenerateBinderCode(IEventSymbol eventSymbol, INamedTypeSymbol baseType, TemplateDocument document) { var eventBinderTemplate = (TemplateDocument)((InnerTemplateSection)document["eventBinderTemplate"]!).InnerTemplate.Clone(); var index = _currentInternalCallIndex; var parameters = (eventSymbol.Type as INamedTypeSymbol)!.TypeArguments.ToList(); - var parametersDeclaration = string.Join(", ", - JoinWithComa(Enumerable.Range(0, parameters.Count).Select(i => "p" + i))); + var parametersDeclaration = string.Join(", ", CodegenUtilities.JoinWithComa(Enumerable.Range(0, parameters.Count).Select(i => "p" + i))); - int pi = 0; - var transferParameters = - JoinWithComa(parameters.Select(i => (i, pi++)).Where(i => !ParameterFilterForType(i.i)) + var pi = 0; + var transferParameters = CodegenUtilities.JoinWithComa(parameters.Select(i => (i, pi++)).Where(i => !ParameterFilterForType(i.i)) .Select(i => "p" + i.Item2)); var requestIndex = parameters.FindIndex(i => i.Name == "RequestContext"); @@ -404,11 +402,6 @@ namespace mROA.Codegen document.Insert("eventBinder", eventBinderCode); } - private static string JoinWithComa(IEnumerable parts) - { - return string.Join(", ", parts); - } - private void GenerateEventCode(IEventSymbol eventSymbol, List invokers, ITypeSymbol baseInterface) { var level = "\t\t\t"; @@ -431,7 +424,7 @@ namespace mROA.Codegen parametersInsertList.Add("special[0] as RequestContext"); break; default: - parametersInsertList.Add(Caster(parameter.i, + parametersInsertList.Add(CodegenUtilities.Caster(parameter.i, $"parameters[{parameter.Item2}]")); break; } @@ -440,7 +433,7 @@ namespace mROA.Codegen var parametersInsert = string.Join(", ", parametersInsertList); var funcInvoking = $@"{{ -{level} (i as {baseInterface.ToUnityString()}).{EventExternalName(eventSymbol)}({parametersInsert}); +{level} (i as {baseInterface.ToUnityString()}).{CodegenUtilities.EventExternalName(eventSymbol)}({parametersInsert}); {level} return null; {level} }}"; @@ -473,8 +466,7 @@ namespace mROA.Codegen var parameterTypes = string.Join(", ", $"{string.Join(", ", method.Parameters.Select(p => "typeof(" + p.Type.ToUnityString() + ")"))}"); var parameterInserts = string.Join(", ", - method.Parameters.Select(p => - Caster(p.Type, "parameters[" + method.Parameters.IndexOf(p) + "]"))); + method.Parameters.Select(p => CodegenUtilities.Caster(p.Type, "parameters[" + method.Parameters.IndexOf(p) + "]"))); var invokerTemplate = (TemplateDocument)_methodInvokerOriginal.Clone(); invokerTemplate.AddDefine("isVoid", "false"); @@ -513,10 +505,9 @@ namespace mROA.Codegen var parameterTypes = string.Join(", ", $"{string.Join(", ", method.Parameters.Select(p => $"typeof({p.Type.ToUnityString()})"))}"); var parameterInserts = string.Join(", ", - method.Parameters.Take(method.Parameters.Length - 1).Select(p => - Caster(p.Type, "parameters[" + method.Parameters.IndexOf(p) + "]"))); + method.Parameters.Take(method.Parameters.Length - 1).Select(p => CodegenUtilities.Caster(p.Type, "parameters[" + method.Parameters.IndexOf(p) + "]"))); - var valueInsert = Caster(method.Parameters.Last().Type, + var valueInsert = CodegenUtilities.Caster(method.Parameters.Last().Type, "parameters[" + (method.Parameters.Length - 1) + "]"); var invokerTemplate = (TemplateDocument)_methodInvokerOriginal.Clone(); @@ -541,7 +532,7 @@ namespace mROA.Codegen $"typeof({method.Parameters.First().Type.ToUnityString()})"); invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString()); invokerTemplate.AddDefine("funcInvoking", - $"(i as {method.ContainingType.ToUnityString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name} = {Caster((method.AssociatedSymbol as IPropertySymbol)!.Type, "parameters[0]")}"); + $"(i as {method.ContainingType.ToUnityString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name} = {CodegenUtilities.Caster((method.AssociatedSymbol as IPropertySymbol)!.Type, "parameters[0]")}"); invokerTemplate.AddDefine("isTrusted", "true"); backend = invokerTemplate.Compile(); @@ -554,36 +545,57 @@ namespace mROA.Codegen _methodRepoTemplate.Insert("invoker", backend); invokers.Add(backend); } + } - private static string ToFullString(IParameterSymbol parameter) + public static class CodegenUtilities + { + public static string EventExternalName(IEventSymbol eventSymbol) + { + return $"{eventSymbol.Name}External"; + } + + public static string Caster(ITypeSymbol type, string inner) + { + if (!type.IsValueType) + return inner + + " as " + + type.ToUnityString(); + return $"({type.ToUnityString()})" + inner; + } + + public static string JoinWithComa(IEnumerable parts) + { + return string.Join(", ", parts); + } + + public static string ToFullString(IParameterSymbol parameter) { return parameter.Type.ToUnityString() + " " + parameter.Name; } - private static string ToFullString(ITypeSymbol type) + public static string ToFullString(ITypeSymbol type) { return type.ToUnityString(); } - private string ExtractTaskType(ITypeSymbol taskType) + public static string ExtractTaskType(ITypeSymbol taskType) { var generics = ((INamedTypeSymbol)taskType).TypeArguments; return generics.Length == 0 ? "void" : generics[0].ToUnityString(); } - private static (InterfaceDeclarationSyntax node, bool usefull) ContainsSoiAttribute( + public static (InterfaceDeclarationSyntax node, bool usefull) ContainsSoiAttribute( GeneratorSyntaxContext context) { var ids = (InterfaceDeclarationSyntax)context.Node; - + // Go through all attributes of the class. - foreach (AttributeListSyntax attributeListSyntax in ids.AttributeLists) - foreach (AttributeSyntax attributeSyntax in attributeListSyntax.Attributes) + foreach (var attributeSyntax in ids.AttributeLists.SelectMany(attributeListSyntax => attributeListSyntax.Attributes)) { if (context.SemanticModel.GetSymbolInfo(attributeSyntax).Symbol is not IMethodSymbol attributeSymbol) continue; // if we can't get the symbol, ignore it - string attributeName = attributeSymbol.ContainingType.ToDisplayString(); + var attributeName = attributeSymbol.ContainingType.ToDisplayString(); // Check the full name of the [Report] attribute. if (attributeName == $"mROA.Implementation.Attributes.SharedObjectInterfaceAttribute") @@ -593,7 +605,7 @@ namespace mROA.Codegen return (ids ,false); } - private List CollectMembers(INamedTypeSymbol type) + public static List CollectMembers(INamedTypeSymbol type) { var methods = type.GetMembers().OfType().ToList(); foreach (var inner in type.AllInterfaces) methods.AddRange(inner.GetMembers().OfType()); @@ -601,34 +613,17 @@ namespace mROA.Codegen methods.RemoveAll(m => m.Name == "Dispose"); return methods.OrderBy(i => i.Name).ToList(); } - - public void Initialize(IncrementalGeneratorInitializationContext context) - { - _methodRepoTemplate = TemplateReader.FromEmbeddedResource("MethodRepo.cstmpl"); - _methodInvokerOriginal = - ((InnerTemplateSection)_methodRepoTemplate["syncInvoker"]!).InnerTemplate; - _classTemplateOriginal = TemplateReader.FromEmbeddedResource("Proxy.cstmpl"); - _binderTemplate = TemplateReader.FromEmbeddedResource("RemoteTypeBinder.cstmpl"); - _interfaceTemplateOriginal = TemplateReader.FromEmbeddedResource("PartialInterface.cstmpl"); - _indexerTemplate = TemplateReader.FromEmbeddedResource("IndexProvider.cstmpl"); - - var syntaxes = context.SyntaxProvider.CreateSyntaxProvider( - (static (node, _) => node is InterfaceDeclarationSyntax), static (node, _) => ContainsSoiAttribute(node)).Where(i => i.usefull).Select((node, _) => node.node); - - context.RegisterSourceOutput(context.CompilationProvider.Combine(syntaxes.Collect()), (productionContext, pair) => GenerateCode(productionContext, pair.Left, pair.Right)); - } } - - public static class CodegenExtentions + + public static class CodegenExtensions { public static string ToUnityString(this ITypeSymbol type) { var parts = type.ToDisplayParts(); - if (parts.Any(i => i.Kind == SymbolDisplayPartKind.Keyword)) - return parts.ToUnityString(); - - return type.ToDisplayString(); + return parts.Any(i => i.Kind == SymbolDisplayPartKind.Keyword) + ? parts.ToUnityString() + : type.ToDisplayString(); } public static string ToUnityString(this IParameterSymbol parameter) @@ -636,7 +631,7 @@ namespace mROA.Codegen return parameter.Type.ToUnityString() + " " + parameter.Name; } - public static string ToUnityString(this ImmutableArray parts) + private static string ToUnityString(this ImmutableArray parts) { var sb = new StringBuilder(); foreach (var displayPart in parts) From 26cdf86bd60bc5328d9fa7fcb26f88a75c97f1be Mon Sep 17 00:00:00 2001 From: Ivan Ansimov Date: Mon, 14 Jul 2025 19:13:19 +0300 Subject: [PATCH 2/6] code reformat --- mROA.Codegen/mROASourceGenerator.cs | 64 +++++++++++++++++------------ 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index 2b791be..dee53b3 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -52,16 +52,19 @@ namespace mROA.Codegen _indexerTemplate = TemplateReader.FromEmbeddedResource("IndexProvider.cstmpl"); var syntaxes = context.SyntaxProvider.CreateSyntaxProvider( - (static (node, _) => node is InterfaceDeclarationSyntax), static (node, _) => CodegenUtilities.ContainsSoiAttribute(node)).Where(i => i.usefull).Select((node, _) => node.node); - - context.RegisterSourceOutput(context.CompilationProvider.Combine(syntaxes.Collect()), (productionContext, pair) => GenerateCode(productionContext, pair.Left, pair.Right)); + (static (node, _) => node is InterfaceDeclarationSyntax), + static (node, _) => CodegenUtilities.ContainsSoiAttribute(node)).Where(i => i.usefull) + .Select((node, _) => node.node); + + context.RegisterSourceOutput(context.CompilationProvider.Combine(syntaxes.Collect()), + (productionContext, pair) => GenerateCode(productionContext, pair.Left, pair.Right)); } - + private void GenerateCode(SourceProductionContext context, Compilation compilation, ImmutableArray classes) { var totalMethods = new List(); - + _indexerTemplate.AddDefine("namespace", compilation.AssemblyName!); var invokers = new List(); var declarations = classes.ToList(); @@ -136,7 +139,8 @@ namespace mROA.Codegen GenerateEventImplementation(classSymbol, invokers, context); var endInvokers = invokers.Count; - _indexerTemplate.Insert("indexSpan", $"{{ typeof({originalName}), new[] {{ {CodegenUtilities.JoinWithComa(Enumerable.Range(startInvokers, endInvokers - startInvokers).Select(i => i.ToString()))} }} }},"); + _indexerTemplate.Insert("indexSpan", + $"{{ typeof({originalName}), new[] {{ {CodegenUtilities.JoinWithComa(Enumerable.Range(startInvokers, endInvokers - startInvokers).Select(i => i.ToString()))} }} }},"); _classTemplate.AddDefine("className", className); _classTemplate.AddDefine("originalName", originalName); _classTemplate.AddDefine("namespaceName", namespaceName); @@ -157,12 +161,13 @@ namespace mROA.Codegen var coCodegenRepoCode = _methodRepoTemplate.Compile(); _indexerTemplate.AddDefine("level", apiLevel.ToString()); _indexerTemplate.AddDefine("len", invokers.Count.ToString()); - + var providerCode = _indexerTemplate.Compile(); #if !DONT_ADD - context.AddSource("GeneratedInvokersCollection.g.cs", SourceText.From(coCodegenRepoCode, Encoding.UTF8)); + context.AddSource("GeneratedInvokersCollection.g.cs", + SourceText.From(coCodegenRepoCode, Encoding.UTF8)); context.AddSource("GeneratedIndexProvider.g.cs", SourceText.From(providerCode, Encoding.UTF8)); - + #endif } @@ -293,7 +298,6 @@ namespace mROA.Codegen if (!isVoid) prefix = "return " + prefix; - } sb.AppendLine("\t\t\t" + prefix + caller + postfix + ";"); @@ -379,12 +383,14 @@ namespace mROA.Codegen var index = _currentInternalCallIndex; var parameters = (eventSymbol.Type as INamedTypeSymbol)!.TypeArguments.ToList(); - var parametersDeclaration = string.Join(", ", CodegenUtilities.JoinWithComa(Enumerable.Range(0, parameters.Count).Select(i => "p" + i))); + var parametersDeclaration = string.Join(", ", + CodegenUtilities.JoinWithComa(Enumerable.Range(0, parameters.Count).Select(i => "p" + i))); + - var pi = 0; - var transferParameters = CodegenUtilities.JoinWithComa(parameters.Select(i => (i, pi++)).Where(i => !ParameterFilterForType(i.i)) - .Select(i => "p" + i.Item2)); + var transferParameters = CodegenUtilities.JoinWithComa(parameters.Select(i => (i, pi++)) + .Where(i => !ParameterFilterForType(i.i)) + .Select(i => "p" + i.Item2)); var requestIndex = parameters.FindIndex(i => i.Name == "RequestContext"); if (requestIndex != -1) @@ -396,7 +402,8 @@ namespace mROA.Codegen eventBinderTemplate.AddDefine("type", baseType.ToUnityString()); eventBinderTemplate.AddDefine("eventName", eventSymbol.Name); eventBinderTemplate.AddDefine("parametersDeclaration", parametersDeclaration); - eventBinderTemplate.AddDefine("commandId", $"context.CallIndexProvider.GetIndices(typeof({baseType.ToUnityString()}))[{index}]"); + eventBinderTemplate.AddDefine("commandId", + $"context.CallIndexProvider.GetIndices(typeof({baseType.ToUnityString()}))[{index}]"); eventBinderTemplate.AddDefine("transferParameters", transferParameters); var eventBinderCode = eventBinderTemplate.Compile(); document.Insert("eventBinder", eventBinderCode); @@ -407,7 +414,8 @@ namespace mROA.Codegen var level = "\t\t\t"; int pi = 0; - var parameters = ((INamedTypeSymbol)eventSymbol.Type).TypeArguments.Select(i => (i, pi++)).ToImmutableArray(); + var parameters = ((INamedTypeSymbol)eventSymbol.Type).TypeArguments.Select(i => (i, pi++)) + .ToImmutableArray(); var parsingParameters = parameters.RemoveAll(i => ParameterFilterForType(i.i)).ToList(); var parameterTypes = string.Join(", ", $"{string.Join(", ", parsingParameters.Select(p => $"typeof({p.i.ToUnityString()})"))}"); @@ -466,7 +474,8 @@ namespace mROA.Codegen var parameterTypes = string.Join(", ", $"{string.Join(", ", method.Parameters.Select(p => "typeof(" + p.Type.ToUnityString() + ")"))}"); var parameterInserts = string.Join(", ", - method.Parameters.Select(p => CodegenUtilities.Caster(p.Type, "parameters[" + method.Parameters.IndexOf(p) + "]"))); + method.Parameters.Select(p => + CodegenUtilities.Caster(p.Type, "parameters[" + method.Parameters.IndexOf(p) + "]"))); var invokerTemplate = (TemplateDocument)_methodInvokerOriginal.Clone(); invokerTemplate.AddDefine("isVoid", "false"); @@ -505,7 +514,8 @@ namespace mROA.Codegen var parameterTypes = string.Join(", ", $"{string.Join(", ", method.Parameters.Select(p => $"typeof({p.Type.ToUnityString()})"))}"); var parameterInserts = string.Join(", ", - method.Parameters.Take(method.Parameters.Length - 1).Select(p => CodegenUtilities.Caster(p.Type, "parameters[" + method.Parameters.IndexOf(p) + "]"))); + method.Parameters.Take(method.Parameters.Length - 1).Select(p => + CodegenUtilities.Caster(p.Type, "parameters[" + method.Parameters.IndexOf(p) + "]"))); var valueInsert = CodegenUtilities.Caster(method.Parameters.Last().Type, "parameters[" + (method.Parameters.Length - 1) + "]"); @@ -538,7 +548,8 @@ namespace mROA.Codegen backend = invokerTemplate.Compile(); } - frontend = $"set => CallAsync(CallIndices[{_currentInternalCallIndex++}], new System.Object[] {{ {parametersArray} }}).Wait();"; + frontend = + $"set => CallAsync(CallIndices[{_currentInternalCallIndex++}], new System.Object[] {{ {parametersArray} }}).Wait();"; } propsCollection.Add((frontend, method)); @@ -588,9 +599,10 @@ namespace mROA.Codegen GeneratorSyntaxContext context) { var ids = (InterfaceDeclarationSyntax)context.Node; - + // Go through all attributes of the class. - foreach (var attributeSyntax in ids.AttributeLists.SelectMany(attributeListSyntax => attributeListSyntax.Attributes)) + foreach (var attributeSyntax in ids.AttributeLists.SelectMany(attributeListSyntax => + attributeListSyntax.Attributes)) { if (context.SemanticModel.GetSymbolInfo(attributeSyntax).Symbol is not IMethodSymbol attributeSymbol) continue; // if we can't get the symbol, ignore it @@ -599,10 +611,10 @@ namespace mROA.Codegen // Check the full name of the [Report] attribute. if (attributeName == $"mROA.Implementation.Attributes.SharedObjectInterfaceAttribute") - return (ids,true); + return (ids, true); } - return (ids ,false); + return (ids, false); } public static List CollectMembers(INamedTypeSymbol type) @@ -614,15 +626,15 @@ namespace mROA.Codegen return methods.OrderBy(i => i.Name).ToList(); } } - + public static class CodegenExtensions { public static string ToUnityString(this ITypeSymbol type) { var parts = type.ToDisplayParts(); - return parts.Any(i => i.Kind == SymbolDisplayPartKind.Keyword) - ? parts.ToUnityString() + return parts.Any(i => i.Kind == SymbolDisplayPartKind.Keyword) + ? parts.ToUnityString() : type.ToDisplayString(); } From abc3bda88e9b97cf2f954e4de62597f779e3df48 Mon Sep 17 00:00:00 2001 From: Ivan Ansimov Date: Mon, 14 Jul 2025 20:01:40 +0300 Subject: [PATCH 3/6] extract TemplateDocument loading logic --- mROA.Codegen/CodeTemplate.cs | 49 +++++++++++++ mROA.Codegen/mROASourceGenerator.cs | 102 ++++++++++++---------------- 2 files changed, 93 insertions(+), 58 deletions(-) create mode 100644 mROA.Codegen/CodeTemplate.cs diff --git a/mROA.Codegen/CodeTemplate.cs b/mROA.Codegen/CodeTemplate.cs new file mode 100644 index 0000000..f0b3a85 --- /dev/null +++ b/mROA.Codegen/CodeTemplate.cs @@ -0,0 +1,49 @@ +using System; +using mROA.CodegenTools; +using mROA.CodegenTools.Reading; + +namespace mROA.Codegen +{ + public class CodeTemplate + { + private const string MethodRepoTemplateName = "MethodRepo.cstmpl"; + private const string ProxyTemplateName = "Proxy.cstmpl"; + private const string RemoteTypeBinderTemplateName = "RemoteTypeBinder.cstmpl"; + private const string PartialInterfaceTemplateName = "PartialInterface.cstmpl"; + private const string IndexProviderTemplateName = "IndexProvider.cstmpl"; + private const string SyncInvokerTag = "syncInvoker"; + + private TemplateDocument? _proxy; + private TemplateDocument? _indexerProvider; + private TemplateDocument? _remoteTypeBinder; + private TemplateDocument? _partialInterface; + private TemplateDocument? _methodRepo; + private TemplateDocument? _methodInvoker; + + public TemplateDocument Proxy => _proxy + ?? throw new InvalidOperationException(); + public TemplateDocument IndexerProvider => _indexerProvider + ?? throw new InvalidOperationException(); + public TemplateDocument RemoteTypeBinder => _remoteTypeBinder + ?? throw new InvalidOperationException(); + public TemplateDocument PartialInterface => _partialInterface + ?? throw new InvalidOperationException(); + public TemplateDocument MethodRepo => _methodRepo + ?? throw new InvalidOperationException(); + public TemplateDocument MethodInvoker => _methodInvoker + ?? throw new InvalidOperationException(); + + public void LoadTemplates() + { + _proxy = TemplateReader.FromEmbeddedResource(ProxyTemplateName); + _indexerProvider = TemplateReader.FromEmbeddedResource(IndexProviderTemplateName); + _remoteTypeBinder = TemplateReader.FromEmbeddedResource(RemoteTypeBinderTemplateName); + _partialInterface = TemplateReader.FromEmbeddedResource(PartialInterfaceTemplateName); + _methodRepo = TemplateReader.FromEmbeddedResource(MethodRepoTemplateName); + + var innerMethodSection = MethodRepo[SyncInvokerTag] as InnerTemplateSection + ?? throw new InvalidOperationException(); + _methodInvoker = innerMethodSection.InnerTemplate; + } + } +} \ No newline at end of file diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index dee53b3..ac70a80 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; using mROA.CodegenTools; -using mROA.CodegenTools.Reading; #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. @@ -30,26 +29,13 @@ namespace mROA.Codegen private static readonly Predicate ParameterFilterForType = i => i.Name is "CancellationToken" or "RequestContext"; - private TemplateDocument _indexerTemplate; - private TemplateDocument _binderTemplate; - private TemplateDocument _classTemplate; - private TemplateDocument _classTemplateOriginal; - private TemplateDocument _interfaceTemplate; - private TemplateDocument _interfaceTemplateOriginal; - private TemplateDocument _methodInvokerOriginal; - private TemplateDocument _methodRepoTemplate; + private readonly CodeTemplate _codeTemplate = new(); + private int _currentInternalCallIndex; - public void Initialize(IncrementalGeneratorInitializationContext context) { - _methodRepoTemplate = TemplateReader.FromEmbeddedResource("MethodRepo.cstmpl"); - _methodInvokerOriginal = - ((InnerTemplateSection)_methodRepoTemplate["syncInvoker"]!).InnerTemplate; - _classTemplateOriginal = TemplateReader.FromEmbeddedResource("Proxy.cstmpl"); - _binderTemplate = TemplateReader.FromEmbeddedResource("RemoteTypeBinder.cstmpl"); - _interfaceTemplateOriginal = TemplateReader.FromEmbeddedResource("PartialInterface.cstmpl"); - _indexerTemplate = TemplateReader.FromEmbeddedResource("IndexProvider.cstmpl"); + _codeTemplate.LoadTemplates(); var syntaxes = context.SyntaxProvider.CreateSyntaxProvider( (static (node, _) => node is InterfaceDeclarationSyntax), @@ -65,7 +51,7 @@ namespace mROA.Codegen { var totalMethods = new List(); - _indexerTemplate.AddDefine("namespace", compilation.AssemblyName!); + _codeTemplate.IndexerProvider.AddDefine("namespace", compilation.AssemblyName!); var invokers = new List(); var declarations = classes.ToList(); var apiLevel = 0; @@ -93,7 +79,7 @@ namespace mROA.Codegen className = className.TrimStart('I') + "Proxy"; - _classTemplate = (TemplateDocument)_classTemplateOriginal.Clone(); + var classTemplate = (TemplateDocument)_codeTemplate.Proxy.Clone(); var propertiesAccessMethods = new List<(string, IMethodSymbol)>(); int startInvokers = invokers.Count; @@ -105,7 +91,7 @@ namespace mROA.Codegen classSymbol); continue; default: - GenerateDeclaredMethod(method, invokers, classSymbol); + GenerateDeclaredMethod(classTemplate, method, invokers, classSymbol); break; } @@ -126,43 +112,43 @@ namespace mROA.Codegen impl = $"public {propertySymbol.Type.ToUnityString()} {symbol.Name} {{ {getter.Item1} {setter.Item1} }}"; - _classTemplate.Insert("methods", impl); + classTemplate.Insert("methods", impl); // declaredMethods.Add(impl); break; case IEventSymbol eventSymbol: - _classTemplate.Insert("methods", + classTemplate.Insert("methods", $"public event {eventSymbol.Type.ToUnityString()}? {eventSymbol.Name};"); // declaredMethods.Add( // $"public event {eventSymbol.Type.ToDisplayString()}? {eventSymbol.Name};"); break; } - GenerateEventImplementation(classSymbol, invokers, context); + GenerateEventImplementation(classTemplate, classSymbol, invokers, context); var endInvokers = invokers.Count; - _indexerTemplate.Insert("indexSpan", + _codeTemplate.IndexerProvider.Insert("indexSpan", $"{{ typeof({originalName}), new[] {{ {CodegenUtilities.JoinWithComa(Enumerable.Range(startInvokers, endInvokers - startInvokers).Select(i => i.ToString()))} }} }},"); - _classTemplate.AddDefine("className", className); - _classTemplate.AddDefine("originalName", originalName); - _classTemplate.AddDefine("namespaceName", namespaceName); + classTemplate.AddDefine("className", className); + classTemplate.AddDefine("originalName", originalName); + classTemplate.AddDefine("namespaceName", namespaceName); - var code = _classTemplate.Compile(); + var code = classTemplate.Compile(); // Add the source code to the compilation. #if !DONT_ADD context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8)); #endif - _indexerTemplate.Insert("remoteTypePair", + _codeTemplate.IndexerProvider.Insert("remoteTypePair", $"{{ typeof({classSymbol.ToUnityString()}), (id, r, c, indices) => new {namespaceName}.{className}(id, r, c, indices) }}"); } if (totalMethods.Count != 0) { - var coCodegenRepoCode = _methodRepoTemplate.Compile(); - _indexerTemplate.AddDefine("level", apiLevel.ToString()); - _indexerTemplate.AddDefine("len", invokers.Count.ToString()); + var coCodegenRepoCode = _codeTemplate.MethodRepo.Compile(); + _codeTemplate.IndexerProvider.AddDefine("level", apiLevel.ToString()); + _codeTemplate.IndexerProvider.AddDefine("len", invokers.Count.ToString()); - var providerCode = _indexerTemplate.Compile(); + var providerCode = _codeTemplate.IndexerProvider.Compile(); #if !DONT_ADD context.AddSource("GeneratedInvokersCollection.g.cs", SourceText.From(coCodegenRepoCode, Encoding.UTF8)); @@ -171,51 +157,51 @@ namespace mROA.Codegen #endif } - if (_indexerTemplate["remoteTypePair+"] != null) + if (_codeTemplate.IndexerProvider["remoteTypePair+"] != null) { - var frontendRepoCode = _binderTemplate.Compile(); + var frontendRepoCode = _codeTemplate.RemoteTypeBinder.Compile(); #if !DONT_ADD context.AddSource("RemoteTypeBinder.g.cs", SourceText.From(frontendRepoCode, Encoding.UTF8)); #endif } } - private void GenerateEventImplementation(INamedTypeSymbol classSymbol, List invokers, + private void GenerateEventImplementation(TemplateDocument classTemplate,INamedTypeSymbol classSymbol, List invokers, SourceProductionContext context) { var events = classSymbol.AllInterfaces.Add(classSymbol).SelectMany(i => i.GetMembers()) .OfType().ToList(); if (events.Count == 0) return; - - _interfaceTemplate = (TemplateDocument)_interfaceTemplateOriginal.Clone(); - _interfaceTemplate.AddDefine("name", classSymbol.Name); - _interfaceTemplate.AddDefine("namespace", classSymbol.ContainingNamespace.ToDisplayString()); + + var interfaceTemplate = (TemplateDocument)_codeTemplate.PartialInterface.Clone(); + interfaceTemplate.AddDefine("name", classSymbol.Name); + interfaceTemplate.AddDefine("namespace", classSymbol.ContainingNamespace.ToDisplayString()); var objectBinderTemplate = - (TemplateDocument)((InnerTemplateSection)_binderTemplate["objectBinderTemplate"]!).InnerTemplate + (TemplateDocument)((InnerTemplateSection)_codeTemplate.RemoteTypeBinder["objectBinderTemplate"]!).InnerTemplate .Clone(); foreach (var currentEvent in events) { var additionalMethod = GenerateMethodExternalCaller(currentEvent, out var signature); - _classTemplate.Insert("methods", additionalMethod); + classTemplate.Insert("methods", additionalMethod); // declaredMethods.Add(additionalMethod); - _interfaceTemplate.Insert("signature", signature); + interfaceTemplate.Insert("signature", signature); GenerateEventCode(currentEvent, invokers, classSymbol); GenerateBinderCode(currentEvent, classSymbol, objectBinderTemplate); } objectBinderTemplate.AddDefine("type", classSymbol.ToUnityString()); - var partialInterface = _interfaceTemplate.Compile(); + var partialInterface = interfaceTemplate.Compile(); var binder = objectBinderTemplate.Compile(); - _binderTemplate.Insert("eventBinder", binder); + _codeTemplate.RemoteTypeBinder.Insert("eventBinder", binder); #if !DONT_ADD context.AddSource($"{classSymbol.Name}.g.cs", SourceText.From(partialInterface, Encoding.UTF8)); #endif } - private string GenerateMethodExternalCaller(IEventSymbol eventSymbol, out string interfaceSignature) + private static string GenerateMethodExternalCaller(IEventSymbol eventSymbol, out string interfaceSignature) { const string level = "\t\t"; var parameters = ((INamedTypeSymbol)eventSymbol.Type).TypeArguments; @@ -232,7 +218,7 @@ namespace mROA.Codegen return caller; } - private void GenerateDeclaredMethod(IMethodSymbol method, List invokers, INamedTypeSymbol baseInterface) + private void GenerateDeclaredMethod(TemplateDocument classTemplate, IMethodSymbol method, List invokers, INamedTypeSymbol baseInterface) { var sb = new StringBuilder(); @@ -303,7 +289,7 @@ namespace mROA.Codegen sb.AppendLine("\t\t\t" + prefix + caller + postfix + ";"); sb.AppendLine("\t\t}"); - _classTemplate.Insert("methods", sb.ToString()); + classTemplate.Insert("methods", sb.ToString()); // declaredMethods.Add(sb.ToString()); var parameterTypes = string.Join(", ", @@ -349,7 +335,7 @@ namespace mROA.Codegen if (isAsync) { var invokerTemplate = - (TemplateDocument)((InnerTemplateSection)_methodRepoTemplate["asyncInvoker"]!).InnerTemplate + (TemplateDocument)((InnerTemplateSection)_codeTemplate.MethodRepo["asyncInvoker"]!).InnerTemplate .Clone(); invokerTemplate.AddDefine("isVoid", isVoid.ToString().ToLower()); invokerTemplate.AddDefine("returnType", CodegenUtilities.ExtractTaskType(method.ReturnType)); @@ -361,7 +347,7 @@ namespace mROA.Codegen } else { - var invokerTemplate = (TemplateDocument)_methodInvokerOriginal.Clone(); + var invokerTemplate = (TemplateDocument)_codeTemplate.MethodInvoker.Clone(); invokerTemplate.AddDefine("isVoid", isVoid.ToString().ToLower()); invokerTemplate.AddDefine("returnType", isVoid ? "void" : method.ReturnType.ToUnityString()); invokerTemplate.AddDefine("parametersType", parameterTypes); @@ -371,7 +357,7 @@ namespace mROA.Codegen backend = invokerTemplate.Compile(); } - _methodRepoTemplate.Insert("invoker", backend); + _codeTemplate.MethodRepo.Insert("invoker", backend); invokers.Add(backend); } @@ -445,7 +431,7 @@ namespace mROA.Codegen {level} return null; {level} }}"; - var invokerTemplate = (TemplateDocument)_methodInvokerOriginal.Clone(); + var invokerTemplate = (TemplateDocument)_codeTemplate.MethodInvoker.Clone(); invokerTemplate.AddDefine("isVoid", "true"); invokerTemplate.AddDefine("returnType", "void"); invokerTemplate.AddDefine("parametersType", parameterTypes); @@ -453,7 +439,7 @@ namespace mROA.Codegen invokerTemplate.AddDefine("funcInvoking", funcInvoking); invokerTemplate.AddDefine("isTrusted", "true"); var backend = invokerTemplate.Compile(); - _methodRepoTemplate.Insert("invoker", backend); + _codeTemplate.MethodRepo.Insert("invoker", backend); invokers.Add(backend); } @@ -477,7 +463,7 @@ namespace mROA.Codegen method.Parameters.Select(p => CodegenUtilities.Caster(p.Type, "parameters[" + method.Parameters.IndexOf(p) + "]"))); - var invokerTemplate = (TemplateDocument)_methodInvokerOriginal.Clone(); + var invokerTemplate = (TemplateDocument)_codeTemplate.MethodInvoker.Clone(); invokerTemplate.AddDefine("isVoid", "false"); invokerTemplate.AddDefine("returnType", method.ReturnType.ToUnityString()); invokerTemplate.AddDefine("parametersType", parameterTypes); @@ -490,7 +476,7 @@ namespace mROA.Codegen } else { - var invokerTemplate = (TemplateDocument)_methodInvokerOriginal.Clone(); + var invokerTemplate = (TemplateDocument)_codeTemplate.MethodInvoker.Clone(); invokerTemplate.AddDefine("isVoid", "false"); invokerTemplate.AddDefine("returnType", method.ReturnType.ToUnityString()); invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString()); @@ -519,7 +505,7 @@ namespace mROA.Codegen var valueInsert = CodegenUtilities.Caster(method.Parameters.Last().Type, "parameters[" + (method.Parameters.Length - 1) + "]"); - var invokerTemplate = (TemplateDocument)_methodInvokerOriginal.Clone(); + var invokerTemplate = (TemplateDocument)_codeTemplate.MethodInvoker.Clone(); invokerTemplate.AddDefine("isVoid", "true"); @@ -534,7 +520,7 @@ namespace mROA.Codegen } else { - var invokerTemplate = (TemplateDocument)_methodInvokerOriginal.Clone(); + var invokerTemplate = (TemplateDocument)_codeTemplate.MethodInvoker.Clone(); invokerTemplate.AddDefine("isVoid", "true"); invokerTemplate.AddDefine("returnType", method.ReturnType.ToUnityString()); @@ -553,7 +539,7 @@ namespace mROA.Codegen } propsCollection.Add((frontend, method)); - _methodRepoTemplate.Insert("invoker", backend); + _codeTemplate.MethodRepo.Insert("invoker", backend); invokers.Add(backend); } } From ec4c008d4c06dc3ab987f1a080627428d92e0667 Mon Sep 17 00:00:00 2001 From: Ivan Ansimov Date: Mon, 14 Jul 2025 21:18:36 +0300 Subject: [PATCH 4/6] refactor creation of syntax provider --- mROA.Codegen/mROASourceGenerator.cs | 64 ++++++++++++++--------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index ac70a80..48c4c94 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Text; +using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; @@ -23,6 +24,8 @@ namespace mROA.Codegen [Generator] public class mROAGenerator : IIncrementalGenerator { + private const string SharedObjectInterfaceAttributeName = "SharedObjectInterface"; + private static readonly Predicate ParameterFilter = i => i.Type.Name is "CancellationToken" or "RequestContext"; @@ -30,7 +33,7 @@ namespace mROA.Codegen i => i.Name is "CancellationToken" or "RequestContext"; private readonly CodeTemplate _codeTemplate = new(); - + private int _currentInternalCallIndex; public void Initialize(IncrementalGeneratorInitializationContext context) @@ -38,14 +41,31 @@ namespace mROA.Codegen _codeTemplate.LoadTemplates(); var syntaxes = context.SyntaxProvider.CreateSyntaxProvider( - (static (node, _) => node is InterfaceDeclarationSyntax), - static (node, _) => CodegenUtilities.ContainsSoiAttribute(node)).Where(i => i.usefull) - .Select((node, _) => node.node); + NodeIsInterfaceWithSharedObjectInterfaceAttribute, + TransformToInterfaceDeclarationSyntax); - context.RegisterSourceOutput(context.CompilationProvider.Combine(syntaxes.Collect()), + var incrementalValueProvider = context.CompilationProvider.Combine(syntaxes.Collect()); + context.RegisterSourceOutput(incrementalValueProvider, (productionContext, pair) => GenerateCode(productionContext, pair.Left, pair.Right)); } + private static InterfaceDeclarationSyntax TransformToInterfaceDeclarationSyntax(GeneratorSyntaxContext context, + CancellationToken _) + { + if (context.Node is not InterfaceDeclarationSyntax interfaceSyntax) + throw new InvalidOperationException(); + return interfaceSyntax; + } + + private static bool NodeIsInterfaceWithSharedObjectInterfaceAttribute(SyntaxNode node, CancellationToken _) + { + if (node is not InterfaceDeclarationSyntax interfaceSyntax) + return false; + + var attributes = interfaceSyntax.AttributeLists.SelectMany(list => list.Attributes); + return attributes.Any(attribute => attribute.ToFullString() == SharedObjectInterfaceAttributeName); + } + private void GenerateCode(SourceProductionContext context, Compilation compilation, ImmutableArray classes) { @@ -166,19 +186,20 @@ namespace mROA.Codegen } } - private void GenerateEventImplementation(TemplateDocument classTemplate,INamedTypeSymbol classSymbol, List invokers, - SourceProductionContext context) + private void GenerateEventImplementation(TemplateDocument classTemplate, INamedTypeSymbol classSymbol, + List invokers, SourceProductionContext context) { var events = classSymbol.AllInterfaces.Add(classSymbol).SelectMany(i => i.GetMembers()) .OfType().ToList(); if (events.Count == 0) return; - + var interfaceTemplate = (TemplateDocument)_codeTemplate.PartialInterface.Clone(); interfaceTemplate.AddDefine("name", classSymbol.Name); interfaceTemplate.AddDefine("namespace", classSymbol.ContainingNamespace.ToDisplayString()); var objectBinderTemplate = - (TemplateDocument)((InnerTemplateSection)_codeTemplate.RemoteTypeBinder["objectBinderTemplate"]!).InnerTemplate + (TemplateDocument)((InnerTemplateSection)_codeTemplate.RemoteTypeBinder["objectBinderTemplate"]!) + .InnerTemplate .Clone(); foreach (var currentEvent in events) { @@ -218,7 +239,8 @@ namespace mROA.Codegen return caller; } - private void GenerateDeclaredMethod(TemplateDocument classTemplate, IMethodSymbol method, List invokers, INamedTypeSymbol baseInterface) + private void GenerateDeclaredMethod(TemplateDocument classTemplate, IMethodSymbol method, List invokers, + INamedTypeSymbol baseInterface) { var sb = new StringBuilder(); @@ -581,28 +603,6 @@ namespace mROA.Codegen return generics.Length == 0 ? "void" : generics[0].ToUnityString(); } - public static (InterfaceDeclarationSyntax node, bool usefull) ContainsSoiAttribute( - GeneratorSyntaxContext context) - { - var ids = (InterfaceDeclarationSyntax)context.Node; - - // Go through all attributes of the class. - foreach (var attributeSyntax in ids.AttributeLists.SelectMany(attributeListSyntax => - attributeListSyntax.Attributes)) - { - if (context.SemanticModel.GetSymbolInfo(attributeSyntax).Symbol is not IMethodSymbol attributeSymbol) - continue; // if we can't get the symbol, ignore it - - var attributeName = attributeSymbol.ContainingType.ToDisplayString(); - - // Check the full name of the [Report] attribute. - if (attributeName == $"mROA.Implementation.Attributes.SharedObjectInterfaceAttribute") - return (ids, true); - } - - return (ids, false); - } - public static List CollectMembers(INamedTypeSymbol type) { var methods = type.GetMembers().OfType().ToList(); From 1cde4b0ed0c53e440132943885fd72f3bd6e1383 Mon Sep 17 00:00:00 2001 From: Ivan Ansimov Date: Tue, 15 Jul 2025 16:37:06 +0300 Subject: [PATCH 5/6] encapsulate template logic --- mROA.Codegen/CodeTemplate.cs | 49 ---- mROA.Codegen/TemplateDocumentExtensions.cs | 16 ++ mROA.Codegen/Templates/EventBinderTemplate.cs | 46 ++++ .../Templates/IndexProviderTemplate.cs | 45 ++++ mROA.Codegen/Templates/InvokerTemplate.cs | 46 ++++ mROA.Codegen/Templates/MethodRepoTemplate.cs | 31 +++ .../Templates/ObjectBinderTemplate.cs | 30 +++ .../Templates/PartialInterfaceTemplate.cs | 28 +++ mROA.Codegen/Templates/ProxyTemplate.cs | 34 +++ .../Templates/RemoteTypeBinderTemplate.cs | 23 ++ mROA.Codegen/Templates/TemplateView.cs | 45 ++++ mROA.Codegen/mROASourceGenerator.cs | 231 +++++++++--------- 12 files changed, 453 insertions(+), 171 deletions(-) delete mode 100644 mROA.Codegen/CodeTemplate.cs create mode 100644 mROA.Codegen/TemplateDocumentExtensions.cs create mode 100644 mROA.Codegen/Templates/EventBinderTemplate.cs create mode 100644 mROA.Codegen/Templates/IndexProviderTemplate.cs create mode 100644 mROA.Codegen/Templates/InvokerTemplate.cs create mode 100644 mROA.Codegen/Templates/MethodRepoTemplate.cs create mode 100644 mROA.Codegen/Templates/ObjectBinderTemplate.cs create mode 100644 mROA.Codegen/Templates/PartialInterfaceTemplate.cs create mode 100644 mROA.Codegen/Templates/ProxyTemplate.cs create mode 100644 mROA.Codegen/Templates/RemoteTypeBinderTemplate.cs create mode 100644 mROA.Codegen/Templates/TemplateView.cs diff --git a/mROA.Codegen/CodeTemplate.cs b/mROA.Codegen/CodeTemplate.cs deleted file mode 100644 index f0b3a85..0000000 --- a/mROA.Codegen/CodeTemplate.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using mROA.CodegenTools; -using mROA.CodegenTools.Reading; - -namespace mROA.Codegen -{ - public class CodeTemplate - { - private const string MethodRepoTemplateName = "MethodRepo.cstmpl"; - private const string ProxyTemplateName = "Proxy.cstmpl"; - private const string RemoteTypeBinderTemplateName = "RemoteTypeBinder.cstmpl"; - private const string PartialInterfaceTemplateName = "PartialInterface.cstmpl"; - private const string IndexProviderTemplateName = "IndexProvider.cstmpl"; - private const string SyncInvokerTag = "syncInvoker"; - - private TemplateDocument? _proxy; - private TemplateDocument? _indexerProvider; - private TemplateDocument? _remoteTypeBinder; - private TemplateDocument? _partialInterface; - private TemplateDocument? _methodRepo; - private TemplateDocument? _methodInvoker; - - public TemplateDocument Proxy => _proxy - ?? throw new InvalidOperationException(); - public TemplateDocument IndexerProvider => _indexerProvider - ?? throw new InvalidOperationException(); - public TemplateDocument RemoteTypeBinder => _remoteTypeBinder - ?? throw new InvalidOperationException(); - public TemplateDocument PartialInterface => _partialInterface - ?? throw new InvalidOperationException(); - public TemplateDocument MethodRepo => _methodRepo - ?? throw new InvalidOperationException(); - public TemplateDocument MethodInvoker => _methodInvoker - ?? throw new InvalidOperationException(); - - public void LoadTemplates() - { - _proxy = TemplateReader.FromEmbeddedResource(ProxyTemplateName); - _indexerProvider = TemplateReader.FromEmbeddedResource(IndexProviderTemplateName); - _remoteTypeBinder = TemplateReader.FromEmbeddedResource(RemoteTypeBinderTemplateName); - _partialInterface = TemplateReader.FromEmbeddedResource(PartialInterfaceTemplateName); - _methodRepo = TemplateReader.FromEmbeddedResource(MethodRepoTemplateName); - - var innerMethodSection = MethodRepo[SyncInvokerTag] as InnerTemplateSection - ?? throw new InvalidOperationException(); - _methodInvoker = innerMethodSection.InnerTemplate; - } - } -} \ No newline at end of file diff --git a/mROA.Codegen/TemplateDocumentExtensions.cs b/mROA.Codegen/TemplateDocumentExtensions.cs new file mode 100644 index 0000000..8889bd1 --- /dev/null +++ b/mROA.Codegen/TemplateDocumentExtensions.cs @@ -0,0 +1,16 @@ +using System; +using mROA.CodegenTools; + +namespace mROA.Codegen +{ + public static class TemplateDocumentExtensions + { + public static TemplateDocument CloneInnerTemplate(this TemplateDocument template, string tag) + { + var innerTemplate = template[tag] as InnerTemplateSection + ?? throw new InvalidOperationException(); + var clone = innerTemplate.InnerTemplate.Clone(); + return (TemplateDocument)clone; + } + } +} \ No newline at end of file diff --git a/mROA.Codegen/Templates/EventBinderTemplate.cs b/mROA.Codegen/Templates/EventBinderTemplate.cs new file mode 100644 index 0000000..5c325cb --- /dev/null +++ b/mROA.Codegen/Templates/EventBinderTemplate.cs @@ -0,0 +1,46 @@ +using mROA.CodegenTools; + +namespace mROA.Codegen.Templates +{ + public class EventBinderTemplate : TemplateView + { + private const string CallFilterTag = "callFilter"; + private const string TypeTag = "type"; + private const string EventNameTag = "eventName"; + private const string ParametersDeclarationTag = "parametersDeclaration"; + private const string CommandIdTag = "commandId"; + private const string TransferParametersTag = "transferParameters"; + + public EventBinderTemplate(TemplateDocument template) : base(template) { } + + public void DefineCallFilter(string value) + { + Define(CallFilterTag, value); + } + + public void DefineType(string value) + { + Define(TypeTag, value); + } + + public void DefineEventName(string value) + { + Define(EventNameTag, value); + } + + public void DefineParametersDeclaration(string value) + { + Define(ParametersDeclarationTag, value); + } + + public void DefineCommandIdTag(string value) + { + Define(CommandIdTag, value); + } + + public void DefineTransferParameters(string value) + { + Define(TransferParametersTag, value); + } + } +} \ No newline at end of file diff --git a/mROA.Codegen/Templates/IndexProviderTemplate.cs b/mROA.Codegen/Templates/IndexProviderTemplate.cs new file mode 100644 index 0000000..cac9637 --- /dev/null +++ b/mROA.Codegen/Templates/IndexProviderTemplate.cs @@ -0,0 +1,45 @@ +namespace mROA.Codegen.Templates +{ + public class IndexProviderTemplate : TemplateView + { + private const string TemplateFile = "IndexProvider.cstmpl"; + + private const string NamespaceTag = "namespace"; + private const string LevelTag = "level"; + private const string LenTag = "len"; + private const string IndexSpanTag = "indexSpan"; + private const string RemoteTypePairTag = "remoteTypePair"; + + public IndexProviderTemplate() : base(TemplateFile) { } + + public void DefineNamespace(string value) + { + Define(NamespaceTag, value); + } + + public void DefineLevel(string value) + { + Define(LevelTag, value); + } + + public void DefineLen(string value) + { + Define(LenTag, value); + } + + public void InsertIndexSpan(string value) + { + Insert(IndexSpanTag, value); + } + + public void InsertRemoteTypePair(string value) + { + Insert(RemoteTypePairTag, value); + } + + public bool IsRemoteTypePairInserted() + { + return Inserted(RemoteTypePairTag); + } + } +} \ No newline at end of file diff --git a/mROA.Codegen/Templates/InvokerTemplate.cs b/mROA.Codegen/Templates/InvokerTemplate.cs new file mode 100644 index 0000000..4373de2 --- /dev/null +++ b/mROA.Codegen/Templates/InvokerTemplate.cs @@ -0,0 +1,46 @@ +using mROA.CodegenTools; + +namespace mROA.Codegen.Templates +{ + public class InvokerTemplate : TemplateView + { + private const string IsVoidTag = "isVoid"; + private const string ReturnTypeTag = "returnType"; + private const string ParametersTypeTag = "parametersType"; + private const string SuitableTypeTag = "suitableType"; + private const string FuncInvokingTag = "funcInvoking"; + private const string IsTrustedTag = "isTrusted"; + + public InvokerTemplate(TemplateDocument template) : base(template) { } + + public void DefineIsVoid(string value) + { + Define(IsVoidTag, value); + } + + public void DefineReturnType(string value) + { + Define(ReturnTypeTag, value); + } + + public void DefineParametersType(string value) + { + Define(ParametersTypeTag, value); + } + + public void DefineSuitableType(string value) + { + Define(SuitableTypeTag, value); + } + + public void DefineFuncInvoking(string value) + { + Define(FuncInvokingTag, value); + } + + public void DefineIsTrusted(string value) + { + Define(IsTrustedTag, value); + } + } +} \ No newline at end of file diff --git a/mROA.Codegen/Templates/MethodRepoTemplate.cs b/mROA.Codegen/Templates/MethodRepoTemplate.cs new file mode 100644 index 0000000..8f028b6 --- /dev/null +++ b/mROA.Codegen/Templates/MethodRepoTemplate.cs @@ -0,0 +1,31 @@ +namespace mROA.Codegen.Templates +{ + public class MethodRepoTemplate : TemplateView + { + private const string TemplateFile = "MethodRepo.cstmpl"; + + private const string SyncInvokerTemplate = "syncInvoker"; + private const string AsyncInvokerTemplate = "asyncInvoker"; + + private const string InvokerTag = "invoke"; + + public MethodRepoTemplate() : base(TemplateFile) { } + + public void InsertInvoke(string value) + { + Insert(InvokerTag, value); + } + + public InvokerTemplate CloneInnerSyncInvoker() + { + var template = CloneInner(SyncInvokerTemplate); + return new InvokerTemplate(template); + } + + public InvokerTemplate CloneInnerAsyncInvoker() + { + var template = CloneInner(AsyncInvokerTemplate); + return new InvokerTemplate(template); + } + } +} \ No newline at end of file diff --git a/mROA.Codegen/Templates/ObjectBinderTemplate.cs b/mROA.Codegen/Templates/ObjectBinderTemplate.cs new file mode 100644 index 0000000..57221b4 --- /dev/null +++ b/mROA.Codegen/Templates/ObjectBinderTemplate.cs @@ -0,0 +1,30 @@ +using mROA.CodegenTools; + +namespace mROA.Codegen.Templates +{ + public partial class ObjectBinderTemplate : TemplateView + { + private const string EventBinderTemplateTag = "eventBinderTemplate"; + + private const string TypeTag = "type"; + private const string EventBinderTag = "eventBinder"; + + public ObjectBinderTemplate(TemplateDocument template) : base(template) { } + + public void DefineType(string value) + { + Define(TypeTag, value); + } + + public void InsertEventBinder(string value) + { + Insert(EventBinderTag, value); + } + + public EventBinderTemplate CloneInnerEventBinder() + { + var template = CloneInner(EventBinderTemplateTag); + return new EventBinderTemplate(template); + } + } +} \ No newline at end of file diff --git a/mROA.Codegen/Templates/PartialInterfaceTemplate.cs b/mROA.Codegen/Templates/PartialInterfaceTemplate.cs new file mode 100644 index 0000000..2441e2a --- /dev/null +++ b/mROA.Codegen/Templates/PartialInterfaceTemplate.cs @@ -0,0 +1,28 @@ +namespace mROA.Codegen.Templates +{ + public class PartialInterfaceTemplate : TemplateView + { + private const string TemplateFile = "PartialInterface.cstmpl"; + + private const string NameTag = "name"; + private const string NamespaceTag = "namespace"; + private const string SignatureTag = "signature"; + + public PartialInterfaceTemplate() : base(TemplateFile) { } + + public void DefineName(string value) + { + Define(NameTag, value); + } + + public void DefineNamespace(string value) + { + Define(NamespaceTag, value); + } + + public void InsertSignature(string value) + { + Insert(SignatureTag, value); + } + } +} \ No newline at end of file diff --git a/mROA.Codegen/Templates/ProxyTemplate.cs b/mROA.Codegen/Templates/ProxyTemplate.cs new file mode 100644 index 0000000..d66f03e --- /dev/null +++ b/mROA.Codegen/Templates/ProxyTemplate.cs @@ -0,0 +1,34 @@ +namespace mROA.Codegen.Templates +{ + public class ProxyTemplate : TemplateView + { + private const string TemplateFile = "Proxy.cstmpl"; + + private const string ClassNameTag = "className"; + private const string OriginalNameTag = "originalName"; + private const string NamespaceNameTag= "namespaceName"; + private const string MethodsTag = "methods"; + + public ProxyTemplate() : base(TemplateFile) { } + + public void DefineClassName(string value) + { + Define(ClassNameTag, value); + } + + public void DefineOriginalName(string value) + { + Define(OriginalNameTag, value); + } + + public void DefineNamespaceName(string value) + { + Define(NamespaceNameTag, value); + } + + public void InsertMethods(string value) + { + Insert(MethodsTag, value); + } + } +} \ No newline at end of file diff --git a/mROA.Codegen/Templates/RemoteTypeBinderTemplate.cs b/mROA.Codegen/Templates/RemoteTypeBinderTemplate.cs new file mode 100644 index 0000000..9aa9add --- /dev/null +++ b/mROA.Codegen/Templates/RemoteTypeBinderTemplate.cs @@ -0,0 +1,23 @@ +namespace mROA.Codegen.Templates +{ + public class RemoteTypeBinderTemplate : TemplateView + { + private const string TemplateFile = "RemoteTypeBinder.cstmpl"; + + private const string ObjectBinderTemplateTag = "objectBinderTemplate"; + private const string EventBinderTag = "eventBinder"; + + public RemoteTypeBinderTemplate() : base(TemplateFile) { } + + public ObjectBinderTemplate CloneInnerObjectBinder() + { + var template = CloneInner(ObjectBinderTemplateTag); + return new ObjectBinderTemplate(template); + } + + public void InsertEventBinder(string value) + { + Insert(EventBinderTag, value); + } + } +} \ No newline at end of file diff --git a/mROA.Codegen/Templates/TemplateView.cs b/mROA.Codegen/Templates/TemplateView.cs new file mode 100644 index 0000000..75fa1d4 --- /dev/null +++ b/mROA.Codegen/Templates/TemplateView.cs @@ -0,0 +1,45 @@ +using mROA.CodegenTools; +using mROA.CodegenTools.Reading; + +namespace mROA.Codegen.Templates +{ + public abstract class TemplateView + { + private readonly TemplateDocument _template; + + protected TemplateView(string templateFile) + { + _template = TemplateReader.FromEmbeddedResource(templateFile); + } + + protected TemplateView(TemplateDocument template) + { + _template = template; + } + + public string Compile() + { + return _template.Compile(); + } + + protected void Define(string tag, string value) + { + _template.AddDefine(tag, value); + } + + protected void Insert(string tag, string value) + { + _template.Insert(tag, value); + } + + protected bool Inserted(string tag) + { + return _template[$"{tag}+"] != null; + } + + protected TemplateDocument CloneInner(string tag) + { + return _template.CloneInnerTemplate(tag); + } + } +} \ No newline at end of file diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index 48c4c94..881ab21 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -9,7 +9,7 @@ using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; -using mROA.CodegenTools; +using mROA.Codegen.Templates; #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. @@ -31,15 +31,11 @@ namespace mROA.Codegen private static readonly Predicate ParameterFilterForType = i => i.Name is "CancellationToken" or "RequestContext"; - - private readonly CodeTemplate _codeTemplate = new(); - + private int _currentInternalCallIndex; public void Initialize(IncrementalGeneratorInitializationContext context) { - _codeTemplate.LoadTemplates(); - var syntaxes = context.SyntaxProvider.CreateSyntaxProvider( NodeIsInterfaceWithSharedObjectInterfaceAttribute, TransformToInterfaceDeclarationSyntax); @@ -69,9 +65,15 @@ namespace mROA.Codegen private void GenerateCode(SourceProductionContext context, Compilation compilation, ImmutableArray classes) { + var methodRepoTemplate = new MethodRepoTemplate(); + var typeBinder = new RemoteTypeBinderTemplate(); + var indexProviderTemplate = new IndexProviderTemplate(); var totalMethods = new List(); - _codeTemplate.IndexerProvider.AddDefine("namespace", compilation.AssemblyName!); + if (compilation.AssemblyName == null) + throw new InvalidOperationException(); + + indexProviderTemplate.DefineNamespace(compilation.AssemblyName); var invokers = new List(); var declarations = classes.ToList(); var apiLevel = 0; @@ -99,7 +101,7 @@ namespace mROA.Codegen className = className.TrimStart('I') + "Proxy"; - var classTemplate = (TemplateDocument)_codeTemplate.Proxy.Clone(); + var proxyTemplate = new ProxyTemplate(); var propertiesAccessMethods = new List<(string, IMethodSymbol)>(); int startInvokers = invokers.Count; @@ -107,11 +109,11 @@ namespace mROA.Codegen switch (method.MethodKind) { case MethodKind.PropertyGet or MethodKind.PropertySet: - GeneratePropertyMethod(method, propertiesAccessMethods, invokers, + GeneratePropertyMethod(methodRepoTemplate, method, propertiesAccessMethods, invokers, classSymbol); continue; default: - GenerateDeclaredMethod(classTemplate, method, invokers, classSymbol); + GenerateDeclaredMethod(proxyTemplate, methodRepoTemplate, method, invokers, classSymbol); break; } @@ -132,43 +134,40 @@ namespace mROA.Codegen impl = $"public {propertySymbol.Type.ToUnityString()} {symbol.Name} {{ {getter.Item1} {setter.Item1} }}"; - classTemplate.Insert("methods", impl); + proxyTemplate.InsertMethods(impl); // declaredMethods.Add(impl); break; case IEventSymbol eventSymbol: - classTemplate.Insert("methods", - $"public event {eventSymbol.Type.ToUnityString()}? {eventSymbol.Name};"); + proxyTemplate.InsertMethods($"public event {eventSymbol.Type.ToUnityString()}? {eventSymbol.Name};"); // declaredMethods.Add( // $"public event {eventSymbol.Type.ToDisplayString()}? {eventSymbol.Name};"); break; } - GenerateEventImplementation(classTemplate, classSymbol, invokers, context); + GenerateEventImplementation(proxyTemplate, methodRepoTemplate, typeBinder, classSymbol, invokers, context); var endInvokers = invokers.Count; - _codeTemplate.IndexerProvider.Insert("indexSpan", - $"{{ typeof({originalName}), new[] {{ {CodegenUtilities.JoinWithComa(Enumerable.Range(startInvokers, endInvokers - startInvokers).Select(i => i.ToString()))} }} }},"); - classTemplate.AddDefine("className", className); - classTemplate.AddDefine("originalName", originalName); - classTemplate.AddDefine("namespaceName", namespaceName); + indexProviderTemplate.InsertIndexSpan($"{{ typeof({originalName}), new[] {{ {CodegenUtilities.JoinWithComa(Enumerable.Range(startInvokers, endInvokers - startInvokers).Select(i => i.ToString()))} }} }},"); + proxyTemplate.DefineClassName(className); + proxyTemplate.DefineOriginalName(originalName); + proxyTemplate.DefineNamespaceName(namespaceName); - var code = classTemplate.Compile(); + var code = proxyTemplate.Compile(); // Add the source code to the compilation. #if !DONT_ADD context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8)); #endif - _codeTemplate.IndexerProvider.Insert("remoteTypePair", - $"{{ typeof({classSymbol.ToUnityString()}), (id, r, c, indices) => new {namespaceName}.{className}(id, r, c, indices) }}"); + indexProviderTemplate.InsertRemoteTypePair($"{{ typeof({classSymbol.ToUnityString()}), (id, r, c, indices) => new {namespaceName}.{className}(id, r, c, indices) }}"); } if (totalMethods.Count != 0) { - var coCodegenRepoCode = _codeTemplate.MethodRepo.Compile(); - _codeTemplate.IndexerProvider.AddDefine("level", apiLevel.ToString()); - _codeTemplate.IndexerProvider.AddDefine("len", invokers.Count.ToString()); + var coCodegenRepoCode = methodRepoTemplate.Compile(); + indexProviderTemplate.DefineLevel(apiLevel.ToString()); + indexProviderTemplate.DefineLen(invokers.Count.ToString()); - var providerCode = _codeTemplate.IndexerProvider.Compile(); + var providerCode = indexProviderTemplate.Compile(); #if !DONT_ADD context.AddSource("GeneratedInvokersCollection.g.cs", SourceText.From(coCodegenRepoCode, Encoding.UTF8)); @@ -177,16 +176,16 @@ namespace mROA.Codegen #endif } - if (_codeTemplate.IndexerProvider["remoteTypePair+"] != null) + if (indexProviderTemplate.IsRemoteTypePairInserted()) { - var frontendRepoCode = _codeTemplate.RemoteTypeBinder.Compile(); + var frontendRepoCode = typeBinder.Compile(); #if !DONT_ADD context.AddSource("RemoteTypeBinder.g.cs", SourceText.From(frontendRepoCode, Encoding.UTF8)); #endif } } - private void GenerateEventImplementation(TemplateDocument classTemplate, INamedTypeSymbol classSymbol, + private void GenerateEventImplementation(ProxyTemplate proxyTemplate, MethodRepoTemplate methodRepoTemplate, RemoteTypeBinderTemplate remoteTypeBinder, INamedTypeSymbol classSymbol, List invokers, SourceProductionContext context) { var events = classSymbol.AllInterfaces.Add(classSymbol).SelectMany(i => i.GetMembers()) @@ -194,28 +193,26 @@ namespace mROA.Codegen if (events.Count == 0) return; - var interfaceTemplate = (TemplateDocument)_codeTemplate.PartialInterface.Clone(); - interfaceTemplate.AddDefine("name", classSymbol.Name); - interfaceTemplate.AddDefine("namespace", classSymbol.ContainingNamespace.ToDisplayString()); - var objectBinderTemplate = - (TemplateDocument)((InnerTemplateSection)_codeTemplate.RemoteTypeBinder["objectBinderTemplate"]!) - .InnerTemplate - .Clone(); + var partialInterfaceTemplate = new PartialInterfaceTemplate(); + partialInterfaceTemplate.DefineName(classSymbol.Name); + partialInterfaceTemplate.DefineNamespace(classSymbol.ContainingNamespace.ToDisplayString()); + + var objectBinderTemplate = remoteTypeBinder.CloneInnerObjectBinder(); foreach (var currentEvent in events) { var additionalMethod = GenerateMethodExternalCaller(currentEvent, out var signature); - classTemplate.Insert("methods", additionalMethod); + proxyTemplate.InsertMethods(additionalMethod); // declaredMethods.Add(additionalMethod); - interfaceTemplate.Insert("signature", signature); - GenerateEventCode(currentEvent, invokers, classSymbol); - GenerateBinderCode(currentEvent, classSymbol, objectBinderTemplate); + partialInterfaceTemplate.InsertSignature(signature); + GenerateEventCode(methodRepoTemplate, currentEvent, invokers, classSymbol); + GenerateBinderCode(objectBinderTemplate, currentEvent, classSymbol); } - - objectBinderTemplate.AddDefine("type", classSymbol.ToUnityString()); - var partialInterface = interfaceTemplate.Compile(); + + objectBinderTemplate.DefineType(classSymbol.ToUnityString()); + var partialInterface = partialInterfaceTemplate.Compile(); var binder = objectBinderTemplate.Compile(); - _codeTemplate.RemoteTypeBinder.Insert("eventBinder", binder); + remoteTypeBinder.InsertEventBinder(binder); #if !DONT_ADD context.AddSource($"{classSymbol.Name}.g.cs", SourceText.From(partialInterface, Encoding.UTF8)); @@ -239,7 +236,7 @@ namespace mROA.Codegen return caller; } - private void GenerateDeclaredMethod(TemplateDocument classTemplate, IMethodSymbol method, List invokers, + private void GenerateDeclaredMethod(ProxyTemplate proxyTemplate, MethodRepoTemplate methodRepoTemplate, IMethodSymbol method, List invokers, INamedTypeSymbol baseInterface) { var sb = new StringBuilder(); @@ -311,7 +308,7 @@ namespace mROA.Codegen sb.AppendLine("\t\t\t" + prefix + caller + postfix + ";"); sb.AppendLine("\t\t}"); - classTemplate.Insert("methods", sb.ToString()); + proxyTemplate.InsertMethods(sb.ToString()); // declaredMethods.Add(sb.ToString()); var parameterTypes = string.Join(", ", @@ -356,38 +353,35 @@ namespace mROA.Codegen if (isAsync) { - var invokerTemplate = - (TemplateDocument)((InnerTemplateSection)_codeTemplate.MethodRepo["asyncInvoker"]!).InnerTemplate - .Clone(); - invokerTemplate.AddDefine("isVoid", isVoid.ToString().ToLower()); - invokerTemplate.AddDefine("returnType", CodegenUtilities.ExtractTaskType(method.ReturnType)); - invokerTemplate.AddDefine("parametersType", parameterTypes); - invokerTemplate.AddDefine("suitableType", baseInterface.ToUnityString()); - invokerTemplate.AddDefine("funcInvoking", funcInvoking); - invokerTemplate.AddDefine("isTrusted", (!isUntrusted).ToString().ToLower()); + var invokerTemplate = methodRepoTemplate.CloneInnerAsyncInvoker(); + invokerTemplate.DefineIsVoid(isVoid.ToString().ToLower()); + invokerTemplate.DefineReturnType(CodegenUtilities.ExtractTaskType(method.ReturnType)); + invokerTemplate.DefineParametersType(parameterTypes); + invokerTemplate.DefineSuitableType(baseInterface.ToUnityString()); + invokerTemplate.DefineFuncInvoking(funcInvoking); + invokerTemplate.DefineIsTrusted((!isUntrusted).ToString().ToLower()); backend = invokerTemplate.Compile(); } else { - var invokerTemplate = (TemplateDocument)_codeTemplate.MethodInvoker.Clone(); - invokerTemplate.AddDefine("isVoid", isVoid.ToString().ToLower()); - invokerTemplate.AddDefine("returnType", isVoid ? "void" : method.ReturnType.ToUnityString()); - invokerTemplate.AddDefine("parametersType", parameterTypes); - invokerTemplate.AddDefine("suitableType", baseInterface.ToUnityString()); - invokerTemplate.AddDefine("funcInvoking", funcInvoking); - invokerTemplate.AddDefine("isTrusted", (!isUntrusted).ToString().ToLower()); + var invokerTemplate = methodRepoTemplate.CloneInnerSyncInvoker(); + invokerTemplate.DefineIsVoid(isVoid.ToString().ToLower()); + invokerTemplate.DefineReturnType(isVoid ? "void" : method.ReturnType.ToUnityString()); + invokerTemplate.DefineParametersType(parameterTypes); + invokerTemplate.DefineSuitableType(baseInterface.ToUnityString()); + invokerTemplate.DefineFuncInvoking(funcInvoking); + invokerTemplate.DefineIsTrusted((!isUntrusted).ToString().ToLower()); backend = invokerTemplate.Compile(); } - _codeTemplate.MethodRepo.Insert("invoker", backend); + methodRepoTemplate.InsertInvoke(backend); invokers.Add(backend); } - private void GenerateBinderCode(IEventSymbol eventSymbol, INamedTypeSymbol baseType, TemplateDocument document) + private void GenerateBinderCode(ObjectBinderTemplate objectBinderTemplate, IEventSymbol eventSymbol, INamedTypeSymbol baseType) { - var eventBinderTemplate = - (TemplateDocument)((InnerTemplateSection)document["eventBinderTemplate"]!).InnerTemplate.Clone(); + var eventBinderTemplate = objectBinderTemplate.CloneInnerEventBinder(); var index = _currentInternalCallIndex; var parameters = (eventSymbol.Type as INamedTypeSymbol)!.TypeArguments.ToList(); @@ -399,25 +393,24 @@ namespace mROA.Codegen var transferParameters = CodegenUtilities.JoinWithComa(parameters.Select(i => (i, pi++)) .Where(i => !ParameterFilterForType(i.i)) .Select(i => "p" + i.Item2)); - + var requestIndex = parameters.FindIndex(i => i.Name == "RequestContext"); if (requestIndex != -1) { var callFilter = $"\n\r\t\t\tif(ownerId == p{requestIndex}.OwnerId) return;"; - eventBinderTemplate.AddDefine("callFilter", callFilter); + eventBinderTemplate.DefineCallFilter(callFilter); } - eventBinderTemplate.AddDefine("type", baseType.ToUnityString()); - eventBinderTemplate.AddDefine("eventName", eventSymbol.Name); - eventBinderTemplate.AddDefine("parametersDeclaration", parametersDeclaration); - eventBinderTemplate.AddDefine("commandId", - $"context.CallIndexProvider.GetIndices(typeof({baseType.ToUnityString()}))[{index}]"); - eventBinderTemplate.AddDefine("transferParameters", transferParameters); + eventBinderTemplate.DefineType(baseType.ToUnityString()); + eventBinderTemplate.DefineEventName(eventSymbol.Name); + eventBinderTemplate.DefineParametersDeclaration(parametersDeclaration); + eventBinderTemplate.DefineCommandIdTag($"context.CallIndexProvider.GetIndices(typeof({baseType.ToUnityString()}))[{index}]"); + eventBinderTemplate.DefineTransferParameters(transferParameters); var eventBinderCode = eventBinderTemplate.Compile(); - document.Insert("eventBinder", eventBinderCode); + objectBinderTemplate.InsertEventBinder(eventBinderCode); } - private void GenerateEventCode(IEventSymbol eventSymbol, List invokers, ITypeSymbol baseInterface) + private void GenerateEventCode(MethodRepoTemplate methodRepoTemplate, IEventSymbol eventSymbol, List invokers, ITypeSymbol baseInterface) { var level = "\t\t\t"; @@ -453,21 +446,21 @@ namespace mROA.Codegen {level} return null; {level} }}"; - var invokerTemplate = (TemplateDocument)_codeTemplate.MethodInvoker.Clone(); - invokerTemplate.AddDefine("isVoid", "true"); - invokerTemplate.AddDefine("returnType", "void"); - invokerTemplate.AddDefine("parametersType", parameterTypes); - invokerTemplate.AddDefine("suitableType", baseInterface.ToUnityString()); - invokerTemplate.AddDefine("funcInvoking", funcInvoking); - invokerTemplate.AddDefine("isTrusted", "true"); + var invokerTemplate = methodRepoTemplate.CloneInnerSyncInvoker(); + invokerTemplate.DefineIsVoid("true"); + invokerTemplate.DefineReturnType("void"); + invokerTemplate.DefineParametersType(parameterTypes); + invokerTemplate.DefineSuitableType(baseInterface.ToUnityString()); + invokerTemplate.DefineFuncInvoking(funcInvoking); + invokerTemplate.DefineIsTrusted("true"); var backend = invokerTemplate.Compile(); - _codeTemplate.MethodRepo.Insert("invoker", backend); + methodRepoTemplate.InsertInvoke(backend); invokers.Add(backend); } - private void GeneratePropertyMethod(IMethodSymbol method, - List<(string, IMethodSymbol)> propsCollection, List invokers, INamedTypeSymbol baseInterace) + private void GeneratePropertyMethod(MethodRepoTemplate methodRepoTemplate, IMethodSymbol method, + List<(string, IMethodSymbol)> propsCollection, List invokers, INamedTypeSymbol baseInterface) { string frontend; string backend; @@ -485,26 +478,25 @@ namespace mROA.Codegen method.Parameters.Select(p => CodegenUtilities.Caster(p.Type, "parameters[" + method.Parameters.IndexOf(p) + "]"))); - var invokerTemplate = (TemplateDocument)_codeTemplate.MethodInvoker.Clone(); - invokerTemplate.AddDefine("isVoid", "false"); - invokerTemplate.AddDefine("returnType", method.ReturnType.ToUnityString()); - invokerTemplate.AddDefine("parametersType", parameterTypes); - invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString()); - invokerTemplate.AddDefine("funcInvoking", - $"(i as {method.ContainingType.ToUnityString()})[{parameterInserts}]"); - invokerTemplate.AddDefine("isTrusted", "true"); + var invokerTemplate = methodRepoTemplate.CloneInnerSyncInvoker(); + invokerTemplate.DefineIsVoid("false"); + invokerTemplate.DefineReturnType(method.ReturnType.ToUnityString()); + invokerTemplate.DefineParametersType(parameterTypes); + invokerTemplate.DefineSuitableType(baseInterface.ToUnityString()); + invokerTemplate.DefineFuncInvoking($"(i as {method.ContainingType.ToUnityString()})[{parameterInserts}]"); + invokerTemplate.DefineIsTrusted("true"); backend = invokerTemplate.Compile(); } else { - var invokerTemplate = (TemplateDocument)_codeTemplate.MethodInvoker.Clone(); - invokerTemplate.AddDefine("isVoid", "false"); - invokerTemplate.AddDefine("returnType", method.ReturnType.ToUnityString()); - invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString()); - invokerTemplate.AddDefine("funcInvoking", - $"(i as {method.ContainingType.ToUnityString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name}"); - invokerTemplate.AddDefine("isTrusted", "true"); + var invokerTemplate = methodRepoTemplate.CloneInnerSyncInvoker(); + invokerTemplate.DefineIsVoid("false"); + invokerTemplate.DefineReturnType(method.ReturnType.ToUnityString()); + invokerTemplate.DefineParametersType(""); + invokerTemplate.DefineSuitableType(baseInterface.ToUnityString()); + invokerTemplate.DefineFuncInvoking($"(i as {method.ContainingType.ToUnityString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name}"); + invokerTemplate.DefineIsTrusted("true"); backend = invokerTemplate.Compile(); } @@ -527,31 +519,26 @@ namespace mROA.Codegen var valueInsert = CodegenUtilities.Caster(method.Parameters.Last().Type, "parameters[" + (method.Parameters.Length - 1) + "]"); - var invokerTemplate = (TemplateDocument)_codeTemplate.MethodInvoker.Clone(); - - - invokerTemplate.AddDefine("isVoid", "true"); - invokerTemplate.AddDefine("returnType", method.ReturnType.ToUnityString()); - invokerTemplate.AddDefine("parametersType", parameterTypes); - invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString()); - invokerTemplate.AddDefine("funcInvoking", - $"(i as {method.ContainingType.ToUnityString()})[{parameterInserts}] = {valueInsert}"); - invokerTemplate.AddDefine("isTrusted", "true"); + + var invokerTemplate = methodRepoTemplate.CloneInnerSyncInvoker(); + invokerTemplate.DefineIsVoid("true"); + invokerTemplate.DefineReturnType(method.ReturnType.ToUnityString()); + invokerTemplate.DefineParametersType(parameterTypes); + invokerTemplate.DefineSuitableType(baseInterface.ToUnityString()); + invokerTemplate.DefineFuncInvoking($"(i as {method.ContainingType.ToUnityString()})[{parameterInserts}] = {valueInsert}"); + invokerTemplate.DefineIsTrusted("true"); backend = invokerTemplate.Compile(); } else { - var invokerTemplate = (TemplateDocument)_codeTemplate.MethodInvoker.Clone(); - - invokerTemplate.AddDefine("isVoid", "true"); - invokerTemplate.AddDefine("returnType", method.ReturnType.ToUnityString()); - invokerTemplate.AddDefine("parametersType", - $"typeof({method.Parameters.First().Type.ToUnityString()})"); - invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString()); - invokerTemplate.AddDefine("funcInvoking", - $"(i as {method.ContainingType.ToUnityString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name} = {CodegenUtilities.Caster((method.AssociatedSymbol as IPropertySymbol)!.Type, "parameters[0]")}"); - invokerTemplate.AddDefine("isTrusted", "true"); + var invokerTemplate = methodRepoTemplate.CloneInnerSyncInvoker(); + invokerTemplate.DefineIsVoid("true"); + invokerTemplate.DefineReturnType(method.ReturnType.ToUnityString()); + invokerTemplate.DefineParametersType($"typeof({method.Parameters.First().Type.ToUnityString()})"); + invokerTemplate.DefineSuitableType(baseInterface.ToUnityString()); + invokerTemplate.DefineFuncInvoking($"(i as {method.ContainingType.ToUnityString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name} = {CodegenUtilities.Caster((method.AssociatedSymbol as IPropertySymbol)!.Type, "parameters[0]")}"); + invokerTemplate.DefineIsTrusted("true"); backend = invokerTemplate.Compile(); } @@ -561,7 +548,7 @@ namespace mROA.Codegen } propsCollection.Add((frontend, method)); - _codeTemplate.MethodRepo.Insert("invoker", backend); + methodRepoTemplate.InsertInvoke(backend); invokers.Add(backend); } } From 151710b7a8dd3f94192abc51ddd1f426576afb61 Mon Sep 17 00:00:00 2001 From: Ivan Ansimov Date: Mon, 21 Jul 2025 14:43:48 +0300 Subject: [PATCH 6/6] fix typo --- mROA.Codegen/Templates/MethodRepoTemplate.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mROA.Codegen/Templates/MethodRepoTemplate.cs b/mROA.Codegen/Templates/MethodRepoTemplate.cs index 8f028b6..9be1276 100644 --- a/mROA.Codegen/Templates/MethodRepoTemplate.cs +++ b/mROA.Codegen/Templates/MethodRepoTemplate.cs @@ -7,7 +7,7 @@ namespace mROA.Codegen.Templates private const string SyncInvokerTemplate = "syncInvoker"; private const string AsyncInvokerTemplate = "asyncInvoker"; - private const string InvokerTag = "invoke"; + private const string InvokerTag = "invoker"; public MethodRepoTemplate() : base(TemplateFile) { }