LILAC
Language to language Interop LAyer Compiler
Loading...
Searching...
No Matches
ParameterPack.cs
Go to the documentation of this file.
1using System.CodeDom.Compiler;
2using System.Runtime.InteropServices;
3using System.Security.Cryptography;
4using System.Text;
5using Microsoft.CodeAnalysis;
6
7namespace Lilac.Generator;
8
9public class ParameterPack
10{
11 private readonly IMethodSymbol _symbol;
12
13 public string Name { get; }
14
15 public ParameterPack(IMethodSymbol symbol)
16 {
17 _symbol = symbol;
18
19 var builder = new StringBuilder();
20 foreach (var parameter in _symbol.Parameters)
21 builder.Append(parameter.Type.ToDisplayString());
22
23 var mangled = HashString(builder.ToString());
24
25 Name = $"__argpack__{symbol.GetUnmanagedMethodName()}_{mangled}";
26 }
27
28 private static string HashString(string data)
29 {
30 return Convert.ToHexString(MD5.HashData(Encoding.UTF8.GetBytes(data)).Take(4).ToArray());
31 }
32
33 public void GenerateManagedStub(IndentedTextWriter builder)
34 {
35 builder.WriteLine("[global::System.Runtime.InteropServices(LayoutKind.Sequential)]");
36 builder.WriteLine($"public struct {Name}");
37 builder.WriteLine("{");
38 builder.Indent++;
39
40 if (!_symbol.IsStatic)
41 builder.WriteLine("public System.IntPtr __this;");
42
43 foreach (var parameter in _symbol.Parameters)
44 {
45 var isPrimitive = parameter.Type.IsPrimitives();
46
47 var type = isPrimitive ? parameter.Type.GetManagedPackedName() : "System.IntPtr";
48 var name = !isPrimitive || type == "unsafe char*" ? $"__unsafe_{parameter.Name}" : parameter.Name;
49
50 builder.WriteLine($"public {type} {name};");
51 }
52
53 if (!_symbol.ReturnsVoid)
54 builder.WriteLine($"public {_symbol.ReturnType.GetManagedPackedName()} __return;");
55
56 foreach (var parameter in _symbol.Parameters)
57 {
58 if (parameter.Type.GetFullName() == "System::String")
59 {
60 builder.WriteLine();
61 builder.WriteLine($"public string {parameter.Name}");
62 builder.WriteLine("{");
63 builder.Indent++;
64 builder.WriteLine("get");
65 builder.WriteLine("{");
66 builder.Indent++;
67 builder.WriteLine($"return System.Runtime.InteropServices.Marshal.PtrToStringUTF8(__unsafe_{parameter.Name});");
68 builder.Indent--;
69 builder.WriteLine("}");
70 builder.Indent--;
71 builder.WriteLine("}");
72 }
73 else if (!parameter.Type.IsPrimitives())
74 {
75 var fullname = parameter.Type.GetManagedFullName();
76
77 builder.WriteLine();
78 builder.WriteLine($"public {fullname} {parameter.Name}");
79 builder.WriteLine("{");
80 builder.Indent++;
81 builder.WriteLine("get");
82 builder.WriteLine("{");
83 builder.Indent++;
84 builder.WriteLine($"return ({fullname})System.Runtime.InteropServices.GCHandle.FromIntPtr(__unsafe_{parameter.Name}).Target;");
85 builder.Indent--;
86 builder.WriteLine("}");
87 builder.Indent--;
88 builder.WriteLine("}");
89 }
90 }
91
92 builder.Indent--;
93 builder.WriteLine("}");
94 }
95
96 public void GenerateUnmanagedStub(IndentedTextWriter builder)
97 {
98 builder.WriteLine($"struct {Name}");
99 builder.WriteLine("{");
100 builder.Indent++;
101
102 if (!_symbol.IsStatic)
103 builder.WriteLine("void* __this;");
104
105 foreach (var parameter in _symbol.Parameters)
106 builder.WriteLine($"{parameter.Type.GetUnmanagedPackedName()} {parameter.Name};");
107
108 if (!_symbol.ReturnsVoid)
109 builder.WriteLine($"{_symbol.ReturnType.GetUnmanagedPackedName()} __return;");
110
111 builder.Indent--;
112 builder.WriteLine("};");
113 }
114}
void GenerateUnmanagedStub(IndentedTextWriter builder)
ParameterPack(IMethodSymbol symbol)
void GenerateManagedStub(IndentedTextWriter builder)