Skip to content

Commit f02b74f

Browse files
authored
Fptr improvements (#1038)
1 parent b486b41 commit f02b74f

File tree

4 files changed

+81
-24
lines changed

4 files changed

+81
-24
lines changed

src/generators/Silk.NET.SilkTouch.DotnetTool/Silk.NET.SilkTouch.DotnetTool.csproj

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@
33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
55
<TargetFramework>net6.0</TargetFramework>
6-
<PackAsTool Condition="'$(Configuration)' != 'Debug'">true</PackAsTool>
76
<ToolCommandName>silktouch</ToolCommandName>
87
<PackageType>DotnetTool</PackageType>
9-
<GeneratePackageOnBuild Condition="'$(Configuration)' != 'Debug'">true</GeneratePackageOnBuild>
108

119
<!-- Workaround for issue https://github.com/microsoft/ClangSharp/issues/129 -->
1210
<RuntimeIdentifier Condition="'$(RuntimeIdentifier)' == '' AND '$(PackAsTool)' != 'true'">$(NETCoreSdkRuntimeIdentifier)</RuntimeIdentifier>

src/generators/Silk.NET.SilkTouch.Scraper/XmlVisitor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public XmlVisitor(ILogger logger, TypeStore typeStore)
2727

2828
public IEnumerable<Symbol> Visit(XmlNode node)
2929
{
30-
_logger.LogTrace("Visiting XML Node of kind {name}", node.Name);
30+
_logger.LogTrace("Visiting XML Node of kind {name} {inner}", node.Name, node.InnerXml);
3131
switch (node)
3232
{
3333
case XmlElement { Name: "bindings" } bindings:

src/generators/Silk.NET.SilkTouch.TypeResolution/FunctionPointerTypeResolver.cs

Lines changed: 65 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Collections.Immutable;
5+
using System.Diagnostics;
56
using System.Text.RegularExpressions;
7+
using Microsoft.Extensions.Logging;
68
using Silk.NET.SilkTouch.Symbols;
79

810
namespace Silk.NET.SilkTouch.TypeResolution;
@@ -12,34 +14,80 @@ namespace Silk.NET.SilkTouch.TypeResolution;
1214
/// </summary>
1315
public class FunctionPointerTypeResolver : SimpleTypeResolverBase
1416
{
15-
private static readonly Regex _regex = new
16-
(/*lang=regex*/
17-
@"delegate\*\sunmanaged(\[((?'modifier'.(?=,\s?)?)+)*\])?\<((?'parameter'(.(?=,\s?)+))(,\s?))*(?'return_type'(.)+)\>",
18-
RegexOptions.CultureInvariant
19-
);
17+
private readonly ILogger _logger;
2018

2119
/// <inheritdoc />
22-
public FunctionPointerTypeResolver(TypeStore typeStore) : base(typeStore)
20+
public FunctionPointerTypeResolver(ILogger<FunctionPointerTypeResolver> logger, TypeStore typeStore) : base(typeStore)
2321
{
22+
_logger = logger;
2423
}
2524

2625
/// <inheritdoc />
2726
protected override bool TryResolve(UnresolvedTypeReference utr, out TypeReference? resolved)
2827
{
29-
if (utr.Text.StartsWith("delegate*"))
28+
int c = 0;
29+
var text = utr.Text;
30+
if (text.Length > "delegate*".Length && text[text.Length - 1] == '>' && text.Substring(c, "delegate*".Length) == "delegate*")
3031
{
31-
var match = _regex.Match(utr.Text);
32-
if (match.Success)
32+
_logger.LogTrace("Attempting to resolve {text} to function pointer after passing preliminary tests", utr.Text);
33+
c += "delegate*".Length;
34+
if (text.Substring(c, " unmanaged".Length) == " unmanaged")
3335
{
34-
var parameters = match.Groups["parameter"]
35-
.Captures.OfType<Capture>()
36-
.Select(x => new UnresolvedTypeReference(x.Value))
37-
.Cast<TypeReference>()
38-
.ToImmutableArray();
39-
var returnType = new UnresolvedTypeReference(match.Groups["return_type"].Value);
36+
c += " unmanaged".Length;
37+
if (text[c] == '[')
38+
{
39+
var endOffset = text.AsSpan(c).IndexOf(']');
40+
41+
var attributeText = text.Substring(c + 1, endOffset - 1);
42+
_logger.LogDebug("{text} may be a function pointer and has unhandled attributes {attributes}", utr.Text, attributeText);
43+
// TODO: parse out function attributes here
44+
45+
c += endOffset + 1;
46+
}
47+
var types = new List<TypeReference>();
48+
if (text[c] == '<')
49+
{
50+
c += 1;
51+
while (true)
52+
{
53+
var typeTextEndIndex = text.AsSpan(c).IndexOf(',');
54+
if (typeTextEndIndex != -1)
55+
{
56+
var typeText = text.Substring(c, typeTextEndIndex);
57+
c += typeTextEndIndex + 1;
58+
if (text[c] == ' ') c++;
59+
types.Add(new UnresolvedTypeReference(typeText));
60+
}
61+
else
62+
{
63+
var l = text.Length - c - 1;
64+
if (l > 0)
65+
{
66+
var typeText = text.Substring(c, l);
67+
types.Add(new UnresolvedTypeReference(typeText));
68+
}
69+
break;
70+
}
71+
}
72+
}
73+
else
74+
{
75+
_logger.LogDebug("{text} may be a function pointer but generic params are somehow scrambled", utr.Text);
76+
}
4077

41-
resolved = new FunctionPointerTypeReference(returnType, parameters);
42-
return true;
78+
79+
// at least a return type is required
80+
if (types.Count > 0)
81+
{
82+
resolved = new FunctionPointerTypeReference
83+
(types.Last(), types.Take(types.Count - 1).ToImmutableArray());
84+
_logger.LogTrace("{text} resolved to function pointer {ptr}", utr.Text, resolved);
85+
return true;
86+
}
87+
}
88+
else
89+
{
90+
_logger.LogDebug("Rejecting {text} as it may be a function pointer, but not unmanaged", utr.Text);
4391
}
4492
}
4593
resolved = null;

tests/Silk.NET.SilkTouch.TypeResolution.Tests/FunctionPointerTypeResolverTests.cs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
using System;
55
using System.Linq;
6+
using Microsoft.Extensions.DependencyInjection;
7+
using Microsoft.Extensions.Logging;
68
using Silk.NET.SilkTouch.Symbols;
79
using Xunit;
810

@@ -17,11 +19,16 @@ public class FunctionPointerTypeResolverTests
1719
InlineData("delegate* unmanaged[Cdecl]<A, B, C>", "C", new[] { "A", "B"}),
1820
InlineData("delegate* unmanaged<A, B,C>", "C", new[] { "A", "B"}),
1921
InlineData("delegate* unmanaged[Cdecl]<A,B, C>", "C", new[] { "A", "B"}),
22+
InlineData("delegate* unmanaged[Cdecl, SupressGCTransition]<A>", "A", new string[0]),
23+
InlineData("delegate* unmanaged[Cdecl, SupressGCTransition]<A, B, C>", "C", new[] { "A", "B"}),
2024
]
2125
public void ShouldMatch(string text, string returnString, string[] parameters)
2226
{
23-
var result = new FunctionPointerTypeResolver(new TypeStore()).Visit(new UnresolvedTypeReference(text));
24-
27+
var serviceProvider = Helpers.CreateServiceProvider();
28+
var result = new FunctionPointerTypeResolver
29+
(serviceProvider.GetRequiredService<ILogger<FunctionPointerTypeResolver>>(), new TypeStore()).Visit
30+
(new UnresolvedTypeReference(text));
31+
2532
var fptr = Assert.IsType<FunctionPointerTypeReference>(result);
2633
Assert.Equal(returnString, Assert.IsType<UnresolvedTypeReference>(fptr.ReturnType).Text);
2734
Assert.Collection
@@ -44,11 +51,15 @@ public void ShouldMatch(string text, string returnString, string[] parameters)
4451
InlineData("longType"),
4552
InlineData("int"),
4653
InlineData("using"),
47-
InlineData("delegate*")
54+
InlineData("delegate*"),
55+
InlineData("delegate* unmanaged<>"),
4856
]
4957
public void ShouldNotMatch(string text)
5058
{
51-
var result = new FunctionPointerTypeResolver(new TypeStore()).Visit(new UnresolvedTypeReference(text));
59+
var serviceProvider = Helpers.CreateServiceProvider();
60+
var result = new FunctionPointerTypeResolver
61+
(serviceProvider.GetRequiredService<ILogger<FunctionPointerTypeResolver>>(), new TypeStore()).Visit
62+
(new UnresolvedTypeReference(text));
5263

5364
Assert.IsNotType<FunctionPointerTypeReference>(result);
5465
}

0 commit comments

Comments
 (0)