tcp_server_handle_events :: macro (server: ^TCP_Server, handler: Code) {
while server->pulse() {
- for server->get_events() {
- #insert handler;
- }
+ for server->get_events() do switch it.kind do #insert handler;
}
}
} CaseToBlock;
struct AstSwitchCase {
+ AstNode_base;
+
// NOTE: All expressions that end up in this block
bh_arr(AstTyped *) values;
AstBlock *block;
+
+ b32 is_default: 1; // Could this be inferred by the values array being null?
};
struct AstSwitch {
AstTyped *expr;
- bh_arr(AstSwitchCase) cases;
+ AstBlock *case_block;
+
+ bh_arr(AstSwitchCase *) cases;
AstBlock *default_case;
i32 yield_return_index;
"USE",
"DEFER",
"SWITCH",
- "SWITCH CASE",
+ "CASE",
"SOLIDIFY",
"STATIC IF",
return 0;
}
+static CheckStatus collect_switch_case_blocks(AstSwitch* switchnode, AstBlock* root) {
+ AstNode *walker = root->body;
+ while (walker != NULL) {
+ switch (walker->kind) {
+ case Ast_Kind_Block:
+ collect_switch_case_blocks(switchnode, (AstBlock *) walker);
+ break;
+
+ case Ast_Kind_Switch_Case: {
+ AstSwitchCase *case_node = (AstSwitchCase *) walker;
+ if (case_node->is_default) {
+ if (switchnode->default_case != NULL && switchnode->default_case != case_node->block) {
+ ERROR(case_node->token->pos, "Multiple #default cases given");
+ ERROR(switchnode->default_case->token->pos, "Multiple #default cases given");
+ return Check_Error;
+ }
+
+ switchnode->default_case = case_node->block;
+ } else {
+ bh_arr_push(switchnode->cases, case_node);
+ }
+ break;
+ }
+
+ default:
+ ERROR(walker->token->pos, "This statement is not allowed here.");
+ }
+
+ walker = walker->next;
+ }
+
+ return Check_Success;
+}
+
CheckStatus check_switch(AstSwitch* switchnode) {
if (switchnode->initialization != NULL) CHECK(statement_chain, &switchnode->initialization);
switch (switchnode->switch_kind) {
case Switch_Kind_Integer:
switchnode->min_case = 0xffffffffffffffff;
- bh_imap_init(&switchnode->case_map, global_heap_allocator, bh_arr_length(switchnode->cases) * 2);
+ bh_imap_init(&switchnode->case_map, global_heap_allocator, 4);
break;
case Switch_Kind_Use_Equals:
- // Guessing the maximum number of case expressions there will be.
- bh_arr_new(global_heap_allocator, switchnode->case_exprs, bh_arr_length(switchnode->cases) * 2);
+ bh_arr_new(global_heap_allocator, switchnode->case_exprs, 4);
break;
default: assert(0);
}
switchnode->flags |= Ast_Flag_Has_Been_Checked;
+ // Should the case block code be checked here?
+ // Or should this just exist to resolve macros and expand #inserts
+ // then the cases are consumed into the array or cases, THEN the blocks
+ // are actually checked?
+ if (switchnode->cases == NULL) {
+ CHECK(block, switchnode->case_block);
+
+ bh_arr_new(global_heap_allocator, switchnode->cases, 4);
+ if (collect_switch_case_blocks(switchnode, switchnode->case_block) != Check_Success) {
+ return Check_Error;
+ }
+
+ // This is important, otherwise if this block has to return to symbol resolution.
+ switchnode->case_block->statement_idx = 0;
+ }
+
fori (i, switchnode->yield_return_index, bh_arr_length(switchnode->cases)) {
- AstSwitchCase *sc = &switchnode->cases[i];
+ AstSwitchCase *sc = switchnode->cases[i];
CHECK(block, sc->block);
bh_arr_each(AstTyped *, value, sc->values) {
case Ast_Kind_Error: break;
case Ast_Kind_Unary_Field_Access: break;
case Ast_Kind_Constraint_Sentinel: break;
+ case Ast_Kind_Switch_Case: break;
default:
retval = Check_Error;
C(AstIfWhile, false_stmt);
break;
+ case Ast_Kind_Switch_Case: {
+ C(AstSwitchCase, block);
+
+ AstSwitchCase *dw = (AstSwitchCase *) nn;
+ AstSwitchCase *sw = (AstSwitchCase *) node;
+
+ dw->values = NULL;
+ bh_arr_new(global_heap_allocator, dw->values, bh_arr_length(sw->values));
+ bh_arr_each(AstTyped *, value, sw->values)
+ bh_arr_push(dw->values, (AstTyped *) ast_clone(a, *value));
+
+ break;
+ }
+
case Ast_Kind_Switch: {
AstSwitch* dw = (AstSwitch *) nn;
AstSwitch* sw = (AstSwitch *) node;
- ((AstSwitch *) nn)->initialization = ast_clone_list(a, ((AstSwitch *) node)->initialization);
- dw->expr = (AstTyped *) ast_clone(a, sw->expr);
+ dw->initialization = ast_clone_list(a, sw->initialization);
+ C(AstSwitch, expr);
- dw->default_case = (AstBlock *) ast_clone(a, sw->default_case);
dw->cases = NULL;
- 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.values = new_values;
- sc.block = (AstBlock *) ast_clone(a, c->block);
- bh_arr_push(dw->cases, sc);
- }
+ C(AstSwitch, case_block);
break;
}
"typeof",
"defer",
"do",
- "switch",
"case",
+ "switch",
"fallthrough",
"macro",
"interface",
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 i32 parse_possible_symbol_declaration(OnyxParser* parser, AstNode** ret);
static AstReturn* parse_return_stmt(OnyxParser* parser);
return for_node;
}
+static AstSwitchCase* parse_case_stmt(OnyxParser* parser) {
+ AstSwitchCase *sc_node = make_node(AstSwitchCase, Ast_Kind_Switch_Case);
+ sc_node->token = expect_token(parser, Token_Type_Keyword_Case);
+
+ if (parse_possible_directive(parser, "default")) {
+ sc_node->is_default = 1;
+
+ } else {
+ bh_arr_new(global_heap_allocator, sc_node->values, 1);
+
+ AstTyped* value = parse_expression(parser, 1);
+ bh_arr_push(sc_node->values, value);
+ while (consume_token_if_next(parser, ',')) {
+ if (parser->hit_unexpected_token) return sc_node;
+
+ value = parse_expression(parser, 1);
+ bh_arr_push(sc_node->values, value);
+ }
+ }
+
+ sc_node->block = parse_block(parser, 1, NULL);
+
+ return sc_node;
+}
+
static AstSwitch* parse_switch_stmt(OnyxParser* parser) {
AstSwitch* switch_node = make_node(AstSwitch, Ast_Kind_Switch);
switch_node->token = expect_token(parser, Token_Type_Keyword_Switch);
- bh_arr_new(global_heap_allocator, switch_node->cases, 4);
-
AstTyped* expr;
AstNode* initialization_or_expr=NULL;
b32 had_initialization = 0;
switch_node->initialization = initialization_or_expr;
switch_node->expr = expr;
- expect_token(parser, '{');
-
- while (consume_token_if_next(parser, Token_Type_Keyword_Case)) {
- if (parser->hit_unexpected_token) return switch_node;
-
- bh_arr(AstTyped *) case_values = NULL;
- bh_arr_new(global_heap_allocator, case_values, 1);
-
- if (parse_possible_directive(parser, "default")) {
- switch_node->default_case = parse_block(parser, 1, NULL);
-
- if (parser->curr->type != '}') {
- onyx_report_error(parser->curr->pos, Error_Critical, "The #default case must be the last case in a switch statement.\n");
- }
- break;
- }
-
- AstTyped* value = parse_expression(parser, 1);
- bh_arr_push(case_values, value);
- while (consume_token_if_next(parser, ',')) {
- if (parser->hit_unexpected_token) return switch_node;
-
- value = parse_expression(parser, 1);
- bh_arr_push(case_values, value);
- }
-
- AstBlock* block = parse_block(parser, 1, NULL);
-
- AstSwitchCase sc_node;
- sc_node.block = block;
- sc_node.values = case_values;
-
- bh_arr_push(switch_node->cases, sc_node);
- }
-
- expect_token(parser, '}');
+ switch_node->case_block = parse_block(parser, 1, NULL);
return switch_node;
}
retval = (AstNode *) parse_switch_stmt(parser);
break;
+ case Token_Type_Keyword_Case:
+ needs_semicolon = 0;
+ retval = (AstNode *) parse_case_stmt(parser);
+ break;
+
case Token_Type_Keyword_Break:
retval = parse_jump_stmt(parser, Token_Type_Keyword_Break, Jump_Type_Break);
break;
static SymresStatus symres_if(AstIfWhile* ifnode);
static SymresStatus symres_while(AstIfWhile* whilenode);
static SymresStatus symres_for(AstFor* fornode);
+static SymresStatus symres_case(AstSwitchCase *casenode);
static SymresStatus symres_switch(AstSwitch* switchnode);
static SymresStatus symres_use(AstUse* use);
static SymresStatus symres_directive_solidify(AstDirectiveSolidify** psolid);
return Symres_Success;
}
+static SymresStatus symres_case(AstSwitchCase *casenode) {
+ if (!casenode->is_default) {
+ bh_arr_each(AstTyped *, expr, casenode->values) {
+ SYMRES(expression, expr);
+ }
+ }
+
+ SYMRES(block, casenode->block);
+ return Symres_Success;
+}
+
static SymresStatus symres_switch(AstSwitch* switchnode) {
if (switchnode->initialization != NULL) {
switchnode->scope = scope_create(context.ast_alloc, curr_scope, switchnode->token->pos);
SYMRES(expression, &switchnode->expr);
- bh_arr_each(AstSwitchCase, sc, switchnode->cases) {
- bh_arr_each(AstTyped *, value, sc->values)
- SYMRES(expression, value);
-
- SYMRES(block, sc->block);
- }
-
- if (switchnode->default_case)
- SYMRES(block, switchnode->default_case);
+ SYMRES(block, switchnode->case_block);
if (switchnode->switch_kind == Switch_Kind_Use_Equals && switchnode->case_exprs) {
bh_arr_each(CaseToBlock, ctb, switchnode->case_exprs) {
case Ast_Kind_Argument: SYMRES(expression, (AstTyped **) &((AstArgument *) *stmt)->value); break;
case Ast_Kind_Block: SYMRES(block, (AstBlock *) *stmt); break;
case Ast_Kind_Defer: SYMRES(statement, &((AstDefer *) *stmt)->stmt, NULL); break;
+ case Ast_Kind_Switch_Case: SYMRES(case, (AstSwitchCase *) *stmt); break;
case Ast_Kind_Jump: break;
case Ast_Kind_Local:
emit_enter_structured_block(mod, &code, SBT_Breakable_Block);
u64 block_num = 0;
- bh_arr_each(AstSwitchCase, sc, switch_node->cases) {
- if (bh_imap_has(&block_map, (u64) sc->block)) continue;
+ bh_arr_each(AstSwitchCase *, sc, switch_node->cases) {
+ if (bh_imap_has(&block_map, (u64) (*sc)->block)) continue;
emit_enter_structured_block(mod, &code, SBT_Fallthrough_Block);
- bh_imap_put(&block_map, (u64) sc->block, block_num);
+ bh_imap_put(&block_map, (u64) (*sc)->block, block_num);
block_num++;
}
}
}
- bh_arr_each(AstSwitchCase, sc, switch_node->cases) {
+ bh_arr_each(AstSwitchCase *, psc, switch_node->cases) {
+ AstSwitchCase *sc = *psc;
if (bh_imap_get(&block_map, (u64) sc->block) == 0xdeadbeef) continue;
u64 bn = bh_imap_get(&block_map, (u64) sc->block);
break;
}
+ case Ast_Kind_Switch_Case: {
+ // This error message should be moved to checking, but this is the
+ // best place to do it right now.
+ onyx_report_error(expr->token->pos, Error_Critical, "'case' statements are only allowed in a 'switch' statement.");
+ break;
+ }
+
default:
bh_printf("Unhandled case: %d\n", expr->kind);
DEBUG_HERE;
Vector2 :: struct { x, y: i32; }
#operator == macro (v1: Vector2, v2: Vector2) => v1.x == v2.x && v1.y == v2.y;
+none_of_the_above :: #code {
+ case #default {
+ println("Got default!");
+ }
+}
+
main :: (args: [] cstr) {
for .[ "Some", "Thing", "Other" ] {
switch it {
case "Thing" do println("Got thing!");
case "Some" do println("Got some!");
- case #default do println("Got default!");
+ #insert none_of_the_above;
}
}
case .{ 0, 1 } do println("0, 1");
case .{ 1, 0 } do println("1, 0");
case .{ 1, 1 } do println("1, 1");
- case #default do println("none of the above.");
+
+ #insert none_of_the_above;
}
}
\ No newline at end of file