using System.Diagnostics; using NubLang.Ast; using NubLang.Diagnostics; using NubLang.Generation; using NubLang.Modules; using NubLang.Syntax; List files = []; List headerFiles = []; for (var i = 0; i < args.Length; i++) { if (args[i] == "-h") { i += 1; if (i > args.Length - 1) { Console.Error.WriteLine("Expected argument after -h"); } headerFiles.Add(args[i]); } else { files.Add(args[i]); } } var diagnostics = new List(); var syntaxTrees = new List(); foreach (var headerFile in headerFiles) { using var bindingsGenerateProc = new Process(); // todo(nub31): Embed python file to remove absolute path bindingsGenerateProc.StartInfo = new ProcessStartInfo("python3", ["/home/oliste/repos/nub-lang/bindings/generate.py", headerFile]) { RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true, UseShellExecute = false, }; bindingsGenerateProc.Start(); var output = await bindingsGenerateProc.StandardOutput.ReadToEndAsync(); var error = await bindingsGenerateProc.StandardError.ReadToEndAsync(); await bindingsGenerateProc.WaitForExitAsync(); if (bindingsGenerateProc.ExitCode != 0) { Console.Error.WriteLine($"Failed to automatically generate bindings for header file {headerFile}\n{error}"); return 1; } var tokenizer = new Tokenizer(headerFile, output); tokenizer.Tokenize(); diagnostics.AddRange(tokenizer.Diagnostics); if (tokenizer.Diagnostics.Any(x => x.Severity == DiagnosticSeverity.Error)) { Console.Error.WriteLine($"Binding generator produced invalid syntax for header file {headerFile}"); return 1; } var parser = new Parser(); var syntaxTree = parser.Parse(tokenizer.Tokens); if (parser.Diagnostics.Any(x => x.Severity == DiagnosticSeverity.Error)) { Console.Error.WriteLine($"Binding generator produced invalid syntax tree for header file {headerFile}"); return 1; } syntaxTrees.Add(syntaxTree); } foreach (var file in files) { var tokenizer = new Tokenizer(file, File.ReadAllText(file)); tokenizer.Tokenize(); diagnostics.AddRange(tokenizer.Diagnostics); var parser = new Parser(); var syntaxTree = parser.Parse(tokenizer.Tokens); diagnostics.AddRange(parser.Diagnostics); syntaxTrees.Add(syntaxTree); } var moduleRepository = new ModuleRepository(syntaxTrees); var definitions = new List(); var referencedStructTypes = new HashSet(); foreach (var syntaxTree in syntaxTrees) { var typeChecker = new TypeChecker(syntaxTree, moduleRepository); typeChecker.Check(); definitions.AddRange(typeChecker.Definitions); diagnostics.AddRange(typeChecker.Diagnostics); foreach (var structType in typeChecker.ReferencedStructTypes) { referencedStructTypes.Add(structType); } } foreach (var diagnostic in diagnostics) { Console.Error.WriteLine(diagnostic.FormatANSI()); } if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Error)) { return 1; } Directory.CreateDirectory(".build"); var generator = new Generator(definitions, referencedStructTypes); var c = generator.Emit(); var cFilePath = Path.Combine(".build", "out.c"); File.WriteAllText(cFilePath, c); using var process = Process.Start("gcc", ["-ffreestanding", "-nostartfiles", "-c", "-o", Path.Combine(".build", "out.o"), cFilePath]); process.WaitForExit(); if (process.ExitCode != 0) { Console.Error.WriteLine($"gcc failed with exit code {process.ExitCode}"); return 1; } return 0;