refactored switch statements; cases can be ranges
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 23 Dec 2020 22:50:45 +0000 (16:50 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 23 Dec 2020 22:50:45 +0000 (16:50 -0600)
include/onyxastnodes.h
onyx
src/onyxchecker.c
src/onyxclone.c
src/onyxparser.c
src/onyxsymres.c

index fd0813983f2ba5d4496e13d279ea7facf2b3b4cf..7b2d5c74404dea3be6947764c1617c830fe2113a 100644 (file)
@@ -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 dc37f1cd2da1ce2881ccb6d4faa19df9c91cc5e0..c8f1d3782fdac06e86a8806b4983b65ab7dc0940 100755 (executable)
Binary files a/onyx and b/onyx differ
index dfbc9df3334b1df837db5ead0814e4281aa0d103..cfdef2e8f008e61cbccdae8d20a78927a19875e0 100644 (file)
@@ -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)
index 6d4bf71c3632877e744958c8cdff2d7a8d7390b3..cd7f18c55c47c4b7f48329957195b09edcf2ede6 100644 (file)
@@ -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);
                        }
index d393cea7ad951e067f1e3a45c01a7dd915bdaa45..3066b560b2bcb717c35fcf65accc430447aa8d0c 100644 (file)
@@ -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;
 }
index fba688fa27de66678a1cc36627379c2852357945..4639913e61db0db1a246eed7efda32a79c5c1b46 100644 (file)
@@ -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);
     }