commit ab56f0bc304805b8c7d4841e0e147e84bf04766e
parent 1cb802942ea7cc8fee8947e8b551bcf4b5f7deb4
Author: Drew DeVault <sir@cmpwn.com>
Date: Tue, 31 Aug 2021 13:53:02 +0200
check: implement yield
I'm not sure if this is the complete solution but it should be fairly
close.
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
3 files changed, 59 insertions(+), 14 deletions(-)
diff --git a/include/scope.h b/include/scope.h
@@ -39,6 +39,8 @@ struct scope {
enum scope_class class;
const char *label;
struct scope *parent;
+ const struct type *hint;
+ struct type_tagged_union *results;
// Linked list in insertion order
// Used for function parameters, where order matters
diff --git a/src/check.c b/src/check.c
@@ -1271,6 +1271,7 @@ check_expr_compound(struct context *ctx,
expr->type = EXPR_COMPOUND;
struct scope *scope = scope_push(&ctx->scope, SCOPE_COMPOUND);
+ scope->hint = hint;
expr->compound.scope = scope;
if (aexpr->compound.label) {
@@ -1282,8 +1283,9 @@ check_expr_compound(struct context *ctx,
struct expressions **next = &list->next;
const struct ast_expression_list *alist = &aexpr->compound.list;
+ struct expression *lexpr;
while (alist) {
- struct expression *lexpr = xcalloc(1, sizeof(struct expression));
+ lexpr = xcalloc(1, sizeof(struct expression));
check_expression(ctx, alist->expr, lexpr, alist->next ? &builtin_type_void : hint);
list->expr = lexpr;
@@ -1292,12 +1294,20 @@ check_expr_compound(struct context *ctx,
*next = xcalloc(1, sizeof(struct expressions));
list = *next;
next = &list->next;
- } else {
- expr->result = lexpr->result;
- expr->terminates = lexpr->terminates;
}
}
+ if (!lexpr->terminates) {
+ struct type_tagged_union *result =
+ xcalloc(1, sizeof(struct type_tagged_union));
+ result->type = lexpr->result;
+ result->next = scope->results;
+ scope->results = result;
+ }
+
+ expr->terminates = lexpr->terminates;
+ expr->result = type_store_reduce_result(ctx->store, scope->results);
+ assert(expr->result);
scope_pop(&ctx->scope);
}
@@ -1486,13 +1496,39 @@ check_expr_control(struct context *ctx,
expr->result = &builtin_type_void;
expr->terminates = true;
expr->control.label = aexpr->control.label;
- expr->control.scope = scope_lookup_ancestor(ctx->scope,
- SCOPE_LOOP, aexpr->control.label);
- if (!expr->control.scope) {
+
+ enum scope_class want;
+ switch (expr->type) {
+ case EXPR_BREAK:
+ case EXPR_CONTINUE:
+ want = SCOPE_LOOP;
+ break;
+ case EXPR_YIELD:
+ want = SCOPE_COMPOUND;
+ break;
+ default:
+ abort(); // Invariant
+ }
+
+ struct scope *scope = scope_lookup_ancestor(
+ ctx->scope, want, aexpr->control.label);
+ if (!scope) {
// XXX: This error message is bad
error(ctx, aexpr->loc, expr, "No eligible loop for operation");
return;
}
+ expr->control.scope = scope;
+
+ if (aexpr->control.value) {
+ expr->control.value = xcalloc(1, sizeof(struct expression));
+ check_expression(ctx, aexpr->control.value,
+ expr->control.value, scope->hint);
+ struct type_tagged_union *result =
+ xcalloc(1, sizeof(struct type_tagged_union));
+ result->type = expr->control.value->result;
+ result->next = scope->results;
+ scope->results = result;
+ }
}
static void
@@ -2587,6 +2623,7 @@ check_expression(struct context *ctx,
break;
case EXPR_BREAK:
case EXPR_CONTINUE:
+ case EXPR_YIELD:
check_expr_control(ctx, aexpr, expr, hint);
break;
case EXPR_CALL:
@@ -2646,8 +2683,6 @@ check_expression(struct context *ctx,
case EXPR_UNARITHM:
check_expr_unarithm(ctx, aexpr, expr, hint);
break;
- case EXPR_YIELD:
- assert(0); // TODO
}
assert(expr->result);
if (hint && hint->storage == STORAGE_VOID) {
diff --git a/src/gen.c b/src/gen.c
@@ -876,7 +876,7 @@ static struct gen_value
gen_expr_control(struct gen_context *ctx, const struct expression *expr)
{
struct gen_scope *scope = gen_scope_lookup(ctx, expr->control.scope);
- assert(scope->scope->class == SCOPE_LOOP);
+
struct gen_scope *deferred = ctx->scope;
while (deferred != NULL) {
gen_defers(ctx, deferred);
@@ -885,10 +885,19 @@ gen_expr_control(struct gen_context *ctx, const struct expression *expr)
}
deferred = deferred->parent;
}
- if (expr->type == EXPR_BREAK) {
+ switch (expr->type) {
+ case EXPR_BREAK:
+ assert(scope->scope->class == SCOPE_LOOP);
pushi(ctx->current, NULL, Q_JMP, scope->end, NULL);
- } else {
+ break;
+ case EXPR_CONTINUE:
+ assert(scope->scope->class == SCOPE_LOOP);
pushi(ctx->current, NULL, Q_JMP, scope->after, NULL);
+ break;
+ case EXPR_YIELD:
+ assert(scope->scope->class == SCOPE_COMPOUND);
+ assert(0); // TODO
+ default: abort(); // Invariant
}
return gv_void;
}
@@ -2523,6 +2532,7 @@ gen_expr(struct gen_context *ctx, const struct expression *expr)
return gen_expr_binding(ctx, expr);
case EXPR_BREAK:
case EXPR_CONTINUE:
+ case EXPR_YIELD:
return gen_expr_control(ctx, expr);
case EXPR_CALL:
return gen_expr_call(ctx, expr);
@@ -2556,8 +2566,6 @@ gen_expr(struct gen_context *ctx, const struct expression *expr)
return gen_expr_switch_with(ctx, expr, NULL);
case EXPR_UNARITHM:
return gen_expr_unarithm(ctx, expr);
- case EXPR_YIELD:
- assert(0); // TODO
case EXPR_SLICE:
case EXPR_STRUCT:
case EXPR_TUPLE: