From dd6a491ccb498dd8786c550896be79990b98a8a2 Mon Sep 17 00:00:00 2001 From: nub31 Date: Fri, 27 Jun 2025 15:55:32 +0200 Subject: [PATCH] ... --- example/compile.sh | 8 ++ example/lib/libruntime_x64.a | Bin 0 -> 8044 bytes example/main.nub | 43 ------- example/{ => src}/c.nub | 0 example/src/main.nub | 6 + run.sh | 4 - src/compiler/CLI/AR.cs | 27 +++- src/compiler/CLI/CLI.csproj | 7 +- src/compiler/CLI/GCC.cs | 52 +++----- src/compiler/CLI/Program.cs | 119 +++++++----------- src/compiler/CLI/QBE.cs | 22 ++-- src/compiler/Syntax/Parsing/Parser.cs | 4 +- src/compiler/Syntax/Parsing/SyntaxTree.cs | 2 +- src/compiler/Syntax/Typing/Binder.cs | 6 +- src/compiler/Syntax/Typing/BoundSyntaxTree.cs | 2 +- src/runtime/.clang-format | 2 +- src/runtime/.gitignore | 4 +- src/runtime/makefile | 18 +-- src/runtime/runtime/runtime.c | 46 +++---- src/runtime/targets/x64.s | 19 +-- 20 files changed, 159 insertions(+), 232 deletions(-) create mode 100755 example/compile.sh create mode 100644 example/lib/libruntime_x64.a delete mode 100644 example/main.nub rename example/{ => src}/c.nub (100%) create mode 100644 example/src/main.nub delete mode 100755 run.sh diff --git a/example/compile.sh b/example/compile.sh new file mode 100755 index 0000000..c3a2341 --- /dev/null +++ b/example/compile.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +object_files=$(dotnet run --project ../src/compiler/CLI/CLI.csproj src/main.nub src/c.nub) + +echo $object_files + +mkdir -p bin +gcc -o bin/out $object_files diff --git a/example/lib/libruntime_x64.a b/example/lib/libruntime_x64.a new file mode 100644 index 0000000000000000000000000000000000000000..dfd438dd9229c449d0cd4653cf98566d0d95aaff GIT binary patch literal 8044 zcmbtZU2I%O6`s56n{K@Rjf3MPrCBGdj_-LDH$BFGR7N_p{SptiZvp z6=QEg#r9aDuTKRzR{!Gg$zuV>p%4{0VnD2L8Wp0eWu-nStApY*Vx#zH^CSO0lU(>P zx$v#q$+w5^qUj?yIX`^YNnSZ~J9%aJZqj+T`3>>Xjq=~Xef@Wa%1y08<+40W9=)(-lPyeuua^8iIV{# zT;YT$aM6IrXYnv;yD{L7gC!%JfQzEB&duh1QkGmDpg^qS87drQ&v$RNpO@}+3BjH2g<86Ts8qtIZhN_UdcF2U42(84h)9P%X$zRtj z!kwYxZL|^^O)GuWhtMv8hV?P$@y*&n=epgSp*h%bakE2>^;M1ayEh+iGn>N{NOfop ztwi^+F zx?tShh~m29uDc!Jj=H;1MBRs}a7J9`ho{Ko2`EYFxDvbW?t+-NA{MBl{+v(c%AQCU z=qwOVe(_9XsQX}~yE~SMbw#4nemU>;PkDK-m`xLlqpg3ouQ%G8h(xC%(aFi8=h0!3 zpP=K2*i>mQpUxBu`9irAE$1&}^Ak}&HJScl=G$RRNkA2q%*0a$Q3An3WRr`aVq+vlqnSbwc1xq zX+1tLrDZtpBj3sdB*y1_PmGr*C%vNSg->G{iD3wbuo-EoP%frDf-cfSp5uZw`8ba2 zV>vD2nZmReFXXZ%--{Q$nL;T}-HPT?`KfrRnAVc_EXS5byj&{AbJ_9uR5~4}`5f&{ zM044Ec{VzgFUPyPjcc+bvwnZDAbqR(VBJ zeV-v;Ii3mYHgNczkgs_m`Ye18?>F%!PwV_ncrpMV&kQfh!wqD zDmLMbm#0Rv`N;yc$$Dyhyy%^;YEBg?hw!RZCJX#6ZpJJ6bL`8@j7}C)(;oNjL5i)UjIr12NZT6Zik;2#veROslWM@s zwTH%WTM!_T4eurlXVd-a;~cSV5>)Z8K16{ivSs%ZjPr0%HCLV^SlC22IWU}akkjXA z2O5d`>1W#n{&UvT?|)z*TlRDf401o?LmK&lNwz-DzgqEk$%_V+Z$KaMW1rgbPY`C? zBuM;;{p)iA7|50#C9IbJG4}scsipiQ+p_)7uuZ$4f8=E0dzM4Z>hhaw=s%6l66teP zaVzm_{VUXfy6s;kzl39bn56Y|`3g1ax+!-+chm%H$i7AxLN(uUQ0Zg+2pEHGv%jG> z__y^(SWxE|+JvqDOKPY!f1zfjF~*8mKP~jr`g;A>@(q<`7L4%Vw6U(Ok2PWMedxFF z{yPT7AbYG^sjZfNhU0(B&_&hOpY2Ul?rCuc`~U80dwS>_UDCbZ)n4Vj1pkA0(6g0B zGx_$7qr^13$%Vh(1}q=g(YPmxQCahzq%zg=jzn^@SLWqNM>)}dj;^B|=U%^c>FRpQ z^GgB)qMwh-Q21t(>J`#o0TOU7In2U{P1qDX(U0mr*X($1&AqJS2X1U3+B=GDJNg?G@@77R zZ*h>u`DhYme<82q)Vh#Y>lfN9V{iNYv|LiAj-QrLn%Ut>N_Za`r^-o@P(CO{$N>7N z$3fd0iO4a$}YyuwE#QM;8BBY|9J1f=Kbnp z9oRPER{Q@F7=vtC?gbbpC=49^*B*g(vP{sp<$BtugkO4sOzTO z`^@Yy!5Xqp5mqbyBoF8!>mz=|ZpWV{td{@v3~pq7UD&ec*U*o!pgk@v+7OrDpt4r{ zI+xe_h(Am}JO1ww23J~+s*?1b6XwSx9lu%fRGVVrDhn(#iWH?*PQF%7beWB|S6N*> X)_6bKYac2h3<}YrDk@JMw+8+PkmNx} literal 0 HcmV?d00001 diff --git a/example/main.nub b/example/main.nub deleted file mode 100644 index 6b487b5..0000000 --- a/example/main.nub +++ /dev/null @@ -1,43 +0,0 @@ -namespace main - -struct Human { - name: cstring -} - -export func main(args: []cstring): i64 { - // let human: Human - - // human = alloc Human { - // name = "member" - // } - - // c::puts(human.name) - - // c::puts("literal") - - // let x: cstring - - // x = "variable" - - // c::puts(x) - - // let y: func(cstring) - - // y = c::puts - - // y("proxy") - - // func(){ c::puts("anon") }() - - // let z: func() - - // z = func() { c::puts("anon variable") } - - // z() - - c::printf("%d\n", "test".count) - - // c::puts("test") - - return 0 -} diff --git a/example/c.nub b/example/src/c.nub similarity index 100% rename from example/c.nub rename to example/src/c.nub diff --git a/example/src/main.nub b/example/src/main.nub new file mode 100644 index 0000000..fd8ef94 --- /dev/null +++ b/example/src/main.nub @@ -0,0 +1,6 @@ +namespace main + +export func main(args: []cstring): i64 { + c::puts("test") + return 0 +} diff --git a/run.sh b/run.sh deleted file mode 100755 index cb2a272..0000000 --- a/run.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -set -e -dotnet run --project src/compiler/CLI/CLI.csproj example/main.nub example/c.nub -./bin/out \ No newline at end of file diff --git a/src/compiler/CLI/AR.cs b/src/compiler/CLI/AR.cs index 8591be6..57eb46f 100644 --- a/src/compiler/CLI/AR.cs +++ b/src/compiler/CLI/AR.cs @@ -1,6 +1,29 @@ +using System.Diagnostics; + namespace CLI; -public class AR +public static class AR { - + public static async Task Invoke(string fileName, IEnumerable objectFiles) + { + using var process = new Process(); + process.StartInfo = new ProcessStartInfo("ar", ["rcs", fileName, ..objectFiles]) + { + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true + }; + + process.Start(); + await process.WaitForExitAsync(); + + var errors = await process.StandardError.ReadToEndAsync(); + if (!string.IsNullOrWhiteSpace(errors)) + { + await Console.Error.WriteLineAsync("ar error when archiving:\n" + errors); + } + + return process.ExitCode == 0; + } } \ No newline at end of file diff --git a/src/compiler/CLI/CLI.csproj b/src/compiler/CLI/CLI.csproj index fec4a24..c101a01 100644 --- a/src/compiler/CLI/CLI.csproj +++ b/src/compiler/CLI/CLI.csproj @@ -1,7 +1,7 @@  - nub + nubc Exe net9.0 enable @@ -14,13 +14,8 @@ - - - - - diff --git a/src/compiler/CLI/GCC.cs b/src/compiler/CLI/GCC.cs index 53e0037..caa69d1 100644 --- a/src/compiler/CLI/GCC.cs +++ b/src/compiler/CLI/GCC.cs @@ -4,49 +4,37 @@ namespace CLI; public static class GCC { - public static async Task Assemble(string asmPath, string objPath) + public static async Task Assemble(string asm, string objPath) { - using var gccProcess = new Process(); - gccProcess.StartInfo = new ProcessStartInfo("gcc", ["-g", "-nostdlib", "-ffreestanding", "-c", asmPath, "-o", objPath]) + var dir = Path.GetDirectoryName(objPath); + if (dir != null) + { + Directory.CreateDirectory(dir); + } + + using var process = new Process(); + process.StartInfo = new ProcessStartInfo("gcc", ["-g", "-xassembler", "-c", "-o", objPath, "-"]) { UseShellExecute = false, + RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true }; - gccProcess.Start(); - await gccProcess.WaitForExitAsync(); + process.Start(); + + await process.StandardInput.WriteAsync(asm); + process.StandardInput.Close(); + + await process.WaitForExitAsync(); - var gccErrors = await gccProcess.StandardError.ReadToEndAsync(); - if (!string.IsNullOrWhiteSpace(gccErrors)) + var errors = await process.StandardError.ReadToEndAsync(); + if (!string.IsNullOrWhiteSpace(errors)) { - await Console.Error.WriteLineAsync("gcc error when assembling:\n" + gccErrors); + await Console.Error.WriteLineAsync("gcc error when assembling:\n" + errors); } - return gccProcess.ExitCode == 0; - } - - public static async Task Link(List objectFiles, string outputPath) - { - using var gccProcess = new Process(); - gccProcess.StartInfo = new ProcessStartInfo("gcc", ["-g", "-nostdlib", "-ffreestanding", "-o", outputPath, ..objectFiles]) - { - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - CreateNoWindow = true - }; - - gccProcess.Start(); - await gccProcess.WaitForExitAsync(); - - var gccErrors = await gccProcess.StandardError.ReadToEndAsync(); - if (!string.IsNullOrWhiteSpace(gccErrors)) - { - await Console.Error.WriteLineAsync("gcc error when linking:\n" + gccErrors); - } - - return gccProcess.ExitCode == 0; + return process.ExitCode == 0; } } diff --git a/src/compiler/CLI/Program.cs b/src/compiler/CLI/Program.cs index e59d992..4bed8be 100644 --- a/src/compiler/CLI/Program.cs +++ b/src/compiler/CLI/Program.cs @@ -1,6 +1,4 @@ -using System.Diagnostics; -using System.Reflection; -using CLI; +using CLI; using Generation.QBE; using Syntax; using Syntax.Diagnostics; @@ -9,40 +7,22 @@ using Syntax.Tokenization; using Syntax.Typing; using Binder = Syntax.Typing.Binder; -const string BIN_DIR = "bin"; -const string BIN_INT_DIR = "bin-int"; +const string OUT_DIR = "bin-int"; -if (Directory.Exists(BIN_DIR)) +if (Directory.Exists(OUT_DIR)) { - Directory.Delete(BIN_DIR, true); + Directory.Delete(OUT_DIR, true); } -if (Directory.Exists(BIN_INT_DIR)) -{ - Directory.Delete(BIN_INT_DIR, true); -} - -Directory.CreateDirectory(BIN_DIR); -Directory.CreateDirectory(BIN_INT_DIR); - var files = new List(); -string? runtimePath = null; - foreach (var arg in args) { - if (arg.StartsWith("-r=")) - { - runtimePath = arg.Substring("-r=".Length); - } - else - { - files.Add(arg); - } + files.Add(arg); } var diagnostics = new List(); -var syntaxTrees = new List(); +var syntaxTrees = new Dictionary(); foreach (var file in files) { @@ -61,29 +41,27 @@ foreach (var file in files) var tokenizeResult = Tokenizer.Tokenize(sourceText, out var tokenizerDiagnostics); diagnostics.AddRange(tokenizerDiagnostics); - var syntaxTree = Parser.ParseFile(tokenizeResult, file, out var parseDiagnostics); + var syntaxTree = Parser.ParseFile(tokenizeResult, out var parseDiagnostics); diagnostics.AddRange(parseDiagnostics); if (syntaxTree != null) { - syntaxTrees.Add(syntaxTree); - } - else - { - throw new Exception(); + syntaxTrees[file] = syntaxTree; } } -var definitionTable = new DefinitionTable(syntaxTrees); +var definitionTable = new DefinitionTable(syntaxTrees.Values); -var boundSyntaxTrees = new List(); +var boundSyntaxTrees = new Dictionary(); -foreach (var syntaxTree in syntaxTrees) +foreach (var (file, syntaxTree) in syntaxTrees) { - boundSyntaxTrees.Add(Binder.Bind(syntaxTree, definitionTable)); + var boundSyntaxTree = Binder.Bind(syntaxTree, definitionTable, out var binderDiagnostics); + diagnostics.AddRange(binderDiagnostics); + boundSyntaxTrees[file] = boundSyntaxTree; } -var boundDefinitionTable = new BoundDefinitionTable(boundSyntaxTrees); +var boundDefinitionTable = new BoundDefinitionTable(boundSyntaxTrees.Values); foreach (var diagnostic in diagnostics) { @@ -97,48 +75,18 @@ if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Erro var objectFiles = new List(); -if (runtimePath == null) +foreach (var file in files) { - const string RUNTIME_NAME = "libruntime_x64"; - await using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(RUNTIME_NAME); - if (stream == null) - { - throw new Exception("Runtime stream is null"); - } - - var tmpDir = Directory.CreateTempSubdirectory("nub"); - runtimePath = Path.Combine(tmpDir.FullName, RUNTIME_NAME + ".a"); - - await using var writer = new FileStream(runtimePath, FileMode.Create, FileAccess.Write); - await stream.CopyToAsync(writer); -} - -objectFiles.Add(runtimePath); - -foreach (var boundSyntaxTree in boundSyntaxTrees) -{ - var relativeFilePath = Path.GetRelativePath(Environment.CurrentDirectory, boundSyntaxTree.FilePath); - var outputPath = Path.Combine(BIN_INT_DIR, relativeFilePath); - - var outputDirectory = Path.GetDirectoryName(outputPath); - Debug.Assert(!string.IsNullOrWhiteSpace(outputDirectory)); - Directory.CreateDirectory(outputDirectory); - - var ssa = QBEGenerator.Emit(boundSyntaxTree, boundDefinitionTable); - var ssaPath = Path.ChangeExtension(outputPath, "ssa"); - File.WriteAllText(ssaPath, ssa); - + var ssa = QBEGenerator.Emit(boundSyntaxTrees[file], boundDefinitionTable); var asm = await QBE.Invoke(ssa); if (asm == null) { return 1; } - var asmPath = Path.ChangeExtension(outputPath, "s"); - await File.WriteAllTextAsync(asmPath, asm); - - var objPath = Path.ChangeExtension(outputPath, "o"); - var asmSuccess = await GCC.Assemble(asmPath, objPath); + var fileName = $"{Path.GetFileNameWithoutExtension(file)}_{StringRandomizer.GenerateUniqueHexString(8)}.o"; + var objPath = Path.Combine(OUT_DIR, fileName); + var asmSuccess = await GCC.Assemble(asm, objPath); if (!asmSuccess) { return 1; @@ -147,5 +95,28 @@ foreach (var boundSyntaxTree in boundSyntaxTrees) objectFiles.Add(objPath); } -var linkSuccess = await GCC.Link(objectFiles, Path.Combine(BIN_DIR, "out")); -return linkSuccess ? 0 : 1; \ No newline at end of file +foreach (var objectFile in objectFiles) +{ + Console.Out.WriteLine(objectFile); +} + +return 0; + +internal static class StringRandomizer +{ + private static readonly char[] StringChars = "0123456789abcdef".ToArray(); + + public static string GenerateUniqueHexString(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/QBE.cs b/src/compiler/CLI/QBE.cs index c592e12..dd3f728 100644 --- a/src/compiler/CLI/QBE.cs +++ b/src/compiler/CLI/QBE.cs @@ -6,8 +6,8 @@ public static class QBE { public static async Task Invoke(string ssa) { - using var qbeProcess = new Process(); - qbeProcess.StartInfo = new ProcessStartInfo + using var process = new Process(); + process.StartInfo = new ProcessStartInfo { FileName = "qbe", UseShellExecute = false, @@ -17,21 +17,21 @@ public static class QBE CreateNoWindow = true }; - qbeProcess.Start(); + process.Start(); - await qbeProcess.StandardInput.WriteAsync(ssa); - qbeProcess.StandardInput.Close(); + await process.StandardInput.WriteAsync(ssa); + process.StandardInput.Close(); - await qbeProcess.WaitForExitAsync(); + await process.WaitForExitAsync(); - var qbeErrors = await qbeProcess.StandardError.ReadToEndAsync(); - if (!string.IsNullOrWhiteSpace(qbeErrors)) + var errors = await process.StandardError.ReadToEndAsync(); + if (!string.IsNullOrWhiteSpace(errors)) { - await Console.Error.WriteLineAsync("qbe error:\n" + qbeErrors); + await Console.Error.WriteLineAsync("qbe error:\n" + errors); } - var asm = await qbeProcess.StandardOutput.ReadToEndAsync(); + var asm = await process.StandardOutput.ReadToEndAsync(); - return qbeProcess.ExitCode == 0 ? asm : null; + return process.ExitCode == 0 ? asm : null; } } diff --git a/src/compiler/Syntax/Parsing/Parser.cs b/src/compiler/Syntax/Parsing/Parser.cs index 546310f..2cbdc47 100644 --- a/src/compiler/Syntax/Parsing/Parser.cs +++ b/src/compiler/Syntax/Parsing/Parser.cs @@ -15,7 +15,7 @@ public static class Parser private static IEnumerable _tokens = []; private static int _index; - public static SyntaxTree? ParseFile(IEnumerable tokens, string filePath, out IEnumerable diagnostics) + public static SyntaxTree? ParseFile(IEnumerable tokens, out IEnumerable diagnostics) { _tokens = tokens; _namespace = null!; @@ -46,7 +46,7 @@ public static class Parser } diagnostics = _diagnostics; - return new SyntaxTree(filePath, _namespace, definitions); + return new SyntaxTree(_namespace, definitions); } catch (ParseException ex) { diff --git a/src/compiler/Syntax/Parsing/SyntaxTree.cs b/src/compiler/Syntax/Parsing/SyntaxTree.cs index 914a9ed..c36babc 100644 --- a/src/compiler/Syntax/Parsing/SyntaxTree.cs +++ b/src/compiler/Syntax/Parsing/SyntaxTree.cs @@ -2,4 +2,4 @@ namespace Syntax.Parsing; -public record SyntaxTree(string FilePath, string Namespace, List Definitions); +public record SyntaxTree(string Namespace, List Definitions); diff --git a/src/compiler/Syntax/Typing/Binder.cs b/src/compiler/Syntax/Typing/Binder.cs index 306d40f..526356c 100644 --- a/src/compiler/Syntax/Typing/Binder.cs +++ b/src/compiler/Syntax/Typing/Binder.cs @@ -1,4 +1,5 @@ using Common; +using Syntax.Diagnostics; using Syntax.Parsing; using Syntax.Parsing.Node; using Syntax.Tokenization; @@ -16,7 +17,7 @@ public static class Binder private static Dictionary _variables = new(); private static NubType? _funcReturnType; - public static BoundSyntaxTree Bind(SyntaxTree syntaxTree, DefinitionTable definitionTable) + public static BoundSyntaxTree Bind(SyntaxTree syntaxTree, DefinitionTable definitionTable, out IEnumerable diagnostics) { _syntaxTree = syntaxTree; _definitionTable = definitionTable; @@ -31,7 +32,8 @@ public static class Binder definitions.Add(BindDefinition(definition)); } - return new BoundSyntaxTree(syntaxTree.FilePath, syntaxTree.Namespace, definitions); + diagnostics = []; + return new BoundSyntaxTree(syntaxTree.Namespace, definitions); } private static BoundDefinitionNode BindDefinition(DefinitionNode node) diff --git a/src/compiler/Syntax/Typing/BoundSyntaxTree.cs b/src/compiler/Syntax/Typing/BoundSyntaxTree.cs index 0dd20b5..30c04fd 100644 --- a/src/compiler/Syntax/Typing/BoundSyntaxTree.cs +++ b/src/compiler/Syntax/Typing/BoundSyntaxTree.cs @@ -2,4 +2,4 @@ namespace Syntax.Typing; -public record BoundSyntaxTree(string FilePath, string Namespace, List Definitions); +public record BoundSyntaxTree(string Namespace, List Definitions); diff --git a/src/runtime/.clang-format b/src/runtime/.clang-format index 795c447..277b2b7 100644 --- a/src/runtime/.clang-format +++ b/src/runtime/.clang-format @@ -8,7 +8,7 @@ PointerAlignment: Left AllowShortFunctionsOnASingleLine: None # Control how short statements are placed -AllowShortBlocksOnASingleLine: Empty +AllowShortBlocksOnASingleLine: Never AllowShortIfStatementsOnASingleLine: Never AllowShortLoopsOnASingleLine: false diff --git a/src/runtime/.gitignore b/src/runtime/.gitignore index 4ad964a..4c66b30 100644 --- a/src/runtime/.gitignore +++ b/src/runtime/.gitignore @@ -1,2 +1,2 @@ -out -out-int \ No newline at end of file +bin +bin-int \ No newline at end of file diff --git a/src/runtime/makefile b/src/runtime/makefile index 6ed4637..f620c40 100644 --- a/src/runtime/makefile +++ b/src/runtime/makefile @@ -1,16 +1,16 @@ CC ?= x86_64-linux-gnu-gcc TARGET ?= x64 -CFLAGS = -nostdlib -ffreestanding -Wall -Werror -Wextra +CFLAGS = -nostdlib -ffreestanding -Wall -Werror -Wextra -g -libruntime: out-int/runtime.o - $(CC) $(CFLAGS) -c targets/$(TARGET).s -o out-int/$(TARGET).o - mkdir -p out - ar rcs out/libruntime_$(TARGET).a out-int/runtime.o out-int/$(TARGET).o +libruntime: bin-int/runtime.o + $(CC) $(CFLAGS) -c targets/$(TARGET).s -o bin-int/$(TARGET).o + mkdir -p bin + ar rcs bin/libruntime_$(TARGET).a bin-int/runtime.o bin-int/$(TARGET).o -out-int/runtime.o: runtime/runtime.c - mkdir -p out-int - $(CC) $(CFLAGS) -c runtime/runtime.c -o out-int/runtime.o +bin-int/runtime.o: runtime/runtime.c + mkdir -p bin-int + $(CC) $(CFLAGS) -c runtime/runtime.c -o bin-int/runtime.o clean: - rm -r out out-int + rm -r bin bin-int diff --git a/src/runtime/runtime/runtime.c b/src/runtime/runtime/runtime.c index b940f17..3a819e9 100644 --- a/src/runtime/runtime/runtime.c +++ b/src/runtime/runtime/runtime.c @@ -1,9 +1,9 @@ #include -#define NUB_PANIC_ERROR_CODE 101 - -extern void nub_write_string(const char* str); -extern void nub_exit(int code); +typedef struct nub_string { + uint64_t size; + uint8_t buffer[]; +} nub_string_t; uint64_t nub_cstring_length(const char* string) { @@ -14,9 +14,22 @@ uint64_t nub_cstring_length(const char* string) return len; } -uint64_t nub_string_length() +uint64_t nub_string_length(const nub_string_t* string) { - return 0; + uint64_t count = 0; + uint64_t i = 0; + + while (i < string->size) { + uint8_t byte = string->buffer[i]; + + if ((byte & 0b11000000) != 0b10000000) { + count++; + } + + i++; + } + + return count; } void nub_memcpy(uint8_t* source, uint8_t* destination, uint64_t length) @@ -32,24 +45,3 @@ void nub_memset(uint8_t* destination, uint8_t value, uint64_t count) destination[i] = value; } } - -void nub_panic_array_oob() -{ - nub_write_string("Array out of bounds\n"); - nub_exit(NUB_PANIC_ERROR_CODE); -} - -void nub_panic_oom() -{ - nub_write_string("Out of memory\n"); - nub_exit(NUB_PANIC_ERROR_CODE); -} - -extern uint64_t main(); - -__attribute__((noreturn)) void _start() -{ - uint64_t exit_code = main(); - nub_exit(exit_code); - __builtin_unreachable(); -} diff --git a/src/runtime/targets/x64.s b/src/runtime/targets/x64.s index e9f94b5..4e6cd53 100644 --- a/src/runtime/targets/x64.s +++ b/src/runtime/targets/x64.s @@ -1,20 +1,9 @@ .intel_syntax noprefix .text -.globl nub_write_string -# void nub_write_string(const char* str) -nub_write_string: - push rdi - call nub_cstring_length - mov rdx, rax - pop rsi - mov rax, 1 - mov rdi, 1 - syscall - -.text -.globl nub_exit -# void nub_exit(int code) -nub_exit: +.globl _start +_start: + mov rdi, rsp + call main mov rax, 60 syscall