mirror of
https://github.com/odin-lang/Odin.git
synced 2026-01-05 04:27:51 +00:00
Add or_break and or_continue constructs
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user