about summary refs log tree commit diff
path: root/boot
diff options
context:
space:
mode:
authorMel <mel@rnrd.eu>2025-03-11 22:34:40 +0100
committerMel <mel@rnrd.eu>2025-03-11 22:34:40 +0100
commitbed8e60da8d8ebc3d367872bacd64137414e7ae9 (patch)
tree993198cc1bca0a3873f997f0f2a764899e121d82 /boot
parent03dd7d175cbfb728e0c9708b515a5b0435eaa29a (diff)
downloadcatskill-bed8e60da8d8ebc3d367872bacd64137414e7ae9.tar.zst
catskill-bed8e60da8d8ebc3d367872bacd64137414e7ae9.zip
Add common library for basic types, functions and macros
Signed-off-by: Mel <mel@rnrd.eu>
Diffstat (limited to 'boot')
-rw-r--r--boot/catboot.c56
-rw-r--r--boot/common.c146
2 files changed, 179 insertions, 23 deletions
diff --git a/boot/catboot.c b/boot/catboot.c
index ae0fc6c..b36bb97 100644
--- a/boot/catboot.c
+++ b/boot/catboot.c
@@ -1,43 +1,53 @@
+/*
+ * # catboot
+ *
+ * the bootstrap compiler for catskill,
+ * implemented as simply as possible,
+ * depending only on the C standard library,
+ * in this case musl, and built statically
+ * in a single union build.
+ *
+ * should only be used to compile `catskill` itself,
+ * as it is not a full-featured compiler, and never will be.
+ * once `catskill` can compile itself using a C backend,
+ * this compiler version will be permanently retired.
+ * (although that's still very far away!! have fun! :3)
+ */
+
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
 
-void
-error(const char* msg) {
-    fprintf(stderr, ":( error: %s\n", msg);
-    exit(EXIT_FAILURE);
-}
+#include "common.c"
 
-const char*
-read_file(const char* path) {
+const ascii*
+read_file(const ascii* path)
+{
     struct stat stat_info;
-    if (stat(path, &stat_info) == -1)
-        error("i couldn't open that file, sorry :(");
+    if (stat(path, &stat_info) == -1) failure("i couldn't open that file, sorry :(");
 
-    const int file = open(path, O_RDONLY);
-    if (file == -1)
-        error("i couldn't open that file, sorry :(");
+    const int32 file_descriptor = open(path, O_RDONLY);
+    check(file_descriptor != -1, "i couldn't open that file, sorry :(");
 
-    const int mmap_prot = PROT_READ;
-    const int mmap_flags = MAP_PRIVATE;
-    const void* file_data = mmap(
-        NULL, stat_info.st_size, mmap_prot, mmap_flags, file, 0
-    );
+    const flags mmap_prot = PROT_READ;
+    const flags mmap_flags = MAP_PRIVATE;
+    const unknown* file_data =
+        mmap(nil, stat_info.st_size, mmap_prot, mmap_flags, file_descriptor, 0);
 
-    return (const char*)file_data;
+    return file_data;
 }
 
-int
-main(const int argc, const char* argv[]) {
+integer
+main(const integer argc, const ascii* argv[])
+{
     if (argc != 2) {
         printf("usage: catboot <filename>\n");
         return EXIT_FAILURE;
     }
-    const char* file_path = argv[1];
-    const char* source = read_file(file_path);
+    const ascii* file_path = argv[1];
+    const ascii* source = read_file(file_path);
 
     printf("%s", source);
 
diff --git a/boot/common.c b/boot/common.c
new file mode 100644
index 0000000..67e13eb
--- /dev/null
+++ b/boot/common.c
@@ -0,0 +1,146 @@
+/*
+ * a small library of types, functions and macros that
+ * are used throughout the bootstrap compiler.
+ * allocation done purely statically.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define uint8 uint8_t
+#define uint16 uint16_t
+#define uint32 uint32_t
+#define uint64 uint64_t
+
+#define int8 int8_t
+#define int16 int16_t
+#define int32 int32_t
+#define int64 int64_t
+
+#define float32 float
+#define float64 double
+#define real float64
+
+#define uint uint64
+#define integer int64
+#define flags int32
+
+#define ascii char
+#define byte char
+
+#define bool _Bool
+#define true 1
+#define false 0
+#define nil NULL
+#define unknown void
+
+// call on irrecoverable failure.
+// prints a very sad, apologetic message for
+// the user and aborts program with failure status.
+void
+failure(const ascii* message)
+{
+    const ascii* format =
+        "\\e[0;31m"
+        ";( sorry, a failure has occurred...\n"
+        "-> %s!\n"
+        "\\e[0m";
+    fprintf(stderr, format, message);
+
+    exit(EXIT_FAILURE);
+}
+
+// check a condition, triggering a failure if it's false.
+void
+check(bool condition, const ascii* message)
+{
+    if (!condition) failure(message);
+}
+
+// the common size of region memory blocks.
+#define REGION_SIZE 65536
+
+// statically allocates a region of memory of a given size
+// for a single type.
+#define REGION_OF_SIZE(type, of, size) \
+    type region_##of[size];            \
+    uint region_##of##_cursor = 0;
+
+// statically allocates a region of memory for a type.
+#define REGION(type, of) REGION_OF_SIZE(type, of, REGION_SIZE)
+
+// the global string region.
+REGION(ascii, string)
+
+// a string.
+struct String
+{
+    ascii* data;
+    uint length;
+};
+
+#define STRING_ITERATE(index, c, str) \
+    ascii c = string_at(str, 0);      \
+    for (uint index = 0; index < str.length; c = string_at(str, ++index))
+
+// allocates a new string in the global string region.
+struct String
+string_new(const ascii* data, uint length)
+{
+    // for compatibility, we include an additional null byte at the end.
+    uint allocation_length = length + 1;
+    check(region_string_cursor + allocation_length < REGION_SIZE, "out of string memory");
+
+    ascii* at = region_string + region_string_cursor;
+    region_string_cursor += allocation_length;
+
+    for (uint i = 0; i < length; ++i) at[i] = data[i];
+    at[length] = '\0';
+
+    return {
+        .data = at,
+        .length = length,
+    };
+}
+
+// allocates a new string in the global string region,
+// taking the data from a null-terminated C string.
+struct String
+string_from_c_string(const char* c_string)
+{
+    uint length = strlen(c_string);
+    return string_new(c_string, length);
+}
+
+// allocates a new string in the global string region,
+// taking the data from a static null-terminated C string.
+//
+// NOTE: The string is not copied, so it MUST have a lifetime
+// spanning the entire program.
+struct String
+string_from_static_c_string(const char* c_string)
+{
+    uint length = strlen(c_string);
+    return {
+        .data = (ascii*)c_string,
+        .length = length,
+    };
+}
+
+// returns the character at a given index.
+// does bounds-checking.
+ascii
+string_at(struct String s, uint index)
+{
+    check(index < s.length, "index out of bounds");
+    return s.data[index];
+}
+
+uint
+string_length(struct String s)
+{
+    return s.length;
+}