MLLIF
a MLIR-based Language to Language Interoperability Flyover
Loading...
Searching...
No Matches
SymbolExtension.cs
Go to the documentation of this file.
1using System.Text;
2using Microsoft.CodeAnalysis;
3
4namespace MLLIFCSharpFront;
5
6public static class SymbolExtension
7{
8 public static bool IsTarget(this ISymbol symbol)
9 {
10 if (symbol is INamespaceOrTypeSymbol t && t.GetMembers().Any(IsTarget))
11 return true;
12 return symbol.GetAttributes().Any(attr => attr.AttributeClass?.Name == "ExportAttribute");
13 }
14
15 public static IEnumerable<INamedTypeSymbol> GetAllTypes(this INamespaceOrTypeSymbol symbol)
16 {
17 if (symbol is INamedTypeSymbol t)
18 yield return t;
19 foreach (var child in symbol.GetMembers().OfType<INamespaceOrTypeSymbol>())
20 foreach (var ret in child.GetAllTypes())
21 yield return ret;
22 }
23
24 public static string GetFullName(this ISymbol symbol, string delimiter = ".")
25 {
26 var queue = new Stack<string>();
27 while (symbol is INamespaceOrTypeSymbol or IMethodSymbol)
28 {
29 if (!string.IsNullOrWhiteSpace(symbol.Name))
30 queue.Push(symbol.Name);
31 symbol = symbol.ContainingSymbol;
32 }
33
34 var builder = new StringBuilder();
35 for (var first = true; queue.Count > 0; first = false)
36 {
37 if (!first)
38 builder.Append(delimiter);
39 builder.Append(queue.Pop());
40 }
41
42 return builder.ToString();
43 }
44
45 private static string? ToMangleCode(this ITypeSymbol type)
46 {
47 if (type.IsReferenceType)
48 return "void*";
49
50 return type.GetFullName() switch
51 {
52 "System.SByte" => "s8",
53 "System.Int16" => "s16",
54 "System.Int32" => "s32",
55 "System.Int64" => "s64",
56 "System.Byte" => "u8",
57 "System.UInt16" => "u16",
58 "System.UInt32" => "u32",
59 "System.UInt64" => "u64",
60 "System.Half" => "fp16",
61 "System.Single" => "fp32",
62 "System.Double" => "fp64",
63 _ => null
64 };
65 }
66
67 public static string ToNativeBridgeType(this ITypeSymbol type)
68 {
69 return type.GetFullName("::") switch
70 {
71 "System::SByte" => "int8_t",
72 "System::Int16" => "int16_t",
73 "System::Int32" => "int32_t",
74 "System::Int64" => "int64_t",
75 "System::Byte" => "uint8_t",
76 "System::UInt16" => "uint16_t",
77 "System::UInt32" => "uint32_t",
78 "System::UInt64" => "uint64_t",
79 "System::Half" => "_Float16",
80 "System::Single" => "float",
81 "System::Double" => "double",
82 _ => "void*"
83 };
84 }
85
86 public static string ToNativeInterfaceType(this ITypeSymbol type, bool ret = false)
87 {
88 var name = type.GetFullName("::");
89 return name switch
90 {
91 "System::SByte" => "int8_t",
92 "System::Int16" => "int16_t",
93 "System::Int32" => "int32_t",
94 "System::Int64" => "int64_t",
95 "System::Byte" => "uint8_t",
96 "System::UInt16" => "uint16_t",
97 "System::UInt32" => "uint32_t",
98 "System::UInt64" => "uint64_t",
99 "System::Half" => "_Float16",
100 "System::Single" => "float",
101 "System::Double" => "double",
102 _ => ret ? name : $"{name}&"
103 };
104 }
105
106 private static bool IsRootNamespace(ISymbol symbol)
107 {
108 INamespaceSymbol? s;
109 return (s = symbol as INamespaceSymbol) != null && s.IsGlobalNamespace;
110 }
111
112 public static string GetFullyQualifiedName(this ISymbol? s)
113 {
114 if (s == null || IsRootNamespace(s))
115 {
116 return string.Empty;
117 }
118
119 var asm = s.ContainingAssembly;
120
121 var sb = new StringBuilder(s.MetadataName);
122 var last = s;
123
124 s = s.ContainingSymbol;
125
126 while (!IsRootNamespace(s))
127 {
128 if (s is ITypeSymbol && last is ITypeSymbol)
129 {
130 sb.Insert(0, '+');
131 }
132 else
133 {
134 sb.Insert(0, '.');
135 }
136
137 sb.Insert(0, s.OriginalDefinition.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat));
138 //sb.Insert(0, s.MetadataName);
139 s = s.ContainingSymbol;
140 }
141
142 return $"{sb}, {asm}";
143 }
144
145 private static Diagnostic UnsupportedType(ITypeSymbol type)
146 => Diagnostic.Create(
147 "MLLIF01", "",
148 $"'{GetFullName(type)}' is not supported by MLLIF",
149 DiagnosticSeverity.Error, DiagnosticSeverity.Error,
150 true, 0);
151
152 public static string? MangleName(this IMethodSymbol method, SourceProductionContext? spc = null)
153 {
154 var builder = new StringBuilder();
155 builder.Append("__mllif__").Append(method.Name);
156
157 foreach (var param in method.Parameters)
158 {
159 if (param.Type.ToMangleCode() is not { } code)
160 {
161 spc?.ReportDiagnostic(UnsupportedType(param.Type));
162 return null;
163 }
164
165 builder.Append('_').Append(code.Replace('*', 'p'));
166 }
167
168 return builder.ToString();
169 }
170}