From 7617ddae730cd8e22e4c030e10648130fc2ad446 Mon Sep 17 00:00:00 2001 From: nub31 Date: Sun, 29 Jun 2025 17:06:57 +0200 Subject: [PATCH] ... --- example/makefile | 9 +- example/src/main.nub | 1 + src/compiler/CLI/CLI.csproj | 5 + src/compiler/CLI/HexString.cs | 38 ++++++++ src/compiler/CLI/Options.cs | 6 ++ src/compiler/CLI/Program.cs | 88 ++++++++++++++++-- .../compiler/CLI/assets}/libruntime_x64.a | Bin 7 files changed, 138 insertions(+), 9 deletions(-) create mode 100644 src/compiler/CLI/HexString.cs create mode 100644 src/compiler/CLI/Options.cs rename {example/lib => src/compiler/CLI/assets}/libruntime_x64.a (100%) diff --git a/example/makefile b/example/makefile index 5fba930..97985e8 100644 --- a/example/makefile +++ b/example/makefile @@ -1,9 +1,12 @@ -CFLAGS = -Wall -Werror -Wextra -g +CFLAGS = -g -example: +bin/out: src/main.nub src/c.nub dotnet run --project ../src/compiler/CLI/CLI.csproj src/main.nub src/c.nub mkdir -p bin - gcc $(CFLAGS) -o bin/out lib/libruntime_x64.a bin-int/out.a + gcc $(CFLAGS) -o bin/out bin-int/out/out.a + +run: bin/out + bin/out clean: rm -r bin-int bin diff --git a/example/src/main.nub b/example/src/main.nub index fd8ef94..4b2905d 100644 --- a/example/src/main.nub +++ b/example/src/main.nub @@ -3,4 +3,5 @@ namespace main export func main(args: []cstring): i64 { c::puts("test") return 0 + } diff --git a/src/compiler/CLI/CLI.csproj b/src/compiler/CLI/CLI.csproj index c101a01..a598c50 100644 --- a/src/compiler/CLI/CLI.csproj +++ b/src/compiler/CLI/CLI.csproj @@ -18,4 +18,9 @@ + + + + + diff --git a/src/compiler/CLI/HexString.cs b/src/compiler/CLI/HexString.cs new file mode 100644 index 0000000..2be6ef3 --- /dev/null +++ b/src/compiler/CLI/HexString.cs @@ -0,0 +1,38 @@ +namespace CLI; + +internal static class HexString +{ + private static readonly HashSet _used = []; + + private static readonly char[] StringChars = "0123456789abcdef".ToArray(); + + public static string CreateUnique(int length) + { + string hex; + + while (true) + { + hex = Create(length); + if (_used.Add(hex)) + { + break; + } + } + + return hex; + } + + public static string Create(int length) + { + var rand = new Random(); + var hexString = ""; + + for (var i = 0; i < length; i++) + { + var randIndex = rand.Next(0, StringChars.Length); + hexString += StringChars[randIndex]; + } + + return hexString; + } +} \ No newline at end of file diff --git a/src/compiler/CLI/Options.cs b/src/compiler/CLI/Options.cs new file mode 100644 index 0000000..947ed50 --- /dev/null +++ b/src/compiler/CLI/Options.cs @@ -0,0 +1,6 @@ +namespace CLI; + +public class Options +{ + public string? CustomRuntime { get; set; } +} \ No newline at end of file diff --git a/src/compiler/CLI/Program.cs b/src/compiler/CLI/Program.cs index 027ff11..44d1be2 100644 --- a/src/compiler/CLI/Program.cs +++ b/src/compiler/CLI/Program.cs @@ -1,20 +1,49 @@ -using CLI; +using System.Reflection; +using CLI; using Generation.QBE; using Syntax; using Syntax.Diagnostics; using Syntax.Parsing; using Syntax.Tokenization; using Syntax.Typing; +using Binder = Syntax.Typing.Binder; -const string OUT_DIR = "bin-int"; +const string INT_DIR = "bin-int"; +var BUILTIN_DIR = Path.Join(INT_DIR, "builtin"); +var OBJECT_DIR = Path.Join(INT_DIR, "obj"); +var OUT_DIR = Path.Join(INT_DIR, "out"); +if (Directory.Exists(INT_DIR)) +{ + Directory.Delete(INT_DIR, true); +} + +Directory.CreateDirectory(BUILTIN_DIR); +Directory.CreateDirectory(OBJECT_DIR); Directory.CreateDirectory(OUT_DIR); +var options = new Options(); + var files = new List(); -foreach (var arg in args) +for (var i = 0; i < args.Length; i++) { - files.Add(arg); + var arg = args[i]; + if (arg.StartsWith("-r") || arg.StartsWith("--runtime")) + { + i++; + if (i >= args.Length - 1) + { + Console.Error.WriteLine($"{arg} must be followed by a value"); + return 1; + } + + options.CustomRuntime = args[i]; + } + else + { + files.Add(arg); + } } var diagnostics = new List(); @@ -80,7 +109,7 @@ foreach (var file in files) return 1; } - var fileName = Path.GetTempFileName(); + var fileName = Path.Join(OBJECT_DIR, $"{HexString.CreateUnique(8)}_{Path.GetFileNameWithoutExtension(file)}.o"); var asmSuccess = await GCC.Assemble(asm, fileName); if (!asmSuccess) { @@ -90,10 +119,57 @@ foreach (var file in files) objectFiles.Add(fileName); } +if (options.CustomRuntime == null) +{ + try + { + objectFiles.Add(await CreateBuiltinRuntime()); + } + catch (RuntimeCreationException e) + { + Console.Error.WriteLine(e.Message); + return 1; + } +} +else +{ + if (!File.Exists(options.CustomRuntime)) + { + Console.Error.WriteLine($"file '{options.CustomRuntime}' does not exist'"); + return 1; + } + + objectFiles.Add(options.CustomRuntime); +} + var archiveResult = await Archive.Invoke(Path.Join(OUT_DIR, "out.a"), objectFiles); if (!archiveResult) { return 1; } -return 0; \ No newline at end of file +return 0; + +async Task CreateBuiltinRuntime() +{ + const string RUNTIME_NAME = "libruntime_x64.a"; + + var resources = Assembly.GetExecutingAssembly().GetManifestResourceNames(); + var runtime = resources.First(r => r.EndsWith(RUNTIME_NAME)); + + await using var reader = Assembly.GetExecutingAssembly().GetManifestResourceStream(runtime); + + if (reader == null) + { + throw new RuntimeCreationException($"Cannot open stream to '{RUNTIME_NAME}'"); + } + + var runtimePath = Path.Combine(BUILTIN_DIR, RUNTIME_NAME); + await using var writer = new FileStream(runtimePath, FileMode.Create); + + reader.CopyTo(writer); + + return runtimePath; +} + +class RuntimeCreationException(string message) : Exception(message); \ No newline at end of file diff --git a/example/lib/libruntime_x64.a b/src/compiler/CLI/assets/libruntime_x64.a similarity index 100% rename from example/lib/libruntime_x64.a rename to src/compiler/CLI/assets/libruntime_x64.a