Skip to content

Commit 226d7df

Browse files
authored
Method symbols (#1032)
1 parent a34dd81 commit 226d7df

File tree

7 files changed

+201
-12
lines changed

7 files changed

+201
-12
lines changed

documentation/for-contributors/generators/symbol-layer/symbols/README.md

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,19 @@ Parent Symbols (Unlisted, abstract):
1717
| Symbol | |
1818
| TypeReference | [here](../type-references.md) |
1919
| TypeSymbol | |
20-
21-
| Name | Symbol Layer File | Symbol Layer Tests | Emitter Tests |
22-
| ----------------------- | ----------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
23-
| ExternalTypeReference | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/ExternalTypeReference.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/ExternalTypeReferenceTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/ExternalTypeReferenceTests.cs) |
24-
| FieldSymbol | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/FieldSymbol.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/FieldTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/EmitterFieldTests.cs) |
25-
| IdentifierSymbol | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/IdentifierSymbol.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/IdentifierTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/IdentifierSymbolTests.cs) |
26-
| InternalTypeReference | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/InternalTypeReference.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/InternalTypeReferenceTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/InternalTypeReferenceTests.cs) |
27-
| NamespaceSymbol | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/NamespaceSymbol.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/NamespaceTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/EmitterNamespaceTests.cs) |
28-
| PointerTypeReference | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/PointerTypeReference.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/PointerTypeReferenceTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/PointerTypeReferenceTests.cs) |
29-
| StructSymbol | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/StructSymbol.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/StructTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/EmitterStructTests.cs) |
30-
| UnresolvedTypeReference | [here](src/generators/Silk.NET.SilkTouch.Symbols/UnresolvedTypeReference.cs) | [here](tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/UnresolvedTypeReferenceTests.cs) | - |
20+
| MethodSymbol |
21+
22+
| Name | Symbol Layer File | Symbol Layer Tests | Emitter Tests |
23+
| -------------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
24+
| ExternalTypeReference | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/ExternalTypeReference.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/ExternalTypeReferenceTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/ExternalTypeReferenceTests.cs) |
25+
| FieldSymbol | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/FieldSymbol.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/FieldTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/EmitterFieldTests.cs) |
26+
| IdentifierSymbol | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/IdentifierSymbol.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/IdentifierTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/IdentifierSymbolTests.cs) |
27+
| InternalTypeReference | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/InternalTypeReference.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/InternalTypeReferenceTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/InternalTypeReferenceTests.cs) |
28+
| NamespaceSymbol | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/NamespaceSymbol.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/NamespaceTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/EmitterNamespaceTests.cs) |
29+
| PointerTypeReference | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/PointerTypeReference.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/PointerTypeReferenceTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/PointerTypeReferenceTests.cs) |
30+
| StaticExternalMethodSymbol | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/StaticExternalMethodSymbol.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/StaticExternalMethodSymbolTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/StaticExternalMethodSymbolTests.cs) |
31+
| StructSymbol | [here](../../../../../src/generators/Silk.NET.SilkTouch.Symbols/StructSymbol.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/StructTests.cs) | [here](../../../../../tests/Silk.NET.SilkTouch.Emitter.Tests/EmitterStructTests.cs) |
32+
| UnresolvedTypeReference | [here](src/generators/Silk.NET.SilkTouch.Symbols/UnresolvedTypeReference.cs) | [here](tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/UnresolvedTypeReferenceTests.cs) | - |
3133

3234
## How to create a symbol
3335

src/generators/Silk.NET.SilkTouch.Emitter/CSharpEmitter.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.CodeDom.Compiler;
66
using System.Collections.Generic;
7+
using System.Collections.Immutable;
78
using System.Diagnostics;
89
using System.Linq;
910
using Microsoft.CodeAnalysis;
@@ -228,6 +229,54 @@ protected override ExternalTypeReference VisitExternalTypeReference(ExternalType
228229
return typeReference;
229230
}
230231

