aboutsummaryrefslogtreecommitdiff
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
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>
-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 = {