commit 1350398abc63b71b0b4cd2c7c070d1e3950c304a
parent 6faec06c9543a42593ce939eeec8d47ed02879ea
Author: Eyal Sawady <ecs@d2evs.net>
Date: Tue, 12 Jan 2021 18:35:33 -0500
check: implement break/continue
Diffstat:
3 files changed, 46 insertions(+), 3 deletions(-)
diff --git a/include/expr.h b/include/expr.h
@@ -138,7 +138,12 @@ union expression_constant {
// TODO: Struct constants
};
+struct expression_control {
+ char *label;
+};
+
struct expression_for {
+ char *label;
struct scope *scope;
struct expression *bindings;
struct expression *cond;
@@ -213,6 +218,7 @@ struct expression {
struct expression_call call;
struct expression_cast cast;
union expression_constant constant;
+ struct expression_control control;
struct expression_for _for;
struct expression_if _if;
struct expression_list list;
diff --git a/include/scope.h b/include/scope.h
@@ -1,5 +1,6 @@
#ifndef HAREC_SCOPE_H
#define HAREC_SCOPE_H
+#include "expr.h"
#include "identifier.h"
#include "trace.h"
@@ -23,6 +24,8 @@ struct scope_object {
};
struct scope {
+ enum expr_type type;
+ const char *label;
struct scope_object *objects;
struct scope_object **next; // List order matters for functions
struct scope *parent;
diff --git a/src/check.c b/src/check.c
@@ -544,6 +544,33 @@ check_expr_constant(struct context *ctx,
}
static void
+check_expr_control(struct context *ctx,
+ const struct ast_expression *aexpr,
+ struct expression *expr)
+{
+ trenter(TR_CHECK, "control");
+ expr->type = aexpr->type;
+ expr->terminates = true;
+ char *label = expr->control.label = aexpr->control.label;
+
+ struct scope *scope = ctx->scope;
+ for (; scope != NULL; scope = scope->parent) {
+ if (scope->type != EXPR_FOR) {
+ continue;
+ }
+ if (label == NULL) {
+ break;
+ }
+ if (scope->label != NULL && strcmp(label, scope->label) == 0) {
+ break;
+ }
+ }
+ expect(&aexpr->loc, scope != NULL, "Unknown label %s",
+ expr->control.label);
+ trleave(TR_CHECK, NULL);
+}
+
+static void
check_expr_for(struct context *ctx,
const struct ast_expression *aexpr,
struct expression *expr)
@@ -552,8 +579,14 @@ check_expr_for(struct context *ctx,
expr->type = EXPR_FOR;
expr->result = &builtin_type_void;
+ if (aexpr->_for.label) {
+ expr->_for.label = strdup(aexpr->_for.label);
+ }
+
struct scope *scope = scope_push(&ctx->scope, TR_CHECK);
expr->_for.scope = scope;
+ scope->type = expr->type;
+ scope->label = expr->_for.label;
struct expression *bindings = NULL,
*cond = NULL, *afterthought = NULL, *body = NULL;
@@ -642,6 +675,7 @@ check_expr_list(struct context *ctx,
struct scope *scope = scope_push(&ctx->scope, TR_CHECK);
expr->list.scope = scope;
+ scope->type = expr->type;
struct expressions *list = &expr->list.exprs;
struct expressions **next = &list->next;
@@ -874,7 +908,9 @@ check_expression(struct context *ctx,
check_expr_binding(ctx, aexpr, expr);
break;
case EXPR_BREAK:
- assert(0); // TODO
+ case EXPR_CONTINUE:
+ check_expr_control(ctx, aexpr, expr);
+ break;
case EXPR_CALL:
check_expr_call(ctx, aexpr, expr);
break;
@@ -884,8 +920,6 @@ check_expression(struct context *ctx,
case EXPR_CONSTANT:
check_expr_constant(ctx, aexpr, expr);
break;
- case EXPR_CONTINUE:
- assert(0); // TODO
case EXPR_FOR:
check_expr_for(ctx, aexpr, expr);
break;