private Assembly CompileCode(List <GeneratedCode> generatedCodes) { // Prepare compiler var parameters = new CompilerParameters(); parameters.GenerateInMemory = true; parameters.TreatWarningsAsErrors = true; parameters.IncludeDebugInformation = true; parameters.CompilerOptions = string.Join(" ", Constants.CompilerOptions); parameters.ReferencedAssemblies.AddRange(Constants.CompilerAssemblies); parameters.ReferencedAssemblies.AddRange(this.ReferencedAssemblies.ToArray()); parameters.ReferencedAssemblies.Add(typeof(TemplateCompiler).Assembly.Location); // Compile CompilerResults compilerResults; using (var codeProvider = new CSharpCodeProvider()) { var codes = generatedCodes.Select(generatedCode => generatedCode.Code).ToArray(); compilerResults = codeProvider.CompileAssemblyFromSource(parameters, codes); } // Report errors foreach (CompilerError compilerError in compilerResults.Errors) { string filename = compilerError.FileName; var textPosition = new TextPosition(); if (compilerError.Line != 0 && compilerError.Column != 0) { GeneratedCode generatedCode = generatedCodes.FirstOrDefault(gcode => string.Compare(gcode.TemplatePath, compilerError.FileName, StringComparison.OrdinalIgnoreCase) == 0); if (generatedCode != null) { var errorPosition = new TextPosition(compilerError.Line, compilerError.Column); TextFilePosition original = generatedCode.SourceMap.FindSourceByGenerated(errorPosition); if (original.IsValid) { textPosition = new TextPosition(original.Line, original.Column); } } else { textPosition = new TextPosition(compilerError.Line, compilerError.Column); } } TraceLevel traceLevel = compilerError.IsWarning ? TraceLevel.Warning : TraceLevel.Error; this.MessageHandler.Message(traceLevel, $"{compilerError.ErrorNumber}: {compilerError.ErrorText}", filename, textPosition); } if (compilerResults.Errors.Count > 0) { return(null); } return(compilerResults.CompiledAssembly); }
/// <summary> /// Loads the given template and compiles it. /// </summary> /// <param name="templateName">Name of template which will be resolved by ITemplateLoader.</param> /// <returns>Compiled template or null in case of an error.</returns> /// <exception cref="ArgumentException">If templateName is null or empty.</exception> public CompiledTemplate Compile(string templateName) { if (string.IsNullOrEmpty(templateName)) { throw new ArgumentException("Can't be null or empty.", nameof(templateName)); } var templateNames = new Queue <string>(); templateNames.Enqueue(templateName); var generatedTargetCodes = new List <GeneratedCode>(); string mainTemplatePath = null; bool mainTemplateFilenameSet = false; var generatedFiles = new HashSet <string>(); while (templateNames.Count > 0) { // Load template string loadTemplateName = templateNames.Dequeue(); Template template = null; try { template = this.TemplateLoader.Load(loadTemplateName); if (mainTemplateFilenameSet == false) { mainTemplatePath = template.Path; mainTemplateFilenameSet = true; } } catch (FileNotFoundException) { this.MessageHandler.Message(TraceLevel.Error, $"Can't find template '{templateName}'.", string.Empty, new TextPosition()); throw; } catch (IOException) { this.MessageHandler.Message(TraceLevel.Error, $"IO error while reading template '{templateName}'.", string.Empty, new TextPosition()); throw; } catch (Exception) { continue; } // Generate Twofold enhanced CSharp code from template List <string> includedFiles; GeneratedCode generatedCode = this.GenerateCode(template.Path, template.Text, out includedFiles); if (generatedCode != null) { generatedFiles.Add(loadTemplateName); generatedTargetCodes.Add(generatedCode); foreach (var includedFile in includedFiles) { if (generatedFiles.Contains(includedFile)) { continue; } templateNames.Enqueue(includedFile); } } } // Compile CSharp code Assembly assembly = this.CompileCode(generatedTargetCodes); if (assembly == null) { return(new CompiledTemplate(mainTemplatePath, generatedTargetCodes)); } // Check Twofold CSharp assembly for entry points/types string mainTypeName = this.DetectMainType(mainTemplatePath, assembly); if (string.IsNullOrEmpty(mainTypeName)) { return(new CompiledTemplate(mainTemplatePath, generatedTargetCodes)); } return(new CompiledTemplate(mainTemplatePath, assembly, mainTypeName, generatedTargetCodes)); }