Add or_break and or_continue constructs

This commit is contained in:
gingerBill
2023-09-30 15:04:17 +01:00
parent 4e97b83312
commit 648b83d6ea
11 changed files with 401 additions and 82 deletions

View File

@@ -3826,6 +3826,15 @@ gb_internal void update_untyped_expr_type(CheckerContext *c, Ast *e, Type *type,
update_untyped_expr_type(c, ore->expr, type, final);
case_end;
case_ast_node(obe, OrBranchExpr, e);
if (old->value.kind != ExactValue_Invalid) {
// See above note in UnaryExpr case
break;
}
update_untyped_expr_type(c, obe->expr, type, final);
case_end;
case_ast_node(oee, OrElseExpr, e);
if (old->value.kind != ExactValue_Invalid) {
// See above note in UnaryExpr case
@@ -8193,6 +8202,104 @@ gb_internal ExprKind check_or_return_expr(CheckerContext *c, Operand *o, Ast *no
return Expr_Expr;
}
gb_internal ExprKind check_or_branch_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
ast_node(be, OrBranchExpr, node);
String name = be->token.string;
Operand x = {};
check_multi_expr_with_type_hint(c, &x, be->expr, type_hint);
if (x.mode == Addressing_Invalid) {
o->mode = Addressing_Value;
o->type = t_invalid;
o->expr = node;
return Expr_Expr;
}
Type *left_type = nullptr;
Type *right_type = nullptr;
check_or_return_split_types(c, &x, name, &left_type, &right_type);
add_type_and_value(c, be->expr, x.mode, x.type, x.value);
if (right_type == nullptr) {
check_or_else_expr_no_value_error(c, name, x, type_hint);
} else {
if (is_type_boolean(right_type) || type_has_nil(right_type)) {
// okay
} else {
gbString s = type_to_string(right_type);
error(node, "'%.*s' requires a boolean or nil-able type, got %s", s);
gb_string_free(s);
}
}
o->expr = node;
o->type = left_type;
if (left_type != nullptr) {
o->mode = Addressing_Value;
} else {
o->mode = Addressing_NoValue;
}
if (c->curr_proc_sig == nullptr) {
error(node, "'%.*s' can only be used within a procedure", LIT(name));
}
Ast *label = be->label;
switch (be->token.kind) {
case Token_or_break:
if ((c->stmt_flags & Stmt_BreakAllowed) == 0 && label == nullptr) {
error(be->token, "'%.*s' only allowed in non-inline loops or 'switch' statements", LIT(name));
}
break;
case Token_or_continue:
if ((c->stmt_flags & Stmt_ContinueAllowed) == 0 && label == nullptr) {
error(be->token, "'%.*s' only allowed in non-inline loops", LIT(name));
}
break;
}
if (label != nullptr) {
if (label->kind != Ast_Ident) {
error(label, "A branch statement's label name must be an identifier");
return Expr_Expr;
}
Ast *ident = label;
String name = ident->Ident.token.string;
Operand o = {};
Entity *e = check_ident(c, &o, ident, nullptr, nullptr, false);
if (e == nullptr) {
error(ident, "Undeclared label name: %.*s", LIT(name));
return Expr_Expr;
}
add_entity_use(c, ident, e);
if (e->kind != Entity_Label) {
error(ident, "'%.*s' is not a label", LIT(name));
return Expr_Expr;
}
Ast *parent = e->Label.parent;
GB_ASSERT(parent != nullptr);
switch (parent->kind) {
case Ast_BlockStmt:
case Ast_IfStmt:
case Ast_SwitchStmt:
if (be->token.kind != Token_or_break) {
error(label, "Label '%.*s' can only be used with 'or_break'", LIT(e->token.string));
}
break;
case Ast_RangeStmt:
case Ast_ForStmt:
if ((be->token.kind != Token_or_break) && (be->token.kind != Token_or_continue)) {
error(label, "Label '%.*s' can only be used with 'or_break' and 'or_continue'", LIT(e->token.string));
}
break;
}
}
return Expr_Expr;
}
gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<Ast *> const &elems, Operand *o, Type *type, bool &is_constant) {
Type *bt = base_type(type);
@@ -9947,6 +10054,10 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
return check_or_return_expr(c, o, node, type_hint);
case_end;
case_ast_node(re, OrBranchExpr, node);
return check_or_branch_expr(c, o, node, type_hint);
case_end;
case_ast_node(cl, CompoundLit, node);
kind = check_compound_literal(c, o, node, type_hint);
case_end;
@@ -10513,6 +10624,16 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan
str = gb_string_appendc(str, " or_return");
case_end;
case_ast_node(oe, OrBranchExpr, node);
str = write_expr_to_string(str, oe->expr, shorthand);
str = gb_string_append_rune(str, ' ');
str = string_append_token(str, oe->token);
if (oe->label) {
str = gb_string_append_rune(str, ' ');
str = write_expr_to_string(str, oe->label, shorthand);
}
case_end;
case_ast_node(pe, ParenExpr, node);
str = gb_string_append_rune(str, '(');
str = write_expr_to_string(str, pe->expr, shorthand);