From: Brendan Hansen Date: Tue, 25 Aug 2020 12:58:55 +0000 (-0500) Subject: added fallthrough on switch statements; code cleanup X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=04a0b47d1dfd3d17626e2b4ab7def92dbeb83488;p=onyx.git added fallthrough on switch statements; code cleanup --- diff --git a/docs/plan b/docs/plan index 9fcbc957..23908c91 100644 --- a/docs/plan +++ b/docs/plan @@ -209,7 +209,9 @@ HOW: [X] Switch statements - [ ] fallthrough on cases in switch statements + [X] fallthrough on cases in switch statements + + [ ] initializers on switch statements [ ] #file and #line directives - string and u32 respectively that represent the current file and line number where the directive is diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index 796d8795..f7a103bf 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -27,8 +27,7 @@ typedef struct AstFileContents AstFileContents; typedef struct AstStructLiteral AstStructLiteral; typedef struct AstReturn AstReturn; -typedef struct AstBreak AstBreak; -typedef struct AstContinue AstContinue; +typedef struct AstJump AstJump; typedef struct AstBlock AstBlock; typedef struct AstIfWhile AstIfWhile; @@ -127,8 +126,7 @@ typedef enum AstKind { Ast_Kind_If, Ast_Kind_For, Ast_Kind_While, - Ast_Kind_Break, - Ast_Kind_Continue, + Ast_Kind_Jump, Ast_Kind_Defer, Ast_Kind_Switch, Ast_Kind_Switch_Case, @@ -253,6 +251,14 @@ typedef enum CallingConvention { CC_Return_Stack } CallingConvention; +typedef enum JumpType { + Jump_Type_Break, + Jump_Type_Continue, + Jump_Type_Fallthrough, + + Jump_Type_Count, +} JumpType; + // Base Nodes #define AstNode_base \ @@ -307,8 +313,7 @@ struct AstStructLiteral { // Intruction Node struct AstReturn { AstNode_base; AstTyped* expr; }; -struct AstBreak { AstNode_base; u64 count; }; -struct AstContinue { AstNode_base; u64 count; }; +struct AstJump { AstNode_base; JumpType jump; u32 count; }; // Structure Nodes struct AstBlock { AstNode_base; AstNode *body; Scope *scope; bh_arr(AstLocal *) locals; }; diff --git a/include/onyxlex.h b/include/onyxlex.h index 8d9ad1f9..21d4b3a0 100644 --- a/include/onyxlex.h +++ b/include/onyxlex.h @@ -32,6 +32,7 @@ typedef enum TokenType { Token_Type_Keyword_Do, Token_Type_Keyword_Case, Token_Type_Keyword_Switch, + Token_Type_Keyword_Fallthrough, Token_Type_Right_Arrow, Token_Type_Left_Arrow, diff --git a/misc/onyx.sublime-syntax b/misc/onyx.sublime-syntax index 4640a218..6a4c4606 100644 --- a/misc/onyx.sublime-syntax +++ b/misc/onyx.sublime-syntax @@ -23,7 +23,7 @@ contexts: # strings in YAML. When using single quoted strings, only single quotes # need to be escaped: this is done by using two single quotes next to each # other. - - match: '\b(package|struct|proc|use|global|enum|if|elseif|else|for|while|do|break|continue|return|as|cast|sizeof|alignof|defer|switch|case)\b' + - match: '\b(package|struct|proc|use|global|enum|if|elseif|else|for|while|do|break|continue|fallthrough|return|as|cast|sizeof|alignof|defer|switch|case)\b' scope: keyword.control.onyx - match: '\b(bool|void|i8|u8|i16|u16|i32|u32|i64|u64|f32|f64|rawptr)\b' diff --git a/misc/onyx.vim b/misc/onyx.vim index 071e6e19..eceb008a 100644 --- a/misc/onyx.vim +++ b/misc/onyx.vim @@ -14,7 +14,7 @@ syn keyword onyxKeyword package struct proc use global syn keyword onyxKeyword if elseif else syn keyword onyxKeyword for while do syn keyword onyxKeyword switch case -syn keyword onyxKeyword break continue return defer +syn keyword onyxKeyword break continue return defer fallthrough syn keyword onyxKeyword as cast sizeof alignof syn keyword onyxType bool void diff --git a/onyx b/onyx index 7083980b..869201d2 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/wasi_test.onyx b/progs/wasi_test.onyx index 7227834d..7ac5eb5a 100644 --- a/progs/wasi_test.onyx +++ b/progs/wasi_test.onyx @@ -337,4 +337,19 @@ main :: proc (args: []cstring) { if ss.count > 0 { print(ss); } + print("\n"); + + num := 36; + switch num { + case 36 do print("6 squared\n"); + + case 42 { + print("The meaning of life\n"); + fallthrough; + } + + case #default { + print("Nothing was found"); + } + } } diff --git a/src/onyxchecker.c b/src/onyxchecker.c index f24d4b0f..cbd8710f 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -998,8 +998,7 @@ CHECK(global, AstGlobal* global) { CHECK(statement, AstNode* stmt) { switch (stmt->kind) { - case Ast_Kind_Break: return 0; - case Ast_Kind_Continue: return 0; + case Ast_Kind_Jump: return 0; case Ast_Kind_Return: return check_return((AstReturn *) stmt); case Ast_Kind_If: return check_if((AstIfWhile *) stmt); diff --git a/src/onyxlex.c b/src/onyxlex.c index 88c849be..4d3e3fdb 100644 --- a/src/onyxlex.c +++ b/src/onyxlex.c @@ -30,6 +30,7 @@ static const char* token_type_names[] = { "do", "switch", "case", + "fallthrough", "->", "<-", @@ -253,98 +254,99 @@ whitespace_skipped: char curr = *tokenizer->curr; switch (curr) { case 'a': - LITERAL_TOKEN("alignof", 1, Token_Type_Keyword_Alignof); - LITERAL_TOKEN("as", 1, Token_Type_Keyword_As); + LITERAL_TOKEN("alignof", 1, Token_Type_Keyword_Alignof); + LITERAL_TOKEN("as", 1, Token_Type_Keyword_As); break; case 'b': - LITERAL_TOKEN("break", 1, Token_Type_Keyword_Break); + LITERAL_TOKEN("break", 1, Token_Type_Keyword_Break); break; case 'c': - LITERAL_TOKEN("case", 1, Token_Type_Keyword_Case); - LITERAL_TOKEN("cast", 1, Token_Type_Keyword_Cast); - LITERAL_TOKEN("continue", 1, Token_Type_Keyword_Continue); + LITERAL_TOKEN("case", 1, Token_Type_Keyword_Case); + LITERAL_TOKEN("cast", 1, Token_Type_Keyword_Cast); + LITERAL_TOKEN("continue", 1, Token_Type_Keyword_Continue); break; case 'd': - LITERAL_TOKEN("defer", 1, Token_Type_Keyword_Defer); - LITERAL_TOKEN("do", 1, Token_Type_Keyword_Do); + LITERAL_TOKEN("defer", 1, Token_Type_Keyword_Defer); + LITERAL_TOKEN("do", 1, Token_Type_Keyword_Do); break; case 'e': - LITERAL_TOKEN("enum" , 1, Token_Type_Keyword_Enum); - LITERAL_TOKEN("elseif", 1, Token_Type_Keyword_Elseif); - LITERAL_TOKEN("else", 1, Token_Type_Keyword_Else); + LITERAL_TOKEN("enum", 1, Token_Type_Keyword_Enum); + LITERAL_TOKEN("elseif", 1, Token_Type_Keyword_Elseif); + LITERAL_TOKEN("else", 1, Token_Type_Keyword_Else); break; case 'f': - LITERAL_TOKEN("for", 1, Token_Type_Keyword_For); - LITERAL_TOKEN("false", 1, Token_Type_Literal_False); + LITERAL_TOKEN("for", 1, Token_Type_Keyword_For); + LITERAL_TOKEN("false", 1, Token_Type_Literal_False); + LITERAL_TOKEN("fallthrough", 1, Token_Type_Keyword_Fallthrough); break; case 'g': - LITERAL_TOKEN("global", 1, Token_Type_Keyword_Global); + LITERAL_TOKEN("global", 1, Token_Type_Keyword_Global); break; case 'i': - LITERAL_TOKEN("if", 1, Token_Type_Keyword_If); + LITERAL_TOKEN("if", 1, Token_Type_Keyword_If); break; case 'p': - LITERAL_TOKEN("package", 1, Token_Type_Keyword_Package); - LITERAL_TOKEN("proc", 1, Token_Type_Keyword_Proc); + LITERAL_TOKEN("package", 1, Token_Type_Keyword_Package); + LITERAL_TOKEN("proc", 1, Token_Type_Keyword_Proc); break; case 'r': - LITERAL_TOKEN("return", 1, Token_Type_Keyword_Return); + LITERAL_TOKEN("return", 1, Token_Type_Keyword_Return); break; case 's': - LITERAL_TOKEN("sizeof", 1, Token_Type_Keyword_Sizeof); - LITERAL_TOKEN("struct", 1, Token_Type_Keyword_Struct); - LITERAL_TOKEN("switch", 1, Token_Type_Keyword_Switch); + LITERAL_TOKEN("sizeof", 1, Token_Type_Keyword_Sizeof); + LITERAL_TOKEN("struct", 1, Token_Type_Keyword_Struct); + LITERAL_TOKEN("switch", 1, Token_Type_Keyword_Switch); break; case 't': - LITERAL_TOKEN("true", 1, Token_Type_Literal_True); + LITERAL_TOKEN("true", 1, Token_Type_Literal_True); break; case 'u': - LITERAL_TOKEN("use", 1, Token_Type_Keyword_Use); + LITERAL_TOKEN("use", 1, Token_Type_Keyword_Use); break; case 'w': - LITERAL_TOKEN("while", 1, Token_Type_Keyword_While); + LITERAL_TOKEN("while", 1, Token_Type_Keyword_While); break; case '-': - LITERAL_TOKEN("->", 0, Token_Type_Right_Arrow); - LITERAL_TOKEN("---", 0, Token_Type_Empty_Block); - LITERAL_TOKEN("-=", 0, Token_Type_Minus_Equal); + LITERAL_TOKEN("->", 0, Token_Type_Right_Arrow); + LITERAL_TOKEN("---", 0, Token_Type_Empty_Block); + LITERAL_TOKEN("-=", 0, Token_Type_Minus_Equal); break; case '<': - LITERAL_TOKEN("<-", 0, Token_Type_Right_Arrow); - LITERAL_TOKEN("<<=", 0, Token_Type_Shl_Equal); - LITERAL_TOKEN("<<", 0, Token_Type_Shift_Left); - LITERAL_TOKEN("<=", 0, Token_Type_Less_Equal); + LITERAL_TOKEN("<-", 0, Token_Type_Right_Arrow); + LITERAL_TOKEN("<<=", 0, Token_Type_Shl_Equal); + LITERAL_TOKEN("<<", 0, Token_Type_Shift_Left); + LITERAL_TOKEN("<=", 0, Token_Type_Less_Equal); break; case '>': - LITERAL_TOKEN(">>>=", 0, Token_Type_Sar_Equal); - LITERAL_TOKEN(">>=", 0, Token_Type_Shr_Equal); - LITERAL_TOKEN(">>>", 0, Token_Type_Shift_Arith_Right); - LITERAL_TOKEN(">>", 0, Token_Type_Shift_Right); - LITERAL_TOKEN(">=", 0, Token_Type_Greater_Equal); + LITERAL_TOKEN(">>>=", 0, Token_Type_Sar_Equal); + LITERAL_TOKEN(">>=", 0, Token_Type_Shr_Equal); + LITERAL_TOKEN(">>>", 0, Token_Type_Shift_Arith_Right); + LITERAL_TOKEN(">>", 0, Token_Type_Shift_Right); + LITERAL_TOKEN(">=", 0, Token_Type_Greater_Equal); break; case '&': - LITERAL_TOKEN("&&", 0, Token_Type_And_And); - LITERAL_TOKEN("&=", 0, Token_Type_And_Equal); + LITERAL_TOKEN("&&", 0, Token_Type_And_And); + LITERAL_TOKEN("&=", 0, Token_Type_And_Equal); break; case '|': - LITERAL_TOKEN("|>", 0, Token_Type_Pipe); - LITERAL_TOKEN("||", 0, Token_Type_Or_Or); - LITERAL_TOKEN("|=", 0, Token_Type_Or_Equal); + LITERAL_TOKEN("|>", 0, Token_Type_Pipe); + LITERAL_TOKEN("||", 0, Token_Type_Or_Or); + LITERAL_TOKEN("|=", 0, Token_Type_Or_Equal); break; default: - LITERAL_TOKEN("^=", 0, Token_Type_Xor_Equal); - LITERAL_TOKEN("==", 0, Token_Type_Equal_Equal); - LITERAL_TOKEN("!=", 0, Token_Type_Not_Equal); - LITERAL_TOKEN("+=", 0, Token_Type_Plus_Equal); - LITERAL_TOKEN("*=", 0, Token_Type_Star_Equal); - LITERAL_TOKEN("/=", 0, Token_Type_Fslash_Equal); - LITERAL_TOKEN("%=", 0, Token_Type_Percent_Equal); + LITERAL_TOKEN("^=", 0, Token_Type_Xor_Equal); + LITERAL_TOKEN("==", 0, Token_Type_Equal_Equal); + LITERAL_TOKEN("!=", 0, Token_Type_Not_Equal); + LITERAL_TOKEN("+=", 0, Token_Type_Plus_Equal); + LITERAL_TOKEN("*=", 0, Token_Type_Star_Equal); + LITERAL_TOKEN("/=", 0, Token_Type_Fslash_Equal); + LITERAL_TOKEN("%=", 0, Token_Type_Percent_Equal); break; } diff --git a/src/onyxparser.c b/src/onyxparser.c index 580ed3cb..e56d3483 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -1027,8 +1027,9 @@ static AstNode* parse_statement(OnyxParser* parser) { break; case Token_Type_Keyword_Break: { - AstBreak* bnode = make_node(AstBreak, Ast_Kind_Break); + AstJump* bnode = make_node(AstJump, Ast_Kind_Jump); bnode->token = expect_token(parser, Token_Type_Keyword_Break); + bnode->jump = Jump_Type_Break; u64 count = 1; while (parser->curr->type == Token_Type_Keyword_Break) { @@ -1042,8 +1043,9 @@ static AstNode* parse_statement(OnyxParser* parser) { } case Token_Type_Keyword_Continue: { - AstContinue* cnode = make_node(AstBreak, Ast_Kind_Continue); + AstJump* cnode = make_node(AstJump, Ast_Kind_Jump); cnode->token = expect_token(parser, Token_Type_Keyword_Continue); + cnode->jump = Jump_Type_Continue; u64 count = 1; while (parser->curr->type == Token_Type_Keyword_Continue) { @@ -1056,6 +1058,22 @@ static AstNode* parse_statement(OnyxParser* parser) { break; } + case Token_Type_Keyword_Fallthrough: { + AstJump* cnode = make_node(AstJump, Ast_Kind_Jump); + cnode->token = expect_token(parser, Token_Type_Keyword_Fallthrough); + cnode->jump = Jump_Type_Fallthrough; + + u64 count = 1; + while (parser->curr->type == Token_Type_Keyword_Fallthrough) { + consume_token(parser); + count++; + } + cnode->count = count; + + retval = (AstNode *) cnode; + break; + } + case Token_Type_Keyword_Defer: { needs_semicolon = 0; diff --git a/src/onyxsymres.c b/src/onyxsymres.c index 169cf9ea..69813369 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -416,8 +416,7 @@ static b32 symres_statement(AstNode** stmt) { case Ast_Kind_Block: symres_block((AstBlock *) *stmt); return 0; case Ast_Kind_Defer: symres_statement(&((AstDefer *) *stmt)->stmt); return 0; - case Ast_Kind_Break: return 0; - case Ast_Kind_Continue: return 0; + case Ast_Kind_Jump: return 0; default: symres_expression((AstTyped **) stmt); return 0; } diff --git a/src/onyxwasm.c b/src/onyxwasm.c index 80936ab7..e370fa07 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -416,15 +416,15 @@ COMPILE_FUNC(block, AstBlock* block, b32 generate_block_headers) { *pcode = code; } -COMPILE_FUNC(structured_jump, i32 jump_count) { +COMPILE_FUNC(structured_jump, i32 jump_count, JumpType jump) { bh_arr(WasmInstruction) code = *pcode; + static const u8 wants[Jump_Type_Count] = { 1, 2, 3 }; + i32 labelidx = 0; - u8 wanted = (jump_count < 0) ? 2 : 1; + u8 wanted = wants[jump]; b32 success = 0; - if (jump_count < 0) jump_count = -jump_count; - i32 len = bh_arr_length(mod->structured_jump_target) - 1; for (u8* t = &bh_arr_last(mod->structured_jump_target); len >= 0; len--, t--) { if (*t == wanted) jump_count--; @@ -454,8 +454,7 @@ COMPILE_FUNC(statement, AstNode* stmt) { case Ast_Kind_While: compile_while(mod, &code, (AstIfWhile *) stmt); break; case Ast_Kind_For: compile_for(mod, &code, (AstFor *) stmt); break; case Ast_Kind_Switch: compile_switch(mod, &code, (AstSwitch *) stmt); break; - case Ast_Kind_Break: compile_structured_jump(mod, &code, ((AstBreak *) stmt)->count); break; - case Ast_Kind_Continue: compile_structured_jump(mod, &code, -((AstContinue *) stmt)->count); break; + case Ast_Kind_Jump: compile_structured_jump(mod, &code, ((AstJump *) stmt)->count, ((AstJump *) stmt)->jump); break; case Ast_Kind_Block: compile_block(mod, &code, (AstBlock *) stmt, 1); break; case Ast_Kind_Defer: compile_defer(mod, &code, (AstDefer *) stmt); break; default: compile_expression(mod, &code, (AstTyped *) stmt); break; @@ -812,9 +811,13 @@ COMPILE_FUNC(switch, AstSwitch* switch_node) { bh_imap block_map; bh_imap_init(&block_map, global_heap_allocator, bh_arr_length(switch_node->cases)); + u32 jump_target = 1; + if (switch_node->default_case != NULL) { WID(WI_BLOCK_START, 0x40); - bh_arr_push(mod->structured_jump_target, 0); + + bh_arr_push(mod->structured_jump_target, jump_target); + jump_target = 3; } u64 block_num = 0; @@ -822,7 +825,7 @@ COMPILE_FUNC(switch, AstSwitch* switch_node) { if (bh_imap_has(&block_map, (u64) sc->block)) continue; WID(WI_BLOCK_START, 0x40); - bh_arr_push(mod->structured_jump_target, 0); + bh_arr_push(mod->structured_jump_target, jump_target); bh_imap_put(&block_map, (u64) sc->block, block_num); block_num++; @@ -2800,6 +2803,23 @@ static void output_instruction(WasmFunc* func, WasmInstruction* instr, bh_buffer bh_buffer_append(buff, leb, leb_len); break; + case WI_JUMP_TABLE: { + BranchTable* bt = (BranchTable *) instr->data.p; + + leb = uint_to_uleb128((u64) bt->count, &leb_len); + bh_buffer_append(buff, leb, leb_len); + + fori (i, 0, bt->count) { + leb = uint_to_uleb128((u64) bt->cases[i], &leb_len); + bh_buffer_append(buff, leb, leb_len); + } + + leb = uint_to_uleb128((u64) bt->default_case, &leb_len); + bh_buffer_append(buff, leb, leb_len); + break; + } + + case WI_CALL_INDIRECT: case WI_I32_STORE: case WI_I32_STORE_8: