Skip to content

Commit f5e0564

Browse files
UserUser
authored andcommitted
Add project files.
1 parent 13f6e89 commit f5e0564

File tree

209 files changed

+9988
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

209 files changed

+9988
-0
lines changed

.editorconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[*.cs]
2+
3+
# IDE0290: Use primary constructor
4+
dotnet_diagnostic.IDE0290.severity = none
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net8.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<ProjectReference Include="..\ILSourceParser\ILSourceParser.csproj" />
12+
</ItemGroup>
13+
14+
</Project>
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
using ILSourceParser;
2+
using ILSourceParser.Syntax;
3+
using ILSourceParser.Syntax.Instructions;
4+
using Sprache;
5+
6+
string input = @".assembly MyAssembly
7+
{
8+
.ver 1:2:3:4
9+
}
10+
.assembly extern System.Runtime
11+
{
12+
}
13+
.assembly extern System.Console
14+
{
15+
}
16+
17+
// My Cool Application !
18+
19+
.imagebase 0x00400000
20+
.line 123
21+
22+
.class public sequential auto ansi beforefieldinit MyValueType extends [System.Runtime]System.ValueType
23+
{
24+
.field private static initonly string s_myString
25+
26+
.method public static hidebysig void .cctor() cil managed
27+
{
28+
ldstr ""Hello, World!""
29+
stsfld string MyValueType::s_myString
30+
}
31+
32+
.method public static void PrintText() cil managed
33+
{
34+
.maxstack 8
35+
36+
ldsfld string MyValueType::s_myString
37+
call void [System.Console]System.Console::WriteLine(string)
38+
39+
ret
40+
}
41+
}";
42+
var syntaxRoot = ILSyntaxTree.ParseText(input).GetRoot();
43+
44+
foreach (var descendant in syntaxRoot.DescendantNodes)
45+
{
46+
switch (descendant)
47+
{
48+
case AssemblyDeclarationSyntax asm:
49+
Console.WriteLine($"Assembly {asm.AssemblyName}, is external: {asm.IsExtern}");
50+
break;
51+
case BaseCommentSyntax comment:
52+
if (comment is InlineCommentSyntax inline)
53+
{
54+
Console.WriteLine($"Inline comment, text: {inline.CommentText}");
55+
}
56+
else if (comment is MultilineCommentSyntax multiline)
57+
{
58+
Console.WriteLine($"Multiline comment, text: {multiline.CommentText}");
59+
}
60+
break;
61+
case ImageBaseDirectiveSyntax imageBase:
62+
Console.WriteLine($"Image base {imageBase.ImageBase}");
63+
break;
64+
case LineDirectiveSyntax line:
65+
Console.WriteLine($"Line {line.Line}");
66+
break;
67+
case ClassDeclarationSyntax @class:
68+
string flags = string.Join(", ", @class.Flags);
69+
Console.WriteLine($"Class named {@class.Name}; flags: {flags}");
70+
break;
71+
}
72+
}

