|
| 1 | +using Microsoft.CodeAnalysis; |
| 2 | +using Microsoft.CodeAnalysis.CSharp; |
| 3 | +using Microsoft.CodeAnalysis.Operations; |
| 4 | +using System; |
| 5 | +using System.Collections.Generic; |
| 6 | +using System.IO; |
| 7 | +using System.Linq; |
| 8 | +using System.Reflection; |
| 9 | +using System.Text; |
| 10 | +using System.Threading.Tasks; |
| 11 | + |
| 12 | +namespace Basic.Reference.Assemblies.UnitTests; |
| 13 | +internal static class CompilationUtil |
| 14 | +{ |
| 15 | + public static MemoryStream CompileToLibrary(string code, string assemblyName, IEnumerable<MetadataReference> references) |
| 16 | + { |
| 17 | + var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary); |
| 18 | + var compilation = CSharpCompilation.Create( |
| 19 | + assemblyName, |
| 20 | + [CSharpSyntaxTree.ParseText(code)], |
| 21 | + references, |
| 22 | + options); |
| 23 | + |
| 24 | + var peStream = new MemoryStream(); |
| 25 | + var emitResult = compilation.Emit(peStream); |
| 26 | + if (!emitResult.Success) |
| 27 | + { |
| 28 | + throw new Exception(GetMessage(emitResult.Diagnostics)); |
| 29 | + } |
| 30 | + |
| 31 | + peStream.Position = 0; |
| 32 | + return peStream; |
| 33 | + |
| 34 | + static string GetMessage(IEnumerable<Diagnostic> diagnostics) |
| 35 | + { |
| 36 | + var builder = new StringBuilder(); |
| 37 | + builder.AppendLine("Compilation failed with the following errors:"); |
| 38 | + foreach (var d in diagnostics) |
| 39 | + { |
| 40 | + builder.AppendLine(d.ToString()); |
| 41 | + } |
| 42 | + return builder.ToString(); |
| 43 | + } |
| 44 | + } |
| 45 | + |
| 46 | + public static Assembly CompileToLibraryAndLoad(string code, string assemblyName, IEnumerable<MetadataReference> references) |
| 47 | + { |
| 48 | + var stream = CompileToLibrary(code, assemblyName, references); |
| 49 | + return Load(stream, assemblyName); |
| 50 | + } |
| 51 | + |
| 52 | + /// <summary> |
| 53 | + /// Compile and run the code expecting to find a static Lib.Go method |
| 54 | + /// </summary> |
| 55 | + public static string? CompileAndRun(string code, string assemblyName, IEnumerable<MetadataReference> references) |
| 56 | + { |
| 57 | + var assembly = CompileToLibraryAndLoad(code, assemblyName, references); |
| 58 | + var libType = assembly |
| 59 | + .GetTypes() |
| 60 | + .Where(x => x.Name == "Lib") |
| 61 | + .Single(); |
| 62 | + var method = libType.GetMethod("Go", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); |
| 63 | + var obj = method!.Invoke(null, null); |
| 64 | + return (string?)obj; |
| 65 | + } |
| 66 | + |
| 67 | + public static Assembly Load(MemoryStream stream, string assemblyName) |
| 68 | + { |
| 69 | + stream.Position = 0; |
| 70 | +#if NET |
| 71 | + var alc = new System.Runtime.Loader.AssemblyLoadContext(assemblyName); |
| 72 | + return alc.LoadFromStream(stream); |
| 73 | +#else |
| 74 | + return Assembly.Load(stream.ToArray()); |
| 75 | +#endif |
| 76 | + } |
| 77 | +} |
0 commit comments