commit 1a0505eba114a4685a73a3aa6ab7c42088b8b566
parent d167704f1e5339b05d80ba81761f4c5cd4289669
Author: Eyal Sawady <ecs@d2evs.net>
Date: Tue, 19 Jan 2021 11:10:08 -0500
Require loop labels to be unique among ancestors
Also update tests acordingly
Diffstat:
4 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/include/ast.h b/include/ast.h
@@ -211,6 +211,7 @@ struct ast_expression_control {
struct ast_expression_for {
char *label;
+ struct location label_loc;
struct ast_expression *bindings;
struct ast_expression *cond;
struct ast_expression *afterthought;
diff --git a/src/check.c b/src/check.c
@@ -652,6 +652,16 @@ check_expr_for(struct context *ctx,
expr->_for.scope = scope;
scope->type = expr->type;
scope->label = expr->_for.label;
+ if (expr->_for.label) {
+ for (scope = scope->parent; scope; scope = scope->parent) {
+ if (scope->label == NULL) {
+ continue;
+ }
+ expect(&aexpr->_for.label_loc,
+ strcmp(scope->label, expr->_for.label) != 0,
+ "for loop label must be unique among its ancestors");
+ }
+ }
struct expression *bindings = NULL,
*cond = NULL, *afterthought = NULL, *body = NULL;
diff --git a/src/parse.c b/src/parse.c
@@ -1554,6 +1554,7 @@ parse_for_expression(struct lexer *lexer)
case T_FOR:
break;
case T_LABEL:
+ exp->_for.label_loc = tok.loc;
exp->_for.label = tok.name;
want(lexer, T_FOR, NULL);
break;
diff --git a/tests/12-loops.ha b/tests/12-loops.ha
@@ -75,9 +75,6 @@ fn label() void = {
let i = 0;
:outer for (i < 10) {
:inner for (let j = 0; j < 7; j += 1) {
- :outer for (true) {
- break :outer;
- };
i += 1;
if (j == 6) {
continue :inner;
@@ -92,6 +89,7 @@ fn label() void = {
assert(rt::compile("fn test() void = { :foo for (true) { break :bar; }; };") != 0);
assert(rt::compile("fn test() void = { for (true) { break :bar; }; };") != 0);
assert(rt::compile("fn test() void = { break :bar; };") != 0);
+ assert(rt::compile("fn test() void = { :foo for (true) { :foo for (true) void; } ; };") != 0);
};
export fn main() void = {