authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-04-19 20:28:44-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-04-19 20:28:44-07:00
loga25307c0a1b45d0c7b83158349fbc57626baf656
tree3a7035c0f54e29298f8f7330239db6fea5097556
parent04364c45cefbba9451af202ceab5ae528cc8bbaa

add optional continue expression to while loop

closes #139

9 files changed, 69 insertions(+), 16 deletions(-)

doc/langref.md+1-1
...@@ -79,7 +79,7 @@ SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" "Symbol" "|") Exp...@@ -79,7 +79,7 @@ SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" "Symbol" "|") Exp
7979
80SwitchItem = Expression | (Expression "..." Expression)80SwitchItem = Expression | (Expression "..." Expression)
8181
82WhileExpression = "while" "(" Expression ")" Expression82WhileExpression = "while" "(" Expression option(";" Expression) ")" Expression
8383
84ForExpression = "for" "(" Expression ")" option("|" "Symbol" option("," "Symbol") "|") Expression84ForExpression = "for" "(" Expression ")" option("|" "Symbol" option("," "Symbol") "|") Expression
8585
src/all_types.hpp+1
...@@ -486,6 +486,7 @@ struct AstNodeIfVarExpr {...@@ -486,6 +486,7 @@ struct AstNodeIfVarExpr {
486486
487struct AstNodeWhileExpr {487struct AstNodeWhileExpr {
488 AstNode *condition;488 AstNode *condition;
489 AstNode *continue_expr;
489 AstNode *body;490 AstNode *body;
490491
491 // populated by semantic analyzer492 // populated by semantic analyzer
src/analyze.cpp+5
...@@ -3507,10 +3507,15 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import,...@@ -3507,10 +3507,15 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import,
35073507
3508 AstNode *condition_node = node->data.while_expr.condition;3508 AstNode *condition_node = node->data.while_expr.condition;
3509 AstNode *while_body_node = node->data.while_expr.body;3509 AstNode *while_body_node = node->data.while_expr.body;
3510 AstNode **continue_expr_node = &node->data.while_expr.continue_expr;
35103511
3511 TypeTableEntry *condition_type = analyze_expression(g, import, context,3512 TypeTableEntry *condition_type = analyze_expression(g, import, context,
3512 g->builtin_types.entry_bool, condition_node);3513 g->builtin_types.entry_bool, condition_node);
35133514
3515 if (*continue_expr_node) {
3516 analyze_expression(g, import, context, g->builtin_types.entry_void, *continue_expr_node);
3517 }
3518
3514 BlockContext *child_context = new_block_context(node, context);3519 BlockContext *child_context = new_block_context(node, context);
3515 child_context->parent_loop_node = node;3520 child_context->parent_loop_node = node;
35163521
src/codegen.cpp+28-4
...@@ -2282,12 +2282,16 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {...@@ -2282,12 +2282,16 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
2282 assert(node->data.while_expr.condition);2282 assert(node->data.while_expr.condition);
2283 assert(node->data.while_expr.body);2283 assert(node->data.while_expr.body);
22842284
2285 AstNode *continue_expr_node = node->data.while_expr.continue_expr;
2286
2285 bool condition_always_true = node->data.while_expr.condition_always_true;2287 bool condition_always_true = node->data.while_expr.condition_always_true;
2286 bool contains_break = node->data.while_expr.contains_break;2288 bool contains_break = node->data.while_expr.contains_break;
2287 if (condition_always_true) {2289 if (condition_always_true) {
2288 // generate a forever loop2290 // generate a forever loop
22892291
2290 LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileBody");2292 LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileBody");
2293 LLVMBasicBlockRef continue_block = continue_expr_node ?
2294 LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileContinue") : body_block;
2291 LLVMBasicBlockRef end_block = nullptr;2295 LLVMBasicBlockRef end_block = nullptr;
2292 if (contains_break) {2296 if (contains_break) {
2293 end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileEnd");2297 end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileEnd");
...@@ -2296,16 +2300,25 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {...@@ -2296,16 +2300,25 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
2296 add_debug_source_node(g, node);2300 add_debug_source_node(g, node);
2297 LLVMBuildBr(g->builder, body_block);2301 LLVMBuildBr(g->builder, body_block);
22982302
2303 if (continue_expr_node) {
2304 LLVMPositionBuilderAtEnd(g->builder, continue_block);
2305
2306 gen_expr(g, continue_expr_node);
2307
2308 add_debug_source_node(g, node);
2309 LLVMBuildBr(g->builder, body_block);
2310 }
2311
2299 LLVMPositionBuilderAtEnd(g->builder, body_block);2312 LLVMPositionBuilderAtEnd(g->builder, body_block);
2300 g->break_block_stack.append(end_block);2313 g->break_block_stack.append(end_block);
2301 g->continue_block_stack.append(body_block);2314 g->continue_block_stack.append(continue_block);
2302 gen_expr(g, node->data.while_expr.body);2315 gen_expr(g, node->data.while_expr.body);
2303 g->break_block_stack.pop();2316 g->break_block_stack.pop();
2304 g->continue_block_stack.pop();2317 g->continue_block_stack.pop();
23052318
2306 if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) {2319 if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) {
2307 add_debug_source_node(g, node);2320 add_debug_source_node(g, node);
2308 LLVMBuildBr(g->builder, body_block);2321 LLVMBuildBr(g->builder, continue_block);
2309 }2322 }
23102323
2311 if (contains_break) {2324 if (contains_break) {
...@@ -2316,11 +2329,22 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {...@@ -2316,11 +2329,22 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
23162329
2317 LLVMBasicBlockRef cond_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileCond");2330 LLVMBasicBlockRef cond_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileCond");
2318 LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileBody");2331 LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileBody");
2332 LLVMBasicBlockRef continue_block = continue_expr_node ?
2333 LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileContinue") : cond_block;
2319 LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileEnd");2334 LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileEnd");
23202335
2321 add_debug_source_node(g, node);2336 add_debug_source_node(g, node);
2322 LLVMBuildBr(g->builder, cond_block);2337 LLVMBuildBr(g->builder, cond_block);
23232338
2339 if (continue_expr_node) {
2340 LLVMPositionBuilderAtEnd(g->builder, continue_block);
2341
2342 gen_expr(g, continue_expr_node);
2343
2344 add_debug_source_node(g, node);
2345 LLVMBuildBr(g->builder, cond_block);
2346 }
2347
2324 LLVMPositionBuilderAtEnd(g->builder, cond_block);2348 LLVMPositionBuilderAtEnd(g->builder, cond_block);
2325 LLVMValueRef cond_val = gen_expr(g, node->data.while_expr.condition);2349 LLVMValueRef cond_val = gen_expr(g, node->data.while_expr.condition);
2326 add_debug_source_node(g, node->data.while_expr.condition);2350 add_debug_source_node(g, node->data.while_expr.condition);
...@@ -2328,13 +2352,13 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {...@@ -2328,13 +2352,13 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
23282352
2329 LLVMPositionBuilderAtEnd(g->builder, body_block);2353 LLVMPositionBuilderAtEnd(g->builder, body_block);
2330 g->break_block_stack.append(end_block);2354 g->break_block_stack.append(end_block);
2331 g->continue_block_stack.append(cond_block);2355 g->continue_block_stack.append(continue_block);
2332 gen_expr(g, node->data.while_expr.body);2356 gen_expr(g, node->data.while_expr.body);
2333 g->break_block_stack.pop();2357 g->break_block_stack.pop();
2334 g->continue_block_stack.pop();2358 g->continue_block_stack.pop();
2335 if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) {2359 if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) {
2336 add_debug_source_node(g, node);2360 add_debug_source_node(g, node);
2337 LLVMBuildBr(g->builder, cond_block);2361 LLVMBuildBr(g->builder, continue_block);
2338 }2362 }
23392363
2340 LLVMPositionBuilderAtEnd(g->builder, end_block);2364 LLVMPositionBuilderAtEnd(g->builder, end_block);
src/eval.cpp+6
...@@ -1014,6 +1014,7 @@ static bool eval_while_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val)...@@ -1014,6 +1014,7 @@ static bool eval_while_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val)
10141014
1015 AstNode *cond_node = node->data.while_expr.condition;1015 AstNode *cond_node = node->data.while_expr.condition;
1016 AstNode *body_node = node->data.while_expr.body;1016 AstNode *body_node = node->data.while_expr.body;
1017 AstNode *continue_expr_node = node->data.while_expr.continue_expr;
10171018
1018 EvalScope *my_scope = allocate<EvalScope>(1);1019 EvalScope *my_scope = allocate<EvalScope>(1);
1019 my_scope->block_context = body_node->block_context;1020 my_scope->block_context = body_node->block_context;
...@@ -1030,6 +1031,11 @@ static bool eval_while_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val)...@@ -1030,6 +1031,11 @@ static bool eval_while_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val)
1030 ConstExprValue body_val = {0};1031 ConstExprValue body_val = {0};
1031 if (eval_expr(ef, body_node, &body_val)) return true;1032 if (eval_expr(ef, body_node, &body_val)) return true;
10321033
1034 if (continue_expr_node) {
1035 ConstExprValue continue_expr_val = {0};
1036 if (eval_expr(ef, continue_expr_node, &continue_expr_val)) return true;
1037 }
1038
1033 ef->root->branches_used += 1;1039 ef->root->branches_used += 1;
1034 }1040 }
10351041
src/parser.cpp+14-3
...@@ -1886,7 +1886,7 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, int *token_index, bool...@@ -1886,7 +1886,7 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, int *token_index, bool
1886}1886}
18871887
1888/*1888/*
1889WhileExpression : token(While) token(LParen) Expression token(RParen) Expression1889WhileExpression = "while" "(" Expression option(";" Expression) ")" Expression
1890*/1890*/
1891static AstNode *ast_parse_while_expr(ParseContext *pc, int *token_index, bool mandatory) {1891static AstNode *ast_parse_while_expr(ParseContext *pc, int *token_index, bool mandatory) {
1892 Token *token = &pc->tokens->at(*token_index);1892 Token *token = &pc->tokens->at(*token_index);
...@@ -1904,9 +1904,20 @@ static AstNode *ast_parse_while_expr(ParseContext *pc, int *token_index, bool ma...@@ -1904,9 +1904,20 @@ static AstNode *ast_parse_while_expr(ParseContext *pc, int *token_index, bool ma
19041904
1905 ast_eat_token(pc, token_index, TokenIdLParen);1905 ast_eat_token(pc, token_index, TokenIdLParen);
1906 node->data.while_expr.condition = ast_parse_expression(pc, token_index, true);1906 node->data.while_expr.condition = ast_parse_expression(pc, token_index, true);
1907 ast_eat_token(pc, token_index, TokenIdRParen);
19081907
1909 node->data.while_expr.body = ast_parse_expression(pc, token_index, true);1908 Token *semi_or_rparen = &pc->tokens->at(*token_index);
1909
1910 if (semi_or_rparen->id == TokenIdRParen) {
1911 *token_index += 1;
1912 node->data.while_expr.body = ast_parse_expression(pc, token_index, true);
1913 } else if (semi_or_rparen->id == TokenIdSemicolon) {
1914 *token_index += 1;
1915 node->data.while_expr.continue_expr = ast_parse_expression(pc, token_index, true);
1916 ast_eat_token(pc, token_index, TokenIdRParen);
1917 node->data.while_expr.body = ast_parse_expression(pc, token_index, true);
1918 } else {
1919 ast_invalid_token_error(pc, semi_or_rparen);
1920 }
19101921
19111922
1912 normalize_parent_ptrs(node);1923 normalize_parent_ptrs(node);
std/rand.zig+2-5
...@@ -107,12 +107,9 @@ pub struct Rand {...@@ -107,12 +107,9 @@ pub struct Rand {
107fn test_float32() {107fn test_float32() {
108 var r = Rand.init(42);108 var r = Rand.init(42);
109109
110 // TODO for loop with range110 {var i: i32 = 0; while (i < 1000; i += 1) {
111 var i: i32 = 0;
112 while (i < 1000) {
113 const val = r.float32();111 const val = r.float32();
114 if (!(val >= 0.0)) unreachable{};112 if (!(val >= 0.0)) unreachable{};
115 if (!(val < 1.0)) unreachable{};113 if (!(val < 1.0)) unreachable{};
116 i += 1;114 }}
117 }
118}115}
std/str.zig+1-3
...@@ -2,9 +2,7 @@ const assert = @import("index.zig").assert;...@@ -2,9 +2,7 @@ const assert = @import("index.zig").assert;
22
3pub fn len(ptr: &const u8) -> isize {3pub fn len(ptr: &const u8) -> isize {
4 var count: isize = 0;4 var count: isize = 0;
5 while (ptr[count] != 0) {5 while (ptr[count] != 0; count += 1) {}
6 count += 1;
7 }
8 return count;6 return count;
9}7}
108
test/self_hosted.zig+11
...@@ -1258,3 +1258,14 @@ fn pub_enum_test(foo: other.APubEnum) {...@@ -1258,3 +1258,14 @@ fn pub_enum_test(foo: other.APubEnum) {
1258fn cast_with_imported_symbol() {1258fn cast_with_imported_symbol() {
1259 assert(other.size_t(42) == 42);1259 assert(other.size_t(42) == 42);
1260}1260}
1261
1262
1263#attribute("test")
1264fn while_with_continue_expr() {
1265 var sum: i32 = 0;
1266 {var i: i32 = 0; while (i < 10; i += 1) {
1267 if (i == 5) continue;
1268 sum += i;
1269 }}
1270 assert(sum == 40);
1271}