for loop supports break and continue

See #51
master
Andrew Kelley 2016-02-04 02:49:12 -07:00
parent fdadab40c6
commit 32642ac9cb
4 changed files with 47 additions and 9 deletions

View File

@ -474,6 +474,7 @@ struct AstNodeWhileExpr {
// populated by semantic analyzer
bool condition_always_true;
bool contains_break;
bool contains_continue;
Expr resolved_expr;
BlockContext *block_context;
};
@ -486,6 +487,7 @@ struct AstNodeForExpr {
// populated by semantic analyzer
bool contains_break;
bool contains_continue;
Expr resolved_expr;
VariableTableEntry *elem_var;
VariableTableEntry *index_var;

View File

@ -3354,6 +3354,7 @@ static TypeTableEntry *analyze_for_expr(CodeGen *g, ImportTableEntry *import, Bl
}
BlockContext *child_context = new_block_context(node, context);
child_context->parent_loop_node = node;
AstNode *elem_var_node = node->data.for_expr.elem_node;
elem_var_node->block_context = child_context;
@ -3385,8 +3386,13 @@ static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import,
AstNode *loop_node = context->parent_loop_node;
if (loop_node) {
assert(loop_node->type == NodeTypeWhileExpr);
loop_node->data.while_expr.contains_break = true;
if (loop_node->type == NodeTypeWhileExpr) {
loop_node->data.while_expr.contains_break = true;
} else if (loop_node->type == NodeTypeForExpr) {
loop_node->data.for_expr.contains_break = true;
} else {
zig_unreachable();
}
} else {
add_node_error(g, node, buf_sprintf("'break' expression outside loop"));
}
@ -3396,7 +3402,16 @@ static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import,
static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node)
{
if (!context->parent_loop_node) {
AstNode *loop_node = context->parent_loop_node;
if (loop_node) {
if (loop_node->type == NodeTypeWhileExpr) {
loop_node->data.while_expr.contains_continue = true;
} else if (loop_node->type == NodeTypeForExpr) {
loop_node->data.for_expr.contains_continue = true;
} else {
zig_unreachable();
}
} else {
add_node_error(g, node, buf_sprintf("'continue' expression outside loop"));
}
return g->builtin_types.entry_unreachable;

View File

@ -2089,6 +2089,7 @@ static LLVMValueRef gen_for_expr(CodeGen *g, AstNode *node) {
LLVMBasicBlockRef cond_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForCond");
LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForBody");
LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForEnd");
LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForContinue");
LLVMValueRef array_val = gen_array_base_ptr(g, node->data.for_expr.array_expr);
add_debug_source_node(g, node);
@ -2122,17 +2123,21 @@ static LLVMValueRef gen_for_expr(CodeGen *g, AstNode *node) {
gen_assign_raw(g, node, BinOpTypeAssign, elem_var->value_ref, elem_val,
elem_var->type, child_type);
g->break_block_stack.append(end_block);
g->continue_block_stack.append(cond_block);
g->continue_block_stack.append(continue_block);
gen_expr(g, node->data.for_expr.body);
g->break_block_stack.pop();
g->continue_block_stack.pop();
if (get_expr_type(node->data.for_expr.body)->id != TypeTableEntryIdUnreachable) {
add_debug_source_node(g, node);
LLVMValueRef new_index_val = LLVMBuildAdd(g->builder, index_val, one_const, "");
LLVMBuildStore(g->builder, new_index_val, index_ptr);
LLVMBuildBr(g->builder, cond_block);
LLVMBuildBr(g->builder, continue_block);
}
LLVMPositionBuilderAtEnd(g->builder, continue_block);
add_debug_source_node(g, node);
LLVMValueRef new_index_val = LLVMBuildAdd(g->builder, index_val, one_const, "");
LLVMBuildStore(g->builder, new_index_val, index_ptr);
LLVMBuildBr(g->builder, cond_block);
LLVMPositionBuilderAtEnd(g->builder, end_block);
return nullptr;
}

View File

@ -52,17 +52,33 @@ error SecondError;
#attribute("test")
fn constant_enum_with_payload() {
should_be_empty(AnEnumWithPayload.Empty);
should_be_13(AnEnumWithPayload.Full(13));
should_be_not_empty(AnEnumWithPayload.Full(13));
}
fn should_be_empty(x: AnEnumWithPayload) {
if (x != AnEnumWithPayload.Empty) unreachable{}
}
fn should_be_13(x: AnEnumWithPayload) {
fn should_be_not_empty(x: AnEnumWithPayload) {
if (x == AnEnumWithPayload.Empty) unreachable{}
}
enum AnEnumWithPayload {
Empty,
Full: i32,
}
#attribute("test")
fn continue_in_for_loop() {
const array = []i32 {1, 2, 3, 4, 5};
var sum : i32 = 0;
for (x, array) {
sum += x;
if (x < 3) {
continue;
}
break;
}
if (sum != 6) unreachable{}
}