using System.Diagnostics; using Compiler; var nubFiles = new List(); var libFiles = new List(); var compileLib = false; for (int i = 0; i < args.Length; i++) { string arg = args[i]; if (arg.StartsWith("--type=")) { var value = arg.Split("--type=")[1]; switch (value) { case "lib": compileLib = true; break; case "exe": compileLib = false; break; default: DiagnosticFormatter.Print(Diagnostic.Error("Type must be 'exe' or 'lib'").Build(), Console.Error); return 1; } } else if (arg.EndsWith(".nub")) { nubFiles.Add(arg); } else if (arg.EndsWith(".nublib")) { libFiles.Add(arg); } else if (arg == "--help") { Console.WriteLine(""" Usage: nubc [options] Options: --type=exe Compile the input files into an executable (default) --type=lib Compile the input files into a library --help Show this help message Files: *.nub Nub source files to compile *.nublib Precompiled Nub libraries to link Example: nubc --type=exe main.nub utils.nub math.nublib """); } else { DiagnosticFormatter.Print(Diagnostic.Error($"Unrecognized option '{arg}'").Build(), Console.Error); return 1; } } var moduleGraphBuilder = ModuleGraph.CreateBuilder(); var asts = new List(); var archivePaths = new List(); foreach (var libPath in libFiles) { var lib = NubLib.Unpack(libPath); archivePaths.Add(lib.ArchivePath); moduleGraphBuilder.AddManifest(lib.Manifest); } foreach (var fileName in nubFiles) { var file = File.ReadAllText(fileName); var tokens = Tokenizer.Tokenize(fileName, file, out var tokenizerDiagnostics); foreach (var diagnostic in tokenizerDiagnostics) DiagnosticFormatter.Print(diagnostic, Console.Error); if (tokens == null) return 1; var ast = Parser.Parse(fileName, tokens, out var parserDiagnostics); foreach (var diagnostic in parserDiagnostics) DiagnosticFormatter.Print(diagnostic, Console.Error); if (ast == null) return 1; moduleGraphBuilder.AddAst(ast); asts.Add(ast); } var moduleGraph = moduleGraphBuilder.Build(out var moduleGraphDiagnostics); foreach (var diagnostic in moduleGraphDiagnostics) DiagnosticFormatter.Print(diagnostic, Console.Error); if (moduleGraph == null) return 1; var functions = new List(); foreach (var ast in asts) { foreach (var func in ast.Definitions.OfType()) { var typedFunction = TypeChecker.CheckFunction(ast.FileName, ast.ModuleName.Ident, func, moduleGraph, out var typeCheckerDiagnostics); foreach (var diagnostic in typeCheckerDiagnostics) DiagnosticFormatter.Print(diagnostic, Console.Error); if (typedFunction == null) return 1; functions.Add(typedFunction); } } var output = Generator.Emit(functions, moduleGraph, compileLib); if (Directory.Exists(".build")) { CleanDirectory(".build"); } else { Directory.CreateDirectory(".build"); } if (compileLib) { File.WriteAllText(".build/out.c", output); Process.Start("gcc", ["-Og", "-fvisibility=hidden", "-fno-builtin", "-c", "-o", ".build/out.o", ".build/out.c", .. archivePaths]).WaitForExit(); Process.Start("ar", ["rcs", ".build/out.a", ".build/out.o"]).WaitForExit(); NubLib.Pack(".build/out.nublib", ".build/out.a", moduleGraph.CreateManifest()); } else { File.WriteAllText(".build/out.c", output); Process.Start("gcc", ["-Og", "-fvisibility=hidden", "-fno-builtin", "-o", ".build/out", ".build/out.c", .. archivePaths]).WaitForExit(); } return 0; static void CleanDirectory(string dirName) { var dir = new DirectoryInfo(dirName); foreach (var file in dir.GetFiles()) { file.Delete(); } foreach (var subdir in dir.GetDirectories()) { CleanDirectory(subdir.FullName); subdir.Delete(); } }