Клинап

This commit is contained in:
2025-03-29 19:31:10 +03:00
parent 361b4cd3f6
commit 5cc53d72fd
18 changed files with 359 additions and 390 deletions
+12 -14
View File
@@ -1,32 +1,30 @@
using System; namespace mROA.Codegen.Tools
namespace mROA.CodegenTools
{ {
public class DefineTemplateSection : ITagged public class DefineTemplateSection : ITagged
{ {
public TemplateDocument Context { get; set; }
public string StoredText { get; }
private readonly string _tag;
public DefineTemplateSection(string storedText, string tag, TemplateDocument context) public DefineTemplateSection(string storedText, string tag, TemplateDocument context)
{ {
StoredText = storedText; StoredText = storedText;
_tag = tag; Tag = tag;
Context = context; Context = context;
} }
public string Tag => _tag; public string StoredText { get; }
public TemplateDocument Context { get; set; }
public string Tag { get; }
public int TargetLength => StoredText.Length; public int TargetLength => StoredText.Length;
public object Clone()
{
return new DefineTemplateSection(StoredText, Tag, Context);
}
public override string ToString() public override string ToString()
{ {
return StoredText; return StoredText;
} }
public object Clone()
{
return new DefineTemplateSection(StoredText, _tag, Context);
}
} }
} }
+1 -2
View File
@@ -1,6 +1,6 @@
using System; using System;
namespace mROA.CodegenTools namespace mROA.Codegen.Tools
{ {
public interface ITemplateSection : ICloneable public interface ITemplateSection : ICloneable
{ {
@@ -13,7 +13,6 @@ namespace mROA.CodegenTools
string Bake(); string Bake();
} }
public interface ITagged : ITemplateSection public interface ITagged : ITemplateSection
{ {
string Tag { get; } string Tag { get; }
+10 -11
View File
@@ -1,25 +1,24 @@
namespace mROA.CodegenTools namespace mROA.Codegen.Tools
{ {
public class InnerTemplateSection : ITemplateSection, ITagged public class InnerTemplateSection : ITemplateSection, ITagged
{ {
private readonly string _tag;
public TemplateDocument Context { get; set; }
public int TargetLength => 0;
public string Tag => _tag;
public TemplateDocument InnerTemplate { get; }
public InnerTemplateSection(string tag, TemplateDocument innerTemplate, TemplateDocument context) public InnerTemplateSection(string tag, TemplateDocument innerTemplate, TemplateDocument context)
{ {
_tag = tag; Tag = tag;
Context = context; Context = context;
InnerTemplate = innerTemplate; InnerTemplate = innerTemplate;
} }
public TemplateDocument InnerTemplate { get; }
public string Tag { get; }
public TemplateDocument Context { get; set; }
public int TargetLength => 0;
public object Clone() public object Clone()
{ {
return new InnerTemplateSection(_tag, InnerTemplate, Context); return new InnerTemplateSection(Tag, InnerTemplate, Context);
} }
} }
} }
+32 -32
View File
@@ -1,24 +1,45 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace mROA.CodegenTools namespace mROA.Codegen.Tools
{ {
public class InsertTemplateSection : ITagged, IBaking public class InsertTemplateSection : ITagged, IBaking
{ {
private object _insertedValue;
private string _tag;
public string Tag => _tag;
public TemplateDocument Context { get; set; }
public readonly List<string> Parameters; public readonly List<string> Parameters;
private object _insertedValue;
public InsertTemplateSection(string tag, TemplateDocument context, params string[] parameters) public InsertTemplateSection(string tag, TemplateDocument context, params string[] parameters)
{ {
_tag = tag; Tag = tag;
Parameters = parameters.ToList(); Parameters = parameters.ToList();
Context = context; Context = context;
} }
public string Bake()
{
switch (_insertedValue)
{
case null:
return string.Empty;
case string s:
return s;
default:
return ((ITemplateSection)_insertedValue).ToString();
}
}
public string Tag { get; private set; }
public TemplateDocument Context { get; set; }
public int TargetLength => 0;
public object Clone()
{
return new InsertTemplateSection(Tag, Context, Parameters.ToArray());
}
private bool IsInserted(object value) private bool IsInserted(object value)
{ {
if (Parameters.IndexOf("r") == -1) return false; if (Parameters.IndexOf("r") == -1) return false;
@@ -32,7 +53,7 @@ namespace mROA.CodegenTools
{ {
var currentIndex = Context.Parts.IndexOf(this); var currentIndex = Context.Parts.IndexOf(this);
var clone = (InsertTemplateSection)MemberwiseClone(); var clone = (InsertTemplateSection)MemberwiseClone();
clone._tag += "+"; clone.Tag += "+";
clone._insertedValue = value; clone._insertedValue = value;
@@ -47,40 +68,19 @@ namespace mROA.CodegenTools
if (sepIndex == -1) if (sepIndex == -1)
return; return;
Context.Parts.Insert(currentIndex, new LiteralTemplateSection(Context[Parameters[sepIndex + 1]].ToString(), Context)); Context.Parts.Insert(currentIndex,
new LiteralTemplateSection(Context[Parameters[sepIndex + 1]].ToString(), Context));
} }
public void Setup(object value) public void Setup(object value)
{ {
if (!(value is string) && !(value is ITemplateSection) ) if (!(value is string) && !(value is ITemplateSection))
return; return;
if (IsInserted(value)) if (IsInserted(value))
return; return;
_insertedValue = value; _insertedValue = value;
} }
public int TargetLength => 0;
public string Bake()
{
switch (_insertedValue)
{
case null:
return string.Empty;
case string s:
return s;
default:
return ((ITemplateSection)_insertedValue).ToString();
}
}
public object Clone()
{
return new InsertTemplateSection(_tag, Context, Parameters.ToArray());
}
} }
} }
+13 -17
View File
@@ -1,43 +1,39 @@
using System.Linq; namespace mROA.Codegen.Tools
namespace mROA.CodegenTools
{ {
public class LinkTemplateSection : ITemplateSection, IBaking public class LinkTemplateSection : ITemplateSection, IBaking
{ {
private readonly string _linkedTag;
public LinkTemplateSection(string linkedTag, TemplateDocument context) public LinkTemplateSection(string linkedTag, TemplateDocument context)
{ {
_linkedTag = linkedTag; LinkedTag = linkedTag;
Context = context; Context = context;
} }
public TemplateDocument Context { get; set; } public string LinkedTag { get; }
public string LinkedTag => _linkedTag; public string Bake()
{
return Context[LinkedTag]?.ToString();
}
public TemplateDocument Context { get; set; }
public int TargetLength public int TargetLength
{ {
get get
{ {
var attached = Context[_linkedTag]; var attached = Context[LinkedTag];
return attached?.TargetLength ?? 0; return attached?.TargetLength ?? 0;
} }
} }
public string Bake() public object Clone()
{ {
return Context[_linkedTag]?.ToString(); return new LinkTemplateSection(LinkedTag, Context);
} }
public override string ToString() public override string ToString()
{ {
return $"{nameof(LinkedTag)}: {_linkedTag}"; return $"{nameof(LinkedTag)}: {LinkedTag}";
}
public object Clone()
{
return new LinkTemplateSection(_linkedTag, Context);
} }
} }
} }
+10 -10
View File
@@ -1,8 +1,8 @@
namespace mROA.CodegenTools namespace mROA.Codegen.Tools
{ {
public class LiteralTemplateSection : ITemplateSection, IBaking public class LiteralTemplateSection : ITemplateSection, IBaking
{ {
private string _internalText; private readonly string _internalText;
public LiteralTemplateSection(string internalText, TemplateDocument context) public LiteralTemplateSection(string internalText, TemplateDocument context)
{ {
@@ -10,22 +10,22 @@ namespace mROA.CodegenTools
Context = context; Context = context;
} }
public TemplateDocument Context { get; set; }
public int TargetLength => _internalText.Length;
public string Bake() public string Bake()
{ {
return ToString(); return ToString();
} }
public TemplateDocument Context { get; set; }
public int TargetLength => _internalText.Length;
public object Clone()
{
return new LiteralTemplateSection(_internalText, Context);
}
public override string ToString() public override string ToString()
{ {
return _internalText; return _internalText;
} }
public object Clone()
{
return new LiteralTemplateSection(_internalText, Context);
}
} }
} }
@@ -1,13 +1,10 @@
using System; using System;
namespace mROA.CodegenTools namespace mROA.Codegen.Tools
{ {
public class ProgrammableTextSection : ITemplateSection, IBaking public class ProgrammableTextSection : ITemplateSection, IBaking
{ {
public TemplateDocument Context { get; set; } private readonly Func<object, string> _bakeFunc;
public int TargetLength => 0;
private Func<object, string> _bakeFunc;
public ProgrammableTextSection(Func<object, string> bakeFunc, TemplateDocument context) public ProgrammableTextSection(Func<object, string> bakeFunc, TemplateDocument context)
{ {
@@ -21,6 +18,9 @@ namespace mROA.CodegenTools
return _bakeFunc(Context.AdditionalContext); return _bakeFunc(Context.AdditionalContext);
} }
public TemplateDocument Context { get; set; }
public int TargetLength => 0;
public object Clone() public object Clone()
{ {
return new ProgrammableTextSection(_bakeFunc, Context); return new ProgrammableTextSection(_bakeFunc, Context);
@@ -1,6 +1,6 @@
using System; using System;
namespace mROA.CodegenTools namespace mROA.Codegen.Tools.Reading
{ {
public class DefineSectionReader : LeadingTextSectionReader public class DefineSectionReader : LeadingTextSectionReader
{ {
+1 -3
View File
@@ -1,6 +1,4 @@
using System.Collections.Generic; namespace mROA.Codegen.Tools.Reading
namespace mROA.CodegenTools
{ {
public interface ISectionReader public interface ISectionReader
{ {
@@ -1,6 +1,6 @@
using System; using System;
namespace mROA.CodegenTools namespace mROA.Codegen.Tools.Reading
{ {
public class InnerTemplateSectionReader : LeadingTextSectionReader public class InnerTemplateSectionReader : LeadingTextSectionReader
{ {
@@ -1,6 +1,6 @@
using System.Linq; using System.Linq;
namespace mROA.CodegenTools namespace mROA.Codegen.Tools.Reading
{ {
public class InsertSectionReader : LeadingTextSectionReader public class InsertSectionReader : LeadingTextSectionReader
{ {
@@ -1,23 +1,17 @@
using System; using System;
namespace mROA.CodegenTools namespace mROA.Codegen.Tools.Reading
{ {
public abstract class LeadingTextSectionReader : ISectionReader public abstract class LeadingTextSectionReader : ISectionReader
{ {
private readonly string _tagLeading;
protected int _currentCaretPosition; protected int _currentCaretPosition;
private string _tagLeading;
protected LeadingTextSectionReader(string tagLeading) protected LeadingTextSectionReader(string tagLeading)
{ {
_tagLeading = tagLeading + " "; _tagLeading = tagLeading + " ";
} }
protected int PassCaretToCloseSymbol()
{
_currentCaretPosition = TemplateText.IndexOf(">", _currentCaretPosition, StringComparison.Ordinal) + 1;
return _currentCaretPosition;
}
public string TemplateText { get; set; } public string TemplateText { get; set; }
public int GetNextSectionIndex(int currentIndex) public int GetNextSectionIndex(int currentIndex)
@@ -30,6 +24,12 @@ namespace mROA.CodegenTools
public abstract ITemplateSection ExtractSection(ref int index, TemplateDocument document); public abstract ITemplateSection ExtractSection(ref int index, TemplateDocument document);
protected int PassCaretToCloseSymbol()
{
_currentCaretPosition = TemplateText.IndexOf(">", _currentCaretPosition, StringComparison.Ordinal) + 1;
return _currentCaretPosition;
}
protected string GetTagValue(int from, int to) protected string GetTagValue(int from, int to)
{ {
var realStart = from + 4; var realStart = from + 4;
@@ -1,4 +1,4 @@
namespace mROA.CodegenTools namespace mROA.Codegen.Tools.Reading
{ {
public class LinkSectionReader : LeadingTextSectionReader public class LinkSectionReader : LeadingTextSectionReader
{ {
+8 -12
View File
@@ -4,11 +4,11 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
namespace mROA.CodegenTools namespace mROA.Codegen.Tools.Reading
{ {
public static class TemplateReader public static class TemplateReader
{ {
private static readonly List<Type> ReaderTypes = new List<Type> private static readonly List<Type> ReaderTypes = new()
{ {
typeof(DefineSectionReader), typeof(DefineSectionReader),
typeof(InsertSectionReader), typeof(InsertSectionReader),
@@ -18,8 +18,7 @@ namespace mROA.CodegenTools
public static TemplateDocument Parse(string templateText) public static TemplateDocument Parse(string templateText)
{ {
var currentIndex = 0;
int currentIndex = 0;
var activeReaders = new List<ISectionReader>(); var activeReaders = new List<ISectionReader>();
foreach (var readerType in ReaderTypes) foreach (var readerType in ReaderTypes)
@@ -33,18 +32,17 @@ namespace mROA.CodegenTools
while (currentIndex < templateText.Length) while (currentIndex < templateText.Length)
{ {
List<(ISectionReader reader, int index)> indices = activeReaders.Select(i => ((ISectionReader Readers, int index))(i, i.GetNextSectionIndex(currentIndex))).Where(i => i.index > -1).ToList(); List<(ISectionReader reader, int index)> indices = activeReaders
int minIndex = templateText.Length; .Select(i => ((ISectionReader Readers, int index))(i, i.GetNextSectionIndex(currentIndex)))
.Where(i => i.index > -1).ToList();
var minIndex = templateText.Length;
ISectionReader minReader = null; ISectionReader minReader = null;
if (indices.Count != 0) if (indices.Count != 0)
{ {
minIndex = indices.Min(i => i.index); minIndex = indices.Min(i => i.index);
minReader = indices.FirstOrDefault(i => i.index == minIndex).reader; minReader = indices.FirstOrDefault(i => i.index == minIndex).reader;
if (indices.Count != activeReaders.Count) if (indices.Count != activeReaders.Count) activeReaders = indices.Select(i => i.reader).ToList();
{
activeReaders = indices.Select(i => i.reader).ToList();
}
} }
@@ -62,8 +60,6 @@ namespace mROA.CodegenTools
var section = minReader.ExtractSection(ref currentIndex, doc); var section = minReader.ExtractSection(ref currentIndex, doc);
doc.Parts.Add(section); doc.Parts.Add(section);
} }
} }
return doc; return doc;
+26 -26
View File
@@ -3,37 +3,14 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
namespace mROA.CodegenTools namespace mROA.Codegen.Tools
{ {
public class TemplateDocument : ICloneable public class TemplateDocument : ICloneable
{ {
public List<ITemplateSection> Parts { get; set; } = new List<ITemplateSection>(); public List<ITemplateSection> Parts { get; set; } = new();
public object AdditionalContext { get; set; } public object AdditionalContext { get; set; }
public ITagged? this[string tag] => Parts.OfType<ITagged>().FirstOrDefault(i => i.Tag == tag); public ITagged? this[string tag] => Parts.OfType<ITagged>().FirstOrDefault(i => i.Tag == tag);
public void Insert(string tag, object value)
{
var selectedPart = this[tag];
if (selectedPart is InsertTemplateSection itp)
{
itp.Setup(value);
}
}
public string Compile()
{
var approximatelyLength = Parts.Sum(i => i.TargetLength);
var stringBuilder = new StringBuilder(approximatelyLength);
foreach (var part in Parts.OfType<IBaking>())
{
var baked = part.Bake();
stringBuilder.Append(baked);
}
return stringBuilder.ToString();
}
public object Clone() public object Clone()
{ {
var cloneDoc = new TemplateDocument var cloneDoc = new TemplateDocument
@@ -51,11 +28,34 @@ namespace mROA.CodegenTools
return cloneDoc; return cloneDoc;
} }
public void Insert(string tag, object value)
{
var selectedPart = this[tag];
if (selectedPart is InsertTemplateSection itp) itp.Setup(value);
}
public string Compile()
{
var approximatelyLength = Parts.Sum(i => i.TargetLength);
var stringBuilder = new StringBuilder(approximatelyLength);
foreach (var part in Parts.OfType<IBaking>())
{
var baked = part.Bake();
stringBuilder.Append(baked);
}
return stringBuilder.ToString();
}
public void AddDefine(string tag, string text) public void AddDefine(string tag, string text)
{ {
Parts.Add(new DefineTemplateSection(text, tag, this)); Parts.Add(new DefineTemplateSection(text, tag, this));
} }
public void AddDefine(string tag, object value) => AddDefine(tag, value.ToString()); public void AddDefine(string tag, object value)
{
AddDefine(tag, value.ToString());
}
} }
} }
+5 -5
View File
@@ -4,7 +4,7 @@
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<IsPackable>true</IsPackable> <IsPackable>true</IsPackable>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<LangVersion>latest</LangVersion> <LangVersion>9</LangVersion>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules> <EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
<IsRoslynComponent>true</IsRoslynComponent> <IsRoslynComponent>true</IsRoslynComponent>
@@ -17,7 +17,7 @@
<RepositoryUrl>https://github.com/YaslePoy/mROA</RepositoryUrl> <RepositoryUrl>https://github.com/YaslePoy/mROA</RepositoryUrl>
<RepositoryType>git</RepositoryType> <RepositoryType>git</RepositoryType>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild> <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Version>1.2.0</Version> <Version>2.0.0</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@@ -34,9 +34,9 @@
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="PartialInterface.cstmpl" /> <EmbeddedResource Include="PartialInterface.cstmpl"/>
<EmbeddedResource Include="RemoteEndpoint.cstmpl" /> <EmbeddedResource Include="RemoteEndpoint.cstmpl"/>
<EmbeddedResource Include="RemoteTypeBinder.cstmpl" /> <EmbeddedResource Include="RemoteTypeBinder.cstmpl"/>
<None Remove="MethodRepo.cstmpl"/> <None Remove="MethodRepo.cstmpl"/>
<EmbeddedResource Include="MethodRepo.cstmpl"/> <EmbeddedResource Include="MethodRepo.cstmpl"/>
</ItemGroup> </ItemGroup>
+177 -196
View File
@@ -3,44 +3,49 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text;
using mROA.CodegenTools; using mROA.Codegen.Tools;
using mROA.Codegen.Tools.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.
namespace mROA.Codegen namespace mROA.Codegen
{ {
/// <summary> /// <summary>
/// A sample source generator that creates a custom report based on class properties. The target class should be annotated with the 'Generators.ReportAttribute' attribute. /// A sample source generator that creates a custom report based on class properties. The target class should be
/// When using the source code as a baseline, an incremental source generator is preferable because it reduces the performance overhead. /// annotated with the 'Generators.ReportAttribute' attribute.
/// When using the source code as a baseline, an incremental source generator is preferable because it reduces the
/// performance overhead.
/// </summary> /// </summary>
[Generator] [Generator]
public class mROASourceGenerator : ISourceGenerator public class MRoaSourceGenerator : ISourceGenerator
{ {
private TemplateDocument MethodRepoTemplate; private static readonly Predicate<IParameterSymbol> ParameterFilter =
private TemplateDocument ClassTemplateOriginal;
private TemplateDocument ClassTemplate;
private TemplateDocument InterfaceTemplateOriginal;
private TemplateDocument InterfaceTemplate;
private TemplateDocument BinderTemplate;
private TemplateDocument MethodInvokerOriginal;
private static Predicate<IParameterSymbol> ParameterFilter =
i => i.Type.Name is "CancellationToken" or "RequestContext"; i => i.Type.Name is "CancellationToken" or "RequestContext";
private static Predicate<ITypeSymbol> ParameterFilterForType = private static readonly Predicate<ITypeSymbol> ParameterFilterForType =
i => i.Name is "CancellationToken" or "RequestContext"; i => i.Name is "CancellationToken" or "RequestContext";
private TemplateDocument _binderTemplate;
private TemplateDocument _classTemplate;
private TemplateDocument _classTemplateOriginal;
private TemplateDocument _interfaceTemplate;
private TemplateDocument _interfaceTemplateOriginal;
private TemplateDocument _methodInvokerOriginal;
private TemplateDocument _methodRepoTemplate;
public void Initialize(GeneratorInitializationContext context) public void Initialize(GeneratorInitializationContext context)
{ {
MethodRepoTemplate = TemplateReader.FromEmbeddedResource("MethodRepo.cstmpl"); _methodRepoTemplate = TemplateReader.FromEmbeddedResource("MethodRepo.cstmpl");
MethodInvokerOriginal = _methodInvokerOriginal =
((InnerTemplateSection)MethodRepoTemplate["syncInvoker"])?.InnerTemplate; ((InnerTemplateSection)_methodRepoTemplate["syncInvoker"]!).InnerTemplate;
ClassTemplateOriginal = TemplateReader.FromEmbeddedResource("RemoteEndpoint.cstmpl"); _classTemplateOriginal = TemplateReader.FromEmbeddedResource("RemoteEndpoint.cstmpl");
BinderTemplate = TemplateReader.FromEmbeddedResource("RemoteTypeBinder.cstmpl"); _binderTemplate = TemplateReader.FromEmbeddedResource("RemoteTypeBinder.cstmpl");
InterfaceTemplateOriginal = TemplateReader.FromEmbeddedResource("PartialInterface.cstmpl"); _interfaceTemplateOriginal = TemplateReader.FromEmbeddedResource("PartialInterface.cstmpl");
} }
public void Execute(GeneratorExecutionContext context) public void Execute(GeneratorExecutionContext context)
@@ -52,28 +57,22 @@ namespace mROA.Codegen
var interfaces = new List<InterfaceDeclarationSyntax>(); var interfaces = new List<InterfaceDeclarationSyntax>();
foreach (var tree in trees) foreach (var tree in trees)
{ {
var node = tree.GetRoot() as CompilationUnitSyntax; var node = (CompilationUnitSyntax)tree.GetRoot();
foreach (var member in node.Members) foreach (var member in node.Members)
{
if (member is InterfaceDeclarationSyntax ids) if (member is InterfaceDeclarationSyntax ids)
{
interfaces.Add(ids); interfaces.Add(ids);
}
else if (member is NamespaceDeclarationSyntax nds) else if (member is NamespaceDeclarationSyntax nds)
{
foreach (var inside in nds.Members) foreach (var inside in nds.Members)
if (inside is InterfaceDeclarationSyntax ids2) if (inside is InterfaceDeclarationSyntax ids2)
if (ContainsSOIAttribute(ids2.AttributeLists, context, ids2)) if (ContainsSoiAttribute(ids2.AttributeLists, context, ids2))
interfaces.Add(ids2); interfaces.Add(ids2);
} }
}
}
GenerateCode(context, context.Compilation, interfaces.ToImmutableArray()); GenerateCode(context, context.Compilation, interfaces.ToImmutableArray());
} }
catch (Exception e) catch (Exception)
{ {
Console.WriteLine("ERROR: Unable to load method repository"); Console.WriteLine("ERROR: Unable to load method repository");
} }
@@ -82,10 +81,10 @@ namespace mROA.Codegen
private void GenerateCode(GeneratorExecutionContext context, Compilation compilation, private void GenerateCode(GeneratorExecutionContext context, Compilation compilation,
ImmutableArray<InterfaceDeclarationSyntax> classes) ImmutableArray<InterfaceDeclarationSyntax> classes)
{ {
List<IMethodSymbol> totalMethods = new List<IMethodSymbol>(); var totalMethods = new List<IMethodSymbol>();
List<string> invokers = new List<string>(); var invokers = new List<string>();
var declarations = classes.ToList().OrderBy(i => i.Identifier.Text).ToList(); var declarations = classes.ToList().OrderBy(i => i.Identifier.Text).ToList();
foreach (var classDeclarationSyntax in declarations) foreach (var classDeclarationSyntax in declarations)
{ {
@@ -93,11 +92,10 @@ namespace mROA.Codegen
if (semanticModel.GetDeclaredSymbol(classDeclarationSyntax) is not INamedTypeSymbol classSymbol) if (semanticModel.GetDeclaredSymbol(classDeclarationSyntax) is not INamedTypeSymbol classSymbol)
continue; continue;
List<IMethodSymbol> innerMethods = new List<IMethodSymbol>();
var namespaceName = classSymbol.ContainingNamespace.ToDisplayString(); var namespaceName = classSymbol.ContainingNamespace.ToDisplayString();
var className = classDeclarationSyntax.Identifier.Text; var className = classDeclarationSyntax.Identifier.Text;
innerMethods = CollectMembers(classSymbol); var innerMethods = CollectMembers(classSymbol);
var associated = innerMethods.Select(i => i.AssociatedSymbol).Where(i => i != null) var associated = innerMethods.Select(i => i.AssociatedSymbol).Where(i => i != null)
.Distinct(SymbolEqualityComparer.Default).Cast<ISymbol>().ToList(); .Distinct(SymbolEqualityComparer.Default).Cast<ISymbol>().ToList();
@@ -111,12 +109,10 @@ namespace mROA.Codegen
className = className.TrimStart('I') + "RemoteEndpoint"; className = className.TrimStart('I') + "RemoteEndpoint";
ClassTemplate = (TemplateDocument)ClassTemplateOriginal.Clone(); _classTemplate = (TemplateDocument)_classTemplateOriginal.Clone();
var declaredMethods = new List<string>();
var propertiesAccessMethods = new List<(string, IMethodSymbol)>(); var propertiesAccessMethods = new List<(string, IMethodSymbol)>();
foreach (var method in innerMethods) foreach (var method in innerMethods)
{
switch (method.MethodKind) switch (method.MethodKind)
{ {
case MethodKind.PropertyGet or MethodKind.PropertySet: case MethodKind.PropertyGet or MethodKind.PropertySet:
@@ -124,13 +120,11 @@ namespace mROA.Codegen
classSymbol); classSymbol);
continue; continue;
default: default:
GenerateDeclaredMethod(method, declaredMethods, invokers, classSymbol); GenerateDeclaredMethod(method, invokers, classSymbol);
break; break;
} }
}
foreach (var symbol in associated) foreach (var symbol in associated)
{
switch (symbol) switch (symbol)
{ {
case IPropertySymbol propertySymbol: case IPropertySymbol propertySymbol:
@@ -141,60 +135,51 @@ namespace mROA.Codegen
i.Item2.AssociatedSymbol!.Name == propertySymbol.Name && !i.Item2.ReturnsVoid); i.Item2.AssociatedSymbol!.Name == propertySymbol.Name && !i.Item2.ReturnsVoid);
string impl; string impl;
if (propertySymbol.IsIndexer) if (propertySymbol.IsIndexer)
{
impl = impl =
$"public {propertySymbol.Type.ToDisplayString()} this[{string.Join(", ", propertySymbol.Parameters.Select(p => p.ToDisplayString()))}] {{ {getter.Item1} {setter.Item1} }}"; $"public {propertySymbol.Type.ToUnityString()} this[{string.Join(", ", propertySymbol.Parameters.Select(p => p.ToDisplayString()))}] {{ {getter.Item1} {setter.Item1} }}";
}
else else
{
impl = impl =
$"public {propertySymbol.Type.ToDisplayString()} {symbol.Name} {{ {getter.Item1} {setter.Item1} }}"; $"public {propertySymbol.Type.ToUnityString()} {symbol.Name} {{ {getter.Item1} {setter.Item1} }}";
}
ClassTemplate.Insert("methods", impl); _classTemplate.Insert("methods", impl);
// declaredMethods.Add(impl); // declaredMethods.Add(impl);
break; break;
case IEventSymbol eventSymbol: case IEventSymbol eventSymbol:
ClassTemplate.Insert("methods", _classTemplate.Insert("methods",
$"public event {eventSymbol.Type.ToDisplayString()}? {eventSymbol.Name};"); $"public event {eventSymbol.Type.ToUnityString()}? {eventSymbol.Name};");
// declaredMethods.Add( // declaredMethods.Add(
// $"public event {eventSymbol.Type.ToDisplayString()}? {eventSymbol.Name};"); // $"public event {eventSymbol.Type.ToDisplayString()}? {eventSymbol.Name};");
break; break;
} }
}
GenerateEventImplementation(classSymbol, invokers, context); GenerateEventImplementation(classSymbol, invokers, context);
ClassTemplate.AddDefine("className", className); _classTemplate.AddDefine("className", className);
ClassTemplate.AddDefine("originalName", originalName); _classTemplate.AddDefine("originalName", originalName);
ClassTemplate.AddDefine("namespaceName", namespaceName); _classTemplate.AddDefine("namespaceName", namespaceName);
var code = ClassTemplate.Compile(); var code = _classTemplate.Compile();
// Add the source code to the compilation. // Add the source code to the compilation.
#if !DONT_ADD #if !DONT_ADD
context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8)); context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8));
#endif #endif
BinderTemplate.Insert("remoteTypePair", _binderTemplate.Insert("remoteTypePair",
$"{{ typeof({classSymbol.ToDisplayString()}), typeof({namespaceName}.{className}) }}"); $"{{ typeof({classSymbol.ToUnityString()}), typeof({namespaceName}.{className}) }}");
} }
if (totalMethods.Count != 0) if (totalMethods.Count != 0)
{ {
var methodsStringed = invokers; var coCodegenRepoCode = _methodRepoTemplate.Compile();
var coCodegenRepoCode = MethodRepoTemplate.Compile();
#if !DONT_ADD #if !DONT_ADD
context.AddSource("CoCodegenMethodRepository.g.cs", SourceText.From(coCodegenRepoCode, Encoding.UTF8)); context.AddSource("CoCodegenMethodRepository.g.cs", SourceText.From(coCodegenRepoCode, Encoding.UTF8));
#endif #endif
} }
if (BinderTemplate["remoteTypePair+"] != null) if (_binderTemplate["remoteTypePair+"] != null)
{ {
var fronendRepoCode = BinderTemplate.Compile(); var fronendRepoCode = _binderTemplate.Compile();
#if !DONT_ADD #if !DONT_ADD
context.AddSource("RemoteTypeBinder.g.cs", SourceText.From(fronendRepoCode, Encoding.UTF8)); context.AddSource("RemoteTypeBinder.g.cs", SourceText.From(fronendRepoCode, Encoding.UTF8));
#endif #endif
@@ -209,29 +194,27 @@ namespace mROA.Codegen
if (events.Count == 0) if (events.Count == 0)
return; return;
InterfaceTemplate = (TemplateDocument)InterfaceTemplateOriginal.Clone(); _interfaceTemplate = (TemplateDocument)_interfaceTemplateOriginal.Clone();
InterfaceTemplate.AddDefine("name", classSymbol.Name); _interfaceTemplate.AddDefine("name", classSymbol.Name);
InterfaceTemplate.AddDefine("namespace", classSymbol.ContainingNamespace.ToDisplayString()); _interfaceTemplate.AddDefine("namespace", classSymbol.ContainingNamespace.ToDisplayString());
var singleEventBinder = new List<string>(events.Count);
var objectBinderTemplate = var objectBinderTemplate =
(TemplateDocument)((InnerTemplateSection)BinderTemplate["objectBinderTemplate"]).InnerTemplate.Clone(); (TemplateDocument)((InnerTemplateSection)_binderTemplate["objectBinderTemplate"]!).InnerTemplate
for (int i = 0; i < events.Count; i++) .Clone();
foreach (var currentEvent in events)
{ {
var currentEvent = events[i];
var additionalMethod = GenerateMethodExternalCaller(currentEvent, out var signature); var additionalMethod = GenerateMethodExternalCaller(currentEvent, out var signature);
ClassTemplate.Insert("methods", additionalMethod); _classTemplate.Insert("methods", additionalMethod);
// declaredMethods.Add(additionalMethod); // declaredMethods.Add(additionalMethod);
InterfaceTemplate.Insert("signature", signature); _interfaceTemplate.Insert("signature", signature);
GenerateEventCode(currentEvent, invokers, classSymbol); GenerateEventCode(currentEvent, invokers, classSymbol);
GenerateBinderCode(currentEvent, invokers, classSymbol, objectBinderTemplate); GenerateBinderCode(currentEvent, invokers, classSymbol, objectBinderTemplate);
} }
objectBinderTemplate.AddDefine("type", classSymbol.ToDisplayString()); objectBinderTemplate.AddDefine("type", classSymbol.ToUnityString());
var partialInterface = InterfaceTemplate.Compile(); var partialInterface = _interfaceTemplate.Compile();
var binder = objectBinderTemplate.Compile(); var binder = objectBinderTemplate.Compile();
BinderTemplate.Insert("eventBinder", binder); _binderTemplate.Insert("eventBinder", binder);
#if !DONT_ADD #if !DONT_ADD
context.AddSource($"{classSymbol.Name}.g.cs", SourceText.From(partialInterface, Encoding.UTF8)); context.AddSource($"{classSymbol.Name}.g.cs", SourceText.From(partialInterface, Encoding.UTF8));
@@ -241,10 +224,10 @@ namespace mROA.Codegen
private string GenerateMethodExternalCaller(IEventSymbol eventSymbol, out string interfaceSignature) private string GenerateMethodExternalCaller(IEventSymbol eventSymbol, out string interfaceSignature)
{ {
var level = "\t\t"; var level = "\t\t";
var parameters = (eventSymbol.Type as INamedTypeSymbol).TypeArguments; var parameters = ((INamedTypeSymbol)eventSymbol.Type).TypeArguments;
var parameterIndex = 0; var parameterIndex = 0;
var parametersDeclaration = var parametersDeclaration =
string.Join(", ", parameters.Select(i => $"{i.ToDisplayString()} p{parameterIndex++}")); string.Join(", ", parameters.Select(i => $"{i.ToUnityString()} p{parameterIndex++}"));
var signature = $@"public void {EventExternalName(eventSymbol)}({parametersDeclaration})"; var signature = $@"public void {EventExternalName(eventSymbol)}({parametersDeclaration})";
interfaceSignature = signature + ";"; interfaceSignature = signature + ";";
var caller = $@"{signature} var caller = $@"{signature}
@@ -255,18 +238,21 @@ namespace mROA.Codegen
return caller; return caller;
} }
public static string EventExternalName(IEventSymbol eventSymbol) => $"{eventSymbol.Name}External"; private static string EventExternalName(IEventSymbol eventSymbol)
{
return $"{eventSymbol.Name}External";
}
private static string Caster(ITypeSymbol type, string inner) private static string Caster(ITypeSymbol type, string inner)
{ {
if (!type.IsValueType) if (!type.IsValueType)
return inner + return inner +
" as " + " as " +
type.ToDisplayString(); type.ToUnityString();
return $"({type.ToDisplayString()})" + inner; return $"({type.ToUnityString()})" + inner;
} }
private void GenerateDeclaredMethod(IMethodSymbol method, List<string> declaredMethods, List<string> invokers, private void GenerateDeclaredMethod(IMethodSymbol method, List<string> invokers,
INamedTypeSymbol baseInterace) INamedTypeSymbol baseInterace)
{ {
var index = invokers.Count; var index = invokers.Count;
@@ -283,7 +269,7 @@ namespace mROA.Codegen
{ {
case INamedTypeSymbol namedType: case INamedTypeSymbol namedType:
isAsync = namedType.Name == "Task"; isAsync = namedType.Name == "Task";
isVoid = isAsync && namedType.TypeParameters.Length == 0 || namedType.Name == "Void"; isVoid = (isAsync && namedType.TypeParameters.Length == 0) || namedType.Name == "Void";
parameters = method.Parameters.ToList(); parameters = method.Parameters.ToList();
parameters.RemoveAll(ParameterFilter); parameters.RemoveAll(ParameterFilter);
isParametrized = parameters.Count != 0; isParametrized = parameters.Count != 0;
@@ -302,18 +288,18 @@ namespace mROA.Codegen
sb.AppendLine("public" + (isAsync sb.AppendLine("public" + (isAsync
? " async " ? " async "
: " ") + : " ") +
$"{method.ReturnType.ToDisplayString()} {method.Name}({string.Join(", ", method.Parameters.Select(ToFullString))}){{"); $"{method.ReturnType.ToUnityString()} {method.Name}({string.Join(", ", method.Parameters.Select(ToFullString))}){{");
var prefix = isAsync ? "await " : ""; var prefix = isAsync ? "await " : "";
var postfix = !isAsync ? isVoid ? ".Wait()" : ".GetAwaiter().GetResult()" : ""; var postfix = !isAsync ? isVoid ? ".Wait()" : ".GetAwaiter().GetResult()" : "";
var parameterLink = isParametrized var parameterLink = isParametrized
? ", new object[] {" + string.Join(", ", parameters.Select(i => i.Name)) + "}" ? ", new System.Object[] { " + string.Join(", ", parameters.Select(i => i.Name)) + " }"
: string.Empty; : string.Empty;
var tokenInsert = isAsync && method.Parameters.FirstOrDefault(i => i.Type.Name == "CancellationToken") is var tokenInsert = isAsync && method.Parameters.FirstOrDefault(i => i.Type.Name == "CancellationToken") is
{ } tokenSymbol { } tokenSymbol
? ", cancellationToken : " + tokenSymbol.Name ? ", cancellationToken : " + tokenSymbol.Name
: String.Empty; : string.Empty;
var caller = isVoid var caller = isVoid
? $"CallAsync({index}{parameterLink}{tokenInsert})" ? $"CallAsync({index}{parameterLink}{tokenInsert})"
: isAsync : isAsync
@@ -326,18 +312,16 @@ namespace mROA.Codegen
sb.AppendLine("\t\t\t" + prefix + caller + postfix + ";"); sb.AppendLine("\t\t\t" + prefix + caller + postfix + ";");
sb.AppendLine("\t\t}"); sb.AppendLine("\t\t}");
ClassTemplate.Insert("methods", sb.ToString()); _classTemplate.Insert("methods", sb.ToString());
// declaredMethods.Add(sb.ToString()); // declaredMethods.Add(sb.ToString());
var parameterTypes = string.Join(", ", var parameterTypes = string.Join(", ",
$"{string.Join(", ", parameters.Select(p => $"typeof({p.Type.ToDisplayString()})"))}"); $"{string.Join(", ", parameters.Select(p => $"typeof({p.Type.ToUnityString()})"))}");
var level = "\t\t\t"; var level = "\t\t\t";
var parametersInsertList = new List<string>(); var parametersInsertList = new List<string>();
for (var i = 0; i < method.Parameters.Length; i++) foreach (var parameter in method.Parameters)
{
var parameter = method.Parameters[i];
switch (parameter.Type.Name) switch (parameter.Type.Name)
{ {
case "CancellationToken": case "CancellationToken":
@@ -351,53 +335,50 @@ namespace mROA.Codegen
$"parameters[{parameters.IndexOf(parameter)}]")); $"parameters[{parameters.IndexOf(parameter)}]"));
break; break;
} }
}
var parametersInsert = string.Join(", ", parametersInsertList); var parametersInsert = string.Join(", ", parametersInsertList);
var backend = string.Empty; string backend;
var funcInvoking = string.Empty; string funcInvoking;
if (isAsync && !isVoid) if (isAsync && !isVoid)
funcInvoking = funcInvoking =
$"(i as {method.ContainingType.ToDisplayString()}).{method.Name}({parametersInsert}).ContinueWith(t => {{ post(t.Result); }})"; $"(i as {method.ContainingType.ToUnityString()}).{method.Name}({parametersInsert}).ContinueWith(t => {{ post(t.Result); }})";
else if (isAsync && isVoid) else if (isAsync && isVoid)
funcInvoking = funcInvoking =
$"(i as {method.ContainingType.ToDisplayString()}).{method.Name}({parametersInsert}).ContinueWith(t => {{ post(null); }})"; $"(i as {method.ContainingType.ToUnityString()}).{method.Name}({parametersInsert}).ContinueWith(t => {{ post(null); }})";
else if (!isAsync && isVoid) else if (!isAsync && isVoid)
{
funcInvoking = $@"{{ funcInvoking = $@"{{
{level} (i as {method.ContainingType.ToDisplayString()}).{method.Name}({parametersInsert}); {level} (i as {method.ContainingType.ToUnityString()}).{method.Name}({parametersInsert});
{level} return null; {level} return null;
{level} }}"; {level} }}";
}
else else
{ funcInvoking = $"(i as {method.ContainingType.ToUnityString()}).{method.Name}({parametersInsert})";
funcInvoking = $"(i as {method.ContainingType.ToDisplayString()}).{method.Name}({parametersInsert})";
}
if (isAsync) if (isAsync)
{ {
var invokerTemplate = (TemplateDocument)((InnerTemplateSection)MethodRepoTemplate["asyncInvoker"]).InnerTemplate.Clone(); var invokerTemplate =
(TemplateDocument)((InnerTemplateSection)_methodRepoTemplate["asyncInvoker"]!).InnerTemplate
.Clone();
invokerTemplate.AddDefine("isVoid", isVoid.ToString().ToLower()); invokerTemplate.AddDefine("isVoid", isVoid.ToString().ToLower());
invokerTemplate.AddDefine("returnType", ExtractTaskType(method.ReturnType)); invokerTemplate.AddDefine("returnType", ExtractTaskType(method.ReturnType));
invokerTemplate.AddDefine("parametersType", parameterTypes); invokerTemplate.AddDefine("parametersType", parameterTypes);
invokerTemplate.AddDefine("suitableType", baseInterace.ToDisplayString()); invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString());
invokerTemplate.AddDefine("funcInvoking", funcInvoking); invokerTemplate.AddDefine("funcInvoking", funcInvoking);
backend = invokerTemplate.Compile(); backend = invokerTemplate.Compile();
} }
else else
{ {
var invokerTemplate = (TemplateDocument)MethodInvokerOriginal.Clone(); var invokerTemplate = (TemplateDocument)_methodInvokerOriginal.Clone();
invokerTemplate.AddDefine("isVoid", isVoid.ToString().ToLower()); invokerTemplate.AddDefine("isVoid", isVoid.ToString().ToLower());
invokerTemplate.AddDefine("returnType", isVoid ? "void" : method.ReturnType.ToDisplayString()); invokerTemplate.AddDefine("returnType", isVoid ? "void" : method.ReturnType.ToUnityString());
invokerTemplate.AddDefine("parametersType", parameterTypes); invokerTemplate.AddDefine("parametersType", parameterTypes);
invokerTemplate.AddDefine("suitableType", baseInterace.ToDisplayString()); invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString());
invokerTemplate.AddDefine("funcInvoking", funcInvoking); invokerTemplate.AddDefine("funcInvoking", funcInvoking);
backend = invokerTemplate.Compile(); backend = invokerTemplate.Compile();
} }
MethodRepoTemplate.Insert("invoker", backend); _methodRepoTemplate.Insert("invoker", backend);
invokers.Add(backend); invokers.Add(backend);
} }
@@ -410,24 +391,21 @@ namespace mROA.Codegen
var index = invokers.Count - 1; var index = invokers.Count - 1;
var parameters = (eventSymbol.Type as INamedTypeSymbol)!.TypeArguments.ToList(); var parameters = (eventSymbol.Type as INamedTypeSymbol)!.TypeArguments.ToList();
int parameterIndex = 0;
var parametersDeclaration = string.Join(", ", var parametersDeclaration = string.Join(", ",
JoinWithComa(Enumerable.Range(0, parameters.Count).Select(i => "p" + i++))); JoinWithComa(Enumerable.Range(0, parameters.Count).Select(i => "p" + i)));
var transferParameters = var transferParameters =
JoinWithComa(parameters.Where(i => !ParameterFilterForType(i)) JoinWithComa(parameters.Where(i => !ParameterFilterForType(i))
.Select(i => "p" + parameters.IndexOf(i))); .Select(i => "p" + parameters.IndexOf(i)));
string callFilter;
var requestIndex = parameters.FindIndex(i => i.Name == "RequestContext"); var requestIndex = parameters.FindIndex(i => i.Name == "RequestContext");
if (requestIndex != -1) if (requestIndex != -1)
{ {
callFilter = $"\n\r\t\t\tif(ownerId == p{requestIndex}.OwnerId) return;"; var callFilter = $"\n\r\t\t\tif(ownerId == p{requestIndex}.OwnerId) return;";
eventBinderTemplate.AddDefine("callFilter", callFilter); eventBinderTemplate.AddDefine("callFilter", callFilter);
} }
eventBinderTemplate.AddDefine("type", baseType.ToDisplayString()); eventBinderTemplate.AddDefine("type", baseType.ToUnityString());
eventBinderTemplate.AddDefine("eventName", eventSymbol.Name); eventBinderTemplate.AddDefine("eventName", eventSymbol.Name);
eventBinderTemplate.AddDefine("parametersDeclaration", parametersDeclaration); eventBinderTemplate.AddDefine("parametersDeclaration", parametersDeclaration);
eventBinderTemplate.AddDefine("commandId", index.ToString()); eventBinderTemplate.AddDefine("commandId", index.ToString());
@@ -436,22 +414,23 @@ namespace mROA.Codegen
document.Insert("eventBinder", eventBinderCode); document.Insert("eventBinder", eventBinderCode);
} }
public static string JoinWithComa(IEnumerable<string> parts) => string.Join(", ", parts); private static string JoinWithComa(IEnumerable<string> parts)
{
return string.Join(", ", parts);
}
private void GenerateEventCode(IEventSymbol eventSymbol, List<string> invokers, ITypeSymbol baseInterface) private void GenerateEventCode(IEventSymbol eventSymbol, List<string> invokers, ITypeSymbol baseInterface)
{ {
var level = "\t\t\t"; var level = "\t\t\t";
var parameters = (eventSymbol.Type as INamedTypeSymbol).TypeArguments; var parameters = ((INamedTypeSymbol)eventSymbol.Type).TypeArguments;
var parsingParameters = parameters.RemoveAll(ParameterFilterForType).ToList(); var parsingParameters = parameters.RemoveAll(ParameterFilterForType).ToList();
var parameterTypes = string.Join(", ", var parameterTypes = string.Join(", ",
$"{string.Join(", ", parsingParameters.Select(p => $"typeof({p.ToDisplayString()})"))}"); $"{string.Join(", ", parsingParameters.Select(p => $"typeof({p.ToUnityString()})"))}");
var parametersInsertList = new List<string>(); var parametersInsertList = new List<string>();
for (var i = 0; i < parameters.Length; i++) foreach (var parameter in parameters)
{
var parameter = parameters[i];
switch (parameter.Name) switch (parameter.Name)
{ {
case "CancellationToken": case "CancellationToken":
@@ -465,25 +444,23 @@ namespace mROA.Codegen
$"parameters[{parameters.IndexOf(parameter)}]")); $"parameters[{parameters.IndexOf(parameter)}]"));
break; break;
} }
}
var parametersInsert = string.Join(", ", parametersInsertList); var parametersInsert = string.Join(", ", parametersInsertList);
var funcInvoking = $@"{{ var funcInvoking = $@"{{
{level} (i as {baseInterface.ToDisplayString()}).{EventExternalName(eventSymbol)}({parametersInsert}); {level} (i as {baseInterface.ToUnityString()}).{EventExternalName(eventSymbol)}({parametersInsert});
{level} return null; {level} return null;
{level} }}"; {level} }}";
var invokerTemplate = (TemplateDocument)MethodInvokerOriginal.Clone(); var invokerTemplate = (TemplateDocument)_methodInvokerOriginal.Clone();
invokerTemplate.AddDefine("isVoid", "true"); invokerTemplate.AddDefine("isVoid", "true");
invokerTemplate.AddDefine("returnType", "void"); invokerTemplate.AddDefine("returnType", "void");
invokerTemplate.AddDefine("parametersType", parameterTypes); invokerTemplate.AddDefine("parametersType", parameterTypes);
invokerTemplate.AddDefine("suitableType", baseInterface.ToDisplayString()); invokerTemplate.AddDefine("suitableType", baseInterface.ToUnityString());
invokerTemplate.AddDefine("funcInvoking", funcInvoking); invokerTemplate.AddDefine("funcInvoking", funcInvoking);
var backend = invokerTemplate.Compile(); var backend = invokerTemplate.Compile();
MethodRepoTemplate.Insert("invoker", backend); _methodRepoTemplate.Insert("invoker", backend);
invokers.Add(backend); invokers.Add(backend);
} }
@@ -491,58 +468,45 @@ namespace mROA.Codegen
private void GeneratePropertyMethod(IMethodSymbol method, private void GeneratePropertyMethod(IMethodSymbol method,
List<(string, IMethodSymbol)> propsCollection, List<string> invokers, INamedTypeSymbol baseInterace) List<(string, IMethodSymbol)> propsCollection, List<string> invokers, INamedTypeSymbol baseInterace)
{ {
var level = "\t\t\t";
var index = invokers.Count; var index = invokers.Count;
string frontend; string frontend;
string backend = string.Empty; string backend;
if (method.MethodKind == MethodKind.PropertyGet) if (method.MethodKind == MethodKind.PropertyGet)
{ {
var parametersArray = ""; var parametersArray = "";
if (method.Parameters.Length != 0) if (method.Parameters.Length != 0)
{ {
parametersArray = $", new object[] {{{string.Join(", ", method.Parameters.Select(p => p.Name))}}}"; parametersArray =
$", new System.Object[] {{ {string.Join(", ", method.Parameters.Select(p => p.Name))} }}";
var parameterTypes = string.Join(", ", var parameterTypes = string.Join(", ",
$"{string.Join(", ", method.Parameters.Select(p => "typeof(" + p.Type.ToDisplayString() + ")"))}"); $"{string.Join(", ", method.Parameters.Select(p => "typeof(" + p.Type.ToUnityString() + ")"))}");
var parameterInserts = string.Join(", ", var parameterInserts = string.Join(", ",
method.Parameters.Select( method.Parameters.Select(
p => Caster(p.Type, "parameters[" + method.Parameters.IndexOf(p) + "]"))); p => Caster(p.Type, "parameters[" + method.Parameters.IndexOf(p) + "]")));
var invokerTemplate = (TemplateDocument)MethodInvokerOriginal.Clone(); var invokerTemplate = (TemplateDocument)_methodInvokerOriginal.Clone();
invokerTemplate.AddDefine("isVoid", "false"); invokerTemplate.AddDefine("isVoid", "false");
invokerTemplate.AddDefine("returnType", method.ReturnType.ToDisplayString()); invokerTemplate.AddDefine("returnType", method.ReturnType.ToUnityString());
invokerTemplate.AddDefine("parametersType", parameterTypes); invokerTemplate.AddDefine("parametersType", parameterTypes);
invokerTemplate.AddDefine("suitableType", baseInterace.ToDisplayString()); invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString());
invokerTemplate.AddDefine("funcInvoking", $"(i as {method.ContainingType.ToDisplayString()})[{parameterInserts}]"); invokerTemplate.AddDefine("funcInvoking",
$"(i as {method.ContainingType.ToUnityString()})[{parameterInserts}]");
backend = invokerTemplate.Compile(); backend = invokerTemplate.Compile();
// backend = $@"new mROA.Implementation.MethodInvoker
// {level}{{
// {level} IsVoid = false,
// {level} ReturnType = typeof({method.ReturnType.ToDisplayString()}),
// {level} ParameterTypes = new Type[] {{ {parameterTypes} }},
// {level} SuitableType = typeof({baseInterace.ToDisplayString()}),
// {level} Invoking = (i, parameters, _) => (i as {method.ContainingType.ToDisplayString()})[{parameterInserts}],
// {level}}}";
} }
else else
{ {
var invokerTemplate = (TemplateDocument)MethodInvokerOriginal.Clone(); var invokerTemplate = (TemplateDocument)_methodInvokerOriginal.Clone();
invokerTemplate.AddDefine("isVoid", "false"); invokerTemplate.AddDefine("isVoid", "false");
invokerTemplate.AddDefine("returnType", method.ReturnType.ToDisplayString()); invokerTemplate.AddDefine("returnType", method.ReturnType.ToUnityString());
invokerTemplate.AddDefine("suitableType", baseInterace.ToDisplayString()); invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString());
invokerTemplate.AddDefine("funcInvoking", $"(i as {method.ContainingType.ToDisplayString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name}"); invokerTemplate.AddDefine("funcInvoking",
$"(i as {method.ContainingType.ToUnityString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name}");
backend = invokerTemplate.Compile(); backend = invokerTemplate.Compile();
// backend = $@"new mROA.Implementation.MethodInvoker
// {level}{{
// {level} IsVoid = false,
// {level} ReturnType = typeof({method.ReturnType.ToDisplayString()}),
// {level} SuitableType = typeof({baseInterace.ToDisplayString()}),
// {level} Invoking = (i, _, _) => (i as {method.ContainingType.ToDisplayString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name},
// {level}}}";
} }
frontend = frontend =
$"get => GetResultAsync<{method.ReturnType.ToDisplayString()}>({index}{parametersArray}).GetAwaiter().GetResult();"; $"get => GetResultAsync<{method.ReturnType.ToUnityString()}>({index}{parametersArray}).GetAwaiter().GetResult();";
} }
else else
{ {
@@ -552,77 +516,63 @@ namespace mROA.Codegen
parametersArray = string.Join(", ", method.Parameters.Select(p => p.Name)); parametersArray = string.Join(", ", method.Parameters.Select(p => p.Name));
var parameterTypes = string.Join(", ", var parameterTypes = string.Join(", ",
$"{string.Join(", ", method.Parameters.Select(p => $"typeof({p.Type.ToDisplayString()})"))}"); $"{string.Join(", ", method.Parameters.Select(p => $"typeof({p.Type.ToUnityString()})"))}");
var parameterInserts = string.Join(", ", var parameterInserts = string.Join(", ",
method.Parameters.Take(method.Parameters.Length - 1).Select(p => method.Parameters.Take(method.Parameters.Length - 1).Select(p =>
Caster(p.Type, "parameters[" + method.Parameters.IndexOf(p) + "]"))); Caster(p.Type, "parameters[" + method.Parameters.IndexOf(p) + "]")));
var valueInsert = Caster(method.Parameters.Last().Type, var valueInsert = Caster(method.Parameters.Last().Type,
"parameters[" + (method.Parameters.Length - 1) + "]"); "parameters[" + (method.Parameters.Length - 1) + "]");
var invokerTemplate = (TemplateDocument)MethodInvokerOriginal.Clone(); var invokerTemplate = (TemplateDocument)_methodInvokerOriginal.Clone();
invokerTemplate.AddDefine("isVoid", "true"); invokerTemplate.AddDefine("isVoid", "true");
invokerTemplate.AddDefine("returnType", method.ReturnType.ToDisplayString()); invokerTemplate.AddDefine("returnType", method.ReturnType.ToUnityString());
invokerTemplate.AddDefine("parametersType", parameterTypes); invokerTemplate.AddDefine("parametersType", parameterTypes);
invokerTemplate.AddDefine("suitableType", baseInterace.ToDisplayString()); invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString());
invokerTemplate.AddDefine("funcInvoking", $"(i as {method.ContainingType.ToDisplayString()})[{parameterInserts}] = {valueInsert}"); invokerTemplate.AddDefine("funcInvoking",
$"(i as {method.ContainingType.ToUnityString()})[{parameterInserts}] = {valueInsert}");
backend = invokerTemplate.Compile(); backend = invokerTemplate.Compile();
// backend = $@"new mROA.Implementation.MethodInvoker
// {level}{{
// {level} IsVoid = true,
// {level} ReturnType = typeof({method.ReturnType.ToDisplayString()}),
// {level} ParameterTypes = new Type[] {{ {parameterTypes} }},
// {level} SuitableType = typeof({baseInterace.ToDisplayString()}),
// {level} Invoking = (i, parameters, _) => (i as {method.ContainingType.ToDisplayString()})[{parameterInserts}] = {valueInsert},
// {level}}}";
} }
else else
{ {
var invokerTemplate = (TemplateDocument)MethodInvokerOriginal.Clone(); var invokerTemplate = (TemplateDocument)_methodInvokerOriginal.Clone();
invokerTemplate.AddDefine("isVoid", "true"); invokerTemplate.AddDefine("isVoid", "true");
invokerTemplate.AddDefine("returnType", method.ReturnType.ToDisplayString()); invokerTemplate.AddDefine("returnType", method.ReturnType.ToUnityString());
invokerTemplate.AddDefine("parametersType", $"typeof({method.Parameters.First().Type.ToDisplayString()})"); invokerTemplate.AddDefine("parametersType",
invokerTemplate.AddDefine("suitableType", baseInterace.ToDisplayString()); $"typeof({method.Parameters.First().Type.ToUnityString()})");
invokerTemplate.AddDefine("funcInvoking", $"(i as {method.ContainingType.ToDisplayString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name} = {Caster((method.AssociatedSymbol as IPropertySymbol)!.Type, "parameters[0]")}"); 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]")}");
backend = invokerTemplate.Compile(); backend = invokerTemplate.Compile();
// backend = $@"new mROA.Implementation.MethodInvoker
// {level}{{
// {level} IsVoid = true,
// {level} ReturnType = typeof({method.ReturnType.ToDisplayString()}),
// {level} ParameterTypes = new Type[] {{ typeof({method.Parameters.First().Type.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}}}";
} }
frontend = $"set => CallAsync({index}, new object[] {{ {parametersArray} }}).Wait();"; frontend = $"set => CallAsync({index}, new System.Object[] {{ {parametersArray} }}).Wait();";
} }
propsCollection.Add((frontend, method)); propsCollection.Add((frontend, method));
MethodRepoTemplate.Insert("invoker", backend); _methodRepoTemplate.Insert("invoker", backend);
invokers.Add(backend); invokers.Add(backend);
} }
private static string ToFullString(IParameterSymbol parameter) private static string ToFullString(IParameterSymbol parameter)
=> /*parameter.Type.ContainingNamespace is null*/ {
/*?*/ parameter.ToDisplayString(); return parameter.ToDisplayParts().ToUnityString();
/*: $"{parameter.Type.ContainingNamespace.ToDisplayString()}.{parameter.Type.MetadataName} {parameter.Name}";*/ }
private static string ToFullString(ITypeSymbol type) => private static string ToFullString(ITypeSymbol type)
// => type.ContainingNamespace is null || type.Name == "Void" {
type.ToDisplayString(); return type.ToUnityString();
// : $"{type.ContainingNamespace.ToDisplayString()}.{type.MetadataName}"; }
private string ExtractTaskType(ITypeSymbol taskType) private string ExtractTaskType(ITypeSymbol taskType)
{ {
var generics = ((INamedTypeSymbol)taskType).TypeArguments; var generics = ((INamedTypeSymbol)taskType).TypeArguments;
return generics.Length == 0 ? "void" : generics[0].ToDisplayString(); return generics.Length == 0 ? "void" : generics[0].ToUnityString();
} }
private bool ContainsSOIAttribute(SyntaxList<AttributeListSyntax> attributes, GeneratorExecutionContext context, private bool ContainsSoiAttribute(SyntaxList<AttributeListSyntax> attributes, GeneratorExecutionContext context,
InterfaceDeclarationSyntax interfaceDeclarationSyntax) InterfaceDeclarationSyntax interfaceDeclarationSyntax)
{ {
foreach (var attributeSyntax in foreach (var attributeSyntax in
@@ -632,7 +582,7 @@ namespace mROA.Codegen
.GetSymbolInfo(attributeSyntax).Symbol is not IMethodSymbol attributeSymbol) .GetSymbolInfo(attributeSyntax).Symbol is not IMethodSymbol attributeSymbol)
continue; // if we can't get the symbol, ignore it 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. // Check the full name of the [Report] attribute.
if (attributeName == "mROA.Implementation.Attributes.SharedObjectInterfaceAttribute") if (attributeName == "mROA.Implementation.Attributes.SharedObjectInterfaceAttribute")
@@ -645,13 +595,44 @@ namespace mROA.Codegen
private List<IMethodSymbol> CollectMembers(INamedTypeSymbol type) private List<IMethodSymbol> CollectMembers(INamedTypeSymbol type)
{ {
var methods = type.GetMembers().OfType<IMethodSymbol>().ToList(); var methods = type.GetMembers().OfType<IMethodSymbol>().ToList();
foreach (var inner in type.AllInterfaces) foreach (var inner in type.AllInterfaces) methods.AddRange(inner.GetMembers().OfType<IMethodSymbol>());
{
methods.AddRange(inner.GetMembers().OfType<IMethodSymbol>());
}
methods.RemoveAll(m => m.Name == "Dispose"); methods.RemoveAll(m => m.Name == "Dispose");
return methods.OrderBy(i => i.Name).ToList(); return methods.OrderBy(i => i.Name).ToList();
} }
} }
public static class CodegenExtentions
{
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();
}
public static string ToUnityString(this ImmutableArray<SymbolDisplayPart> parts)
{
var sb = new StringBuilder();
foreach (var displayPart in parts)
if (displayPart.Kind == SymbolDisplayPartKind.Keyword)
{
if (displayPart.ToString() == "void")
{
sb.Append(displayPart.ToString());
continue;
}
sb.Append($"{displayPart.Symbol!.ContainingNamespace.ToDisplayString()}.{displayPart.Symbol.Name}");
}
else
{
sb.Append(displayPart.ToString());
}
return sb.ToString();
}
}
} }
@@ -23,6 +23,8 @@ namespace mROA.Implementation
} }
} }
public int Id => (_interaction ?? throw new NullReferenceException("Interaction is not initialized")) public int Id => (_interaction ?? throw new NullReferenceException("Interaction is not initialized"))
.ConnectionId; .ConnectionId;