ILSourceParser.Tests/AssemblyTests.cs

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
using ILSourceParser.Common;
2+
using ILSourceParser.Syntax;
3+
using ILSourceParser.Utilities;
4+
using Sprache;
5+
6+
namespace ILSourceParser.Tests;
7+
8+
public class AssemblyTests
9+
{
10+
private static readonly byte[] s_complexCustomAttributePermissionSetDescendantByteData =
11+
[
12+
0x2e, 0x01, 0x80, 0x8a, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x53, 0x65, 0x63,
13+
0x75, 0x72, 0x69, 0x74, 0x79, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69,
14+
0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x50, 0x65,
15+
0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62,
16+
0x75, 0x74, 0x65, 0x2c, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x52, 0x75,
17+
0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2c, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
18+
0x3d, 0x38, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x43, 0x75, 0x6c, 0x74,
19+
0x75, 0x72, 0x65, 0x3d, 0x6e, 0x65, 0x75, 0x74, 0x72, 0x61, 0x6c, 0x2c, 0x20, 0x50,
20+
0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x3d,
21+
0x62, 0x30, 0x33, 0x66, 0x35, 0x66, 0x37, 0x66, 0x31, 0x31, 0x64, 0x35, 0x30, 0x61,
22+
0x33, 0x61, 0x15, 0x01, 0x54, 0x02, 0x10, 0x53, 0x6b, 0x69, 0x70, 0x56, 0x65, 0x72,
23+
0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x01
24+
];
25+
26+
[Fact]
27+
public void Simple()
28+
{
29+
var parser = new Parser();
30+
var asmParser = parser.ParseAssemblyDeclaration();
31+
var result = asmParser.Parse(@".assembly extern System.Private.CoreLib
32+
{
33+
.line 123
34+
}");
35+
36+
Assert.True(result.IsExtern);
37+
Assert.Equal("System.Private.CoreLib", result.AssemblyName);
38+
Assert.Single(result.DescendantNodes);
39+
40+
Assert.True(result.DescendantNodes.ElementAt(0) is LineDirectiveSyntax);
41+
}
42+
43+
[Fact]
44+
public void Complex()
45+
{
46+
var parser = new Parser();
47+
var asmParser = parser.ParseAssemblyDeclaration();
48+
var result = asmParser.Parse(@".assembly _
49+
{
50+
.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = (
51+
01 00 08 00 00 00 00 00
52+
)
53+
.custom instance void [System.Runtime]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = (
54+
01 00 01 00 54 02 16 57 72 61 70 4e 6f 6e 45 78
55+
63 65 70 74 69 6f 6e 54 68 72 6f 77 73 01
56+
)
57+
.custom instance void [System.Runtime]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [System.Runtime]System.Diagnostics.DebuggableAttribute/DebuggingModes) = (
58+
01 00 02 00 00 00 00 00
59+
)
60+
.permissionset reqmin = (
61+
2e 01 80 8a 53 79 73 74 65 6d 2e 53 65 63 75 72
62+
69 74 79 2e 50 65 72 6d 69 73 73 69 6f 6e 73 2e
63+
53 65 63 75 72 69 74 79 50 65 72 6d 69 73 73 69
64+
6f 6e 41 74 74 72 69 62 75 74 65 2c 20 53 79 73
65+
74 65 6d 2e 52 75 6e 74 69 6d 65 2c 20 56 65 72
66+
73 69 6f 6e 3d 38 2e 30 2e 30 2e 30 2c 20 43 75
67+
6c 74 75 72 65 3d 6e 65 75 74 72 61 6c 2c 20 50
68+
75 62 6c 69 63 4b 65 79 54 6f 6b 65 6e 3d 62 30
69+
33 66 35 66 37 66 31 31 64 35 30 61 33 61 15 01
70+
54 02 10 53 6b 69 70 56 65 72 69 66 69 63 61 74
71+
69 6f 6e 01
72+
)
73+
.hash algorithm 0x00008004 // SHA1
74+
.ver 0:0:0:0
75+
}");
76+
77+
Assert.False(result.IsExtern);
78+
Assert.Equal("_", result.AssemblyName);
79+
Assert.Equal(7, result.DescendantNodes.Count()); // Don't forget that we also have an inline comment with text "SHA1" next to ".hash algorithm" node.
80+
81+
Assert.True(result.DescendantNodes.ElementAt(0) is CustomAttributeSyntax);
82+
Assert.True(result.DescendantNodes.ElementAt(1) is CustomAttributeSyntax);
83+
Assert.True(result.DescendantNodes.ElementAt(2) is CustomAttributeSyntax);
84+
Assert.True(result.DescendantNodes.ElementAt(3) is PermissionSetSyntax);
85+
Assert.True(result.DescendantNodes.ElementAt(4) is HashAlgorithmSyntax);
86+
Assert.True(result.DescendantNodes.ElementAt(5) is InlineCommentSyntax);
87+
Assert.True(result.DescendantNodes.ElementAt(6) is VerDirectiveSyntax);
88+
89+
TestElement1();
90+
TestElement2();
91+
TestElement3();
92+
TestElement4();
93+
TestElement5();
94+
TestElement6();
95+
TestElement7();
96+
97+
void TestElement1()
98+
{
99+
var element = (CustomAttributeSyntax)result.DescendantNodes.ElementAt(0);
100+
Assert.True(element.AttributeConstructorTarget.MethodInvocation.TypeReference is NonGenericTypeReferenceSyntax);
101+
Assert.True(element.AttributeConstructorTarget.MethodInvocation.MethodName == ".ctor");
102+
Assert.True(((NonGenericTypeReferenceSyntax)element.AttributeConstructorTarget.MethodInvocation.TypeReference).ClassName == "System.Runtime.CompilerServices.CompilationRelaxationsAttribute");
103+
Assert.Single(element.AttributeConstructorTarget.MethodInvocation.Arguments.Arguments);
104+
Assert.True(element.AttributeConstructorTarget.MethodInvocation.Arguments.Arguments.ElementAt(0) is PredefinedTypeSyntax predefinedType
105+
&& predefinedType.Kind == PredefinedTypeKind.Int32
106+
&& predefinedType.TypeName == "int32");
107+
Assert.True(
108+
Enumerable.SequenceEqual(
109+
element.GetRawBytes(),
110+
new byte[] { 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 }
111+
)
112+
);
113+
}
114+
115+
void TestElement2()
116+
{
117+
var element = (CustomAttributeSyntax)result.DescendantNodes.ElementAt(1);
118+
Assert.True(element.AttributeConstructorTarget.MethodInvocation.TypeReference is NonGenericTypeReferenceSyntax);
119+
Assert.True(element.AttributeConstructorTarget.MethodInvocation.MethodName == ".ctor");
120+
Assert.True(((NonGenericTypeReferenceSyntax)element.AttributeConstructorTarget.MethodInvocation.TypeReference).ClassName == "System.Runtime.CompilerServices.RuntimeCompatibilityAttribute");
121+
Assert.Empty(element.AttributeConstructorTarget.MethodInvocation.Arguments.Arguments);
122+
Assert.True(
123+
Enumerable.SequenceEqual(
124+
element.GetRawBytes(),
125+
new byte[]
126+
{
127+
0x01, 0x00, 0x01, 0x00, 0x54, 0x02, 0x16, 0x57,
128+
0x72, 0x61, 0x70, 0x4e, 0x6f, 0x6e, 0x45, 0x78, 0x63, 0x65,
129+
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x68, 0x72, 0x6f, 0x77,
130+
0x73, 0x01
131+
}
132+
)
133+
);
134+
}
135+
136+
void TestElement3()
137+
{
138+
var element = (CustomAttributeSyntax)result.DescendantNodes.ElementAt(2);
139+
Assert.True(element.AttributeConstructorTarget.MethodInvocation.TypeReference is NonGenericTypeReferenceSyntax);
140+
Assert.True(element.AttributeConstructorTarget.MethodInvocation.MethodName == ".ctor");
141+
Assert.Equal("System.Runtime", ((NonGenericTypeReferenceSyntax)element.AttributeConstructorTarget.MethodInvocation.TypeReference).AssemblyReference?.AssemblyName);
142+
Assert.Equal("System.Diagnostics.DebuggableAttribute", (((NonGenericTypeReferenceSyntax)element.AttributeConstructorTarget.MethodInvocation.TypeReference).ClassName));
143+
Assert.True(element.AttributeConstructorTarget.MethodInvocation.Arguments.Arguments.First() is NonGenericTypeReferenceSyntax nonGeneric &&
144+
nonGeneric.Prefix == TypePrefix.ValueType &&
145+
nonGeneric.ClassName == "System.Diagnostics.DebuggableAttribute/DebuggingModes");
146+
Assert.True(
147+
Enumerable.SequenceEqual(
148+
element.GetRawBytes(),
149+
new byte[]
150+
{
151+
0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00
152+
}
153+
)
154+
);
155+
}
156+
157+
void TestElement4()
158+
{
159+
var element = (PermissionSetSyntax)result.DescendantNodes.ElementAt(3);
160+
Assert.Equal(SecurityAction.ReqMin, element.SecurityAction);
161+
Assert.True(element.GetRawBytes().SequenceEqual(
162+
s_complexCustomAttributePermissionSetDescendantByteData));
163+
}
164+
165+
void TestElement5()
166+
{
167+
var hash = (HashAlgorithmSyntax)result.DescendantNodes.ElementAt(4);
168+
Assert.Equal("0x00008004", hash.Value);
169+
}
170+
171+
void TestElement6()
172+
{
173+
var inlineComment = (InlineCommentSyntax)result.DescendantNodes.ElementAt(5);
174+
Assert.Equal("SHA1", inlineComment.CommentText.Trim()); // remove leading and trailing whitespaces in comment text
175+
}
176+
177+
void TestElement7()
178+
{
179+
var verDirective = (VerDirectiveSyntax)result.DescendantNodes.ElementAt(6);
180+
Assert.Equal('0', verDirective.Major);
181+
Assert.Equal('0', verDirective.Minor);
182+
Assert.Equal('0', verDirective.Build);
183+
Assert.Equal('0', verDirective.Revision);
184+
}
185+
}
186+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using ILSourceParser.Syntax;
2+
using ILSourceParser.Utilities;
3+
using Sprache;
4+
5+
namespace ILSourceParser.Tests;
6+
7+
public class AttributeParsingTests
8+
{
9+
[Fact]
10+
public void TestCustomAttributeSimple()
11+
{
12+
var parser = new Parser();
13+
// .ParseCustomAttribute will choose either anonymous or custom
14+
// .CustomAttributeWithData enforces custom
15+
var attributeParser = parser.ParseCustomAttributeWithData();
16+
var parseResult = attributeParser.Parse(@".custom instance void [System.Private.CoreLib]System.STAThreadAttribute::.ctor() = (
17+
01 00 00 00
18+
)");
19+
byte[] expectedAttributeData = [0x01, 0x00, 0x00, 0x00];
20+
21+
Assert.Equal("System.Private.CoreLib", parseResult.GetAssemblyName());
22+
Assert.Equal("System.STAThreadAttribute", (parseResult.AttributeConstructorTarget.MethodInvocation.TypeReference as NonGenericTypeReferenceSyntax)!.ClassName);
23+
Assert.Equal(expectedAttributeData, parseResult.GetRawBytes());
24+
}
25+
26+
[Fact]
27+
public void TestAnonymousCustomAttribute()
28+
{
29+
var parser = new Parser();
30+
var attributeParser = parser.ParseAnonymousCustomAttribute();
31+
var parseResult = attributeParser.Parse(@".custom instance void [System.Private.CoreLib]System.STAThreadAttribute::.ctor()");
32+
Assert.Equal("System.Private.CoreLib", parseResult.GetAssemblyName());
33+
Assert.Equal("System.STAThreadAttribute", (parseResult.AttributeConstructorTarget.MethodInvocation.TypeReference as NonGenericTypeReferenceSyntax)!.ClassName);
34+
Assert.Equal([], parseResult.GetRawBytes());
35+
}
36+
37+
[Fact]
38+
public void TestParserAttributeDecisions()
39+
{
40+
var parser = new Parser();
41+
string input1 = @".custom instance void [System.Private.CoreLib]System.STAThreadAttribute::.ctor() = (
42+
01 00 00 00
43+
)";
44+
string input2 = @".custom instance void [System.Private.CoreLib]System.STAThreadAttribute::.ctor()";
45+
46+
// .ParseCustomAttribute() automatically returns an anonymous or custom
47+
// attribute based on the input. .ParseCustomAttributeWithData() and
48+
// .ParseAnonymousCustomAttribute() enforce to parse custom and anonymous
49+
// attribute, respectively.
50+
var customAttributeParser = parser.ParseCustomAttribute();
51+
52+
Assert.True(customAttributeParser.Parse(input1) is CustomAttributeSyntax);
53+
Assert.True(customAttributeParser.Parse(input2) is AnonymousCustomAttributeSyntax);
54+
}
55+
}

ILSourceParser.Tests/ClassTests.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using ILSourceParser.Syntax;
2+
using Sprache;
3+
4+
namespace ILSourceParser.Tests;
5+
6+
public class ClassTests
7+
{
8+
[Fact]
9+
public void Simple()
10+
{
11+
const string input = @".class public static auto ansi beforefieldinit Program {
12+
.field private static initonly string s_myString
13+
14+
.method private static void .cctor() {
15+
ldstr ""Hello, yet again!""
16+
stsfld string Program::s_myString
17+
ret
18+
}
19+
20+
.method public static void Main(string[] args) {
21+
.entrypoint
22+
.maxstack 8
23+
24+
ldstr ""Hello, World!""
25+
call void [System.Console]System.Console::WriteLine(string)
26+
27+
call void Program::DoPrintSomething()
28+
29+
ret
30+
}
31+
32+
.method public static void DoPrintSomething() {
33+
ldsfld string Program::s_myString
34+
call void [System.Console]System.Console::WriteLine(string)
35+
ret
36+
}
37+
}";
38+
var parser = new Parser();
39+
var classParser = parser.ParseClassDeclaration();
40+
var result = classParser.Parse(input);
41+
42+
Assert.Equal(4, result.DescendantNodes.Count());
43+
Assert.True(result.DescendantNodes.ElementAt(0) is FieldDeclarationSyntax);
44+
Assert.True(result.DescendantNodes.ElementAt(1) is MethodDeclarationSyntax);
45+
Assert.True(result.DescendantNodes.ElementAt(2) is MethodDeclarationSyntax);
46+
Assert.True(result.DescendantNodes.ElementAt(3) is MethodDeclarationSyntax);
47+
}
48+
}

0 commit comments

Comments
 (0)