瀏覽代碼

Add named branches for match statements

Ginger Bill 8 年之前
父節點
當前提交
c34d839f9f
共有 3 個文件被更改,包括 69 次插入111 次删除
  1. 1 2
      code/demo.odin
  2. 41 45
      src/ir.c
  3. 27 64
      src/parser.c

+ 1 - 2
code/demo.odin

@@ -66,7 +66,6 @@ main :: proc() {
 				}
 			}
 		}
-		return;
 	}
 
 	{
@@ -82,7 +81,7 @@ main :: proc() {
 		// Ternary operator
 		y := cond ? 3 : 4;
 
-		FOO :: true ? 123 : 432; // Constant ternary operation
+		FOO :: true ? 123 : 432; // Constant ternary expression
 		fmt.println("Ternary values:", y, FOO);
 	}
 

+ 41 - 45
src/ir.c

@@ -2867,14 +2867,48 @@ void ir_mangle_add_sub_type_name(irModule *m, Entity *field, String parent) {
 }
 
 
+irBranchBlocks ir_lookup_branch_blocks(irProcedure *proc, AstNode *ident) {
+	GB_ASSERT(ident->kind == AstNode_Ident);
+	Entity **found = map_entity_get(&proc->module->info->uses, hash_pointer(ident));
+	GB_ASSERT(found != NULL);
+	Entity *e = *found;
+	GB_ASSERT(e->kind == Entity_Label);
+	for_array(i, proc->branch_blocks) {
+		irBranchBlocks *b = &proc->branch_blocks.e[i];
+		if (b->label == e->Label.node) {
+			return *b;
+		}
+	}
 
-void ir_push_target_list(irProcedure *proc, irBlock *break_, irBlock *continue_, irBlock *fallthrough_) {
+	GB_PANIC("Unreachable");
+	return (irBranchBlocks){0};
+}
+
+
+void ir_push_target_list(irProcedure *proc, AstNode *label, irBlock *break_, irBlock *continue_, irBlock *fallthrough_) {
 	irTargetList *tl = gb_alloc_item(proc->module->allocator, irTargetList);
 	tl->prev          = proc->target_list;
 	tl->break_        = break_;
 	tl->continue_     = continue_;
 	tl->fallthrough_  = fallthrough_;
 	proc->target_list = tl;
+
+	if (label != NULL) { // Set label blocks
+		GB_ASSERT(label->kind == AstNode_Label);
+
+		for_array(i, proc->branch_blocks) {
+			irBranchBlocks *b = &proc->branch_blocks.e[i];
+			GB_ASSERT(b->label != NULL && label != NULL);
+			GB_ASSERT(b->label->kind == AstNode_Label);
+			if (b->label == label) {
+				b->break_    = break_;
+				b->continue_ = continue_;
+				return;
+			}
+		}
+
+		GB_PANIC("ir_set_label_blocks: Unreachable");
+	}
 }
 
 void ir_pop_target_list(irProcedure *proc) {
@@ -4842,43 +4876,7 @@ void ir_build_range_interval(irProcedure *proc, AstNodeIntervalExpr *node, Type
 	if (done_) *done_ = done;
 }
 
-void ir_set_label_blocks(irProcedure *proc, AstNode *label, irBlock *break_, irBlock *continue_) {
-	if (label == NULL) {
-		return;
-	}
-	GB_ASSERT(label->kind == AstNode_Label);
-
 
-	for_array(i, proc->branch_blocks) {
-		irBranchBlocks *b = &proc->branch_blocks.e[i];
-		GB_ASSERT(b->label != NULL && label != NULL);
-		GB_ASSERT(b->label->kind == AstNode_Label);
-		if (b->label == label) {
-			b->break_    = break_;
-			b->continue_ = continue_;
-			return;
-		}
-	}
-
-	GB_PANIC("ir_set_label_blocks: Unreachable");
-}
-
-irBranchBlocks ir_lookup_branch_blocks(irProcedure *proc, AstNode *ident) {
-	GB_ASSERT(ident->kind == AstNode_Ident);
-	Entity **found = map_entity_get(&proc->module->info->uses, hash_pointer(ident));
-	GB_ASSERT(found != NULL);
-	Entity *e = *found;
-	GB_ASSERT(e->kind == Entity_Label);
-	for_array(i, proc->branch_blocks) {
-		irBranchBlocks *b = &proc->branch_blocks.e[i];
-		if (b->label == e->Label.node) {
-			return *b;
-		}
-	}
-
-	GB_PANIC("Unreachable");
-	return (irBranchBlocks){0};
-}
 
 
 void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
@@ -5264,8 +5262,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 			ir_start_block(proc, body);
 		}
 
-		ir_set_label_blocks(proc, fs->label, done, post);
-		ir_push_target_list(proc, done, post, NULL);
+		ir_push_target_list(proc, fs->label, done, post, NULL);
 
 		ir_open_scope(proc);
 		ir_build_stmt(proc, fs->body);
@@ -5399,8 +5396,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 			ir_addr_store(proc, idx_addr, index);
 		}
 
-		ir_set_label_blocks(proc, rs->label, done, loop);
-		ir_push_target_list(proc, done, loop, NULL);
+		ir_push_target_list(proc, rs->label, done, loop, NULL);
 
 		ir_open_scope(proc);
 		ir_build_stmt(proc, rs->body);
@@ -5474,7 +5470,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 			}
 			ir_start_block(proc, body);
 
