diff --git a/src/generators/Silk.NET.SilkTouch.Symbols/PointerTypeReference.cs b/src/generators/Silk.NET.SilkTouch.Symbols/PointerTypeReference.cs new file mode 100644 index 0000000000..144927da2d --- /dev/null +++ b/src/generators/Silk.NET.SilkTouch.Symbols/PointerTypeReference.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Silk.NET.SilkTouch.Symbols; + +/// +/// A representing a pointer type +/// +/// A reference to the pointed to type +public sealed record PointerTypeReference(TypeReference Underlying) : TypeReference; diff --git a/src/generators/Silk.NET.SilkTouch.Symbols/SymbolVisitor.cs b/src/generators/Silk.NET.SilkTouch.Symbols/SymbolVisitor.cs index 4b02981e1a..fc33285300 100644 --- a/src/generators/Silk.NET.SilkTouch.Symbols/SymbolVisitor.cs +++ b/src/generators/Silk.NET.SilkTouch.Symbols/SymbolVisitor.cs @@ -60,7 +60,7 @@ protected virtual MemberSymbol VisitMember(MemberSymbol memberSymbol) /// The field symbol to visit /// The rewritten symbol /// - /// The order in which the parts of the struct are visited is kept as an implementation detail. Do not rely on this order. + /// The order in which the parts are visited is kept as an implementation detail. Do not rely on this order. /// protected virtual FieldSymbol VisitField(FieldSymbol fieldSymbol) { @@ -73,7 +73,7 @@ protected virtual FieldSymbol VisitField(FieldSymbol fieldSymbol) /// The type reference to visit /// The rewritten symbol /// - /// The order in which the parts of the struct are visited is kept as an implementation detail. Do not rely on this order. + /// The order in which the parts are visited is kept as an implementation detail. Do not rely on this order. /// /// /// By default visiting will throw. Visitors involved in type resolution should override this method directly. @@ -83,16 +83,30 @@ protected virtual TypeReference VisitTypeReference(TypeReference typeReference) if (typeReference is ExternalTypeReference etr) return VisitExternalTypeReference(etr); if (typeReference is InternalTypeReference itr) return VisitInternalTypeReference(itr); if (typeReference is UnresolvedTypeReference utr) UnresolvedTypeReference.ThrowInvalidSymbol(); + if (typeReference is PointerTypeReference ptr) return VisitPointerTypeReference(ptr); return ThrowUnknownSymbol(typeReference); } + /// + /// Visit a . Will call the appropriate methods to visit the different parts of the symbol. + /// + /// The pointer type reference to visit + /// The rewritten symbol + /// + /// The order in which the parts are visited is kept as an implementation detail. Do not rely on this order. + /// + protected virtual PointerTypeReference VisitPointerTypeReference(PointerTypeReference pointerTypeReference) + { + return new PointerTypeReference(VisitTypeReference(pointerTypeReference.Underlying)); + } + /// /// Visit a . Will call the appropriate methods to visit the different parts of the symbol. /// /// The type reference to visit /// The rewritten symbol /// - /// The order in which the parts of the struct are visited is kept as an implementation detail. Do not rely on this order. + /// The order in which the parts are visited is kept as an implementation detail. Do not rely on this order. /// protected virtual InternalTypeReference VisitInternalTypeReference(InternalTypeReference typeReference) { @@ -105,7 +119,7 @@ protected virtual InternalTypeReference VisitInternalTypeReference(InternalTypeR /// The type reference to visit /// The rewritten symbol /// - /// The order in which the parts of the struct are visited is kept as an implementation detail. Do not rely on this order. + /// The order in which the parts are visited is kept as an implementation detail. Do not rely on this order. /// protected virtual ExternalTypeReference VisitExternalTypeReference(ExternalTypeReference typeReference) { @@ -155,7 +169,7 @@ protected virtual TypeSymbol VisitType(TypeSymbol typeSymbol) /// The rewritten symbol /// /// - /// The order in which the parts of the struct are visited is kept as an implementation detail. Do not rely on this order. + /// The order in which the parts are visited is kept as an implementation detail. Do not rely on this order. /// protected virtual StructSymbol VisitStruct(StructSymbol structSymbol) { diff --git a/src/generators/Silk.NET.SilkTouch.TypeResolution/PointerTypeResolver.cs b/src/generators/Silk.NET.SilkTouch.TypeResolution/PointerTypeResolver.cs new file mode 100644 index 0000000000..15750815f9 --- /dev/null +++ b/src/generators/Silk.NET.SilkTouch.TypeResolution/PointerTypeResolver.cs @@ -0,0 +1,53 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Silk.NET.SilkTouch.Symbols; + +namespace Silk.NET.SilkTouch.TypeResolution; + +/// +/// Resolves s with Text like "a*", "a.b.c*" to a with the underlying set to an with text = "a", "a.b.c", etc. +/// +/// +/// +/// +/// Input Tree +/// Output Tree +/// +/// +/// +/// (Text = "a.b.c*") +/// (Underlying = (Text = "a.b.c")) +/// +/// +/// +/// (Text = "int*") +/// (Underlying = (Text = "int")) +/// +/// +/// +/// (Text = "a") +/// (Text = "a") +/// +/// +/// +public sealed class PointerTypeResolver : SimpleTypeResolverBase +{ + + /// + public PointerTypeResolver(TypeStore typeStore) : base(typeStore) + { + } + + /// + protected override bool TryResolve(UnresolvedTypeReference utr, out TypeReference? resolved) + { + if (utr.Text.Length > 1 && utr.Text[utr.Text.Length - 1] == '*') + { + resolved = new PointerTypeReference(new UnresolvedTypeReference(utr.Text.Substring(0, utr.Text.Length - 1))); + return true; + } + resolved = null; + return false; + } +} diff --git a/src/generators/Silk.NET.SilkTouch.TypeResolution/SimpleTypeResolverBase.cs b/src/generators/Silk.NET.SilkTouch.TypeResolution/SimpleTypeResolverBase.cs new file mode 100644 index 0000000000..41abafb00c --- /dev/null +++ b/src/generators/Silk.NET.SilkTouch.TypeResolution/SimpleTypeResolverBase.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Silk.NET.SilkTouch.Symbols; + +namespace Silk.NET.SilkTouch.TypeResolution; + +/// +/// A base to simplify creation of basic type resolvers that only need simple text matching. +/// +public abstract class SimpleTypeResolverBase : SymbolVisitor +{ + /// + protected SimpleTypeResolverBase(TypeStore typeStore) : base(typeStore) + { + } + + /// + protected override TypeReference VisitTypeReference(TypeReference typeSymbol) + { + if (typeSymbol is UnresolvedTypeReference utr) + { + return TryResolve(utr, out var result) ? result! : utr; + } + return base.VisitTypeReference(typeSymbol); + } + + /// + /// Resolve an + /// + /// THe unresolved reference to attempt to resolve + /// The resolved reference. May not be null if true is returned. + /// Whether resolution was successful + /// + /// This method is free to return a partial resolution, and still return true. + /// Partial resolutions are such that do not have a at the root, + /// but have somewhere in the tree. + /// + protected abstract bool TryResolve(UnresolvedTypeReference utr, out TypeReference? resolved); +} diff --git a/tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/PointerTypeReferenceTests.cs b/tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/PointerTypeReferenceTests.cs new file mode 100644 index 0000000000..54ffad42c1 --- /dev/null +++ b/tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/PointerTypeReferenceTests.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Moq; +using Moq.Protected; +using Xunit; + +namespace Silk.NET.SilkTouch.Symbols.Tests.SymbolVisitorTests; + +public class PointerTypeReferenceTests +{ + [Fact, Trait("Category", "Type Resolution")] + public void RefIsVisitedAsSelf() + { + var symbol = new PointerTypeReference(new InternalTypeReference(TypeId.CreateNew())); + + var visitor = new Mock { CallBase = true }; + + visitor.Object.Visit(symbol); + + visitor.Protected() + .Verify + ("VisitPointerTypeReference", Times.Once(), ItExpr.IsAny()); + } + + [Fact, Trait("Category", "Type Resolution")] + public void RefIsVisitedAsRef() + { + var symbol = new PointerTypeReference(new InternalTypeReference(TypeId.CreateNew())); + + var visitor = new Mock { CallBase = true }; + + visitor.Object.Visit(symbol); + + visitor.Protected() + .Verify + ("VisitTypeReference", Times.Once(), ItExpr.Is(x => ReferenceEquals(x, symbol))); + } + + [Fact, Trait("Category", "Type Resolution")] + public void RefUnderlyingIsVisitedAsRef() + { + var underlying = new InternalTypeReference(TypeId.CreateNew()); + var symbol = new PointerTypeReference(underlying); + + var visitor = new Mock { CallBase = true }; + + visitor.Object.Visit(symbol); + + visitor.Protected() + .Verify + ("VisitTypeReference", Times.Once(), ItExpr.Is(x => ReferenceEquals(x, underlying))); + } +} diff --git a/tests/Silk.NET.SilkTouch.TestFramework/SilkTouchTestFramework.cs b/tests/Silk.NET.SilkTouch.TestFramework/SilkTouchTestFramework.cs index bd3657748a..2873d4fc51 100644 --- a/tests/Silk.NET.SilkTouch.TestFramework/SilkTouchTestFramework.cs +++ b/tests/Silk.NET.SilkTouch.TestFramework/SilkTouchTestFramework.cs @@ -73,7 +73,7 @@ ITestFrameworkDiscoveryOptions discoveryOptions foreach (var (name, value) in traits) { if (name is "Category" && - value is not "Integration" and not "Scraper" and not "Symbols" and not "Emitter" and not "TypeStore") + value is not "Integration" and not "Scraper" and not "Symbols" and not "Emitter" and not "TypeStore" and not "Type Resolution") { return this.ReportDiscoveredTestCase ( diff --git a/tests/Silk.NET.SilkTouch.TypeResolution.Tests/PointerResolverTests.cs b/tests/Silk.NET.SilkTouch.TypeResolution.Tests/PointerResolverTests.cs new file mode 100644 index 0000000000..1d014f79cd --- /dev/null +++ b/tests/Silk.NET.SilkTouch.TypeResolution.Tests/PointerResolverTests.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Silk.NET.SilkTouch.Symbols; +using Xunit; + +namespace Silk.NET.SilkTouch.TypeResolution.Tests; + +public sealed class PointerResolverTests +{ + [Theory, Trait("Category", "Type Resolution"), + InlineData("a*"), + InlineData("a.b.c*"), + InlineData("int*") + ] + public void ShouldResolve(string text) + { + var symbol = new UnresolvedTypeReference(text); + var output = new PointerTypeResolver(new TypeStore()); + + var finalSymbol = output.Visit(symbol); + Assert.IsType(finalSymbol); + } + + [Theory, Trait("Category", "Type Resolution"), + InlineData(""), + InlineData("a"), + InlineData("*"), + InlineData("a.b.c"), + InlineData("longType"), + InlineData("int"), + InlineData("using") + ] + public void ShouldNotResolve(string text) + { + var symbol = new UnresolvedTypeReference(text); + var output = new PointerTypeResolver(new TypeStore()); + + var finalSymbol = output.Visit(symbol); + Assert.IsNotType(finalSymbol); + } +}