harec

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

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:
Minclude/scope.h | 2++
Msrc/check.c | 53++++++++++++++++++++++++++++++++++++++++++++---------
Msrc/gen.c | 18+++++++++++++-----
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: