harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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:
Msrc/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);