1
1
using Microsoft . CodeAnalysis ;
2
+ using Microsoft . CodeAnalysis . CSharp ;
3
+ using System . Reflection ;
4
+ using static LearnJsonEverything . Services . Iconography ;
2
5
3
6
namespace LearnJsonEverything . Services ;
4
7
5
8
public static class CompilationHelpers
6
9
{
7
10
private static MetadataReference [ ] ? _references ;
8
11
9
- private static readonly string [ ] _ensuredAssemblies =
12
+ private static readonly string [ ] EnsuredAssemblies =
10
13
[
11
14
"Json.More" ,
12
15
"JsonPointer.Net" ,
@@ -22,7 +25,7 @@ public static async Task<MetadataReference[]> LoadAssemblyReferences(HttpClient
22
25
var names = refs
23
26
. Where ( x => ! x . IsDynamic )
24
27
. Select ( x => x . FullName ! . Split ( ',' ) [ 0 ] )
25
- . Concat ( _ensuredAssemblies )
28
+ . Concat ( EnsuredAssemblies )
26
29
. OrderBy ( x => x )
27
30
. ToArray ( ) ;
28
31
@@ -50,4 +53,57 @@ public static async Task<MetadataReference[]> LoadAssemblyReferences(HttpClient
50
53
51
54
return _references ;
52
55
}
56
+
57
+ public static ( ILessonRunner < T > ? , string [ ] ) GetRunner < T > ( LessonData lesson , string userCode )
58
+ {
59
+ if ( _references is null )
60
+ throw new Exception ( "Compilation assemblies not loaded." ) ;
61
+
62
+ var fullSource = lesson . ContextCode
63
+ . Replace ( "/* USER CODE */" , userCode ) ;
64
+
65
+ Console . WriteLine ( $ "Compiling...\n \n { fullSource } ") ;
66
+
67
+ var syntaxTree = CSharpSyntaxTree . ParseText ( fullSource ) ;
68
+ var assemblyPath = Path . ChangeExtension ( Path . GetTempFileName ( ) , "dll" ) ;
69
+
70
+ var compilation = CSharpCompilation . Create ( Path . GetFileName ( assemblyPath ) )
71
+ . WithOptions ( new CSharpCompilationOptions ( OutputKind . DynamicallyLinkedLibrary ) )
72
+ . AddReferences ( _references )
73
+ . AddSyntaxTrees ( syntaxTree ) ;
74
+
75
+ using var dllStream = new MemoryStream ( ) ;
76
+ using var pdbStream = new MemoryStream ( ) ;
77
+ using var xmlStream = new MemoryStream ( ) ;
78
+ var emitResult = compilation . Emit ( dllStream , pdbStream , xmlStream ) ;
79
+ if ( ! emitResult . Success )
80
+ {
81
+ var diagnostics = new List < string > ( ) ;
82
+ foreach ( var diagnostic in emitResult . Diagnostics )
83
+ {
84
+ var icon = diagnostic . Severity switch
85
+ {
86
+ DiagnosticSeverity . Info => MessageIcon ,
87
+ DiagnosticSeverity . Warning => WarnIcon ,
88
+ DiagnosticSeverity . Error => ErrorIcon ,
89
+ _ => string . Empty
90
+ } ;
91
+ diagnostics . Add ( $ "{ icon } { diagnostic . GetMessage ( ) } ") ;
92
+ }
93
+ return ( null , [ .. diagnostics ] ) ;
94
+ }
95
+
96
+ #pragma warning disable IL2026
97
+ #pragma warning disable IL2072
98
+ #pragma warning disable IL2070
99
+ var assembly = Assembly . Load ( dllStream . ToArray ( ) ) ;
100
+
101
+ var type = assembly . DefinedTypes . Single ( x => ! x . IsInterface && x . ImplementedInterfaces . Contains ( typeof ( ILessonRunner < T > ) ) ) ;
102
+ var runner = ( ILessonRunner < T > ) Activator . CreateInstance ( type ) ! ;
103
+ #pragma warning restore IL2070
104
+ #pragma warning restore IL2072
105
+ #pragma warning restore IL2026
106
+
107
+ return ( runner , [ ] ) ;
108
+ }
53
109
}
0 commit comments