Skip to content

Commit

Permalink
Fptr improvements (#1038)
Browse files Browse the repository at this point in the history
  • Loading branch information
HurricanKai committed Aug 13, 2022
1 parent b486b41 commit f02b74f
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 24 deletions.
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

0 comments on commit f02b74f

Please sign in to comment.