initial implementation of switch expressions
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 29 Sep 2023 21:58:01 +0000 (16:58 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 29 Sep 2023 21:58:01 +0000 (16:58 -0500)
18 files changed:
compiler/include/astnodes.h
compiler/src/astnodes.c
compiler/src/checker.c
compiler/src/parser.c
compiler/src/symres.c
compiler/src/wasm_emit.c
core/container/optional.onyx
core/container/result.onyx
core/encoding/hex.onyx
core/encoding/json/parser.onyx
core/io/stdio.onyx
core/net/net.onyx
core/onyx/cbindgen.onyx
core/runtime/info/helper.onyx
tests/aoc-2020/day20.onyx
tests/switch_expressions [new file with mode: 0644]
tests/switch_expressions.onyx [new file with mode: 0644]
tests/tagged_unions.onyx

index c88f5bdf3a244ca5ff4e37dddf2e9d873ed210e0..1bf3145000a6c75747a646be2621294114ef7623 100644 (file)
@@ -881,7 +881,7 @@ typedef enum SwitchKind {
 typedef struct CaseToBlock {
     AstTyped *original_value;
     AstBinaryOp *comparison;
-    AstBlock *block;
+    AstSwitchCase *casestmt;
 } CaseToBlock;
 
 struct AstSwitchCase {
@@ -890,16 +890,21 @@ struct AstSwitchCase {
     // NOTE: All expressions that end up in this block
     bh_arr(AstTyped *) values;
 
-    AstBlock *block;
+    union {
+        AstBlock *block;
+        AstTyped *expr;
+    };
 
     AstLocal *capture;
+    Scope *scope; // Scope for the capture
 
     b32 is_default: 1; // Could this be inferred by the values array being null?
     b32 capture_is_by_pointer: 1;
+    b32 body_is_expr : 1;
 };
 
 struct AstSwitch {
-    AstNode_base;
+    AstTyped_base;
 
     Scope *scope;
     AstNode* initialization;
@@ -918,6 +923,8 @@ struct AstSwitch {
     // been handled.
     u8 *union_variants_handled;
 
+    b32 is_expr;
+
     union {
         struct {
             // NOTE: This is a mapping from the compile time known case value
index f8f43626301bb3aea5a0728a0acb3dd913cb4984..1c4583f72c6ca38d4e4a0e92f7643456c603efcc 100644 (file)
@@ -770,6 +770,34 @@ TypeMatch unify_node_and_type_(AstTyped** pnode, Type* type, b32 permanent) {
         }
     }
 
+    if (node->kind == Ast_Kind_Switch) {
+        AstSwitch *switchnode = (AstSwitch *) node;
+        if (!switchnode->is_expr) return TYPE_MATCH_FAILED;
+
+        if (switchnode->cases == NULL) return TYPE_MATCH_YIELD;
+
+        bh_arr_each(AstSwitchCase *, pcasestmt, switchnode->cases) {
+            AstSwitchCase *casestmt = *pcasestmt;
+            if (!casestmt->body_is_expr) continue;
+
+            switch (unify_node_and_type_(&casestmt->expr, type, permanent)) {
+                case TYPE_MATCH_SUCCESS: break;
+                case TYPE_MATCH_FAILED: return TYPE_MATCH_FAILED;
+                case TYPE_MATCH_YIELD: return TYPE_MATCH_YIELD;
+            }
+        }
+
+        if (switchnode->default_case) {
+            switch (unify_node_and_type_((AstTyped **) &switchnode->default_case, type, permanent)) {
+                case TYPE_MATCH_SUCCESS: break;
+                case TYPE_MATCH_FAILED: return TYPE_MATCH_FAILED;
+                case TYPE_MATCH_YIELD: return TYPE_MATCH_YIELD;
+            }
+        }
+
+        if (permanent) switchnode->type = type;
+        return TYPE_MATCH_SUCCESS;
+    }
 
     // If the destination type is an optional, and the node's type is a value of
     // the same underlying type, then we can construct an optional with a value
index 6c8aff4293560cf3e028efa832af6062c2b284ed..01f4fc28c1f030412193f34d45f5b58087a7d30b 100644 (file)
@@ -362,7 +362,7 @@ fornode_expr_checked:
     return Check_Success;
 }
 
-static b32 add_case_to_switch_statement(AstSwitch* switchnode, u64 case_value, AstBlock* block, OnyxFilePos pos) {
+static b32 add_case_to_switch_statement(AstSwitch* switchnode, u64 case_value, AstSwitchCase* casestmt, OnyxFilePos pos) {
     assert(switchnode->switch_kind == Switch_Kind_Integer || switchnode->switch_kind == Switch_Kind_Union);
 
     switchnode->min_case = bh_min(switchnode->min_case, case_value);
@@ -373,7 +373,7 @@ static b32 add_case_to_switch_statement(AstSwitch* switchnode, u64 case_value, A
         return 1;
     }
 
-    bh_imap_put(&switchnode->case_map, case_value, (u64) block);
+    bh_imap_put(&switchnode->case_map, case_value, (u64) casestmt);
     return 0;
 }
 
@@ -488,7 +488,7 @@ CheckStatus check_switch(AstSwitch* switchnode) {
         AstSwitchCase *sc = switchnode->cases[i];
 
         if (sc->capture && bh_arr_length(sc->values) != 1) {
-            ERROR(sc->token->pos, "Expected exactly one value in switch-case when using a capture, i.e. `case X => Y { ... }`.");
+            ERROR(sc->token->pos, "Expected exactly one value in switch-case when using a capture, i.e. `case value: X { ... }`.");
         }
 
         if (sc->capture && switchnode->switch_kind != Switch_Kind_Union) {
@@ -519,7 +519,7 @@ CheckStatus check_switch(AstSwitch* switchnode) {
 
                 // NOTE: This is inclusive!!!!
                 fori (case_value, lower, upper + 1) {
-                    if (add_case_to_switch_statement(switchnode, case_value, sc->block, rl->token->pos))
+                    if (add_case_to_switch_statement(switchnode, case_value, sc, rl->token->pos))
                         return Check_Error;
                 }
 
@@ -573,7 +573,7 @@ CheckStatus check_switch(AstSwitch* switchnode) {
                     if (!is_valid)
                         ERROR_((*value)->token->pos, "Case statement expected compile time known integer. Got '%s'.", onyx_ast_node_kind_string((*value)->kind));
 
-                    if (add_case_to_switch_statement(switchnode, integer_value, sc->block, sc->block->token->pos))
+                    if (add_case_to_switch_statement(switchnode, integer_value, sc, sc->block->token->pos))
                         return Check_Error;
 
                     break;
@@ -592,7 +592,7 @@ CheckStatus check_switch(AstSwitch* switchnode) {
                     if (found) break;
 
                     CaseToBlock ctb;
-                    ctb.block = sc->block;
+                    ctb.casestmt = sc;
                     ctb.original_value = *value;
                     ctb.comparison = make_binary_op(context.ast_alloc, Binary_Op_Equal, switchnode->expr, *value);
                     ctb.comparison->token = (*value)->token;
@@ -607,13 +607,52 @@ CheckStatus check_switch(AstSwitch* switchnode) {
         sc->flags |= Ast_Flag_Has_Been_Checked;
 
       check_switch_case_block:
-        CHECK(block, sc->block);
+        if (switchnode->is_expr) {
+            if (!sc->body_is_expr) {
+                onyx_report_error(sc->token->pos, Error_Critical, "Inside a switch expression, all cases must return a value.");
+                ERROR(sc->token->pos, "Change the case statement to look like 'case X => expr'.");
+            }
+        } else {
+            if (sc->body_is_expr) {
+                ERROR(sc->token->pos, "This kind of case statement is only allowed in switch expressions, not switch statements.");
+            }
+        }
+
+        if (sc->body_is_expr) {
+            CHECK(expression, &sc->expr);
+            if (switchnode->type == NULL) {
+                switchnode->type = resolve_expression_type(sc->expr);
+            } else {
+                TYPE_CHECK(&sc->expr, switchnode->type) { 
+                    ERROR_(sc->token->pos, "Expected case expression to be of type '%s', got '%s'.",
+                        type_get_name(switchnode->type),
+                        type_get_name(sc->expr->type));
+                }
+            }
+
+        } else {
+            CHECK(block, sc->block);
+        }
 
         switchnode->yield_return_index += 1;
     }
 
     if (switchnode->default_case) {
-        CHECK(block, switchnode->default_case);
+        if (switchnode->is_expr) {
+            AstTyped **default_case = (AstTyped **) &switchnode->default_case;
+            CHECK(expression, default_case);
+
+            if (switchnode->type) {
+                TYPE_CHECK(default_case, switchnode->type) { 
+                    ERROR_((*default_case)->token->pos, "Expected case expression to be of type '%s', got '%s'.",
+                        type_get_name(switchnode->type),
+                        type_get_name((*default_case)->type));
+                }
+            }
+
+        } else {
+            CHECK(block, switchnode->default_case);
+        }
 
     } else if (switchnode->switch_kind == Switch_Kind_Union) {
         // If there is no default case, and this is a union switch,
@@ -2411,6 +2450,15 @@ CheckStatus check_expression(AstTyped** pexpr) {
             break;
         }
 
+        case Ast_Kind_Switch: {
+            AstSwitch* switch_node = (AstSwitch *) expr;
+            assert(switch_node->is_expr);
+
+            CHECK(switch, switch_node);
+            break;
+        }
+
+        case Ast_Kind_Switch_Case: break;
         case Ast_Kind_File_Contents: break;
         case Ast_Kind_Overloaded_Function: break;
         case Ast_Kind_Enum_Value: break;
@@ -2418,7 +2466,6 @@ CheckStatus check_expression(AstTyped** pexpr) {
         case Ast_Kind_Package: break;
         case Ast_Kind_Error: break;
         case Ast_Kind_Unary_Field_Access: break;
-        case Ast_Kind_Switch_Case: break;
         case Ast_Kind_Foreign_Block: break;
         case Ast_Kind_Zero_Value: break;
         case Ast_Kind_Interface: break;
index c06c2ac9635e19696883b74d19fdcdaba0504ab7..123cc07467ddaafc91d02576f717380bb2d98605 100644 (file)
@@ -50,7 +50,7 @@ static AstIfWhile*    parse_if_stmt(OnyxParser* parser);
 static AstIfWhile*    parse_while_stmt(OnyxParser* parser);
 static AstFor*        parse_for_stmt(OnyxParser* parser);
 static AstSwitchCase* parse_case_stmt(OnyxParser* parser);
-static AstSwitch*     parse_switch_stmt(OnyxParser* parser);
+static AstSwitch*     parse_switch_stmt(OnyxParser* parser, b32 switch_is_expr);
 static i32            parse_possible_symbol_declaration(OnyxParser* parser, AstNode** ret);
 static AstReturn*     parse_return_stmt(OnyxParser* parser);
 static AstBlock*      parse_block(OnyxParser* parser, b32 make_a_new_scope, char* block_name);
@@ -631,6 +631,11 @@ static AstTyped* parse_factor(OnyxParser* parser) {
             break;
         }
 
+        case Token_Type_Keyword_Switch: {
+            retval = (AstTyped *) parse_switch_stmt(parser, 1);
+            break;
+        }
+
         case '[': {
             // HACK CLEANUP
             // :LinearTokenDependent
@@ -1336,6 +1341,23 @@ static AstSwitchCase* parse_case_stmt(OnyxParser* parser) {
         sc_node->is_default = 1;
 
     } else {
+        if (   next_tokens_are(parser, 3, '&', Token_Type_Symbol, ':')
+            || next_tokens_are(parser, 3, '^', Token_Type_Symbol, ':')
+            || next_tokens_are(parser, 2, Token_Type_Symbol, ':')
+       ) {
+            b32 is_pointer = 0;
+            if (consume_token_if_next(parser, '&') || consume_token_if_next(parser, '^'))
+                is_pointer = 1;
+            
+            OnyxToken *capture_symbol = expect_token(parser, Token_Type_Symbol);
+            AstLocal *capture = make_local(parser->allocator, capture_symbol, NULL);
+            
+            sc_node->capture = capture;
+            sc_node->capture_is_by_pointer = is_pointer;
+
+            expect_token(parser, ':');
+        }
+
         bh_arr_new(global_heap_allocator, sc_node->values, 1);
 
         parser->parse_quick_functions = 0;
@@ -1352,26 +1374,19 @@ static AstSwitchCase* parse_case_stmt(OnyxParser* parser) {
     }
 
     if (consume_token_if_next(parser, Token_Type_Fat_Right_Arrow)) {
-        // Captured value for union switching
-        b32 is_pointer = 0;
-        if (consume_token_if_next(parser, '&') || consume_token_if_next(parser, '^'))
-            is_pointer = 1;
-        
-        OnyxToken *capture_symbol = expect_token(parser, Token_Type_Symbol);
-        AstLocal *capture = make_local(parser->allocator, capture_symbol, NULL);
-        
-        sc_node->capture = capture;
-        sc_node->capture_is_by_pointer = is_pointer;
+        sc_node->expr = parse_expression(parser, 0);
+        sc_node->body_is_expr = 1;
+    } else {
+        sc_node->block = parse_block(parser, 1, NULL);
     }
 
-    sc_node->block = parse_block(parser, 1, NULL);
-
     return sc_node;
 }
 
-static AstSwitch* parse_switch_stmt(OnyxParser* parser) {
+static AstSwitch* parse_switch_stmt(OnyxParser* parser, b32 switch_is_expr) {
     AstSwitch* switch_node = make_node(AstSwitch, Ast_Kind_Switch);
     switch_node->token = expect_token(parser, Token_Type_Keyword_Switch);
+    switch_node->is_expr = switch_is_expr;
 
     AstTyped* expr;
     AstNode* initialization_or_expr=NULL;
@@ -1642,7 +1657,7 @@ static AstNode* parse_statement(OnyxParser* parser) {
 
         case Token_Type_Keyword_Switch:
             needs_semicolon = 0;
-            retval = (AstNode *) parse_switch_stmt(parser);
+            retval = (AstNode *) parse_switch_stmt(parser, 0);
             break;
 
         case Token_Type_Keyword_Case:
index 6f934039e067828e88ab05cb7c6f7635e337dbc3..9ec553ca7da2d1326012f428cff45ff4fd23ff3c 100644 (file)
@@ -744,6 +744,11 @@ static SymresStatus symres_expression(AstTyped** expr) {
             break;
         }
 
+        case Ast_Kind_Switch: {
+            SYMRES(switch, (AstSwitch *) *expr);
+            break;
+        }
+
         default: break;
     }
 
@@ -832,11 +837,24 @@ static SymresStatus symres_case(AstSwitchCase *casenode) {
     }
 
     if (casenode->capture) {
-        casenode->block->scope = scope_create(context.ast_alloc, current_scope, casenode->block->token->pos);
-        symbol_introduce(casenode->block->scope, casenode->capture->token, (AstNode *) casenode->capture);
+        if (casenode->scope == NULL) {
+            casenode->scope = scope_create(context.ast_alloc, current_scope, casenode->token->pos);
+            symbol_introduce(casenode->scope, casenode->capture->token, (AstNode *) casenode->capture);
+        }
+
+        scope_enter(casenode->scope);
+    }
+
+    if (casenode->body_is_expr) {
+        SYMRES(expression, &casenode->expr);
+    } else {
+        SYMRES(block, casenode->block);
+    }
+
+    if (casenode->capture) {
+        scope_leave();
     }
 
-    SYMRES(block, casenode->block);
     return Symres_Success;
 }
 
@@ -857,7 +875,13 @@ static SymresStatus symres_switch(AstSwitch* switchnode) {
             SYMRES(case, *pcase);
         }
 
-        if (switchnode->default_case) SYMRES(block, switchnode->default_case);
+        if (switchnode->default_case) {
+            if (switchnode->is_expr) {
+                SYMRES(expression, (AstTyped **) &switchnode->default_case);
+            } else {
+                SYMRES(block, switchnode->default_case);
+            }
+        }
     }
 
     if (switchnode->switch_kind == Switch_Kind_Use_Equals && switchnode->case_exprs) {
index 7afd7c6d83488df36baf704e2acba770155b5e12..93d1f395ecd555b70e528acf58b1d5676557ff79 100644 (file)
@@ -1612,6 +1612,12 @@ EMIT_FUNC(switch, AstSwitch* switch_node) {
     bh_imap block_map;
     bh_imap_init(&block_map, global_heap_allocator, bh_arr_length(switch_node->cases));
 
+    u64 expr_result_local = 0;
+    if (switch_node->is_expr) {
+        expr_result_local = local_allocate(mod->local_alloc, (AstTyped *) switch_node);
+        bh_imap_put(&mod->local_map, (u64) switch_node, expr_result_local);
+    }
+
     if (switch_node->initialization != NULL) {
         forll (AstNode, stmt, switch_node->initialization, next) {
             emit_statement(mod, &code, stmt);
@@ -1622,11 +1628,11 @@ EMIT_FUNC(switch, AstSwitch* switch_node) {
 
     u64 block_num = 0;
     bh_arr_each(AstSwitchCase *, sc, switch_node->cases) {
-        if (bh_imap_has(&block_map, (u64) (*sc)->block)) continue;
+        if (bh_imap_has(&block_map, (u64) *sc)) continue;
 
         emit_enter_structured_block(mod, &code, SBT_Fallthrough_Block, (*sc)->block->token);
 
-        bh_imap_put(&block_map, (u64) (*sc)->block, block_num);
+        bh_imap_put(&block_map, (u64) *sc, block_num);
         block_num++;
     }
 
@@ -1642,6 +1648,7 @@ EMIT_FUNC(switch, AstSwitch* switch_node) {
             fori (i, 0, bt->count) bt->cases[i] = bt->default_case;
 
             bh_arr_each(bh__imap_entry, sc, switch_node->case_map.entries) {
+                assert(bh_imap_has(&block_map, (u64) sc->value));
                 bt->cases[sc->key - switch_node->min_case] = bh_imap_get(&block_map, (u64) sc->value);
             }
 
@@ -1691,7 +1698,7 @@ EMIT_FUNC(switch, AstSwitch* switch_node) {
             bh_arr_each(CaseToBlock, ctb, switch_node->case_exprs) {
                 emit_expression(mod, &code, (AstTyped *) ctb->comparison);
 
-                u64 bn = bh_imap_get(&block_map, (u64) ctb->block);
+                u64 bn = bh_imap_get(&block_map, (u64) ctb->casestmt);
                 WID(switch_node->expr->token, WI_IF_START, 0x40);
                 WID(switch_node->expr->token, WI_JUMP, bn + 1);
                 WI(switch_node->expr->token, WI_IF_END);
@@ -1707,7 +1714,7 @@ EMIT_FUNC(switch, AstSwitch* switch_node) {
         AstSwitchCase *sc = *psc;
         if (bh_imap_get(&block_map, (u64) sc->block) == 0xdeadbeef) continue;
 
-        u64 bn = bh_imap_get(&block_map, (u64) sc->block);
+        u64 bn = bh_imap_get(&block_map, (u64) sc);
 
         if (sc->capture) {
             assert(union_capture_idx != 0);
@@ -1744,7 +1751,14 @@ EMIT_FUNC(switch, AstSwitch* switch_node) {
 
         // Maybe the Symbol Frame idea should be controlled as a block_flag?
         debug_enter_symbol_frame(mod);
-        emit_block(mod, &code, sc->block, 0);
+        if (sc->body_is_expr) {
+            emit_expression(mod, &code, sc->expr);
+            emit_generic_store_instruction(mod, &code, (AstTyped *) switch_node, switch_node->token);
+
+        } else {
+            emit_block(mod, &code, sc->block, 0);
+        }
+
         debug_leave_symbol_frame(mod);
 
         if (bh_arr_last(code).type != WI_JUMP)
@@ -1752,16 +1766,35 @@ EMIT_FUNC(switch, AstSwitch* switch_node) {
 
         emit_leave_structured_block(mod, &code);
 
-        bh_imap_put(&block_map, (u64) sc->block, 0xdeadbeef);
+        bh_imap_put(&block_map, (u64) sc, 0xdeadbeef);
     }
 
     if (switch_node->default_case != NULL) {
-        emit_block(mod, &code, switch_node->default_case, 0);
+        if (switch_node->is_expr) {
+            emit_expression(mod, &code, (AstTyped *) switch_node->default_case);
+            emit_generic_store_instruction(mod, &code, (AstTyped *) switch_node, switch_node->token);
+
+        } else {
+            emit_block(mod, &code, switch_node->default_case, 0);
+        }
     }
 
     if (union_capture_idx != 0) local_raw_free(mod->local_alloc, WASM_TYPE_PTR);
     emit_leave_structured_block(mod, &code);
 
+    if (switch_node->is_expr) {
+        if ((expr_result_local & LOCAL_IS_WASM) == 0) {
+            u64 offset = 0;
+            emit_local_location(mod, &code, (AstLocal *) switch_node, &offset);
+            emit_load_instruction(mod, &code, switch_node->type, offset);
+
+        } else {
+            WIL(switch_node->token, WI_LOCAL_GET, expr_result_local);
+        }
+
+        local_free(mod->local_alloc, (AstTyped *) switch_node);
+    }
+
     bh_imap_free(&block_map);
     *pcode = code;
 }
@@ -3279,7 +3312,8 @@ EMIT_FUNC(location_return_offset, AstTyped* expr, u64* offset_return) {
         case Ast_Kind_Do_Block:
         case Ast_Kind_If_Expression:
         case Ast_Kind_Call_Site:
-        case Ast_Kind_Zero_Value: {
+        case Ast_Kind_Zero_Value:
+        case Ast_Kind_Switch: {
             emit_local_location(mod, &code, (AstLocal *) expr, offset_return);
             break;
         }
@@ -3822,8 +3856,16 @@ EMIT_FUNC(expression, AstTyped* expr) {
             break;
         }
 
+        case Ast_Kind_Switch: {
+            AstSwitch* switchnode = (AstSwitch *) expr;
+            assert(switchnode->is_expr);
+
+            emit_switch(mod, &code, switchnode);
+            break;
+        }
+
         default:
-            bh_printf("Unhandled case: %d\n", expr->kind);
+            bh_printf("Unhandled case: %s\n", onyx_ast_node_kind_string(expr->kind));
             DEBUG_HERE;
             assert(0);
     }
index fa7bad9477d8d421b055fec45b713c259766842b..c9c7a99264f58e1e38717f79823db82a5d0e6650 100644 (file)
@@ -46,11 +46,9 @@ use core
         Extracts the value from the Optional, or uses a default if
         no value is present.
     """
-    value_or :: (o: ?$T, default: T) -> T {
-        switch o {
-            case .Some => v do return v;
-            case #default do return default;
-        }
+    value_or :: (o: ?$T, default: T) => switch o {
+        case v: .Some => v;
+        case #default => default;
     }
 
     #doc "Clears the value in the Optional, zeroing the memory of the value."
@@ -65,16 +63,16 @@ use core
 
     #doc "Monadic chaining operation."
     and_then :: (o: ?$T, transform: (T) -> ?$R) -> ?R {
-        switch o {
-            case .Some => v do return transform(v);
-            case #default do return .{ None = .{} };
-        }
+        return switch o {
+            case v: .Some => transform(v);
+            case #default => .{ None = .{} };
+        };
     }
 
     #doc "Changes the value inside the optional, if present."
     transform :: (o: ?$T, transform: (T) -> $R) -> ?R {
         switch o {
-            case .Some => v do return .{ Some = transform(v) };
+            case v: .Some do return .{ Some = transform(v) };
             case #default do return .{ None = .{} };
         }
     }
@@ -84,10 +82,10 @@ use core
         provide a function to generate a value.
     """
     or_else :: (o: ?$T, generate: () -> ?T) -> ?T {
-        switch o {
-            case .Some => v do return o;
-            case #default do return generate();
-        }
+        return switch o {
+            case .Some => o;
+            case #default => generate();
+        };
     }
 
     #doc """
@@ -97,7 +95,7 @@ use core
     """
     unwrap :: (o: ?$T) -> T {
         switch o {
-            case .Some => v do return v;
+            case v: .Some do return v;
             case #default {
                 assert(false, "Unwrapping empty Optional.");
             }
@@ -111,7 +109,7 @@ use core
     """
     unwrap_ptr :: (o: & ?$T) -> &T {
         switch o {
-            case .Some => &v do return v;
+            case &v: .Some do return v;
             case #default {
                 assert(false, "Unwrapping empty Optional.");
             }
@@ -121,7 +119,7 @@ use core
     or_return :: #match {
         macro (o: ?$T) -> T {
             switch value := o; value {
-                case .Some => v do return v;
+                case v: .Some do return v;
                 case #default {
                     return return .{};
                 }
@@ -129,7 +127,7 @@ use core
         },
         macro (o: ?$T, return_value: $R) -> T {
             switch value := o; value {
-                case .Some => v do return v;
+                case v: .Some do return v;
                 case #default {
                     return return return_value;
                 }
@@ -139,7 +137,7 @@ use core
 
     catch :: macro (o: ?$T, body: Code) -> T {
         switch value := o; value {
-            case .Some => v do return v;
+            case v: .Some do return v;
             case .None {
                 #unquote body;
             }
@@ -149,7 +147,7 @@ use core
     with :: macro (o: ?$T, body: Code) {
         switch o {
             case .None ---;
-            case .Some => it {
+            case it: .Some {
                 #unquote body(it);
             }
         }
@@ -207,35 +205,31 @@ use core
     }
 
 
-    hash :: (o: ?$T/core.hash.Hashable) -> u32 {
-        switch o {
-            case .Some => v do return core.hash.hash(v);
-            case #default do return 0;
-        }
+    hash :: (o: ?$T/core.hash.Hashable) => switch o {
+        case v: .Some => core.hash.hash(v);
+        case #default => 0;
     }
 }
 
 #operator == (o1, o2: ?$T) -> bool {
     if cast(Optional(T).tag_enum, o1) != cast(Optional(T).tag_enum, o2) do return false;
-    switch o1 {
-        case .None do return true;
-        case .Some => v1 {
-            v2 := o2->unwrap();
-            return v1 == v2;
-        }
-    }
+
+    return switch o1 {
+        case .None => true;
+        case v1: .Some => v1 == o2->unwrap();
+    };
 }
 
 #operator ?? macro (opt: ?$T, default: T) -> T {
-    switch value := opt; value {
-        case .Some => v do return v;
-        case #default do return default;
-    }
+    return switch value := opt; value {
+        case v: .Some => v;
+        case #default => default;
+    };
 }
 
 #operator ?? macro (opt: ?$T, catch: Code) -> T {
     switch value := opt; value {
-        case .Some => v do return v;
+        case v: .Some do return v;
         case #default ---
     }
 
@@ -244,7 +238,7 @@ use core
 
 #operator ? macro (opt: ?$T) -> T {
     switch value := opt; value {
-        case .Some => v do return v;
+        case v: .Some do return v;
         case #default do return return .{};
     }
 }
index 7183b8f6ef9f683835f1b86a619636c5646a0702..a266d0629f8a86be72b109c2620e46f6281bc188 100644 (file)
@@ -27,34 +27,34 @@ Result :: union (Ok_Type: type_expr, Err_Type: type_expr) {
 #inject Result {
     #doc "Returns true if the result contains an Ok value."
     is_ok :: (r: #Self) -> bool {
-        switch r {
-            case .Ok do return true;
-            case #default do return false;
-        }
+        return switch r {
+            case .Ok => true;
+            case #default => false;
+        };
     }
 
     #doc "Returns true if the result contains an Err value."
     is_err :: (r: #Self) -> bool {
-        switch r {
-            case .Err do return true;
-            case #default do return false;
-        }
+        return switch r {
+            case .Err => true;
+            case #default => false;
+        };
     }
 
     #doc "Returns an Optional of the Ok type."
     ok :: (r: #Self) -> Optional(r.Ok_Type) {
-        switch r {
-            case .Ok => v do return v;
-            case #default do return .{};
-        }
+        return switch r {
+            case v: .Ok => Optional.make(v);
+            case #default => .{};
+        };
     }
 
     #doc "Returns an Optional of the Err type."
     err :: (r: #Self) -> Optional(r.Err_Type) {
-        switch r {
-            case .Err => v do return v;
-            case #default do return .{};
-        }
+        return switch r {
+            case v: .Err => Optional.make(v);
+            case #default => .{};
+        };
     }
 
     #doc """
@@ -63,8 +63,8 @@ Result :: union (Ok_Type: type_expr, Err_Type: type_expr) {
     """
     unwrap :: (r: #Self) -> r.Ok_Type {
         switch r {
-            case .Ok => v do return v;
-            case .Err => err {
+            case v: .Ok do return v;
+            case err: .Err {
                 msg := tprintf("Unwrapping Result with error '{}'.", err);
                 assert(false, msg);
                 return .{};
@@ -77,10 +77,10 @@ Result :: union (Ok_Type: type_expr, Err_Type: type_expr) {
         result contains an Err, the empty .{} value is returned.
     """
     unwrap_or_default :: (r: #Self) -> r.Ok_Type {
-        switch r {
-            case .Ok => v do return v;
-            case #default do return .{};
-        }
+        return switch r {
+            case v: .Ok => v;
+            case #default => .{};
+        };
     }
 
     #doc """
@@ -89,7 +89,7 @@ Result :: union (Ok_Type: type_expr, Err_Type: type_expr) {
     """
     expect :: (r: #Self, msg: str) -> r.Ok_Type {
         switch r {
-            case .Ok => v do return v;
+            case v: .Ok do return v;
             case #default {
                 assert(false, msg);
             }
@@ -102,26 +102,26 @@ Result :: union (Ok_Type: type_expr, Err_Type: type_expr) {
             Err(e) => Err(e)
     """
     transform :: (r: Result($T, $E), f: (T) -> $R) -> Result(R, E) {
-        switch r {
-            case .Ok => v  do return .{ Ok = f(v) };
-            case .Err => v do return .{ Err = v };
-        }
+        return switch r {
+            case v: .Ok => .{ Ok = f(v) };
+            case v: .Err => .{ Err = v };
+        };
     }
 
     #doc "Monadic chaining operation."
     and_then :: (r: #Self, f: (r.Ok_Type) -> Result($R, r.Err_Type)) -> Result(R, r.Err_Type) {
-        switch r {
-            case .Ok => v  do return f(v);
-            case .Err => v do return .{ Err = v };
-        }
+        return switch r {
+            case v: .Ok  => f(v);
+            case v: .Err => .{ Err = v };
+        };
     }
 
     #doc "If the Result contains Err, generate is called to make a value"
     or_else :: (r: #Self, generate: () -> typeof r) => {
-        switch r {
-            case .Ok => v do return v;
-            case #default do return generate();
-        }
+        return switch r {
+            case v: .Ok   => v;
+            case #default => generate();
+        };
     }
 
     #doc """
@@ -142,8 +142,8 @@ Result :: union (Ok_Type: type_expr, Err_Type: type_expr) {
     """
     forward_err :: macro (r: Result($T, $E)) -> T {
         switch res := r; res {
-            case .Ok => v  do return v;
-            case .Err => v do return return .{ Err = v };
+            case v: .Ok  do return v;
+            case v: .Err do return return .{ Err = v };
         }
     }
 
@@ -153,7 +153,7 @@ Result :: union (Ok_Type: type_expr, Err_Type: type_expr) {
     """
     or_return :: macro (r: Result($T, $E), v: $V) -> T {
         switch res := r; res {
-            case .Ok => v  do return v;
+            case v: .Ok  do return v;
             case .Err do return return v;
         }
     }
@@ -168,8 +168,8 @@ Result :: union (Ok_Type: type_expr, Err_Type: type_expr) {
     """
     catch :: macro (r: Result($T, $E), on_err: Code) -> T {
         switch res := r; res {
-            case .Ok => v  do return v;
-            case .Err => err {
+            case v: .Ok  do return v;
+            case err: .Err {
                 #unquote on_err(err);
             }
         }
@@ -182,16 +182,16 @@ __implicit_bool_cast :: macro (r: Result($O, $E)) => cast(Result(O, E).tag_enum,
 
 #operator ? macro (r: Result($T, $E)) -> T {
     switch res := r; res {
-        case .Ok => v  do return v;
-        case .Err => v do return return .{ Err = v };
+        case v: .Ok do return v;
+        case v: .Err do return return .{ Err = v };
     }
 }
 
 #operator ?? macro (r: Result($T, $E), v: T) -> T {
-    switch res := r; res {
-        case .Ok => v do return v;
-        case .Err do return v;
-    }
+    return switch res := r; res {
+        case val: .Ok => val;
+        case .Err => v;
+    };
 }
 
 
index bb1c4158191868e53d19263dcc3915eddb8249c5..2feb1991817c3f22991e5c73a95cd0cf87865482 100644 (file)
@@ -23,12 +23,11 @@ decode :: (s: str, allocator := context.allocator) -> str {
     return new_str;
 
     digit_to_value :: (it: u8) -> u32 {
-        switch it {
-            case #char "0" .. #char "9" do return ~~(it - #char "0");
-            case #char "a" .. #char "f" do return ~~(it - #char "a" + 10);
-            case #char "A" .. #char "F" do return ~~(it - #char "A" + 10);
-        }
-
-        return 0;
+        return ~~ switch it {
+            case #char "0" .. #char "9" => it - #char "0";
+            case #char "a" .. #char "f" => it - #char "a" + 10;
+            case #char "A" .. #char "F" => it - #char "A" + 10;
+            case #default => 0;
+        };
     }
 }
\ No newline at end of file
index 5ebb2f011fbf6445ca4110bd7ea61913f84b70f1..72a73048519ac36fcae8d3934f24acdf7023a64e 100644 (file)
@@ -405,25 +405,23 @@ parse_and_write_utf8_character :: (s: str, out: [&] u8) -> (i32, i32) {
     return 0, 0;
 
     digit_to_hex :: (c: u8) -> i32 {
-        switch c {
-            case #char "0" do return 0;
-            case #char "1" do return 1;
-            case #char "2" do return 2;
-            case #char "3" do return 3;
-            case #char "4" do return 4;
-            case #char "5" do return 5;
-            case #char "6" do return 6;
-            case #char "7" do return 7;
-            case #char "8" do return 8;
-            case #char "9" do return 9;
-            case #char "A", #char "a" do return 10;
-            case #char "B", #char "b" do return 11;
-            case #char "C", #char "c" do return 12;
-            case #char "D", #char "d" do return 13;
-            case #char "E", #char "e" do return 14;
-            case #char "F", #char "f" do return 15;
-        }
-
-        return 0;
+        return switch c {
+            case '0' => 0;
+            case '1' => 1;
+            case '2' => 2;
+            case '3' => 3;
+            case '4' => 4;
+            case '5' => 5;
+            case '6' => 6;
+            case '7' => 7;
+            case '8' => 8;
+            case '9' => 9;
+            case 'A', 'a' => 10;
+            case 'B', 'b' => 11;
+            case 'C', 'c' => 12;
+            case 'D', 'd' => 13;
+            case 'E', 'e' => 14;
+            case 'F', 'f' => 15;
+        };
     }
 }
index 14317c9b036e0d91fcd9647246defa8db99b5c41..f9c832045ad09b996600b89c92050203d1d9a8f0 100644 (file)
@@ -156,25 +156,25 @@ __byte_dump :: (ptr: rawptr, byte_count: u32, bytes_per_line := 8) {
 
 
     map_to_ascii :: (x: u8) -> u8 {
-        switch x {
-            case 0 do return  #char "0";
-            case 1 do return  #char "1";
-            case 2 do return  #char "2";
-            case 3 do return  #char "3";
-            case 4 do return  #char "4";
-            case 5 do return  #char "5";
-            case 6 do return  #char "6";
-            case 7 do return  #char "7";
-            case 8 do return  #char "8";
-            case 9 do return  #char "9";
-            case 10 do return #char "A";
-            case 11 do return #char "B";
-            case 12 do return #char "C";
-            case 13 do return #char "D";
-            case 14 do return #char "E";
-            case 15 do return #char "F";
-            case #default do return #char "X";
-        }
+        return switch x {
+            case 0 =>  #char "0";
+            case 1 =>  #char "1";
+            case 2 =>  #char "2";
+            case 3 =>  #char "3";
+            case 4 =>  #char "4";
+            case 5 =>  #char "5";
+            case 6 =>  #char "6";
+            case 7 =>  #char "7";
+            case 8 =>  #char "8";
+            case 9 =>  #char "9";
+            case 10 => #char "A";
+            case 11 => #char "B";
+            case 12 => #char "C";
+            case 13 => #char "D";
+            case 14 => #char "E";
+            case 15 => #char "F";
+            case #default => #char "X";
+        };
     }
 }
 
index ae8238bd25154916220b04a5dc012632f45a55d6..4c3cdf449b5a30d632fb97e32c4cdc13b24be5a9 100644 (file)
@@ -137,11 +137,11 @@ socket_is_alive :: (s: &Socket) -> bool {
 }
 
 socket_connect :: (s: &Socket, host: str, port: u16 = 0) -> SocketError {
-    switch s.family {
-        case .Inet do return __net_connect_ipv4(s.handle, host, port);
-        case .Unix do return __net_connect_unix(s.handle, host);
-        case #default do return .BadSettings;
-    }
+    return switch s.family {
+        case .Inet => __net_connect_ipv4(s.handle, host, port);
+        case .Unix => __net_connect_unix(s.handle, host);
+        case #default => .BadSettings;
+    };
 }
 
 socket_bind :: (s: &Socket, bind_address: &Socket_Address) -> bool {
index b2678a88d8dd804c3d3d92abc63685af1cb5e2bb..b351145ae4954501eb4b0c300770ce4faef39c94 100644 (file)
@@ -293,26 +293,26 @@ compile_c_file :: (
 
         param_info := get_type_info(t);
         switch param_info.kind {
-            case .Basic do switch t {
-                case bool do return "i32";
-                case i8   do return "i32";
-                case u8   do return "i32";
-                case i16  do return "i32";
-                case u16  do return "i32";
-                case i32  do return "i32";
-                case u32  do return "i32";
-                case i64  do return "i64";
-                case u64  do return "i64";
-
-                case f32  do return "f32";
-                case f64  do return "f64";
-
-                case rawptr do return "ptr"; 
+            case .Basic do return switch t {
+                case bool => "i32";
+                case i8   => "i32";
+                case u8   => "i32";
+                case i16  => "i32";
+                case u16  => "i32";
+                case i32  => "i32";
+                case u32  => "i32";
+                case i64  => "i64";
+                case u64  => "i64";
+
+                case f32  => "f32";
+                case f64  => "f64";
+
+                case rawptr => "ptr"; 
                 
-                case i8x16, i16x8, i32x4, i64x2, f32x4, f64x2, v128 do return "v128";
+                case i8x16, i16x8, i32x4, i64x2, f32x4, f64x2, v128 => "v128";
 
-                case type_expr do return "i32";
-            }
+                case type_expr => "i32";
+            };
 
             case .Pointer do return "ptr"; 
             case .Multi_Pointer do return "ptr"; 
@@ -350,26 +350,26 @@ compile_c_file :: (
 
         param_info := get_type_info(t);
         switch param_info.kind {
-            case .Basic do switch t {
-                case bool do return "WASM_I32";
-                case i8   do return "WASM_I32";
-                case u8   do return "WASM_I32";
-                case i16  do return "WASM_I32";
-                case u16  do return "WASM_I32";
-                case i32  do return "WASM_I32";
-                case u32  do return "WASM_I32";
-                case i64  do return "WASM_I64";
-                case u64  do return "WASM_I64";
-
-                case f32  do return "WASM_F32";
-                case f64  do return "WASM_F64";
-
-                case rawptr do return "WASM_I32"; // This will have to depend on the pointer size...
+            case .Basic do return switch t {
+                case bool => "WASM_I32";
+                case i8   => "WASM_I32";
+                case u8   => "WASM_I32";
+                case i16  => "WASM_I32";
+                case u16  => "WASM_I32";
+                case i32  => "WASM_I32";
+                case u32  => "WASM_I32";
+                case i64  => "WASM_I64";
+                case u64  => "WASM_I64";
+
+                case f32  => "WASM_F32";
+                case f64  => "WASM_F64";
+
+                case rawptr => "WASM_I32"; // This will have to depend on the pointer size...
                 
-                case i8x16, i16x8, i32x4, i64x2, f32x4, f64x2, v128 do return "WASM_V128";
+                case i8x16, i16x8, i32x4, i64x2, f32x4, f64x2, v128 => "WASM_V128";
 
-                case type_expr do return "WASM_I32";
-            }
+                case type_expr => "WASM_I32";
+            };
 
             case .Pointer do return "WASM_I32"; // This will also have to depend on the pointer size...
             case .Multi_Pointer do return "WASM_I32"; // This will also have to depend on the pointer size...
index 74fb82ae112f019137fb68660b87b14fee995d6c..ac8a6c410aac18ed03cbb19c4684cb9df30543aa 100644 (file)
@@ -26,15 +26,15 @@ write_type_name :: (writer: &io.Writer, t: type_expr) {
                 case .F32  do io.write_str(writer, "f32");
                 case .F64  do io.write_str(writer, "f64");
 
-                case .Rawptr do return io.write_str(writer, "rawptr");
+                case .Rawptr do io.write_str(writer, "rawptr");
 
-                case .I8X16 do return io.write_str(writer, "i8x16");
-                case .I16X8 do return io.write_str(writer, "i16x8");
-                case .I32X4 do return io.write_str(writer, "i32x4");
-                case .I64X2 do return io.write_str(writer, "i64x2");
-                case .F32X4 do return io.write_str(writer, "f32x4");
-                case .F64X2 do return io.write_str(writer, "f64x2");
-                case .V128  do return io.write_str(writer, "v128");
+                case .I8X16 do io.write_str(writer, "i8x16");
+                case .I16X8 do io.write_str(writer, "i16x8");
+                case .I32X4 do io.write_str(writer, "i32x4");
+                case .I64X2 do io.write_str(writer, "i64x2");
+                case .F32X4 do io.write_str(writer, "f32x4");
+                case .F64X2 do io.write_str(writer, "f64x2");
+                case .V128  do io.write_str(writer, "v128");
 
                 case .Type_Index do io.write_str(writer, "type_expr");
                 case .Unsized_Int do io.write_str(writer, "<unsized int>");
@@ -154,57 +154,57 @@ size_of :: (t: type_expr) -> u32 {
     info := get_type_info(t);
     if info == null do return 0;
 
-    switch info.kind {
-        case .Basic {
+    return switch info.kind {
+        case .Basic => do {
             basic := cast(&Type_Info_Basic) info;
 
-            switch basic.basic_kind {
-                case .Void do return 0;
-                case .Bool, .U8, .I8 do return 1;
-                case .U16, .I16 do return 2;
-                case .U32, .I32, .F32, .Type_Index do return 4;
-                case .U64, .I64, .F64 do return 8;
-                case .I8X16, .I16X8, .I32X4, .I64X2, .F32X4, .F64X2, .V128 do return 16;
-                case .Rawptr do return sizeof rawptr;
-
-                case .Unsized_Int do return 0;
-                case .Unsized_Float do return 0;
-            }
+            return switch basic.basic_kind {
+                case .Void => 0;
+                case .Bool, .U8, .I8 => 1;
+                case .U16, .I16 => 2;
+                case .U32, .I32, .F32, .Type_Index => 4;
+                case .U64, .I64, .F64 => 8;
+                case .I8X16, .I16X8, .I32X4, .I64X2, .F32X4, .F64X2, .V128 => 16;
+                case .Rawptr => sizeof rawptr;
+
+                case .Unsized_Int => 0;
+                case .Unsized_Float => 0;
+            };
         }
 
-        case .Pointer do return sizeof rawptr;
+        case .Pointer => sizeof rawptr
 
-        case .Array {
+        case .Array => do {
             arr := cast(&Type_Info_Array) info;
             return size_of(arr.of) * arr.count;
         }
 
-        case .Slice do return sizeof str;
-        case .Dynamic_Array do return sizeof [..] void;
-        case .Variadic_Argument do return sizeof str;
-        case .Enum {
+        case .Slice => sizeof str;
+        case .Dynamic_Array => sizeof [..] void;
+        case .Variadic_Argument => sizeof str;
+        case .Enum => do {
             e := cast(&Type_Info_Enum) info;
             return e.size;
         }
 
-        case .Struct {
+        case .Struct => do {
             s := cast(&Type_Info_Struct) info;
             return s.size;
         }
 
-        case .Polymorphic_Struct do return 0;
+        case .Polymorphic_Struct => 0;
 
-        case .Compound do return 0;
+        case .Compound => 0;
 
-        case .Function do return 4;
+        case .Function => 4;
 
-        case .Distinct {
+        case .Distinct => do {
             d := cast(&Type_Info_Distinct) info;
             return size_of(d.base_type);
         }
-    }
 
-    return 0;
+        case #default => 0;
+    };
 }
 
 offset_of :: (T: type_expr, member_name: str) -> u32 {
index 9ae73e7cd1f8b2eb89c24fc0a22dacc4b7ec2247..a4ed485802a7e11fd705e04ba408644bf5cfad16 100644 (file)
@@ -180,18 +180,17 @@ apply_orientation :: (t: &Tile, ori: TO) {
 }
 
 index_square_with_orientation :: (data: [&] $T, ori: TO, size: i32, x: i32, y: i32) -> &T {
-    switch ori {
-        case TO.N     do return &data[x + y * size];
-        case TO.R90   do return &data[y + (size - 1 - x) * size];
-        case TO.R180  do return &data[(size - 1 - x) + (size - 1 - y) * size];
-        case TO.R270  do return &data[(size - 1 - y) + x * size];
-        case TO.F     do return &data[x + (size - 1 - y) * size];
-        case TO.FR90  do return &data[y + x * size];
-        case TO.FR180 do return &data[(size - 1 - x) + y * size];
-        case TO.FR270 do return &data[(size - 1 - y) + (size - 1 - x) * size];
-    }
-
-    return null;
+    return switch ori {
+        case TO.N     => &data[x + y * size];
+        case TO.R90   => &data[y + (size - 1 - x) * size];
+        case TO.R180  => &data[(size - 1 - x) + (size - 1 - y) * size];
+        case TO.R270  => &data[(size - 1 - y) + x * size];
+        case TO.F     => &data[x + (size - 1 - y) * size];
+        case TO.FR90  => &data[y + x * size];
+        case TO.FR180 => &data[(size - 1 - x) + y * size];
+        case TO.FR270 => &data[(size - 1 - y) + (size - 1 - x) * size];
+        case #default => null
+    };
 }
 
 sea_monster_width  := 20;
diff --git a/tests/switch_expressions b/tests/switch_expressions
new file mode 100644 (file)
index 0000000..d11c0e3
--- /dev/null
@@ -0,0 +1,5 @@
+Val3
+Val1
+123
+12.3400
+A string
diff --git a/tests/switch_expressions.onyx b/tests/switch_expressions.onyx
new file mode 100644 (file)
index 0000000..65f9e9d
--- /dev/null
@@ -0,0 +1,55 @@
+use core {*}
+
+Foo :: enum {
+    Val1;
+    Val2;
+    Val3;
+}
+
+assignment_test :: () {
+    v: Foo = switch 3 {
+        case 1 => .Val1;
+        case 2 => .Val2;
+        case 3 => .Val3;
+    };
+
+    printf("{}\n", v);
+}
+
+quick_map_test :: () {
+    println(quick_map(3));
+
+    quick_map :: (n: i32) -> Foo {
+        return switch n {
+            case 4 => .Val1;
+            case 5 => .Val2;
+            case 6 => .Val3;
+            case #default => .Val1;
+        };
+    }
+}
+
+quick_union_map :: () { 
+
+    quick_map(SomeUnion.{ x = 123 }) |> println();
+    quick_map(SomeUnion.{ y = 12.34 }) |> println();
+    quick_map(SomeUnion.{ z = "A string" }) |> println();
+
+    SomeUnion :: union {
+        x: i32;
+        y: f32;
+        z: str;
+    }
+
+    quick_map :: (v: $T) => switch v {
+        case val: .z => val;
+        case val: .y => conv.format("{}", val);
+        case val: .x => conv.format("{}", val);
+    }
+}
+
+main :: () {
+    assignment_test();
+    quick_map_test();
+    quick_union_map();
+}
\ No newline at end of file
index c0ad0c3a5e54b7b578fd9af9300a75aeed93c2eb..962187480a51dca00621c755870bd83a372ea4fa 100644 (file)
@@ -7,7 +7,7 @@ union_is :: macro (u: $U, $variant: U.tag_enum) -> bool {
 
 extract_variant :: macro (u: $U, $variant: U.tag_enum) => {
     switch u {
-        case variant => v {
+        case v: variant {
             return Optional.make(v);
         }
     }
@@ -44,15 +44,15 @@ extraction_example :: () {
     value := Extraction.{ string = "This works" };
 
     switch value {
-        case .int => int_value {
+        case int_value: .int {
             printf("This is an integer: {}\n", int_value);
         }
 
-        case .float => float_value {
+        case float_value: .float {
             printf("This is a float: {}\n", float_value);
         }
 
-        case .string => string_value {
+        case string_value: .string {
             printf("This is a string: {}\n", string_value);
         }
     }
@@ -66,15 +66,15 @@ method_example :: () {
 
         do_the_thing :: (value: &Methoded) {
             switch *value {
-                case .int => int_value {
+                case int_value: .int {
                     printf("This is an integer: {}\n", int_value);
                 }
 
-                case .float => float_value {
+                case float_value: .float {
                     printf("This is a float: {}\n", float_value);
                 }
 
-                case .string => string_value {
+                case string_value: .string {
                     printf("This is a string: {}\n", string_value);
                 }
             }
@@ -100,7 +100,7 @@ linked_list_example :: () {
             switch walker {
                 case .End do break break;
 
-                case .Next => &next {
+                case &next: .Next {
                     printf("{}\n", next.data);
                     walker = next.next;
                 }