JITCompiler.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Runtime;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. using NTERA.Engine.Compiler;
  10. namespace NTERA.Engine.Runtime
  11. {
  12. public class JITCompiler : IExecutionProvider
  13. {
  14. public ICollection<FunctionDefinition> DefinedProcedures { get; protected set; }
  15. public ICollection<FunctionDefinition> DefinedFunctions { get; protected set; }
  16. public ICollection<FunctionVariable> DefinedConstants { get; protected set; }
  17. public CSVDefinition CSVDefinition { get; protected set; }
  18. protected Dictionary<FunctionDefinition, string> ProcedureFiles { get; set; }
  19. public Dictionary<FunctionDefinition, ExecutionNode[]> CompiledProcedures { get; protected set; } = new Dictionary<FunctionDefinition, ExecutionNode[]>();
  20. public string InputDirectory { get; }
  21. public static int Threads = 4;
  22. public JITCompiler(string path)
  23. {
  24. InputDirectory = path;
  25. Compile();
  26. }
  27. protected void Compile()
  28. {
  29. string csvPath = Path.Combine(InputDirectory, "CSV");
  30. string erbPath = Path.Combine(InputDirectory, "ERB");
  31. var csvDefinition = new CSVDefinition();
  32. Console.WriteLine("Preprocessing CSV files...");
  33. foreach (var file in Directory.EnumerateFiles(csvPath, "*.csv", SearchOption.AllDirectories))
  34. {
  35. string path = Path.GetFileNameWithoutExtension(file);
  36. if (path.EndsWith("_TR"))
  37. continue;
  38. Preprocessor.ProcessCSV(csvDefinition, path, File.ReadLines(file, Encoding.UTF8));
  39. }
  40. Console.WriteLine("Preprocessing header files...");
  41. ConcurrentBag<FunctionVariable> preprocessedConstants = new ConcurrentBag<FunctionVariable>();
  42. #if DEBUG
  43. foreach (var file in Directory.EnumerateFiles(erbPath, "*.erh", SearchOption.AllDirectories))
  44. #else
  45. Parallel.ForEach(Directory.EnumerateFiles(erbPath, "*.erh", SearchOption.AllDirectories), new ParallelOptions
  46. {
  47. MaxDegreeOfParallelism = Threads
  48. }, file =>
  49. #endif
  50. {
  51. foreach (var variable in Preprocessor.PreprocessHeaderFile(File.ReadAllText(file)))
  52. preprocessedConstants.Add(variable);
  53. #if DEBUG
  54. }
  55. #else
  56. });
  57. #endif
  58. DefinedConstants = preprocessedConstants.ToArray();
  59. Console.WriteLine("Preprocessing functions...");
  60. ProcedureFiles = new Dictionary<FunctionDefinition, string>();
  61. ConcurrentDictionary<FunctionDefinition, string> preprocessedFunctions = new ConcurrentDictionary<FunctionDefinition, string>();
  62. #if DEBUG
  63. foreach (var file in Directory.EnumerateFiles(erbPath, "*.erb", SearchOption.AllDirectories))
  64. #else
  65. Parallel.ForEach(Directory.EnumerateFiles(erbPath, "*.erb", SearchOption.AllDirectories), new ParallelOptions
  66. {
  67. MaxDegreeOfParallelism = Threads
  68. }, file =>
  69. #endif
  70. {
  71. foreach (var kv in Preprocessor.PreprocessCodeFile(File.ReadAllText(file), Path.GetFileName(file), DefinedConstants))
  72. {
  73. preprocessedFunctions[kv.Key] = kv.Value;
  74. ProcedureFiles[kv.Key] = file;
  75. }
  76. #if DEBUG
  77. }
  78. #else
  79. });
  80. #endif
  81. DefinedProcedures = preprocessedFunctions.Select(kv => kv.Key).ToArray();
  82. var declaredFunctions = BaseDefinitions.DefaultGlobalFunctions.ToList();
  83. declaredFunctions.AddRange(DefinedProcedures.Where(x => x.IsReturnFunction));
  84. DefinedFunctions = declaredFunctions;
  85. GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
  86. GC.Collect();
  87. }
  88. public IEnumerable<ExecutionNode> GetExecutionNodes(FunctionDefinition function)
  89. {
  90. if (CompiledProcedures.ContainsKey(function))
  91. return CompiledProcedures[function];
  92. string filename = ProcedureFiles[function];
  93. var preprocessed = Preprocessor.PreprocessCodeFile(File.ReadAllText(filename), Path.GetFileName(filename), DefinedConstants);
  94. Parser parser = new Parser(preprocessed.Single(x => x.Key.Name == function.Name).Value, function, DefinedFunctions, DefinedProcedures.Where(x => !x.IsReturnFunction).ToArray(), BaseDefinitions.DefaultGlobalVariables, function.Variables, BaseDefinitions.DefaultKeywords, CSVDefinition, DefinedConstants);
  95. var nodes = parser.Parse(out var localErrors, out var localWarnings)?.ToArray();
  96. if (localErrors.Count > 0)
  97. throw new ParserException($"Failed to compile '{function.Name}'");
  98. CompiledProcedures.Add(function, nodes);
  99. return nodes;
  100. }
  101. }
  102. }