using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.Loader; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Emit; namespace Fission.DotNetCore.Compiler { //adapted from this article http://www.tugberkugurlu.com/archive/compiling-c-sharp-code-into-memory-and-executing-it-with-roslyn class FissionCompiler { public static Function Compile(string code, out List errors) { errors = new List(); SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code); string assemblyName = Path.GetRandomFileName(); var coreDir = Directory.GetParent(typeof(Enumerable).GetTypeInfo().Assembly.Location); List references = new List { MetadataReference.CreateFromFile(coreDir.FullName + Path.DirectorySeparatorChar + "mscorlib.dll"), MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location), MetadataReference.CreateFromFile(Assembly.GetEntryAssembly().Location), MetadataReference.CreateFromFile(typeof(System.Runtime.Serialization.Json.DataContractJsonSerializer).GetTypeInfo().Assembly.Location) }; foreach (var referencedAssembly in Assembly.GetEntryAssembly().GetReferencedAssemblies()) { var assembly = Assembly.Load(referencedAssembly); references.Add(MetadataReference.CreateFromFile(assembly.Location)); } CSharpCompilation compilation = CSharpCompilation.Create( assemblyName, syntaxTrees: new[] { syntaxTree }, references: references, options: new CSharpCompilationOptions( OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Release)); using (var ms = new MemoryStream()) { EmitResult result = compilation.Emit(ms); if (!result.Success) { IEnumerable failures = result.Diagnostics.Where(diagnostic => diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error).ToList(); foreach (Diagnostic diagnostic in failures) { errors.Add($"{diagnostic.Id}: {diagnostic.GetMessage()}"); } } else { ms.Seek(0, SeekOrigin.Begin); Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(ms); var type = assembly.GetType("FissionFunction"); var info = type.GetMember("Execute").First() as MethodInfo; return new Function(assembly, type, info); } } return null; } } }