Skip to content

Commit 43eb1cd

Browse files
authored
Fields (#880)
1 parent 84ea299 commit 43eb1cd

File tree

8 files changed

+229
-16
lines changed

8 files changed

+229
-16
lines changed

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

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ private class Visitor : Silk.NET.SilkTouch.Symbols.SymbolVisitor
5151
public CSharpSyntaxNode? Syntax => _syntax;
5252
private CSharpSyntaxNode? _syntax = null;
5353

54-
protected override Symbol VisitStruct(StructSymbol structSymbol)
54+
protected override StructSymbol VisitStruct(StructSymbol structSymbol)
5555
{
5656
var members = List<MemberDeclarationSyntax>();
5757
var modifiers = TokenList(Token(SyntaxTriviaList.Empty, SyntaxKind.PublicKeyword, TriviaList(Space)));
@@ -61,7 +61,26 @@ protected override Symbol VisitStruct(StructSymbol structSymbol)
6161
List<TypeParameterConstraintClauseSyntax>(), members
6262
)
6363
.WithKeyword(Token(SyntaxTriviaList.Empty, SyntaxKind.StructKeyword, TriviaList(Space)));
64-
return base.VisitStruct(structSymbol);
64+
return structSymbol;
65+
}
66+
67+
protected override FieldSymbol VisitField(FieldSymbol fieldSymbol)
68+
{
69+
_syntax = FieldDeclaration
70+
(
71+
List<AttributeListSyntax>(),
72+
TokenList(Token(SyntaxTriviaList.Empty, SyntaxKind.PublicKeyword, TriviaList(Space))),
73+
VariableDeclaration
74+
(
75+
IdentifierName(fieldSymbol.Type.Identifier.Value),
76+
SingletonSeparatedList
77+
(
78+
VariableDeclarator
79+
(Identifier(TriviaList(Space), fieldSymbol.Identifier.Value, SyntaxTriviaList.Empty))
80+
)
81+
)
82+
);
83+
return fieldSymbol;
6584
}
6685
}
6786
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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+
namespace Silk.NET.SilkTouch.Symbols;
5+
6+
/// <summary>
7+
/// A <see cref="FieldSymbol"/>. A field is simply a named location that can hold some type.
8+
/// </summary>
9+
/// <seealso cref="MemberSymbol"/>
10+
public sealed class FieldSymbol : MemberSymbol
11+
{
12+
/// <summary>
13+
/// Create a field symbol from the parent <see cref="TypeSymbol"/>, the type of the field and it's identifier
14+
/// </summary>
15+
/// <param name="type">The type of the data stored in this field</param>
16+
/// <param name="identifier">The identifier of this field</param>
17+
public FieldSymbol(TypeSymbol type, IdentifierSymbol identifier)
18+
{
19+
Type = type;
20+
Identifier = identifier;
21+
}
22+
23+
/// <summary>
24+
/// The <see cref="TypeSymbol"/> of the data stored in this field
25+
/// </summary>
26+
public TypeSymbol Type { get; }
27+
28+
/// <summary>
29+
/// The Identifier of this field
30+
/// </summary>
31+
public IdentifierSymbol Identifier { get; }
32+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
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+
namespace Silk.NET.SilkTouch.Symbols;
5+
6+
/// <summary>
7+
/// A <see cref="MemberSymbol"/>, representing a generic member of some <see cref="TypeSymbol"/>
8+
/// </summary>
9+
/// <seealso cref="FieldSymbol"/>
10+
public abstract class MemberSymbol : Symbol
11+
{
12+
}

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

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,33 +16,62 @@ public abstract class SymbolVisitor
1616
public virtual Symbol Visit(Symbol symbol)
1717
{
1818
if (symbol is TypeSymbol ts) return VisitType(ts);
19+
if (symbol is MemberSymbol ms) return VisitMember(ms);
1920

20-
return ThrowUnknownSymbol(nameof(Symbol), symbol);
21+
if (symbol is IdentifierSymbol @is) return VisitIdentifier(@is);
22+
23+
return ThrowUnknownSymbol<Symbol>(symbol);
24+
}
25+
26+
/// <summary>
27+
/// Visit a <see cref="MemberSymbol"/>. This will call the appropriate method based on the actual type of the <paramref name="memberSymbol"/>
28+
/// </summary>
29+
/// <param name="memberSymbol">The member symbol to visit</param>
30+
/// <returns>The rewritten symbol</returns>
31+
/// <seealso cref="VisitField"/>
32+
protected virtual MemberSymbol VisitMember(MemberSymbol memberSymbol)
33+
{
34+
if (memberSymbol is FieldSymbol fs) return VisitField(fs);
35+
36+
return ThrowUnknownSymbol<MemberSymbol>(memberSymbol);
37+
}
38+
39+
/// <summary>
40+
/// Visit a <see cref="FieldSymbol"/>. Will call the appropriate methods to visit the different parts of the field.
41+
/// </summary>
42+
/// <param name="fieldSymbol">The field symbol to visit</param>
43+
/// <returns>The rewritten symbol</returns>
44+
/// <remarks>
45+
/// The order in which the parts of the struct are visited is kept as an implementation detail. Do not rely on this order.
46+
/// </remarks>
47+
protected virtual FieldSymbol VisitField(FieldSymbol fieldSymbol)
48+
{
49+
return new FieldSymbol(VisitType(fieldSymbol.Type), VisitIdentifier(fieldSymbol.Identifier));
2150
}
2251

2352
/// <summary>
2453
/// Visit a <see cref="TypeSymbol"/>. This will call the appropriate method based on the actual type of the <paramref name="typeSymbol"/>
2554
/// </summary>
2655
/// <param name="typeSymbol">The type symbol to visit</param>
27-
/// <returns>The rewritten symbol. May or may not be a <see cref="TypeSymbol"/></returns>
56+
/// <returns>The rewritten symbol</returns>
2857
/// <seealso cref="VisitStruct"/>
29-
protected virtual Symbol VisitType(TypeSymbol typeSymbol)
58+
protected virtual TypeSymbol VisitType(TypeSymbol typeSymbol)
3059
{
3160
if (typeSymbol is StructSymbol @struct) return VisitStruct(@struct);
3261

33-
return ThrowUnknownSymbol(nameof(TypeSymbol), typeSymbol);
62+
return ThrowUnknownSymbol<TypeSymbol>(typeSymbol);
3463
}
3564

3665
/// <summary>
3766
/// Visit a <see cref="StructSymbol"/>. Will call the appropriate methods to visit the different parts of the struct.
3867
/// </summary>
3968
/// <param name="structSymbol">The struct symbol to visit</param>
40-
/// <returns>The rewritten symbol. May or may not be a <see cref="StructSymbol"/></returns>
69+
/// <returns>The rewritten symbol</returns>
4170
/// <seealso cref="VisitType"/>
4271
/// <remarks>
4372
/// The order in which the parts of the struct are visited is kept as an implementation detail. Do not rely on this order.
4473
/// </remarks>
45-
protected virtual Symbol VisitStruct(StructSymbol structSymbol)
74+
protected virtual StructSymbol VisitStruct(StructSymbol structSymbol)
4675
{
4776
return new StructSymbol(VisitIdentifier(structSymbol.Identifier));
4877
}
@@ -57,8 +86,8 @@ protected virtual IdentifierSymbol VisitIdentifier(IdentifierSymbol identifierSy
5786
return identifierSymbol;
5887
}
5988

60-
private static Symbol ThrowUnknownSymbol(string type, Symbol symbol)
89+
private static T ThrowUnknownSymbol<T>(Symbol symbol)
6190
{
62-
throw new NotImplementedException($"Unknown symbol of type {symbol.GetType().FullName} subclass of {type}");
91+
throw new NotImplementedException($"Unknown symbol of type {symbol.GetType().FullName} subclass of {typeof(T).Name}");
6392
}
6493
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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 Silk.NET.SilkTouch.Symbols;
5+
using Xunit;
6+
7+
namespace Silk.NET.SilkTouch.Emitter.Tests;
8+
9+
public sealed class EmitterFieldIntegrationTests : EmitterTest
10+
{
11+
[Fact]
12+
public void StructHasStructKeyword()
13+
{
14+
var emitter = CreateEmitter();
15+
16+
var symbol = new FieldSymbol(new StructSymbol(new IdentifierSymbol("int")), new IdentifierSymbol("Test"));
17+
18+
var syntax = emitter.Transform(symbol);
19+
20+
var result = syntax.ToFullString();
21+
Assert.Equal("public int Test;", result);
22+
}
23+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
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 Moq;
5+
using Moq.Protected;
6+
using Xunit;
7+
8+
namespace Silk.NET.SilkTouch.Symbols.Tests.SymbolVisitorTests;
9+
10+
public class FieldTests
11+
{
12+
[Fact]
13+
public void FieldIsVisitedAsField()
14+
{
15+
var symbol = new FieldSymbol(new StructSymbol(new IdentifierSymbol("")), new IdentifierSymbol(""));
16+
var visitor = new Mock<SymbolVisitor>
17+
{
18+
CallBase = true
19+
};
20+
21+
visitor.Object.Visit(symbol);
22+
23+
visitor.Protected()
24+
.Verify<FieldSymbol>("VisitField", Times.Once(), ItExpr.IsAny<FieldSymbol>());
25+
}
26+
27+
[Fact]
28+
public void FieldIsVisitedAsMember()
29+
{
30+
var symbol = new FieldSymbol(new StructSymbol(new IdentifierSymbol("")), new IdentifierSymbol(""));
31+
var visitor = new Mock<SymbolVisitor>
32+
{
33+
CallBase = true
34+
};
35+
36+
visitor.Object.Visit(symbol);
37+
38+
visitor.Protected()
39+
.Verify<MemberSymbol>("VisitMember", Times.Once(), ItExpr.IsAny<MemberSymbol>());
40+
}
41+
42+
[Fact]
43+
public void FieldTypeIsVisited()
44+
{
45+
var symbol = new FieldSymbol(new StructSymbol(new IdentifierSymbol("")), new IdentifierSymbol(""));
46+
var visitor = new Mock<SymbolVisitor>
47+
{
48+
CallBase = true
49+
};
50+
51+
visitor.Object.Visit(symbol);
52+
53+
visitor.Protected()
54+
.Verify<TypeSymbol>("VisitType", Times.Once(), ItExpr.IsAny<TypeSymbol>());
55+
}
56+
57+
[Fact]
58+
public void FieldIdentifierIsVisited()
59+
{
60+
var symbol = new FieldSymbol(new StructSymbol(new IdentifierSymbol("")), new IdentifierSymbol(""));
61+
var visitor = new Mock<SymbolVisitor>
62+
{
63+
CallBase = true
64+
};
65+
66+
visitor.Object.Visit(symbol);
67+
68+
// note that this also tests whether the struct identifier is visited, there's just no good way of testing JUST the field identifier
69+
visitor.Protected()
70+
.Verify<IdentifierSymbol>("VisitIdentifier", Times.Exactly(2), ItExpr.IsAny<IdentifierSymbol>());
71+
}
72+
}
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 Moq;
5+
using Moq.Protected;
6+
using Xunit;
7+
8+
namespace Silk.NET.SilkTouch.Symbols.Tests.SymbolVisitorTests;
9+
10+
public class IdentifierTests
11+
{
12+
[Fact]
13+
public void IdentifierIsVisitedAsIdentifier()
14+
{
15+
var symbol = new IdentifierSymbol("");
16+
var visitor = new Mock<SymbolVisitor>
17+
{
18+
CallBase = true
19+
};
20+
21+
visitor.Object.Visit(symbol);
22+
23+
visitor.Protected()
24+
.Verify<IdentifierSymbol>("VisitIdentifier", Times.Once(), ItExpr.IsAny<IdentifierSymbol>());
25+
}
26+
}

tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests.cs renamed to tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/StructTests.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
// Licensed to the .NET Foundation under one or more agreements.
1+
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using Moq;
55
using Moq.Protected;
66
using Xunit;
77

8-
namespace Silk.NET.SilkTouch.Symbols.Tests;
8+
namespace Silk.NET.SilkTouch.Symbols.Tests.SymbolVisitorTests;
99

10-
public sealed class SymbolVisitorTests
10+
public class StructTests
1111
{
1212
[Fact]
1313
public void StructSymbolIsVisitedAsType()
@@ -21,7 +21,7 @@ public void StructSymbolIsVisitedAsType()
2121
visitor.Object.Visit(symbol);
2222

2323
visitor.Protected()
24-
.Verify<Symbol>("VisitType", Times.Once(), ItExpr.IsAny<TypeSymbol>());
24+
.Verify<TypeSymbol>("VisitType", Times.Once(), ItExpr.IsAny<TypeSymbol>());
2525
}
2626

2727
[Fact]
@@ -36,7 +36,7 @@ public void StructSymbolIsVisitedAsStruct()
3636
visitor.Object.Visit(symbol);
3737

3838
visitor.Protected()
39-
.Verify<Symbol>("VisitStruct", Times.Once(), ItExpr.IsAny<StructSymbol>());
39+
.Verify<StructSymbol>("VisitStruct", Times.Once(), ItExpr.IsAny<StructSymbol>());
4040
}
4141

4242
[Fact]
@@ -51,6 +51,6 @@ public void StructIdentifierIsVisitedAsIdentifier()
5151
visitor.Object.Visit(symbol);
5252

5353
visitor.Protected()
54-
.Verify<Symbol>("VisitIdentifier", Times.Once(), ItExpr.IsAny<IdentifierSymbol>());
54+
.Verify<IdentifierSymbol>("VisitIdentifier", Times.Once(), ItExpr.IsAny<IdentifierSymbol>());
5555
}
5656
}

0 commit comments

Comments
 (0)