From d6447149a3a581cea90021ec4434ecb175da7a7a Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Mon, 3 Feb 2025 09:08:05 +0100 Subject: [PATCH 1/2] Create MsilStructureTests.cs --- .../CodeGeneration/MsilStructureTests.cs | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 src/Draco.Compiler.Tests/CodeGeneration/MsilStructureTests.cs diff --git a/src/Draco.Compiler.Tests/CodeGeneration/MsilStructureTests.cs b/src/Draco.Compiler.Tests/CodeGeneration/MsilStructureTests.cs new file mode 100644 index 000000000..7543f6367 --- /dev/null +++ b/src/Draco.Compiler.Tests/CodeGeneration/MsilStructureTests.cs @@ -0,0 +1,77 @@ +using System.Reflection; +using Draco.Compiler.Internal; + +namespace Draco.Compiler.Tests.CodeGeneration; + +public sealed class MsilStructureTests +{ + private readonly struct RelayDisposable(Action dispose) : IDisposable + { + public void Dispose() => dispose(); + } + + private const BindingFlags AllBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; + + private string? CurrentNamespace => this.namespaceStack.Count == 0 + ? null + : string.Join(".", this.namespaceStack.Reverse()); + private Type CurrentType => this.typeStack.Peek(); + + private Assembly assembly = null!; + private readonly Stack typeStack = new(); + private readonly Stack namespaceStack = new(); + + private void Compile(string source) + { + this.assembly = TestUtilities.CompileToAssembly(source); + } + + private RelayDisposable Ns(string name) + { + this.namespaceStack.Push(name); + return new RelayDisposable(() => this.namespaceStack.Pop()); + } + + private RelayDisposable C(string name, Func predicate) + { + var type = this.typeStack.Count == 0 + // Look up in root assembly + ? this.assembly.GetType(name) + // Look up in current type + : this.CurrentType.GetNestedType(name, AllBindingFlags); + + Assert.NotNull(type); + Assert.Equal(this.CurrentNamespace, type.Namespace); + Assert.True(predicate(type)); + this.typeStack.Push(type); + + return new RelayDisposable(() => this.typeStack.Pop()); + } + + private RelayDisposable StaticC(string name, Func predicate) => + this.C(name, t => t.IsAbstract && t.IsSealed && predicate(t)); + + private void M(string name, Func predicate) + { + var method = this.CurrentType.GetMethod(name, AllBindingFlags); + Assert.NotNull(method); + Assert.True(predicate(method)); + } + + [Fact] + public void HelloWorld() + { + this.Compile(""" + import System.Console; + + func main() { + WriteLine("Hello, World!"); + } + """); + + using (this.StaticC(CompilerConstants.DefaultModuleName, t => !t.IsPublic)) + { + this.M("main", m => !m.IsPublic && m.IsStatic); + } + } +} From 34ecbc5635e1621568e5b48d266cf29467340baa Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Mon, 3 Feb 2025 10:49:27 +0100 Subject: [PATCH 2/2] Update MsilStructureTests.cs --- .../CodeGeneration/MsilStructureTests.cs | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/Draco.Compiler.Tests/CodeGeneration/MsilStructureTests.cs b/src/Draco.Compiler.Tests/CodeGeneration/MsilStructureTests.cs index 7543f6367..1f1e613aa 100644 --- a/src/Draco.Compiler.Tests/CodeGeneration/MsilStructureTests.cs +++ b/src/Draco.Compiler.Tests/CodeGeneration/MsilStructureTests.cs @@ -21,9 +21,11 @@ private readonly struct RelayDisposable(Action dispose) : IDisposable private readonly Stack typeStack = new(); private readonly Stack namespaceStack = new(); - private void Compile(string source) + private void Compile(string source, string? rootModulePath = null) { - this.assembly = TestUtilities.CompileToAssembly(source); + this.assembly = TestUtilities.CompileToAssembly( + sourceCode: source, + rootModulePath: rootModulePath); } private RelayDisposable Ns(string name) @@ -74,4 +76,28 @@ func main() { this.M("main", m => !m.IsPublic && m.IsStatic); } } + + [Fact] + public void HelloWorldInModule() + { + this.Compile(""" + import System.Console; + + func main() { + WriteLine("Hello, World!"); + } + """, + rootModulePath: "foo/bar"); + + using (this.Ns("foo")) + { + using (this.StaticC("bar", t => !t.IsPublic)) + { + using (this.StaticC(CompilerConstants.DefaultModuleName, t => !t.IsPublic)) + { + this.M("main", m => !m.IsPublic && m.IsStatic); + } + } + } + } }