-			ir_push_target_list(proc, done, NULL, fall);
+			ir_push_target_list(proc, ms->label, done, NULL, fall);
 			ir_open_scope(proc);
 			ir_build_stmt_list(proc, cc->stmts);
 			ir_close_scope(proc, irDeferExit_Default, body);
@@ -5489,7 +5485,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 			ir_emit_jump(proc, default_block);
 			ir_start_block(proc, default_block);
 
-			ir_push_target_list(proc, done, NULL, default_fall);
+			ir_push_target_list(proc, ms->label, done, NULL, default_fall);
 			ir_open_scope(proc);
 			ir_build_stmt_list(proc, default_stmts);
 			ir_close_scope(proc, irDeferExit_Default, default_block);
@@ -5645,7 +5641,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 
 			ir_start_block(proc, body);
 
-			ir_push_target_list(proc, done, NULL, NULL);
+			ir_push_target_list(proc, ms->label, done, NULL, NULL);
 			ir_open_scope(proc);
 			ir_build_stmt_list(proc, cc->stmts);
 			ir_close_scope(proc, irDeferExit_Default, body);
@@ -5660,7 +5656,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 			ir_emit_jump(proc, default_block);
 			ir_start_block(proc, default_block);
 
-			ir_push_target_list(proc, done, NULL, NULL);
+			ir_push_target_list(proc, ms->label, done, NULL, NULL);
 			ir_open_scope(proc);
 			ir_build_stmt_list(proc, default_stmts);
 			ir_close_scope(proc, irDeferExit_Default, default_block);

+ 27 - 64
src/parser.c

@@ -241,12 +241,14 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
 	}) \
 	AST_NODE_KIND(MatchStmt, "match statement", struct { \
 		Token token;   \
+		AstNode *label; \
 		AstNode *init; \
 		AstNode *tag;  \
 		AstNode *body; \
 	}) \
 	AST_NODE_KIND(TypeMatchStmt, "type match statement", struct { \
 		Token    token; \
+		AstNode *label; \
 		AstNode *tag;   \
 		AstNode *body;  \
 	}) \
@@ -876,10 +878,9 @@ AstNode *ast_return_stmt(AstFile *f, Token token, AstNodeArray results) {
 }
 
 
