using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using NTERA.Engine.Compiler; namespace NTERA.Engine.Runtime { public class JITCompiler : IExecutionProvider { public ICollection DefinedProcedures { get; protected set; } public ICollection DefinedFunctions { get; protected set; } public ICollection DefinedConstants { get; protected set; } public CSVDefinition CSVDefinition { get; protected set; } public Dictionary CompiledProcedures { get; protected set; } = new Dictionary(); public string InputDirectory { get; } public static int Threads = 4; public JITCompiler(string path) { InputDirectory = path; Compile(); } protected void Compile() { string csvPath = Path.Combine(InputDirectory, "CSV"); string erbPath = Path.Combine(InputDirectory, "ERB"); var csvDefinition = new CSVDefinition(); Console.WriteLine("Preprocessing CSV files..."); foreach (var file in Directory.EnumerateFiles(csvPath, "*.csv", SearchOption.AllDirectories)) { string path = Path.GetFileNameWithoutExtension(file); if (path.EndsWith("_TR")) continue; Preprocessor.ProcessCSV(csvDefinition, path, File.ReadLines(file, Encoding.UTF8)); } Console.WriteLine("Preprocessing header files..."); ConcurrentBag preprocessedConstants = new ConcurrentBag(); #if DEBUG foreach (var file in Directory.EnumerateFiles(erbPath, "*.erh", SearchOption.AllDirectories)) #else Parallel.ForEach(Directory.EnumerateFiles(erbPath, "*.erh", SearchOption.AllDirectories), new ParallelOptions { MaxDegreeOfParallelism = Threads }, file => #endif { foreach (var variable in Preprocessor.PreprocessHeaderFile(File.ReadAllText(file))) preprocessedConstants.Add(variable); #if DEBUG } #else }); #endif Console.WriteLine("Preprocessing functions..."); ConcurrentDictionary preprocessedFunctions = new ConcurrentDictionary(); #if DEBUG foreach (var file in Directory.EnumerateFiles(erbPath, "*.erb", SearchOption.AllDirectories)) #else Parallel.ForEach(Directory.EnumerateFiles(erbPath, "*.erb", SearchOption.AllDirectories), new ParallelOptions { MaxDegreeOfParallelism = Threads }, file => #endif { foreach (var kv in Preprocessor.PreprocessCodeFile(File.ReadAllText(file), Path.GetFileName(file), preprocessedConstants.ToArray())) preprocessedFunctions[kv.Key] = kv.Value; #if DEBUG } #else }); #endif DefinedProcedures = preprocessedFunctions.Select(kv => kv.Key).ToArray(); var DeclaredProcedures = preprocessedFunctions.ToDictionary(kv => kv.Key, kv => kv.Value); var declaredFunctions = BaseDefinitions.DefaultGlobalFunctions.ToList(); declaredFunctions.AddRange(DeclaredProcedures.Keys.Where(x => x.IsReturnFunction)); var procedures = DeclaredProcedures.Keys.Where(x => !x.IsReturnFunction).ToList(); Console.WriteLine("Compiling functions..."); #if DEBUG foreach (var kv in DeclaredProcedures) #else Parallel.ForEach(DeclaredProcedures, new ParallelOptions { MaxDegreeOfParallelism = Threads }, kv => #endif { Parser parser = new Parser(kv.Value, kv.Key, declaredFunctions, procedures, BaseDefinitions.DefaultGlobalVariables, kv.Key.Variables, BaseDefinitions.DefaultKeywords, csvDefinition, preprocessedConstants.ToArray()); var nodes = parser.Parse(out var localErrors, out var localWarnings); if (localErrors.Count > 0) throw new ParserException($"Failed to compile '{kv.Key.Name}'"); CompiledProcedures.Add(kv.Key, nodes.ToArray()); #if DEBUG } #else }); #endif } public IEnumerable GetExecutionNodes(FunctionDefinition function) { return CompiledProcedures[function]; } } }