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 {...@@ -474,6 +474,7 @@ struct AstNodeWhileExpr {
474 // populated by semantic analyzer474 // populated by semantic analyzer
475 bool condition_always_true;475 bool condition_always_true;
476 bool contains_break;476 bool contains_break;
477 bool contains_continue;
477 Expr resolved_expr;478 Expr resolved_expr;
478 BlockContext *block_context;479 BlockContext *block_context;
479};480};
...@@ -486,6 +487,7 @@ struct AstNodeForExpr {...@@ -486,6 +487,7 @@ struct AstNodeForExpr {
486487
487 // populated by semantic analyzer488 // populated by semantic analyzer
488 bool contains_break;489 bool contains_break;
490 bool contains_continue;
489 Expr resolved_expr;491 Expr resolved_expr;
490 VariableTableEntry *elem_var;492 VariableTableEntry *elem_var;
491 VariableTableEntry *index_var;493 VariableTableEntry *index_var;
src/analyze.cpp+18-3
...@@ -3354,6 +3354,7 @@ static TypeTableEntry *analyze_for_expr(CodeGen *g, ImportTableEntry *import, Bl...@@ -3354,6 +3354,7 @@ static TypeTableEntry *analyze_for_expr(CodeGen *g, ImportTableEntry *import, Bl
3354 }3354 }
33553355
3356 BlockContext *child_context = new_block_context(node, context);3356 BlockContext *child_context = new_block_context(node, context);
3357 child_context->parent_loop_node = node;
33573358
3358 AstNode *elem_var_node = node->data.for_expr.elem_node;3359 AstNode *elem_var_node = node->data.for_expr.elem_node;
3359 elem_var_node->block_context = child_context;3360 elem_var_node->block_context = child_context;
...@@ -3385,8 +3386,13 @@ static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import,...@@ -3385,8 +3386,13 @@ static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import,
33853386
3386 AstNode *loop_node = context->parent_loop_node;3387 AstNode *loop_node = context->parent_loop_node;
3387 if (loop_node) {3388 if (loop_node) {
3388 assert(loop_node->type == NodeTypeWhileExpr);3389 if (loop_node->type == NodeTypeWhileExpr) {
3389 loop_node->data.while_expr.contains_break = true;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 }
3390 } else {3396 } else {
3391 add_node_error(g, node, buf_sprintf("'break' expression outside loop"));3397 add_node_error(g, node, buf_sprintf("'break' expression outside loop"));
3392 }3398 }
...@@ -3396,7 +3402,16 @@ static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import,...@@ -3396,7 +3402,16 @@ static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import,
3396static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,3402static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
3397 TypeTableEntry *expected_type, AstNode *node)3403 TypeTableEntry *expected_type, AstNode *node)
3398{3404{
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 {
3400 add_node_error(g, node, buf_sprintf("'continue' expression outside loop"));3415 add_node_error(g, node, buf_sprintf("'continue' expression outside loop"));
3401 }3416 }
3402 return g->builtin_types.entry_unreachable;3417 return g->builtin_types.entry_unreachable;
src/codegen.cpp+9-4
...@@ -2089,6 +2089,7 @@ static LLVMValueRef gen_for_expr(CodeGen *g, AstNode *node) {...@@ -2089,6 +2089,7 @@ static LLVMValueRef gen_for_expr(CodeGen *g, AstNode *node) {
2089 LLVMBasicBlockRef cond_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForCond");2089 LLVMBasicBlockRef cond_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForCond");
2090 LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForBody");2090 LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForBody");
2091 LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForEnd");2091 LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForEnd");
2092 LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForContinue");
20922093
2093 LLVMValueRef array_val = gen_array_base_ptr(g, node->data.for_expr.array_expr);2094 LLVMValueRef array_val = gen_array_base_ptr(g, node->data.for_expr.array_expr);
2094 add_debug_source_node(g, node);2095 add_debug_source_node(g, node);
...@@ -2122,17 +2123,21 @@ static LLVMValueRef gen_for_expr(CodeGen *g, AstNode *node) {...@@ -2122,17 +2123,21 @@ static LLVMValueRef gen_for_expr(CodeGen *g, AstNode *node) {
2122 gen_assign_raw(g, node, BinOpTypeAssign, elem_var->value_ref, elem_val,2123 gen_assign_raw(g, node, BinOpTypeAssign, elem_var->value_ref, elem_val,
2123 elem_var->type, child_type);2124 elem_var->type, child_type);
2124 g->break_block_stack.append(end_block);2125 g->break_block_stack.append(end_block);
2125 g->continue_block_stack.append(cond_block);2126 g->continue_block_stack.append(continue_block);
2126 gen_expr(g, node->data.for_expr.body);2127 gen_expr(g, node->data.for_expr.body);
2127 g->break_block_stack.pop();2128 g->break_block_stack.pop();
2128 g->continue_block_stack.pop();2129 g->continue_block_stack.pop();
2129 if (get_expr_type(node->data.for_expr.body)->id != TypeTableEntryIdUnreachable) {2130 if (get_expr_type(node->data.for_expr.body)->id != TypeTableEntryIdUnreachable) {
2130 add_debug_source_node(g, node);2131 add_debug_source_node(g, node);
2131 LLVMValueRef new_index_val = LLVMBuildAdd(g->builder, index_val, one_const, "");2132 LLVMBuildBr(g->builder, continue_block);
2132 LLVMBuildStore(g->builder, new_index_val, index_ptr);
2133 LLVMBuildBr(g->builder, cond_block);
2134 }2133 }
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
2136 LLVMPositionBuilderAtEnd(g->builder, end_block);2141 LLVMPositionBuilderAtEnd(g->builder, end_block);
2137 return nullptr;2142 return nullptr;
2138}2143}
test/self_hosted.zig+18-2
...@@ -52,17 +52,33 @@ error SecondError;...@@ -52,17 +52,33 @@ error SecondError;
52#attribute("test")52#attribute("test")
53fn constant_enum_with_payload() {53fn constant_enum_with_payload() {
54 should_be_empty(AnEnumWithPayload.Empty);54 should_be_empty(AnEnumWithPayload.Empty);
55 should_be_13(AnEnumWithPayload.Full(13));55 should_be_not_empty(AnEnumWithPayload.Full(13));
56}56}
5757
58fn should_be_empty(x: AnEnumWithPayload) {58fn should_be_empty(x: AnEnumWithPayload) {
59 if (x != AnEnumWithPayload.Empty) unreachable{}59 if (x != AnEnumWithPayload.Empty) unreachable{}
60}60}
6161
62fn should_be_13(x: AnEnumWithPayload) {62fn should_be_not_empty(x: AnEnumWithPayload) {
63 if (x == AnEnumWithPayload.Empty) unreachable{}
63}64}
6465
65enum AnEnumWithPayload {66enum AnEnumWithPayload {
66 Empty,67 Empty,
67 Full: i32,68 Full: i32,
68}69}
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}