-AstNode *ast_for_stmt(AstFile *f, Token token, AstNode *label, AstNode *init, AstNode *cond, AstNode *post, AstNode *body) {
+AstNode *ast_for_stmt(AstFile *f, Token token, AstNode *init, AstNode *cond, AstNode *post, AstNode *body) {
 	AstNode *result = make_ast_node(f, AstNode_ForStmt);
 	result->ForStmt.token = token;
-	result->ForStmt.label = label;
 	result->ForStmt.init  = init;
 	result->ForStmt.cond  = cond;
 	result->ForStmt.post  = post;
@@ -887,9 +888,8 @@ AstNode *ast_for_stmt(AstFile *f, Token token, AstNode *label, AstNode *init, As
 	return result;
 }
 
-AstNode *ast_range_stmt(AstFile *f, Token token, AstNode *label, AstNode *value, AstNode *index, Token in_token, AstNode *expr, AstNode *body) {
+AstNode *ast_range_stmt(AstFile *f, Token token, AstNode *value, AstNode *index, Token in_token, AstNode *expr, AstNode *body) {
 	AstNode *result = make_ast_node(f, AstNode_RangeStmt);
-	result->RangeStmt.label = label;
 	result->RangeStmt.token = token;
 	result->RangeStmt.value = value;
 	result->RangeStmt.index = index;
@@ -3009,7 +3009,7 @@ AstNode *parse_return_stmt(AstFile *f) {
 // 	return ast_expr_stmt(f, ge);
 // }
 
-AstNode *parse_for_stmt(AstFile *f, AstNode *label) {
+AstNode *parse_for_stmt(AstFile *f) {
 	if (f->curr_proc == NULL) {
 		syntax_error(f->curr_token, "You cannot use a for statement in the file scope");
 		return ast_bad_stmt(f, f->curr_token, f->curr_token);
@@ -3073,51 +3073,11 @@ AstNode *parse_for_stmt(AstFile *f, AstNode *label) {
 		if (cond->AssignStmt.rhs.count > 0) {
 			rhs = cond->AssignStmt.rhs.e[0];
 		}
-		return ast_range_stmt(f, token, label, value, index, in_token, rhs, body);
+		return ast_range_stmt(f, token, value, index, in_token, rhs, body);
 	}
 
 	cond = convert_stmt_to_expr(f, cond, str_lit("boolean expression"));
-	return ast_for_stmt(f, token, label, init, cond, post, body);
-
-#if 0
-	Token token = expect_token(f, Token_for);
-	AstNodeArray names = parse_ident_list(f);
-	parse_check_name_list_for_reserves(f, names);
-	Token colon = expect_token_after(f, Token_in, "for name list");
-
-	isize prev_level = f->expr_level;
-	f->expr_level = -1;
-	AstNode *expr = parse_expr(f, false);
-	switch (f->curr_token.kind) {
-	case Token_HalfOpenRange:
-	case Token_Ellipsis: {
-		Token op = f->curr_token;
-		next_token(f);
-		AstNode *right = parse_expr(f, false);
-		expr = ast_interval_expr(f, op, expr, right);
-	} break;
-	}
-	f->expr_level = prev_level;
-
-	AstNode *value = NULL;
-	AstNode *index = NULL;
-	AstNode *body  = parse_block_stmt(f, false);
-
-	switch (names.count) {
-	case 1:
-		value = names.e[0];
-		break;
-	case 2:
-		value = names.e[0];
-		index = names.e[1];
-		break;
-	default:
-		error(token, "Expected at 1 or 2 identifiers");
-		return ast_bad_stmt(f, token, f->curr_token);
-	}
-
-	return ast_range_stmt(f, token, value, index, expr, body);
-#endif
+	return ast_for_stmt(f, token, init, cond, post, body);
 }
 
 
@@ -3284,7 +3244,7 @@ AstNode *parse_stmt(AstFile *f) {
 
 	case Token_if:     return parse_if_stmt(f);
 	case Token_when:   return parse_when_stmt(f);
-	case Token_for:    return parse_for_stmt(f, NULL);
+	case Token_for:    return parse_for_stmt(f);
 	case Token_match:  return parse_match_stmt(f);
 	case Token_defer:  return parse_defer_stmt(f);
 	case Token_asm:    return parse_asm_stmt(f);
@@ -3386,7 +3346,25 @@ AstNode *parse_stmt(AstFile *f) {
 		Token name = expect_token(f, Token_Ident);
 		String tag = name.string;
 
-		if (str_eq(tag, str_lit("import"))) {
+		if (str_eq(tag, str_lit("label"))) {
+			AstNode *name  = parse_ident(f);
+			AstNode *label = ast_label_decl(f, token, name);
+			AstNode *stmt  = parse_stmt(f);
+
+		#define _SET_LABEL(Kind_, label_) case GB_JOIN2(AstNode_, Kind_): (stmt->Kind_).label = label_; break
+			switch (stmt->kind) {
+			_SET_LABEL(ForStmt, label);
+			_SET_LABEL(RangeStmt, label);
+			_SET_LABEL(MatchStmt, label);
+			_SET_LABEL(TypeMatchStmt, label);
+			default:
+				syntax_error(token, "#label may only be applied to a loop");
+				break;
+			}
+		#undef _SET_LABEL
+
+			return stmt;
+		} else if (str_eq(tag, str_lit("import"))) {
 			AstNode *cond = NULL;
 			Token import_name = {0};
 
@@ -3544,23 +3522,8 @@ AstNode *parse_stmt(AstFile *f) {
 				syntax_error(token, "#bounds_check and #no_bounds_check cannot be applied together");
 			}
 			return s;
-		} else if (str_eq(tag, str_lit("label"))) {
-			AstNode *name = parse_ident(f);
-			AstNode *label = ast_label_decl(f, token, name);
-
-			Token tok = f->curr_token;
-			switch (tok.kind) {
-			case Token_for:
-				return parse_for_stmt(f, label);
-			default:
-				syntax_error(token, "#label may only be applied to a loop");
-				fix_advance_to_next_stmt(f);
-				s = ast_bad_stmt(f, token, f->curr_token);
-				return s;
-			}
 		}
 
-
 		if (str_eq(tag, str_lit("include"))) {
 			syntax_error(token, "#include is not a valid import declaration kind. Use #load instead");
 			s = ast_bad_stmt(f, token, f->curr_token);