232+
protected override StaticExternalMethodSymbol VisitStaticExternalMethod(StaticExternalMethodSymbol staticExternalMethodSymbol)
233+
{
234+
AssertClearState();
235+
236+
VisitTypeReference(staticExternalMethodSymbol.ReturnType);
237+
if (_syntax is not TypeSyntax returnSyntaxToken)
238+
throw new InvalidOperationException("Type Reference not correctly visited");
239+
ClearState();
240+
241+
VisitIdentifier(staticExternalMethodSymbol.Identifier);
242+
if (_syntaxToken is not {} identifierToken)
243+
throw new InvalidOperationException("Type Reference not correctly visited");
244+
ClearState();
245+
246+
var parameters = staticExternalMethodSymbol.Parameters.Select
247+
(
248+
x =>
249+
{
250+
VisitTypeReference(x.TypeReference);
251+
if (_syntax is not TypeSyntax resultToken)
252+
throw new InvalidOperationException("Type Reference not correctly visited");
253+
ClearState();
254+
255+
VisitIdentifier(x.Identifier);
256+
if (_syntaxToken is not {} identifierToken2)
257+
throw new InvalidOperationException("Syntax Token was not correctly visited");
258+
ClearState();
259+
260+
return Parameter(identifierToken2).WithType(resultToken);
261+
}
262+
).ToImmutableArray();
263+
264+
_syntax = MethodDeclaration(returnSyntaxToken.WithLeadingTrivia(Space), identifierToken.WithLeadingTrivia(Space))
265+
.WithModifiers
266+
(
267+
TokenList
268+
(
269+
Token(SyntaxKind.PublicKeyword),
270+
Token(SyntaxKind.StaticKeyword).WithLeadingTrivia(Space),
271+
Token(SyntaxKind.ExternKeyword).WithLeadingTrivia(Space)
272+
)
273+
)
274+
.WithParameterList(ParameterList(SeparatedList(parameters)))
275+
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken));
276+
277+
return staticExternalMethodSymbol;
278+
}
279+
231280
protected override IdentifierSymbol VisitIdentifier(IdentifierSymbol identifierSymbol)
232281
{
233282
AssertClearState();
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Collections.Immutable;
5+
6+
namespace Silk.NET.SilkTouch.Symbols;
7+
8+
/// <summary>
9+
/// A <see cref="MemberSymbol"/> representing a method with a signature.
10+
/// </summary>
11+
public abstract record MethodSymbol(TypeReference ReturnType, ImmutableArray<Parameter> Parameters, IdentifierSymbol Identifier) : MemberSymbol;
12+
13+
/// <summary>
14+
/// Represents a Parameter to a <see cref="MethodSymbol"/>
15+
/// </summary>
16+
/// <param name="TypeReference">The type of this parameter</param>
17+
/// <param name="Identifier">The identifier of this parameter</param>
18+
public sealed record Parameter(TypeReference TypeReference, IdentifierSymbol Identifier);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Collections.Immutable;
5+
6+
namespace Silk.NET.SilkTouch.Symbols;
7+
8+
/// <summary>
9+
/// A static external method symbol.
10+
/// External meaning it must be loaded
11+
/// </summary>
12+
public sealed record StaticExternalMethodSymbol
13+
(TypeReference ReturnType, ImmutableArray<Parameter> Parameters, IdentifierSymbol Identifier)
14+
: MethodSymbol(ReturnType, Parameters, Identifier)
15+
{
16+
}

src/generators/Silk.NET.SilkTouch.Symbols/SymbolVisitor.cs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public virtual Symbol Visit(Symbol symbol)
5050
protected virtual MemberSymbol VisitMember(MemberSymbol memberSymbol)
5151
{
5252
if (memberSymbol is FieldSymbol fs) return VisitField(fs);
53+
if (memberSymbol is MethodSymbol ms) return VisitMethod(ms);
5354

5455
return ThrowUnknownSymbol<MemberSymbol>(memberSymbol);
5556
}
@@ -66,7 +67,42 @@ protected virtual FieldSymbol VisitField(FieldSymbol fieldSymbol)
6667
{
6768
return new FieldSymbol(VisitTypeReference(fieldSymbol.Type), VisitIdentifier(fieldSymbol.Identifier));
6869
}
69-
70+
71+
/// <summary>
72+
/// Visit a <see cref="MethodSymbol"/>. Will call the appropriate methods to visit the different parts of the symbol.
73+
/// </summary>
74+
/// <param name="methodSymbol">The method to visit</param>
75+
/// <returns>The rewritten symbol</returns>
76+
/// <remarks>
77+
/// The order in which the parts are visited is kept as an implementation detail. Do not rely on this order.
78+
/// </remarks>
79+
protected virtual MethodSymbol VisitMethod(MethodSymbol methodSymbol)
80+
{
81+
if (methodSymbol is StaticExternalMethodSymbol stms) return VisitStaticExternalMethod(stms);
82+
return ThrowUnknownSymbol<MethodSymbol>(methodSymbol);
83+
}
84+
85+
/// <summary>
86+
/// Visit a <see cref="StaticExternalMethodSymbol"/>. Will call the appropriate methods to visit the different parts of the symbol.
87+
/// </summary>
88+
/// <param name="staticExternalMethodSymbol">The method to visit</param>
89+
/// <returns>The rewritten symbol</returns>
90+
/// <remarks>
91+
/// The order in which the parts are visited is kept as an implementation detail. Do not rely on this order.
92+
/// </remarks>
93+
protected virtual StaticExternalMethodSymbol VisitStaticExternalMethod
94+
(StaticExternalMethodSymbol staticExternalMethodSymbol)
95+
{
96+
return new StaticExternalMethodSymbol
97+
(
98+
VisitTypeReference(staticExternalMethodSymbol.ReturnType),
99+
staticExternalMethodSymbol.Parameters.Select
100+
(x => new Parameter(VisitTypeReference(x.TypeReference), VisitIdentifier(x.Identifier)))
101+
.ToImmutableArray(),
102+
VisitIdentifier(staticExternalMethodSymbol.Identifier)
103+
);
104+
}
105+
70106
/// <summary>
71107
/// Visit a <see cref="TypeReference"/>. Will call the appropriate methods to visit the different parts of the symbol.
72108
/// </summary>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Collections.Immutable;
5+
using Silk.NET.SilkTouch.Symbols;
6+
using Xunit;
7+
8+
namespace Silk.NET.SilkTouch.Emitter.Tests;
9+
10+
public class StaticExternalMethodSymbolTests : EmitterTest
11+
{
12+
[Fact, Trait("Category", "Symbols")]
13+
public void StringTestNoParameters()
14+
{
15+
var symbol = new StaticExternalMethodSymbol
16+
(
17+
new ExternalTypeReference(null, new IdentifierSymbol("int")),
18+
ImmutableArray<Parameter>.Empty,
19+
new IdentifierSymbol("M")
20+
);
21+
22+
var transformed = Transform(symbol);
23+
24+
Assert.Equal("public static extern int M();", transformed.ToFullString());
25+
}
26+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Collections.Immutable;
5+
using Moq;
6+
using Moq.Protected;
7+
using Xunit;
8+
9+
namespace Silk.NET.SilkTouch.Symbols.Tests.SymbolVisitorTests;
10+
11+
public class StaticExternalMethodSymbolTests
12+
{
13+
[Fact, Trait("Category", "Symbols")]
14+
public void VisitedAsSelf()
15+
{
16+
var symbol = new StaticExternalMethodSymbol
17+
(new InternalTypeReference(TypeId.CreateNew()), ImmutableArray<Parameter>.Empty, new IdentifierSymbol(""));
18+
19+
var visitor = new Mock<MockSymbolVisitor> { CallBase = true };
20+
21+
visitor.Object.Visit(symbol);
22+
23+
visitor.Protected()
24+
.Verify<StaticExternalMethodSymbol>
25+
("VisitStaticExternalMethod", Times.Once(), ItExpr.IsAny<StaticExternalMethodSymbol>());
26+
}
27+
28+
[Fact, Trait("Category", "Symbols")]
29+
public void VisitedAsMethod()
30+
{
31+
var symbol = new StaticExternalMethodSymbol
32+
(new InternalTypeReference(TypeId.CreateNew()), ImmutableArray<Parameter>.Empty, new IdentifierSymbol(""));
33+
34+
var visitor = new Mock<MockSymbolVisitor> { CallBase = true };
35+
36+
visitor.Object.Visit(symbol);
37+
38+
visitor.Protected()
39+
.Verify<MethodSymbol>
40+
("VisitMethod", Times.Once(), ItExpr.IsAny<MethodSymbol>());
41+
}
42+
}

0 commit comments

Comments
 (0)