diff options
| author | Mel <mel@rnrd.eu> | 2026-05-04 22:35:21 +0200 |
|---|---|---|
| committer | Mel <mel@rnrd.eu> | 2026-05-04 22:35:21 +0200 |
| commit | 7233ae62b43ae1274ffcb53eb1a62fc91ba540e7 (patch) | |
| tree | a35207523b1e4ddea2e082c1e5c13bbc1b5599f9 | |
| parent | b7d0a532d7557b1efa74e6dbc35863e4b112a146 (diff) | |
| download | catskill-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.c | 35 |
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), }; |
