Compiler.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. using System.Xml;
  9. using NTERA.Engine;
  10. using NTERA.Engine.Compiler;
  11. using NTERA.Engine.Runtime;
  12. namespace NTERA.Compiler
  13. {
  14. public class Compiler
  15. {
  16. public string InputDirectory { get; }
  17. public List<Tuple<ParserError, string>> Errors { get; } = new List<Tuple<ParserError, string>>();
  18. public List<Tuple<ParserError, string>> Warnings { get; } = new List<Tuple<ParserError, string>>();
  19. public Dictionary<FunctionDefinition, string> DeclaredProcedures = new Dictionary<FunctionDefinition, string>();
  20. public int Threads { get; set; }
  21. public Compiler(string inputDirectory, int threads)
  22. {
  23. InputDirectory = inputDirectory;
  24. Threads = threads;
  25. }
  26. public void Compile(string outputDirectory)
  27. {
  28. string csvPath = Path.Combine(InputDirectory, "CSV");
  29. string erbPath = Path.Combine(InputDirectory, "ERB");
  30. var csvDefinition = new CSVDefinition();
  31. Console.WriteLine("Preprocessing CSV files...");
  32. foreach (var file in Directory.EnumerateFiles(csvPath, "*.csv", SearchOption.AllDirectories))
  33. {
  34. string path = Path.GetFileNameWithoutExtension(file);
  35. if (path.EndsWith("_TR"))
  36. continue;
  37. Preprocessor.ProcessCSV(csvDefinition, path, File.ReadLines(file, Encoding.UTF8));
  38. }
  39. Console.WriteLine("Preprocessing header files...");
  40. ConcurrentBag<FunctionVariable> preprocessedConstants = new ConcurrentBag<FunctionVariable>();
  41. #if DEBUG
  42. foreach (var file in Directory.EnumerateFiles(erbPath, "*.erh", SearchOption.AllDirectories))
  43. #else
  44. Parallel.ForEach(Directory.EnumerateFiles(erbPath, "*.erh", SearchOption.AllDirectories), new ParallelOptions
  45. {
  46. MaxDegreeOfParallelism = Threads
  47. }, file =>
  48. #endif
  49. {
  50. try
  51. {
  52. foreach (var variable in Preprocessor.PreprocessHeaderFile(File.ReadAllText(file)))
  53. preprocessedConstants.Add(variable);
  54. }
  55. catch (Exception ex)
  56. {
  57. lock (Errors)
  58. Errors.Add(new Tuple<ParserError, string>(new ParserError($"Internal pre-process lexer error [{ex}]", new Marker()), Path.GetFileName(file)));
  59. }
  60. #if DEBUG
  61. }
  62. #else
  63. });
  64. #endif
  65. Console.WriteLine("Preprocessing functions...");
  66. ConcurrentDictionary<FunctionDefinition, string> preprocessedFunctions = new ConcurrentDictionary<FunctionDefinition, string>();
  67. #if DEBUG
  68. foreach (var file in Directory.EnumerateFiles(erbPath, "*.erb", SearchOption.AllDirectories))
  69. #else
  70. Parallel.ForEach(Directory.EnumerateFiles(erbPath, "*.erb", SearchOption.AllDirectories), new ParallelOptions
  71. {
  72. MaxDegreeOfParallelism = Threads
  73. }, file =>
  74. #endif
  75. {
  76. try
  77. {
  78. foreach (var kv in Preprocessor.PreprocessCodeFile(File.ReadAllText(file), Path.GetFileName(file), preprocessedConstants.ToArray()))
  79. preprocessedFunctions[kv.Key] = kv.Value;
  80. }
  81. catch (Exception ex)
  82. {
  83. lock (Errors)
  84. Errors.Add(new Tuple<ParserError, string>(new ParserError($"Internal pre-process lexer error [{ex}]", new Marker()), Path.GetFileName(file)));
  85. }
  86. #if DEBUG
  87. }
  88. #else
  89. });
  90. #endif
  91. DeclaredProcedures = preprocessedFunctions.ToDictionary(kv => kv.Key, kv => kv.Value);
  92. var declaredFunctions = BaseDefinitions.DefaultGlobalFunctions.ToList();
  93. declaredFunctions.AddRange(DeclaredProcedures.Keys.Where(x => x.IsReturnFunction));
  94. var procedures = DeclaredProcedures.Keys.Where(x => !x.IsReturnFunction).ToList();
  95. Console.WriteLine("Compiling functions...");
  96. #if DEBUG
  97. foreach (var kv in DeclaredProcedures)
  98. #else
  99. Parallel.ForEach(DeclaredProcedures, new ParallelOptions
  100. {
  101. MaxDegreeOfParallelism = Threads
  102. }, kv =>
  103. #endif
  104. {
  105. try
  106. {
  107. Parser parser = new Parser(kv.Value, kv.Key, declaredFunctions, procedures, BaseDefinitions.DefaultGlobalVariables, kv.Key.Variables, BaseDefinitions.DefaultKeywords, csvDefinition, preprocessedConstants.ToArray());
  108. var nodes = parser.Parse(out var localErrors, out var localWarnings);
  109. using (var str = File.Create(Path.Combine(outputDirectory, $"{kv.Key.Name}.xml")))
  110. using (var xml = XmlWriter.Create(str, new XmlWriterSettings
  111. {
  112. Indent = true
  113. }))
  114. {
  115. new ExecutionNode
  116. {
  117. Type = "exec",
  118. Metadata =
  119. {
  120. ["ast-version"] = "2",
  121. ["name"] = kv.Key.Name,
  122. ["filename"] = kv.Key.Filename,
  123. ["position"] = kv.Key.Position.ToString()
  124. },
  125. SubNodes = nodes.ToArray()
  126. }.WriteXml(xml);
  127. }
  128. lock (Errors)
  129. Errors.AddRange(localErrors.Select(x => new Tuple<ParserError, string>(x, $"{kv.Key.Filename} - {kv.Key.Name}")));
  130. lock (Warnings)
  131. Warnings.AddRange(localWarnings.Select(x => new Tuple<ParserError, string>(x, $"{kv.Key.Filename} - {kv.Key.Name}")));
  132. }
  133. catch (Exception ex)
  134. {
  135. lock (Errors)
  136. Errors.Add(new Tuple<ParserError, string>(new ParserError($"Internal post-process lexer error [{ex}]", new Marker()), $"{kv.Key.Filename} - {kv.Key.Name}"));
  137. }
  138. #if DEBUG
  139. }
  140. #else
  141. });
  142. #endif
  143. long fileSize = 0;
  144. int fileCount = 0;
  145. foreach (var file in Directory.EnumerateFiles(InputDirectory, "*.erb", SearchOption.AllDirectories))
  146. {
  147. var info = new FileInfo(file);
  148. fileSize += info.Length;
  149. fileCount++;
  150. }
  151. var htmlWriter = new HTMLWriter
  152. {
  153. Errors = Errors.OrderBy(x => x.Item2).ToList(),
  154. Warnings = Warnings.OrderBy(x => x.Item2).ToList(),
  155. FunctionCount = DeclaredProcedures.Count,
  156. TotalFileSize = fileSize,
  157. TotalFileCount = fileCount
  158. };
  159. using (var stream = File.Create(Path.Combine(outputDirectory, "report.html")))
  160. htmlWriter.WriteReportToFile(stream);
  161. }
  162. }
  163. }