Skip to content

Commit bcb2631

Browse files
authored
XML Visiting (#909)
1 parent 956c5f2 commit bcb2631

File tree

6 files changed

+240
-120
lines changed

6 files changed

+240
-120
lines changed

src/generators/Silk.NET.SilkTouch.Scraper/ClangScraper.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,27 @@ public sealed class ClangScraper
2727
/// Placeholder used in place of library paths
2828
/// </summary>
2929
public static readonly string LibraryNamespacePlaceholder = "LIBRARY_NAMESPACE";
30-
30+
31+
/// <summary>
32+
/// Scrapes the given XML document for symbols
33+
/// </summary>
34+
/// <param name="document">A XML Document, the format is assumed to be similar to what ClangSharp would output.</param>
35+
/// <returns>Any number of symbols scraped from the given xml</returns>
36+
public IEnumerable<Symbol> ScrapeXML(XmlDocument document)
37+
{
38+
var bindings = document.ChildNodes.Cast<XmlNode>().FirstOrDefault(x => x.LocalName == "bindings" && x is XmlElement) as XmlElement;
39+
40+
if (bindings is null)
41+
{
42+
return Enumerable.Empty<Symbol>();
43+
}
44+
45+
var visitor = new XmlVisitor();
46+
visitor.Visit(bindings);
47+
48+
return visitor.Symbols;
49+
}
50+
3151
/// <summary>
3252
/// Calls into Clang to generate XML used to scrape symbols.
3353
/// </summary>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Xml;
8+
using Silk.NET.SilkTouch.Symbols;
9+
10+
namespace Silk.NET.SilkTouch.Scraper;
11+
12+
internal sealed class XmlVisitor
13+
{
14+
private List<Symbol> _symbols = new();
15+
16+
public IEnumerable<Symbol> Symbols => _symbols;
17+
18+
public void Visit(XmlNode node)
19+
{
20+
switch (node)
21+
{
22+
case XmlElement { Name: "bindings" } bindings:
23+
{
24+
foreach (var child in bindings.ChildNodes.Cast<XmlNode>())
25+
{
26+
if (child is null) continue;
27+
Visit(child);
28+
}
29+
break;
30+
}
31+
default:
32+
{
33+
throw new NotImplementedException();
34+
}
35+
}
36+
}
37+
}

tests/Silk.NET.SilkTouch.Emitter.Tests/EmitterFieldTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public void FieldIsPublic()
2929
(
3030
new FieldSymbol
3131
(
32-
new StructSymbol(new IdentifierSymbol("int"), ImmutableArray<MemberSymbol>.Empty),
32+
new StructSymbol(new IdentifierSymbol("int"), StructLayout.Empty),
3333
new IdentifierSymbol("Test")
3434
)
3535
) as FieldDeclarationSyntax;
@@ -45,7 +45,7 @@ public void FieldHasCorrectTypeIdentifier()
4545
(
4646
new FieldSymbol
4747
(
48-
new StructSymbol(new IdentifierSymbol("int"), ImmutableArray<MemberSymbol>.Empty),
48+
new StructSymbol(new IdentifierSymbol("int"), StructLayout.Empty),
4949
new IdentifierSymbol("Test")
5050
)
5151
) as FieldDeclarationSyntax;
@@ -63,7 +63,7 @@ public void FieldHasCorrectIdentifier()
6363
(
6464
new FieldSymbol
6565
(
66-
new StructSymbol(new IdentifierSymbol("int"), ImmutableArray<MemberSymbol>.Empty),
66+
new StructSymbol(new IdentifierSymbol("int"), StructLayout.Empty),
6767
new IdentifierSymbol("Test")
6868
)
6969
) as FieldDeclarationSyntax;
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
using System;
2+
using System.ComponentModel;
3+
using System.Diagnostics;
4+
using System.IO;
5+
using System.Linq;
6+
using System.Reflection;
7+
using System.Runtime.InteropServices;
8+
using System.Runtime.Loader;
9+
using System.Xml;
10+
using Xunit;
11+
12+
namespace Silk.NET.SilkTouch.Scraper.Tests;
13+
14+
public class BasicXMLTests
15+
{
16+
/*
17+
* NOTE:
18+
* MOST OF THE FUNCTIONALITY TESTED HERE REALLY DEPENDS ON CLANG(SHARP).
19+
* THEREFORE IT IS UNNECESSARY TO TEST IT AS DETAILED AS OTHER PARTS OF THIS SYSTEM.
20+
* ONLY CREATE TESTS HERE IF THERE IS AN ISSUE IN OUR SYSTEM THAT YOU NEED TO TRACK DOWN
21+
* DO NOT JUST CREATE TESTS TO TEST CLANGSHARP.
22+
* IF THERE ARE ISSUES WITH THE XML NOT REFLECTING PART OF A HEADER:
23+
* 1. CHECK OUR CONFIGURATION. ITS FAIRLY SIMPLE AND BAREBONES.
24+
* 2. IF 1. DID NOT RESOLVE THE PROBLEM, RAISE WITH CLANGSHARP/CLANG INSTEAD.
25+
* WE DO NOT WANT TO REWRITE THE XML IN ANY WAY.
26+
*/
27+
28+
29+
private const string TempFileHeader = @"/* This file is temporarily created for use by Silk.NET tests. If you don't intend to run such a test, feel free to delete this file. */";
30+
31+
32+
[Fact]
33+
public void BasicStructScrapingTest()
34+
{
35+
var tempFile = Path.GetTempFileName();
36+
37+
File.WriteAllText(tempFile, TempFileHeader + @"
38+
#include <stdint.h>
39+
40+
typedef struct {
41+
int32_t f1;
42+
int32_t f2;
43+
} Test;");
44+
45+
var scraper = new ClangScraper();
46+
var xml = scraper.GenerateXML
47+
(tempFile, Array.Empty<string>(), Array.Empty<string>(), Array.Empty<string>(), Array.Empty<string>());
48+
49+
/*
50+
Next, Assert the XML looks something like this:
51+
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
52+
<bindings>
53+
<namespace name="<PLACEHOLDER>">
54+
<struct name="Test">
55+
<field name="f1">
56+
<type native="int32_t">int</type>
57+
</field>
58+
<field name="f2">
59+
<type native="int32_t">int</type>
60+
</field>
61+
</struct>
62+
</namespace>
63+
</bindings>
64+
*/
65+
66+
Assert.NotNull(xml);
67+
// Root
68+
Assert.Collection(xml!.ChildNodes.Cast<XmlNode>(),
69+
static dec => Assert.IsType<XmlDeclaration>(dec), // Top Declaration
70+
static bindings => // Root Bindings Element
71+
{
72+
var e = Assert.IsType<XmlElement>(bindings);
73+
Assert.Equal("bindings", e.LocalName);
74+
Assert.Collection(e.ChildNodes.Cast<XmlNode>(), // namespaces
75+
static @namespace =>
76+
{
77+
var e = Assert.IsType<XmlElement>(@namespace);
78+
var nameAtt = e.Attributes["name"];
79+
Assert.NotNull(nameAtt);
80+
Assert.Equal(ClangScraper.LibraryNamespacePlaceholder, nameAtt!.Value);
81+
82+
Assert.Collection(e.ChildNodes.Cast<XmlNode>(), // namespace members
83+
static @struct =>
84+
{
85+
var e = Assert.IsType<XmlElement>(@struct);
86+
var nameAtt = e.Attributes["name"];
87+
Assert.NotNull(nameAtt);
88+
Assert.Equal("Test", nameAtt!.Value);
89+
90+
Assert.Collection(e.ChildNodes.Cast<XmlNode>(), // struct members
91+
static field =>
92+
{
93+
var e = Assert.IsType<XmlElement>(field);
94+
var nameAtt = e.Attributes["name"];
95+
Assert.NotNull(nameAtt);
96+
Assert.Equal("f1", nameAtt!.Value);
97+
98+
Assert.Collection(e.ChildNodes.Cast<XmlNode>(), // field infos
99+
static type =>
100+
{
101+
var e = Assert.IsType<XmlElement>(type);
102+
var nativeAtt = e.Attributes["native"];
103+
Assert.NotNull(nativeAtt);
104+
Assert.Equal("int32_t", nativeAtt!.Value);
105+
106+
Assert.Collection(e.ChildNodes.Cast<XmlNode>(), // unwrap converted type
107+
static type =>
108+
{
109+
var e = Assert.IsType<XmlText>(type);
110+
Assert.Equal("int", e.Value);
111+
});
112+
});
113+
}, static field =>
114+
{
115+
var e = Assert.IsType<XmlElement>(field);
116+
var nameAtt = e.Attributes["name"];
117+
Assert.NotNull(nameAtt);
118+
Assert.Equal("f2", nameAtt!.Value);
119+
120+
Assert.Collection(e.ChildNodes.Cast<XmlNode>(), // field infos
121+
static type =>
122+
{
123+
var e = Assert.IsType<XmlElement>(type);
124+
var nativeAtt = e.Attributes["native"];
125+
Assert.NotNull(nativeAtt);
126+
Assert.Equal("int32_t", nativeAtt!.Value);
127+
128+
Assert.Collection(e.ChildNodes.Cast<XmlNode>(), // unwrap converted type
129+
static type =>
130+
{
131+
var e = Assert.IsType<XmlText>(type);
132+
Assert.Equal("int", e.Value);
133+
});
134+
});
135+
});
136+
});
137+
});
138+
});
139+
}
140+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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.Linq;
5+
using System.Xml;
6+
using Xunit;
7+
8+
namespace Silk.NET.SilkTouch.Scraper.Tests;
9+
10+
public class IdentityScrapingTests
11+
{
12+
[Fact]
13+
public void EmptyXmlGeneratesNoSymbols()
14+
{
15+
var doc = new XmlDocument();
16+
17+
var symbols = new ClangScraper().ScrapeXML(doc);
18+
19+
Assert.Empty(symbols);
20+
}
21+
22+
[Fact]
23+
public void EmptyBindingsXmlGeneratesNoSymbols()
24+
{
25+
var doc = new XmlDocument();
26+
doc.LoadXml(@"<bindings>
27+
</bindings>
28+
");
29+
30+
var symbols = new ClangScraper().ScrapeXML(doc);
31+
32+
Assert.Empty(symbols);
33+
}
34+
}
35+

0 commit comments

Comments
 (0)