about summary refs log tree commit diff
path: root/boot
diff options
context:
space:
mode:
authorMel <mel@rnrd.eu>2025-08-05 22:51:26 +0200
committerMel <mel@rnrd.eu>2025-08-05 22:51:26 +0200
commitcbda0181b9f5480cfce2c08e17fd998babb77d4d (patch)
tree41497eeb154f27ff693e598e3c64b1528fd6ce0f /boot
parentc2c84f4d15d964fb663f390046b1d17441145c61 (diff)
downloadcatskill-cbda0181b9f5480cfce2c08e17fd998babb77d4d.tar.zst
catskill-cbda0181b9f5480cfce2c08e17fd998babb77d4d.zip
Add runtime library for catskill transpiled artifacts, wrapping main function with correct types
Signed-off-by: Mel <mel@rnrd.eu>
Diffstat (limited to 'boot')
-rw-r--r--boot/runtime/runtime.c48
-rw-r--r--boot/transpile.c40
2 files changed, 82 insertions, 6 deletions
diff --git a/boot/runtime/runtime.c b/boot/runtime/runtime.c
new file mode 100644
index 0000000..47958a6
--- /dev/null
+++ b/boot/runtime/runtime.c
@@ -0,0 +1,48 @@
+/*
+ * the catskill transpiled-source runtime.
+ * wraps the catskill source entry point in a normal c main function,
+ * and provides some basic runtime startup and exit functionality.
+ *
+ * Copyright (c) 2025, Mel G. <mel@rnrd.eu>
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ */
+
+// catskill programs that use the runtime are expected to
+// provide a `main` which can have the following signatures:
+// * main = fun () {}
+// * main = fun (args [string]) {}
+// the transpiler will define the macro `CATSKILL_MAIN_TAKES_ARGS`
+// to indicate that the main function takes arguments.
+// exit codes are returned with the use of the `exit` function.
+#ifdef CATSKILL_MAIN_TAKES_ARGS
+void catskill_main(Array(struct String) args);
+#else
+void catskill_main(void);
+#endif
+
+// the main function that wraps the catskill main function
+// and provides the runtime startup and exit functionality.
+int
+main(int argc, char* argv[])
+{
+#ifdef CATSKILL_MAIN_TAKES_ARGS
+    Array(struct String) args = array_new(struct String);
+    for (int i = 0; i < argc; i++) {
+        struct String arg = string_from(argv[i]);
+        array_push(&args, &arg);
+    }
+
+    catskill_main(args);
+
+    ARRAY_FREE_ELEMENTS(struct String, args, string_free);
+    array_free(&args);
+#else
+    catskill_main();
+
+    (void)argc;
+    (void)argv;
+#endif
+    // on error catskill_main will call `exit` with a non-zero code.
+    return 0;
+}
diff --git a/boot/transpile.c b/boot/transpile.c
index 25a3d79..7ab13e9 100644
--- a/boot/transpile.c
+++ b/boot/transpile.c
@@ -11,14 +11,14 @@
 #pragma once
 
 #include "catboot.h"
-#include "visit.c"
-#include <stdio.h>
 
 struct Transpile_Context
 {
     bool in_function;
     struct String function_name;
     struct String function_return_type;
+    bool main_function_found;
+    bool main_function_takes_args;
 };
 
 #define CONTEXT_START(name)        \
@@ -47,6 +47,8 @@ transpiler_new(struct Transpiler* transpiler, FILE* output)
             .in_function = false,
             .function_name = string_empty(),
             .function_return_type = string_empty(),
+            .main_function_found = false,
+            .main_function_takes_args = false,
         },
     };
 }
@@ -293,7 +295,21 @@ transpiler_visit_expression_binary_operation(struct Visit* visit, struct Express
 
         VISIT(visit_type_node, header->return_type);
         fprintf(transpiler->output, " ");
-        VISIT(visit_expression, name_expr);
+
+        // check if this is a main function assignment
+        if (name_expr && name_expr->kind == EXPRESSION_NAME) {
+            struct Expression_Name* name = &name_expr->value.name;
+            if (string_equals_c_str(name->name, "main")) {
+                transpiler->context.main_function_found = true;
+                transpiler->context.main_function_takes_args =
+                    header->parameters_type_and_name != nil;
+                fprintf(transpiler->output, "catskill_main");
+            } else {
+                VISIT(visit_expression, name_expr);
+            }
+        } else {
+            VISIT(visit_expression, name_expr);
+        }
         VISIT(visit_function_header_node, header);
         fprintf(transpiler->output, " ");
 
@@ -380,13 +396,25 @@ transpiler_visit_tree(struct Visit* visit, struct Tree* tree)
     // for transpiled catskill programs.
     // other headers can be included by the user
     // with the pragma `| c-header "header.h"`.
-    fprintf(transpiler->output, "#include <stdio.h>\n");
-    fprintf(transpiler->output, "#include <stdint.h>\n");
-    fprintf(transpiler->output, "#include <stdbool.h>\n\n");
+    // TODO: for now we just reference the path to it in this repo
+    // exactly, when we actually just want to fully include the string
+    // of the entire file into the transpiled output, for development it's
+    // okay for now.
+    fprintf(transpiler->output, "#include \"boot/runtime/core.c\"\n");
 
     FOR_EACH (struct Statement*, statement, tree->top_level_statements) {
         VISIT(visit_statement, statement);
     }
+
+    // check if we found a main function and define the appropriate macro for the runtime
+    // TODO: create a nice lookup table of all the functions and types we found through
+    // the catskill source.
+    if (transpiler->context.main_function_found) {
+        if (transpiler->context.main_function_takes_args) {
+            fprintf(transpiler->output, "\n#define CATSKILL_MAIN_TAKES_ARGS\n");
+        }
+        fprintf(transpiler->output, "#include \"boot/runtime/runtime.c\"\n");
+    }
 }
 
 struct Visit_Table transpiler_visit_functions = {