authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-02-04 02:49:12-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-02-04 02:49:12-07:00
log32642ac9cb00b59fef97c1888e0424b0eb4db784
tree11fc77184d633811f0a78289d0feb7c663175f08
parentfdadab40c61a6f70a65472cc95ccd5ba52c01772

for loop supports break and continue

See #51

4 files changed, 47 insertions(+), 9 deletions(-)

src/all_types.hpp+2
......@@ -474,6 +474,7 @@ struct AstNodeWhileExpr {
474474 // populated by semantic analyzer
475475 bool condition_always_true;
476476 bool contains_break;
477 bool contains_continue;
477478 Expr resolved_expr;
478479 BlockContext *block_context;
479480};
......@@ -486,6 +487,7 @@ struct AstNodeForExpr {
486487
487488 // populated by semantic analyzer
488489 bool contains_break;
490 bool contains_continue;
489491 Expr resolved_expr;
490492 VariableTableEntry *elem_var;
491493 VariableTableEntry *index_var;
src/analyze.cpp+18-3
......@@ -3354,6 +3354,7 @@ static TypeTableEntry *analyze_for_expr(CodeGen *g, ImportTableEntry *import, Bl
33543354 }
33553355
33563356 BlockContext *child_context = new_block_context(node, context);
3357 child_context->parent_loop_node = node;
33573358
33583359 AstNode *elem_var_node = node->data.for_expr.elem_node;
33593360 elem_var_node->block_context = child_context;
......@@ -3385,8 +3386,13 @@ static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import,
33853386
33863387 AstNode *loop_node = context->parent_loop_node;
33873388 if (loop_node) {
3388 assert(loop_node->type == NodeTypeWhileExpr);
3389 loop_node->data.while_expr.contains_break = true;
3389 if (loop_node->type == NodeTypeWhileExpr) {
3390 loop_node->data.while_expr.contains_break = true;
3391 } else if (loop_node->type == NodeTypeForExpr) {
3392 loop_node->data.for_expr.contains_break = true;
3393 } else {
3394 zig_unreachable();
3395 }
33903396 } else {
33913397 add_node_error(g, node, buf_sprintf("'break' expression outside loop"));
33923398 }
......@@ -3396,7 +3402,16 @@ static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import,
33963402static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
33973403 TypeTableEntry *expected_type, AstNode *node)
33983404{
3399 if (!context->parent_loop_node) {
3405 AstNode *loop_node = context->parent_loop_node;
3406 if (loop_node) {
3407 if (loop_node->type == NodeTypeWhileExpr) {
3408 loop_node->data.while_expr.contains_continue = true;
3409 } else if (loop_node->type == NodeTypeForExpr) {
3410 loop_node->data.for_expr.contains_continue = true;
3411 } else {
3412 zig_unreachable();
3413 }
3414 } else {
34003415 add_node_error(g, node, buf_sprintf("'continue' expression outside loop"));
34013416 }
34023417 return g->builtin_types.entry_unreachable;
src/codegen.cpp+9-4
......@@ -2089,6 +2089,7 @@ static LLVMValueRef gen_for_expr(CodeGen *g, AstNode *node) {
20892089 LLVMBasicBlockRef cond_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForCond");
20902090 LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForBody");
20912091 LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForEnd");
2092 LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForContinue");
20922093
20932094 LLVMValueRef array_val = gen_array_base_ptr(g, node->data.for_expr.array_expr);
20942095 add_debug_source_node(g, node);
......@@ -2122,17 +2123,21 @@ static LLVMValueRef gen_for_expr(CodeGen *g, AstNode *node) {
21222123 gen_assign_raw(g, node, BinOpTypeAssign, elem_var->value_ref, elem_val,
21232124 elem_var->type, child_type);
21242125 g->break_block_stack.append(end_block);
2125 g->continue_block_stack.append(cond_block);
2126 g->continue_block_stack.append(continue_block);
21262127 gen_expr(g, node->data.for_expr.body);
21272128 g->break_block_stack.pop();
21282129 g->continue_block_stack.pop();
21292130 if (get_expr_type(node->data.for_expr.body)->id != TypeTableEntryIdUnreachable) {
21302131 add_debug_source_node(g, node);
2131 LLVMValueRef new_index_val = LLVMBuildAdd(g->builder, index_val, one_const, "");
2132 LLVMBuildStore(g->builder, new_index_val, index_ptr);
2133 LLVMBuildBr(g->builder, cond_block);
2132 LLVMBuildBr(g->builder, continue_block);
21342133 }
21352134
2135 LLVMPositionBuilderAtEnd(g->builder, continue_block);
2136 add_debug_source_node(g, node);
2137 LLVMValueRef new_index_val = LLVMBuildAdd(g->builder, index_val, one_const, "");
2138 LLVMBuildStore(g->builder, new_index_val, index_ptr);
2139 LLVMBuildBr(g->builder, cond_block);
2140
21362141 LLVMPositionBuilderAtEnd(g->builder, end_block);
21372142 return nullptr;
21382143}
test/self_hosted.zig+18-2
......@@ -52,17 +52,33 @@ error SecondError;
5252#attribute("test")
5353fn constant_enum_with_payload() {
5454 should_be_empty(AnEnumWithPayload.Empty);
55 should_be_13(AnEnumWithPayload.Full(13));
55 should_be_not_empty(AnEnumWithPayload.Full(13));
5656}
5757
5858fn should_be_empty(x: AnEnumWithPayload) {
5959 if (x != AnEnumWithPayload.Empty) unreachable{}
6060}
6161
62fn should_be_13(x: AnEnumWithPayload) {
62fn should_be_not_empty(x: AnEnumWithPayload) {
63 if (x == AnEnumWithPayload.Empty) unreachable{}
6364}
6465
6566enum AnEnumWithPayload {
6667 Empty,
6768 Full: i32,
6869}
70
71
72#attribute("test")
73fn continue_in_for_loop() {
74 const array = []i32 {1, 2, 3, 4, 5};
75 var sum : i32 = 0;
76 for (x, array) {
77 sum += x;
78 if (x < 3) {
79 continue;
80 }
81 break;
82 }
83 if (sum != 6) unreachable{}
84}