From: Brendan Hansen Date: Wed, 23 Dec 2020 22:50:45 +0000 (-0600) Subject: refactored switch statements; cases can be ranges X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=0715266caccbece32b5f72b87a5e8c8762f48f70;p=onyx.git refactored switch statements; cases can be ranges --- diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index fd081398..7b2d5c74 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -553,11 +553,15 @@ struct AstIfWhile { AstBlock *true_stmt; AstBlock *false_stmt; }; -struct AstSwitchCase { AstTyped *value; AstBlock *block; }; +struct AstSwitchCase { + // NOTE: All expressions that end up in this block + bh_arr(AstTyped *) values; + + AstBlock *block; +}; struct AstSwitch { AstNode_base; - // NOTE: These are not currently used; Scope *scope; AstLocal *local; AstBinaryOp *assignment; diff --git a/onyx b/onyx index dc37f1cd..c8f1d378 100755 Binary files a/onyx and b/onyx differ diff --git a/src/onyxchecker.c b/src/onyxchecker.c index dfbc9df3..cfdef2e8 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -186,6 +186,19 @@ b32 check_for(AstFor* fornode) { return 0; } +static b32 add_case_to_switch_statement(AstSwitch* switchnode, i64 case_value, AstBlock* block, OnyxFilePos pos) { + switchnode->min_case = bh_min(switchnode->min_case, case_value); + switchnode->max_case = bh_max(switchnode->max_case, case_value); + + if (bh_imap_has(&switchnode->case_map, case_value)) { + onyx_report_error(pos, "Multiple cases for values '%d'.", case_value); + return 1; + } + + bh_imap_put(&switchnode->case_map, case_value, (u64) block); + return 0; +} + b32 check_switch(AstSwitch* switchnode) { if (switchnode->assignment != NULL) check_statement((AstNode *) switchnode->assignment); @@ -201,30 +214,43 @@ b32 check_switch(AstSwitch* switchnode) { bh_arr_each(AstSwitchCase, sc, switchnode->cases) { if (check_block(sc->block)) return 1; - if (check_expression(&sc->value)) return 1; - if (sc->value->kind == Ast_Kind_Enum_Value) { - sc->value = (AstTyped *) ((AstEnumValue *) sc->value)->value; - } + bh_arr_each(AstTyped *, value, sc->values) { + if (check_expression(value)) return 1; - if (sc->value->kind != Ast_Kind_NumLit) { - onyx_report_error(sc->value->token->pos, "case statement expected compile time known integer"); - return 1; - } + if ((*value)->kind == Ast_Kind_Range_Literal) { + AstRangeLiteral* rl = (AstRangeLiteral *) (*value); + resolve_expression_type(rl->low); + resolve_expression_type(rl->high); + assert(rl->low->kind == Ast_Kind_NumLit && rl->high->kind == Ast_Kind_NumLit); - resolve_expression_type(sc->value); - promote_numlit_to_larger((AstNumLit *) sc->value); + promote_numlit_to_larger((AstNumLit *) rl->low); + promote_numlit_to_larger((AstNumLit *) rl->high); - u64 value = ((AstNumLit *) sc->value)->value.l; - switchnode->min_case = bh_min(switchnode->min_case, value); - switchnode->max_case = bh_max(switchnode->max_case, value); + i64 lower = ((AstNumLit *) rl->low)->value.l; + i64 upper = ((AstNumLit *) rl->high)->value.l; - if (bh_imap_has(&switchnode->case_map, value)) { - onyx_report_error(sc->value->token->pos, "Multiple cases for values '%d'.", value); - return 1; - } + // NOTE: This is inclusive!!!! + fori (case_value, lower, upper + 1) + add_case_to_switch_statement(switchnode, case_value, sc->block, rl->token->pos); + + continue; + } + + if ((*value)->kind == Ast_Kind_Enum_Value) { + (*value) = (AstTyped *) ((AstEnumValue *) (*value))->value; + } - bh_imap_put(&switchnode->case_map, value, (u64) sc->block); + if ((*value)->kind != Ast_Kind_NumLit) { + onyx_report_error((*value)->token->pos, "case statement expected compile time known integer"); + return 1; + } + + resolve_expression_type((*value)); + promote_numlit_to_larger((AstNumLit *) (*value)); + + add_case_to_switch_statement(switchnode, ((AstNumLit *) (*value))->value.l, sc->block, sc->block->token->pos); + } } if (switchnode->default_case) diff --git a/src/onyxclone.c b/src/onyxclone.c index 6d4bf71c..cd7f18c5 100644 --- a/src/onyxclone.c +++ b/src/onyxclone.c @@ -262,8 +262,13 @@ AstNode* ast_clone(bh_allocator a, void* n) { bh_arr_new(global_heap_allocator, dw->cases, bh_arr_length(sw->cases)); bh_arr_each(AstSwitchCase, c, sw->cases) { + bh_arr(AstTyped *) new_values = NULL; + bh_arr_new(global_heap_allocator, new_values, bh_arr_length(c->values)); + bh_arr_each(AstTyped *, value, c->values) + bh_arr_push(new_values, (AstTyped *) ast_clone(a, *value)); + AstSwitchCase sc; - sc.value = (AstTyped *) ast_clone(a, c->value); + sc.values = new_values; sc.block = (AstBlock *) ast_clone(a, c->block); bh_arr_push(dw->cases, sc); } diff --git a/src/onyxparser.c b/src/onyxparser.c index d393cea7..3066b560 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -488,7 +488,7 @@ static AstTyped* parse_factor(OnyxParser* parser) { else if (parse_possible_directive(parser, "char")) { AstNumLit* char_lit = make_node(AstNumLit, Ast_Kind_NumLit); char_lit->flags |= Ast_Flag_Comptime; - char_lit->type_node = (AstType *) &basic_type_u8; + char_lit->type_node = (AstType *) &basic_type_int_unsized; char_lit->token = expect_token(parser, Token_Type_Literal_String); @@ -921,11 +921,10 @@ static AstSwitch* parse_switch_stmt(OnyxParser* parser) { switch_node->expr = parse_expression(parser); expect_token(parser, '{'); - AstTyped** batch_cases = NULL; - // NOTE: Look into bugs relating to switching this to the scratch allocator - bh_arr_new(global_heap_allocator, batch_cases, 16); - while (parser->curr->type == Token_Type_Keyword_Case) { + bh_arr(AstTyped *) case_values = NULL; + bh_arr_new(global_heap_allocator, case_values, 1); + expect_token(parser, Token_Type_Keyword_Case); if (parser->hit_unexpected_token) return switch_node; @@ -939,30 +938,24 @@ static AstSwitch* parse_switch_stmt(OnyxParser* parser) { } AstTyped* value = parse_expression(parser); - bh_arr_push(batch_cases, value); + bh_arr_push(case_values, value); while (parser->curr->type == ',') { if (parser->hit_unexpected_token) return switch_node; consume_token(parser); value = parse_expression(parser); - bh_arr_push(batch_cases, value); + bh_arr_push(case_values, value); } AstBlock* block = parse_block(parser); AstSwitchCase sc_node; - sc_node.block = block; + sc_node.block = block; + sc_node.values = case_values; - bh_arr_each(AstTyped *, value, batch_cases) { - sc_node.value = *value; - bh_arr_push(switch_node->cases, sc_node); - } - - bh_arr_clear(batch_cases); + bh_arr_push(switch_node->cases, sc_node); } - bh_arr_free(batch_cases); - expect_token(parser, '}'); return switch_node; } diff --git a/src/onyxsymres.c b/src/onyxsymres.c index fba688fa..4639913e 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -540,7 +540,9 @@ static void symres_switch(AstSwitch* switchnode) { symres_expression(&switchnode->expr); bh_arr_each(AstSwitchCase, sc, switchnode->cases) { - symres_expression(&sc->value); + bh_arr_each(AstTyped *, value, sc->values) + symres_expression(value); + symres_block(sc->block); }