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:
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