commit f4fea315b612524493833607d463b47019f50c64
parent 17628e5e79de400e908e214454454aaef5834e3b
Author: Drew DeVault <sir@cmpwn.com>
Date: Mon, 2 Aug 2021 11:47:56 +0200
gen: introduce _with gen_expr construct
This allows us to merge the non-at and -at implementations of
gen_expr_list by introducing a new -with variant, for functions which
don't have a preferred allocation paradigm.
This gives us the best of both worlds, such that:
let x = {
10;
};
let y = {
coords { ... };
};
{
coords { ... };
};
All use the optimal allocation strategy. And so does this:
foobar(match (x) {
a => y,
b => coords { ... },
});
Only one object is allocated and there are zero copies.
In summary:
- gen_expr_* variants use callee-allocated storage and return their
result to the caller.
- gen_expr_*_at variants use caller-allocated storage, and write their
result into that storage.
- gen_expr_*_with variants do not have a preference, and will use
caller-allocated storage if available, or return the result if not.
gen_expr() shims -at only functions by allocating storage for them.
gen_expr_at() shims non-at functions by writing their result to the
caller-provided storage. Both functions use -with functions in similar
ways, either providing or not providing a place to store the result.
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
M | src/gen.c | | | 35 | ++++++++++++----------------------- |
1 file changed, 12 insertions(+), 23 deletions(-)
diff --git a/src/gen.c b/src/gen.c
@@ -207,34 +207,24 @@ gen_expr_const(struct gen_context *ctx, const struct expression *expr)
abort(); // Invariant
}
-// TODO: Decide how/if gen_expr_list and gen_expr_list_at should be merged
static struct gen_value
-gen_expr_list(struct gen_context *ctx, const struct expression *expr)
-{
- // TODO: Set up defer scope
- for (const struct expressions *exprs = &expr->list.exprs;
- true; exprs = exprs->next) {
- if (!exprs->next) {
- return gen_expr(ctx, exprs->expr);
- }
- gen_expr(ctx, exprs->expr);
- }
- abort(); // Unreachable
-}
-
-static void
-gen_expr_list_at(struct gen_context *ctx,
+gen_expr_list_with(struct gen_context *ctx,
const struct expression *expr,
- struct gen_value out)
+ struct gen_value *out)
{
// TODO: Set up defer scope
for (const struct expressions *exprs = &expr->list.exprs;
exprs; exprs = exprs->next) {
- if (!exprs->next) {
- gen_expr_at(ctx, exprs->expr, out);
+ if (!exprs->next && out) {
+ gen_expr_at(ctx, exprs->expr, *out);
+ return *out;
+ } else if (!exprs->next && !out) {
+ return gen_expr(ctx, exprs->expr);
+ } else {
+ gen_expr(ctx, exprs->expr);
}
- gen_expr(ctx, exprs->expr);
}
+ abort(); // Unreachable
}
static struct gen_value
@@ -314,7 +304,7 @@ gen_expr(struct gen_context *ctx, const struct expression *expr)
case EXPR_INSERT:
assert(0); // TODO
case EXPR_LIST:
- return gen_expr_list(ctx, expr);
+ return gen_expr_list_with(ctx, expr, NULL);
case EXPR_MATCH:
case EXPR_MEASURE:
assert(0); // TODO
@@ -323,7 +313,6 @@ gen_expr(struct gen_context *ctx, const struct expression *expr)
case EXPR_RETURN:
return gen_expr_return(ctx, expr);
case EXPR_SLICE:
- assert(0); // TODO
case EXPR_SWITCH:
case EXPR_TUPLE:
case EXPR_UNARITHM:
@@ -350,7 +339,7 @@ gen_expr_at(struct gen_context *ctx,
switch (expr->type) {
case EXPR_LIST:
- gen_expr_list_at(ctx, expr, out);
+ gen_expr_list_with(ctx, expr, &out);
return;
case EXPR_STRUCT:
gen_expr_struct_at(ctx, expr, out);