1
+ using System ;
2
+ using System . IO ;
3
+ using System . Linq ;
4
+ using System . Reflection ;
5
+ using Common . Logging ;
6
+
7
+ using Roslyn . Scripting ;
8
+ using ScriptCs . Contracts ;
9
+ using ScriptCs . Exceptions ;
10
+
11
+ namespace ScriptCs . Engine . Roslyn
12
+ {
13
+ public abstract class RoslynScriptCompilerEngine : RoslynScriptEngine
14
+ {
15
+ private const string CompiledScriptClass = "Submission#0" ;
16
+
17
+ private const string CompiledScriptMethod = "<Factory>" ;
18
+
19
+ protected RoslynScriptCompilerEngine ( IScriptHostFactory scriptHostFactory , ILog logger )
20
+ : base ( scriptHostFactory , logger )
21
+ {
22
+ }
23
+
24
+ protected abstract bool ShouldCompile ( ) ;
25
+
26
+ protected abstract Assembly LoadAssembly ( byte [ ] exeBytes , byte [ ] pdbBytes ) ;
27
+
28
+ protected abstract Assembly LoadAssemblyFromCache ( ) ;
29
+
30
+ protected override ScriptResult Execute ( string code , Session session )
31
+ {
32
+ Guard . AgainstNullArgument ( "session" , session ) ;
33
+
34
+ return ShouldCompile ( )
35
+ ? CompileAndExecute ( code , session )
36
+ : InvokeEntryPointMethod ( session , LoadAssemblyFromCache ( ) ) ;
37
+ }
38
+
39
+ private ScriptResult CompileAndExecute ( string code , Session session )
40
+ {
41
+ Logger . Debug ( "Compiling submission" ) ;
42
+ try
43
+ {
44
+ var submission = session . CompileSubmission < object > ( code ) ;
45
+
46
+ using ( var exeStream = new MemoryStream ( ) )
47
+ using ( var pdbStream = new MemoryStream ( ) )
48
+ {
49
+ var result = submission . Compilation . Emit ( exeStream , pdbStream : pdbStream ) ;
50
+
51
+ if ( result . Success )
52
+ {
53
+ Logger . Debug ( "Compilation was successful." ) ;
54
+
55
+ var assembly = LoadAssembly ( exeStream . ToArray ( ) , pdbStream . ToArray ( ) ) ;
56
+
57
+ return InvokeEntryPointMethod ( session , assembly ) ;
58
+ }
59
+
60
+ var errors = string . Join ( Environment . NewLine , result . Diagnostics . Select ( x => x . ToString ( ) ) ) ;
61
+
62
+ Logger . ErrorFormat ( "Error occurred when compiling: {0})" , errors ) ;
63
+
64
+ return new ScriptResult ( compilationException : new ScriptCompilationException ( errors ) ) ;
65
+ }
66
+ }
67
+ catch ( Exception compileException )
68
+ {
69
+ //we catch Exception rather than CompilationErrorException because there might be issues with assembly loading too
70
+ return new ScriptResult ( compilationException : new ScriptCompilationException ( compileException . Message , compileException ) ) ;
71
+ }
72
+ }
73
+
74
+ private ScriptResult InvokeEntryPointMethod ( Session session , Assembly assembly )
75
+ {
76
+ Logger . Debug ( "Retrieving compiled script class (reflection)." ) ;
77
+
78
+ // the following line can throw NullReferenceException, if that happens it's useful to notify that an error ocurred
79
+ var type = assembly . GetType ( CompiledScriptClass ) ;
80
+ Logger . Debug ( "Retrieving compiled script method (reflection)." ) ;
81
+ var method = type . GetMethod ( CompiledScriptMethod , BindingFlags . Static | BindingFlags . Public ) ;
82
+
83
+ try
84
+ {
85
+ Logger . Debug ( "Invoking method." ) ;
86
+
87
+ return new ScriptResult ( returnValue : method . Invoke ( null , new object [ ] { session } ) ) ;
88
+ }
89
+ catch ( Exception executeException )
90
+ {
91
+ Logger . Error ( "An error occurred when executing the scripts." ) ;
92
+
93
+ var ex = executeException . InnerException ?? executeException ;
94
+
95
+ return new ScriptResult ( executionException : ex ) ;
96
+ }
97
+ }
98
+ }
99
+ }
0 commit comments