about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMel <mel@rnrd.eu>2026-05-04 22:35:21 +0200
committerMel <mel@rnrd.eu>2026-05-04 22:35:21 +0200
commit7233ae62b43ae1274ffcb53eb1a62fc91ba540e7 (patch)
treea35207523b1e4ddea2e082c1e5c13bbc1b5599f9
parentb7d0a532d7557b1efa74e6dbc35863e4b112a146 (diff)
downloadcatskill-7233ae62b43ae1274ffcb53eb1a62fc91ba540e7.tar.zst
catskill-7233ae62b43ae1274ffcb53eb1a62fc91ba540e7.zip
Lift out any function closures in lowering pass 2
Signed-off-by: Mel <mel@rnrd.eu>
-rw-r--r--boot/lower.c35
1 files changed, 34 insertions, 1 deletions
diff --git a/boot/lower.c b/boot/lower.c
index aea49ce..f3c04d3 100644
--- a/boot/lower.c
+++ b/boot/lower.c
@@ -80,6 +80,9 @@ struct Lower_Context
     // monotonic counter of synthesized types
     uint synthetic_type_counter;
 
+    // monotonic counter for other synthetic objects (lambdas, temporaries).
+    uint synthetic_counter;
+
     // stack of lexical scopes.
     // all top-level declarations are stored are stored in the first unit scope.
     Array(struct Scope) scope_stack;
@@ -241,6 +244,16 @@ lower_synthesize_type_name(struct Lower_Context* ctx)
     return string_from_c_string(name_buf);
 }
 
+// create a synthetic name for some non-type object, e.g. a lifted lambda.
+// `kind` is a short tag baked into the name for easier observability.
+struct String
+lower_synthesize_name(struct Lower_Context* ctx, const ascii* kind)
+{
+    ascii name_buf[64];
+    snprintf(name_buf, sizeof name_buf, "__cat_%s_%lu", kind, ctx->synthetic_counter++);
+    return string_from_c_string(name_buf);
+}
+
 // look up an existing structural synthetic by hash, or build a fresh one.
 // inner type references are interned, contributing to dependencies.
 Type_Id
@@ -880,12 +893,31 @@ lower_expression(struct Lower_Context* ctx, struct Tree_Expression* tree_expr)
         lower_emit_error_c(
             ctx->unit, tree_expr->span, "type expression not allowed inside a function body");
         return nil;
+    case TREE_EXPRESSION_FUNCTION: {
+        // anonymous function: lift it up as a synthetic function table entry,
+        // replace the expression with a name reference.
+        // TODO: should we have a better kind of reference here than a name?
+        // maybe a function reference somehow?
+        struct String name = lower_synthesize_name(ctx, "lambda");
+
+        // NOTE: we are allowed to register functions whenever we want,
+        // even while iterating over them, the pass will eventually get to them.
+        if (!lower_register_function_shell(ctx->unit, name, tree_expr->span)) return nil;
+
+        Function_Id id;
+        lower_function_lookup_by_name(ctx->unit, name, &id);
+
+        struct Function* fn = *array_at(struct Function*, &ctx->unit->functions.entries, id);
+        fn->synthetic = true;
+        lower_fill_function_signature(ctx, fn, tree_expr);
+
+        return lower_make_name_expression(name, tree_expr->span);
+    }
     case TREE_EXPRESSION_SUBSCRIPT:
     case TREE_EXPRESSION_MEMBER:
     case TREE_EXPRESSION_INCREMENT_DECREMENT:
     case TREE_EXPRESSION_TRY:
     case TREE_EXPRESSION_MUST:
-    case TREE_EXPRESSION_FUNCTION:
         // TODO: implement these
     default:
         lower_emit_error_c(ctx->unit, tree_expr->span, "unimplemented: this expression kind");
@@ -1501,6 +1533,7 @@ lower_tree(struct Tree* tree, struct Source_File source, struct Unit* unit)
         .unit = unit,
         .source = source,
         .synthetic_type_counter = 0,
+        .synthetic_counter = 0,
         .scope_stack = array_new(struct Scope, 32),
     };