about summary refs log tree commit diff
path: root/boot
diff options
context:
space:
mode:
Diffstat (limited to 'boot')
-rw-r--r--boot/transpile.c81
1 files changed, 79 insertions, 2 deletions
diff --git a/boot/transpile.c b/boot/transpile.c
index a239b2b..384b7c1 100644
--- a/boot/transpile.c
+++ b/boot/transpile.c
@@ -262,6 +262,69 @@ struct Visit_Table transpile_definition_visit_functions = {
     .visit_type_function = walk_type_primitive, // no-op, already done in pass 1
 };
 
+// the c-side name a function is emitted under.
+// `main` becomes `catskill_main` so the runtime trailer can wrap it.
+const ascii*
+transpile_function_c_name(struct Function* function)
+{
+    if (function->is_main) return "catskill_main";
+    return string_c_str(function->name);
+}
+
+// emits c-side format of a function header.
+// shared by the signature and body passes.
+void
+transpile_function_emit_signature(struct Visit* visit, struct Function* function)
+{
+    TRANSPILE_PREAMBLE
+
+    VISIT(visit_type_ref, &function->return_type);
+    TRANSPILE_WRITE(" %s(", transpile_function_c_name(function));
+    if (array_length(&function->params) == 0) {
+        TRANSPILE_WRITE("void");
+    } else {
+        bool first = true;
+        FOR_EACH_ARRAY (struct Param, param, &function->params) {
+            if (!first) TRANSPILE_WRITE(", ");
+            VISIT(visit_type_ref, &param->type);
+            TRANSPILE_WRITE(" %s", string_c_str(param->name));
+            first = false;
+        }
+        if (function->variadic) TRANSPILE_WRITE(", ...");
+    }
+    TRANSPILE_WRITE(")");
+}
+
+void
+transpile_visit_function_signature(struct Visit* visit, struct Function* function)
+{
+    TRANSPILE_PREAMBLE
+    transpile_function_emit_signature(visit, function);
+    TRANSPILE_WRITE(";\n");
+}
+
+void
+transpile_visit_function_body(struct Visit* visit, struct Function* function)
+{
+    TRANSPILE_PREAMBLE
+    transpile_function_emit_signature(visit, function);
+    TRANSPILE_WRITE(" {\n}\n");
+}
+
+// transpilation pass 3 visit table
+// emits forward declarations of functions
+struct Visit_Table transpile_signature_visit_functions = {
+    .visit_type_ref = transpile_visit_type_ref,
+    .visit_function = transpile_visit_function_signature,
+};
+
+// transpilation pass 4 visit table
+// emits full definitions of functions
+struct Visit_Table transpile_body_visit_functions = {
+    .visit_type_ref = transpile_visit_type_ref,
+    .visit_function = transpile_visit_function_body,
+};
+
 // walk a lowered translation unit and emit c source into the transpiler's output.
 // the order of the translation unit, and thus the final source output is fixed.
 // preamble, then imports, type forwards, type definitions in topological dependency
@@ -273,6 +336,8 @@ transpile_unit(struct Transpiler* transpiler, struct Unit* unit)
 
     visit_table_fill_defaults(&transpile_forward_visit_functions);
     visit_table_fill_defaults(&transpile_definition_visit_functions);
+    visit_table_fill_defaults(&transpile_signature_visit_functions);
+    visit_table_fill_defaults(&transpile_body_visit_functions);
 
     struct Visit visit_value = { .user_data = transpiler };
     struct Visit* visit = &visit_value;
@@ -283,19 +348,31 @@ transpile_unit(struct Transpiler* transpiler, struct Unit* unit)
         TRANSPILE_WRITE("#include \"%.*s\"\n", (int)import->path.length, import->path.data);
     }
 
-    // trigger pass 1 walk
+    // pass 1: type forwards
     visit->table = &transpile_forward_visit_functions;
     FOR_EACH_ARRAY (struct Type*, type_slot, &unit->types.entries) {
         VISIT(visit_type, *type_slot);
     }
 
-    // trigger pass 2 walk
+    // pass 2: type definitions
     visit->table = &transpile_definition_visit_functions;
     FOR_EACH_ARRAY (Type_Id, ordered_id, &unit->type_emission_order) {
         struct Type* type = *array_at(struct Type*, &unit->types.entries, *ordered_id);
         VISIT(visit_type, type);
     }
 
+    // pass 3: function signatures
+    visit->table = &transpile_signature_visit_functions;
+    FOR_EACH_ARRAY (struct Function*, function_slot, &unit->functions.entries) {
+        VISIT(visit_function, *function_slot);
+    }
+
+    // pass 4: function definitions
+    visit->table = &transpile_body_visit_functions;
+    FOR_EACH_ARRAY (struct Function*, function_slot, &unit->functions.entries) {
+        VISIT(visit_function, *function_slot);
+    }
+
     bool main_takes_args = false;
     bool has_main = false;
     FOR_EACH_ARRAY (struct Function*, function_slot, &unit->functions.entries) {