diff options
| author | gingerBill <bill@gingerbill.org> | 2019-12-22 12:03:48 +0000 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2019-12-22 12:03:48 +0000 |
| commit | d1c9fd4e012e16cee73e9ef0af716caf34430d81 (patch) | |
| tree | 048a9dd6ed2294d685761e31081620a924ee6ef9 /src | |
| parent | 45937306321df28266c793b7225eb10ad3d741e2 (diff) | |
Implement `#complete switch` by default, replace with `#partial switch` #511
Diffstat (limited to 'src')
| -rw-r--r-- | src/check_stmt.cpp | 57 | ||||
| -rw-r--r-- | src/parser.cpp | 22 | ||||
| -rw-r--r-- | src/parser.hpp | 24 |
3 files changed, 56 insertions, 47 deletions
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 7d5648018..7bb6924b4 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -807,12 +807,11 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { } } - bool complete = ss->complete; + bool is_partial = ss->partial; - if (complete) { + if (is_partial) { if (!is_type_enum(x.type)) { - error(x.expr, "#complete switch statement can be only used with an enum type"); - complete = false; + error(x.expr, "#partial switch statement can be only used with an enum type"); } } @@ -877,9 +876,6 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { Operand a1 = lhs; Operand b1 = rhs; check_comparison(ctx, &a1, &b1, Token_LtEq); - if (complete) { - error(lhs.expr, "#complete switch statement does not allow ranges"); - } add_constant_switch_case(ctx, &seen, lhs); if (upper_op == Token_GtEq) { @@ -926,9 +922,6 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { continue; } if (y.mode != Addressing_Constant) { - if (complete) { - error(y.expr, "#complete switch statement only allows constant case clauses"); - } continue; } @@ -942,7 +935,7 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { check_close_scope(ctx); } - if (complete) { + if (!is_partial && is_type_enum(x.type)) { Type *et = base_type(x.type); GB_ASSERT(is_type_enum(et)); auto fields = et->Enum.fields; @@ -968,18 +961,17 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { defer (begin_error_block()); if (unhandled.count == 1) { - error_no_newline(node, "Unhandled switch case: "); + error_no_newline(node, "Unhandled switch case: %.*s", LIT(unhandled[0]->token.string)); } else { error_no_newline(node, "Unhandled switch cases: "); - } - for_array(i, unhandled) { - Entity *f = unhandled[i]; - if (i > 0) { - error_line(", "); + for_array(i, unhandled) { + Entity *f = unhandled[i]; + error_line("\t%.*s\n", LIT(f->token.string)); } - error_line("%.*s", LIT(f->token.string)); } error_line("\n"); + + error_line("\tSuggestion: Was '#partial switch' wanted? This replaces the previous '#complete switch'.\n"); } } } @@ -1042,11 +1034,10 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { return; } - bool complete = ss->complete; - if (complete) { + bool is_partial = ss->partial; + if (is_partial) { if (switch_kind != TypeSwitch_Union) { - error(node, "#complete switch statement may only be used with a union"); - complete = false; + error(node, "#partial switch statement may only be used with a union"); } } @@ -1174,7 +1165,7 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { check_close_scope(ctx); } - if (complete) { + if (!is_partial && is_type_union(type_deref(x.type))) { Type *ut = base_type(type_deref(x.type)); GB_ASSERT(is_type_union(ut)); auto variants = ut->Union.variants; @@ -1191,20 +1182,20 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { if (unhandled.count > 0) { if (unhandled.count == 1) { - error_no_newline(node, "Unhandled switch case: "); + gbString s = type_to_string(unhandled[0]); + error_no_newline(node, "Unhandled switch case: %s", s); + gb_string_free(s); } else { - error_no_newline(node, "Unhandled switch cases: "); - } - for_array(i, unhandled) { - Type *t = unhandled[i]; - if (i > 0) { - error_line(", "); + error_no_newline(node, "Unhandled switch cases:\n"); + for_array(i, unhandled) { + Type *t = unhandled[i]; + gbString s = type_to_string(t); + error_line("\t%s\n", s); + gb_string_free(s); } - gbString s = type_to_string(t); - error_line("%s", s); - gb_string_free(s); } error_line("\n"); + error_line("\tSuggestion: Was '#partial switch' wanted? This replaces the previous '#complete switch'.\n"); } } } diff --git a/src/parser.cpp b/src/parser.cpp index fbbb9e1cb..0e9b20e52 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -766,6 +766,7 @@ Ast *ast_switch_stmt(AstFile *f, Token token, Ast *init, Ast *tag, Ast *body) { result->SwitchStmt.init = init; result->SwitchStmt.tag = tag; result->SwitchStmt.body = body; + result->SwitchStmt.partial = false; return result; } @@ -775,6 +776,7 @@ Ast *ast_type_switch_stmt(AstFile *f, Token token, Ast *tag, Ast *body) { result->TypeSwitchStmt.token = token; result->TypeSwitchStmt.tag = tag; result->TypeSwitchStmt.body = body; + result->TypeSwitchStmt.partial = false; return result; } @@ -4060,16 +4062,32 @@ Ast *parse_stmt(AstFile *f) { s = parse_stmt(f); switch (s->kind) { case Ast_SwitchStmt: - s->SwitchStmt.complete = true; + s->SwitchStmt.partial = false; + syntax_warning(token, "#complete is now the default and has been replaced with its opposite: #partial"); break; case Ast_TypeSwitchStmt: - s->TypeSwitchStmt.complete = true; + s->TypeSwitchStmt.partial = false; + syntax_warning(token, "#complete is now the default and has been replaced with its opposite: #partial"); break; default: syntax_error(token, "#complete can only be applied to a switch statement"); break; } return s; + } else if (tag == "partial") { + s = parse_stmt(f); + switch (s->kind) { + case Ast_SwitchStmt: + s->SwitchStmt.partial = true; + break; + case Ast_TypeSwitchStmt: + s->TypeSwitchStmt.partial = true; + break; + default: + syntax_error(token, "#partial can only be applied to a switch statement"); + break; + } + return s; } else if (tag == "assert") { Ast *t = ast_basic_directive(f, hash_token, tag); return ast_expr_stmt(f, parse_call_expr(f, t)); diff --git a/src/parser.hpp b/src/parser.hpp index 7101e0247..983db1042 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -363,20 +363,20 @@ AST_KIND(_ComplexStmtBegin, "", bool) \ Entity *implicit_entity; \ }) \ AST_KIND(SwitchStmt, "switch statement", struct { \ - Token token; \ - Ast *label; \ - Ast *init; \ - Ast *tag; \ - Ast *body; \ - bool complete; \ + Token token; \ + Ast *label; \ + Ast *init; \ + Ast *tag; \ + Ast *body; \ + bool partial; \ }) \ AST_KIND(TypeSwitchStmt, "type switch statement", struct { \ - Token token; \ - Ast *label; \ - Ast *tag; \ - Ast *body; \ - bool complete; \ - }) \ + Token token; \ + Ast *label; \ + Ast *tag; \ + Ast *body; \ + bool partial; \ +}) \ AST_KIND(DeferStmt, "defer statement", struct { Token token; Ast *stmt; }) \ AST_KIND(BranchStmt, "branch statement", struct { Token token; Ast *label; }) \ AST_KIND(UsingStmt, "using statement", struct { \ |