using System.Diagnostics; using NubLang.Ast; using NubLang.Diagnostics; using NubLang.Generation; using NubLang.Modules; using NubLang.Syntax; var diagnostics = new List(); var syntaxTrees = new List(); var nubFiles = args.Where(x => Path.GetExtension(x) == ".nub"); var objectFiles = args.Where(x => Path.GetExtension(x) is ".o" or ".a"); foreach (var file in nubFiles) { 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 compileProcess = Process.Start("gcc", [ "-ffreestanding", "-nostartfiles", "-std=c23", "-g", "-lm", "-c", "-o", Path.Combine(".build", "out.o"), cFilePath, ]); compileProcess.WaitForExit(); if (compileProcess.ExitCode != 0) { Console.Error.WriteLine($"gcc failed with exit code {compileProcess.ExitCode}"); return 1; } if (moduleRepository.Modules().TryGetValue("main", out var mainModule)) { var mainFunction = mainModule .Functions(true) .FirstOrDefault(x => x.ExternSymbol == "main"); if (mainFunction is { ExternSymbol: not null }) { var runtime = $""" .intel_syntax noprefix .text .globl _start _start: mov rdi, rsp # Pass stack pointer to main (argv-like) call {mainFunction.ExternSymbol} mov rdi, rax # Move return value into rdi mov rax, 60 # syscall: exit syscall """; var runtimePath = Path.Combine(".build", "runtime.s"); File.WriteAllText(runtimePath, runtime); using var assembleProcess = Process.Start(new ProcessStartInfo("as", ["-c", runtimePath, "-o", Path.Combine(".build", "runtime.o")])); if (assembleProcess == null) return 1; if (assembleProcess.ExitCode != 0) { Console.Error.WriteLine($"gcc failed with exit code {assembleProcess.ExitCode}"); return 1; } if (assembleProcess.ExitCode != 0) return 1; using var linkProcess = Process.Start(new ProcessStartInfo("gcc", [ "-ffreestanding", "-nostartfiles", "-std=c23", "-g", "-lm", "-o", Path.Combine(".build", "out"), Path.Combine(".build", "out.o"), Path.Combine(".build", "runtime.o"), ..objectFiles ])); if (linkProcess == null) return 1; linkProcess.WaitForExit(); if (linkProcess.ExitCode != 0) { Console.Error.WriteLine($"gcc failed with exit code {linkProcess.ExitCode}"); return 1; } Console.WriteLine("Build successful: .build/out"); } else { Console.WriteLine("No main function found in module main, skipping link step"); } } else { Console.WriteLine("No main function found in module main, skipping link step"); } return 0;