harec

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

commit ef58168ea800f0a74bea8d3f3889b79583d18137
parent 7fc0ec9f68b3513c8988d8465a91295cd410b360
Author: Drew DeVault <sir@cmpwn.com>
Date:   Thu,  5 Aug 2021 13:29:22 +0200

gen: implement defer

Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Minclude/gen.h | 11+++++++++++
Msrc/gen.c | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Atests/909-defer.ha | 15+++++++++++++++
Mtests/configure | 3++-
4 files changed, 93 insertions(+), 13 deletions(-)

diff --git a/include/gen.h b/include/gen.h @@ -42,6 +42,16 @@ struct gen_binding { struct gen_binding *next; }; +struct gen_defer { + const struct expression *expr; + struct gen_defer *next; +}; + +struct gen_scope { + struct gen_defer *defers; + struct gen_scope *parent; +}; + struct gen_context { struct qbe_program *out; struct gen_arch arch; @@ -53,6 +63,7 @@ struct gen_context { struct qbe_func *current; const struct type *functype; struct gen_binding *bindings; + struct gen_scope *scope; }; struct unit; diff --git a/src/gen.c b/src/gen.c @@ -13,6 +13,53 @@ static const struct gen_value gv_void = { .type = &builtin_type_void, }; +static struct gen_value gen_expr(struct gen_context *ctx, + const struct expression *expr); +static void gen_expr_at(struct gen_context *ctx, + const struct expression *expr, + struct gen_value out); +static struct gen_value gen_expr_with(struct gen_context *ctx, + const struct expression *expr, + struct gen_value *out); + +static void +gen_defers(struct gen_context *ctx) +{ + assert(ctx->scope); + if (ctx->scope->defers) { + pushc(ctx->current, "gen defers"); + } + for (struct gen_defer *defer = ctx->scope->defers; defer; + defer = defer->next) { + gen_expr(ctx, defer->expr); + } +} + +static void +push_scope(struct gen_context *ctx) +{ + struct gen_scope *scope = xcalloc(1, sizeof(struct gen_scope)); + scope->parent = ctx->scope; + ctx->scope = scope; +} + +static void +pop_scope(struct gen_context *ctx, bool gendefers) +{ + if (gendefers) { + gen_defers(ctx); + } + struct gen_scope *scope = ctx->scope; + ctx->scope = scope->parent; + for (struct gen_defer *defer = scope->defers; defer; /* n/a */) { + struct gen_defer *next = defer->next; + free(defer); + defer = next; + } + free(scope); +} + + static void gen_copy_memcpy(struct gen_context *ctx, struct gen_value dest, struct gen_value src) @@ -133,15 +180,6 @@ gen_autoderef(struct gen_context *ctx, struct gen_value val) return val; } -static struct gen_value gen_expr(struct gen_context *ctx, - const struct expression *expr); -static void gen_expr_at(struct gen_context *ctx, - const struct expression *expr, - struct gen_value out); -static struct gen_value gen_expr_with(struct gen_context *ctx, - const struct expression *expr, - struct gen_value *out); - static struct gen_value gen_access_ident(struct gen_context *ctx, const struct expression *expr) { @@ -662,6 +700,16 @@ gen_expr_const(struct gen_context *ctx, const struct expression *expr) } static struct gen_value +gen_expr_defer(struct gen_context *ctx, const struct expression *expr) +{ + struct gen_defer *defer = xcalloc(1, sizeof(struct gen_defer)); + defer->expr = expr->defer.deferred; + defer->next = ctx->scope->defers; + ctx->scope->defers = defer; + return gv_void; +} + +static struct gen_value gen_expr_for(struct gen_context *ctx, const struct expression *expr) { struct qbe_statement lloop, lbody, lafter, lend; @@ -732,11 +780,14 @@ gen_expr_list_with(struct gen_context *ctx, const struct expression *expr, struct gen_value *out) { - // TODO: Set up defer scope + push_scope(ctx); for (const struct expressions *exprs = &expr->list.exprs; exprs; exprs = exprs->next) { if (!exprs->next) { - return gen_expr_with(ctx, exprs->expr, out); + struct gen_value gv = gen_expr_with( + ctx, exprs->expr, out); + pop_scope(ctx, !exprs->expr->terminates); + return gv; } gen_expr(ctx, exprs->expr); } @@ -792,9 +843,9 @@ gen_expr_measure(struct gen_context *ctx, const struct expression *expr) static struct gen_value gen_expr_return(struct gen_context *ctx, const struct expression *expr) { - // TODO: Run defers struct gen_value ret = gen_expr(ctx, expr->_return.value); struct qbe_value qret = mkqval(ctx, &ret); + gen_defers(ctx); pushi(ctx->current, NULL, Q_RET, &qret, NULL); return gv_void; } @@ -906,7 +957,9 @@ gen_expr(struct gen_context *ctx, const struct expression *expr) case EXPR_CONSTANT: return gen_expr_const(ctx, expr); case EXPR_CONTINUE: + assert(0); // TODO case EXPR_DEFER: + return gen_expr_defer(ctx, expr); case EXPR_DELETE: assert(0); // TODO case EXPR_FOR: diff --git a/tests/909-defer.ha b/tests/909-defer.ha @@ -0,0 +1,15 @@ +let x: int = 0; + +fn basics() void = { + x = 10; + defer x += 1; + assert(x == 10); + defer x += 1; + x = 20; +}; + +export fn main() int = { + basics(); + assert(x == 22); + return 0; +}; diff --git a/tests/configure b/tests/configure @@ -12,7 +12,8 @@ tests() { 905-assign \ 906-if \ 907-casts \ - 908-loops + 908-loops \ + 909-defer do cat <<EOF tests/$t: harec tests/$t.ha tests/rt.o