private static RootNodeDefinition ParseSyntax( string fbsPath, IIncludeLoader includeLoader) { string rootPath = Path.GetFullPath(fbsPath); // First, visit includes. We need to figure out which files warrant a thorough look. HashSet <string> includes = new HashSet <string>() { rootPath }; Queue <string> visitOrder = new Queue <string>(); visitOrder.Enqueue(rootPath); var rootNode = new RootNodeDefinition(rootPath); var schemaVisitor = new SchemaVisitor(rootNode); // SHA256 -> 32 bytes. byte[] hash = new byte[32]; string asmVersion = typeof(FlatSharpCompiler).Assembly.GetCustomAttribute <AssemblyFileVersionAttribute>()?.Version ?? "unknown"; Encoding.UTF8.GetBytes(asmVersion, 0, asmVersion.Length, hash, 0); while (visitOrder.Count > 0) { string next = visitOrder.Dequeue(); string fbs = includeLoader.LoadInclude(next); using (var sha256 = SHA256Managed.Create()) { byte[] componentHash = sha256.ComputeHash(Encoding.UTF8.GetBytes(fbs)); for (int i = 0; i < hash.Length; ++i) { hash[i] ^= componentHash[i]; } } schemaVisitor.CurrentFileName = next; // Traverse the graph of includes. var includeVisitor = new IncludeVisitor(next, includes, visitOrder); ErrorContext.Current.WithScope(next, () => { var schema = GetParser(fbs).schema(); ErrorContext.Current.ThrowIfHasErrors(); includeVisitor.Visit(schema); ErrorContext.Current.ThrowIfHasErrors(); schemaVisitor.Visit(schema); ErrorContext.Current.ThrowIfHasErrors(); }); } rootNode.InputHash = $"{asmVersion}.{Convert.ToBase64String(hash)}"; return(rootNode); }
static int Main(string[] args) { using (var context = ErrorContext.Current) { try { context.PushScope("$"); // Read existing file to see if we even need to do any work. string fbsFileName = Path.GetFileName(args[0]); string outputFileName = fbsFileName + ".generated.cs"; string outputPath = args.Length < 2 || string.IsNullOrEmpty(args[1]) ? Path.GetDirectoryName(args[0]) : args[1]; string outputFullPath = Path.Combine(outputPath, outputFileName); // string fbsText = File.ReadAllText(args[0]); int attemptCount = 0; while (attemptCount++ <= 5) { try { RootNodeDefinition rootNode = ParseSyntax(args[0], new IncludeFileLoader()); if (File.Exists(outputFullPath)) { string existingOutput = File.ReadAllText(outputFullPath); if (existingOutput.Contains(rootNode.InputHash)) { // Input file unchanged. return(0); } } string cSharp = CreateCSharp(rootNode); File.WriteAllText(outputFullPath, cSharp); } catch (IOException) { // Some projects built multiple targets at once, and this can // cause contention between different invocations of the compiler. // Usually, one will succeed, the others will fail, then they'll wake up and // see that the file looks right to them. Thread.Sleep(TimeSpan.FromMilliseconds(new Random().Next(20, 200))); } } } catch (InvalidFbsFileException ex) { foreach (var message in ex.Errors) { Console.Error.WriteLine(message); } return(-1); } catch (FlatSharpCompilationException ex) { foreach (var message in ex.CompilerErrors) { Console.Error.WriteLine(message); } return(-1); } catch (FileNotFoundException) { Console.Error.WriteLine($"File '{args[0]}' was not found"); return(-1); } catch (IndexOutOfRangeException) { Console.Error.WriteLine($"No file specified"); return(-1); } finally { context.PopScope(); } return(0); } }
public SchemaVisitor(RootNodeDefinition rootNode) { this.schemaRoot = rootNode; }