Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fptr improvements #1038

Merged
merged 2 commits into from
Aug 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<PackAsTool Condition="'$(Configuration)' != 'Debug'">true</PackAsTool>
<ToolCommandName>silktouch</ToolCommandName>
<PackageType>DotnetTool</PackageType>
<GeneratePackageOnBuild Condition="'$(Configuration)' != 'Debug'">true</GeneratePackageOnBuild>

<!-- Workaround for issue https://github.com/microsoft/ClangSharp/issues/129 -->
<RuntimeIdentifier Condition="'$(RuntimeIdentifier)' == '' AND '$(PackAsTool)' != 'true'">$(NETCoreSdkRuntimeIdentifier)</RuntimeIdentifier>
Expand Down
2 changes: 1 addition & 1 deletion src/generators/Silk.NET.SilkTouch.Scraper/XmlVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public XmlVisitor(ILogger logger, TypeStore typeStore)

public IEnumerable<Symbol> Visit(XmlNode node)
{
_logger.LogTrace("Visiting XML Node of kind {name}", node.Name);
_logger.LogTrace("Visiting XML Node of kind {name} {inner}", node.Name, node.InnerXml);
switch (node)
{
case XmlElement { Name: "bindings" } bindings:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Immutable;
using System.Diagnostics;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Logging;
using Silk.NET.SilkTouch.Symbols;

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

/// <inheritdoc />
public FunctionPointerTypeResolver(TypeStore typeStore) : base(typeStore)
public FunctionPointerTypeResolver(ILogger<FunctionPointerTypeResolver> logger, TypeStore typeStore) : base(typeStore)
{
_logger = logger;
}

/// <inheritdoc />
protected override bool TryResolve(UnresolvedTypeReference utr, out TypeReference? resolved)
{
if (utr.Text.StartsWith("delegate*"))
int c = 0;
var text = utr.Text;
if (text.Length > "delegate*".Length && text[text.Length - 1] == '>' && text.Substring(c, "delegate*".Length) == "delegate*")
{
var match = _regex.Match(utr.Text);
if (match.Success)
_logger.LogTrace("Attempting to resolve {text} to function pointer after passing preliminary tests", utr.Text);
c += "delegate*".Length;
if (text.Substring(c, " unmanaged".Length) == " unmanaged")
{
var parameters = match.Groups["parameter"]
.Captures.OfType<Capture>()
.Select(x => new UnresolvedTypeReference(x.Value))
.Cast<TypeReference>()
.ToImmutableArray();
var returnType = new UnresolvedTypeReference(match.Groups["return_type"].Value);
c += " unmanaged".Length;
if (text[c] == '[')
{
var endOffset = text.AsSpan(c).IndexOf(']');

var attributeText = text.Substring(c + 1, endOffset - 1);
_logger.LogDebug("{text} may be a function pointer and has unhandled attributes {attributes}", utr.Text, attributeText);
// TODO: parse out function attributes here

c += endOffset + 1;
}
var types = new List<TypeReference>();
if (text[c] == '<')
{
c += 1;
while (true)
{
var typeTextEndIndex = text.AsSpan(c).IndexOf(',');
if (typeTextEndIndex != -1)
{
var typeText = text.Substring(c, typeTextEndIndex);
c += typeTextEndIndex + 1;
if (text[c] == ' ') c++;
types.Add(new UnresolvedTypeReference(typeText));
}
else
{
var l = text.Length - c - 1;
if (l > 0)
{
var typeText = text.Substring(c, l);
types.Add(new UnresolvedTypeReference(typeText));
}
break;
}
}
}
else
{
_logger.LogDebug("{text} may be a function pointer but generic params are somehow scrambled", utr.Text);
}

resolved = new FunctionPointerTypeReference(returnType, parameters);
return true;

// at least a return type is required
if (types.Count > 0)
{
resolved = new FunctionPointerTypeReference
(types.Last(), types.Take(types.Count - 1).ToImmutableArray());
_logger.LogTrace("{text} resolved to function pointer {ptr}", utr.Text, resolved);
return true;
}
}
else
{
_logger.LogDebug("Rejecting {text} as it may be a function pointer, but not unmanaged", utr.Text);
}
}
resolved = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

using System;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Silk.NET.SilkTouch.Symbols;
using Xunit;

Expand All @@ -17,11 +19,16 @@ public class FunctionPointerTypeResolverTests
InlineData("delegate* unmanaged[Cdecl]<A, B, C>", "C", new[] { "A", "B"}),
InlineData("delegate* unmanaged<A, B,C>", "C", new[] { "A", "B"}),
InlineData("delegate* unmanaged[Cdecl]<A,B, C>", "C", new[] { "A", "B"}),
InlineData("delegate* unmanaged[Cdecl, SupressGCTransition]<A>", "A", new string[0]),
InlineData("delegate* unmanaged[Cdecl, SupressGCTransition]<A, B, C>", "C", new[] { "A", "B"}),
]
public void ShouldMatch(string text, string returnString, string[] parameters)
{
var result = new FunctionPointerTypeResolver(new TypeStore()).Visit(new UnresolvedTypeReference(text));

var serviceProvider = Helpers.CreateServiceProvider();
var result = new FunctionPointerTypeResolver
(serviceProvider.GetRequiredService<ILogger<FunctionPointerTypeResolver>>(), new TypeStore()).Visit
(new UnresolvedTypeReference(text));

var fptr = Assert.IsType<FunctionPointerTypeReference>(result);
Assert.Equal(returnString, Assert.IsType<UnresolvedTypeReference>(fptr.ReturnType).Text);
Assert.Collection
Expand All @@ -44,11 +51,15 @@ public void ShouldMatch(string text, string returnString, string[] parameters)
InlineData("longType"),
InlineData("int"),
InlineData("using"),
InlineData("delegate*")
InlineData("delegate*"),
InlineData("delegate* unmanaged<>"),
]
public void ShouldNotMatch(string text)
{
var result = new FunctionPointerTypeResolver(new TypeStore()).Visit(new UnresolvedTypeReference(text));
var serviceProvider = Helpers.CreateServiceProvider();
var result = new FunctionPointerTypeResolver
(serviceProvider.GetRequiredService<ILogger<FunctionPointerTypeResolver>>(), new TypeStore()).Visit
(new UnresolvedTypeReference(text));

Assert.IsNotType<FunctionPointerTypeReference>(result);
}
Expand Down