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
7979
8080SwitchItem = Expression | (Expression "..." Expression)
8181
82WhileExpression = "while" "(" Expression ")" Expression
82WhileExpression = "while" "(" Expression option(";" Expression) ")" Expression
8383
8484ForExpression = "for" "(" Expression ")" option("|" "Symbol" option("," "Symbol") "|") Expression
8585
src/all_types.hpp+1
......@@ -486,6 +486,7 @@ struct AstNodeIfVarExpr {
486486
487487struct AstNodeWhileExpr {
488488 AstNode *condition;
489 AstNode *continue_expr;
489490 AstNode *body;
490491
491492 // populated by semantic analyzer
src/analyze.cpp+5
......@@ -3507,10 +3507,15 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import,
35073507
35083508 AstNode *condition_node = node->data.while_expr.condition;
35093509 AstNode *while_body_node = node->data.while_expr.body;
3510 AstNode **continue_expr_node = &node->data.while_expr.continue_expr;
35103511
35113512 TypeTableEntry *condition_type = analyze_expression(g, import, context,
35123513 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
35143519 BlockContext *child_context = new_block_context(node, context);
35153520 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) {
22822282 assert(node->data.while_expr.condition);
22832283 assert(node->data.while_expr.body);
22842284
2285 AstNode *continue_expr_node = node->data.while_expr.continue_expr;
2286
22852287 bool condition_always_true = node->data.while_expr.condition_always_true;
22862288 bool contains_break = node->data.while_expr.contains_break;
22872289 if (condition_always_true) {
22882290 // generate a forever loop
22892291
22902292 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;
22912295 LLVMBasicBlockRef end_block = nullptr;
22922296 if (contains_break) {
22932297 end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileEnd");
......@@ -2296,16 +2300,25 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
22962300 add_debug_source_node(g, node);
22972301 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
22992312 LLVMPositionBuilderAtEnd(g->builder, body_block);
23002313 g->break_block_stack.append(end_block);
2301 g->continue_block_stack.append(body_block);
2314 g->continue_block_stack.append(continue_block);
23022315 gen_expr(g, node->data.while_expr.body);
23032316 g->break_block_stack.pop();
23042317 g->continue_block_stack.pop();
23052318
23062319 if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) {
23072320 add_debug_source_node(g, node);
2308 LLVMBuildBr(g->builder, body_block);
2321 LLVMBuildBr(g->builder, continue_block);
23092322 }
23102323
23112324 if (contains_break) {
......@@ -2316,11 +2329,22 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
23162329
23172330 LLVMBasicBlockRef cond_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileCond");
23182331 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;
23192334 LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileEnd");
23202335
23212336 add_debug_source_node(g, node);
23222337 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
23242348 LLVMPositionBuilderAtEnd(g->builder, cond_block);
23252349 LLVMValueRef cond_val = gen_expr(g, node->data.while_expr.condition);
23262350 add_debug_source_node(g, node->data.while_expr.condition);
......@@ -2328,13 +2352,13 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
23282352
23292353 LLVMPositionBuilderAtEnd(g->builder, body_block);
23302354 g->break_block_stack.append(end_block);
2331 g->continue_block_stack.append(cond_block);
2355 g->continue_block_stack.append(continue_block);
23322356 gen_expr(g, node->data.while_expr.body);
23332357 g->break_block_stack.pop();
23342358 g->continue_block_stack.pop();
23352359 if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) {
23362360 add_debug_source_node(g, node);
2337 LLVMBuildBr(g->builder, cond_block);
2361 LLVMBuildBr(g->builder, continue_block);
23382362 }
23392363
23402364 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)
10141014
10151015 AstNode *cond_node = node->data.while_expr.condition;
10161016 AstNode *body_node = node->data.while_expr.body;
1017 AstNode *continue_expr_node = node->data.while_expr.continue_expr;
10171018
10181019 EvalScope *my_scope = allocate<EvalScope>(1);
10191020 my_scope->block_context = body_node->block_context;
......@@ -1030,6 +1031,11 @@ static bool eval_while_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val)
10301031 ConstExprValue body_val = {0};
10311032 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
10331039 ef->root->branches_used += 1;
10341040 }
10351041
src/parser.cpp+14-3
......@@ -1886,7 +1886,7 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, int *token_index, bool
18861886}
18871887
18881888/*
1889WhileExpression : token(While) token(LParen) Expression token(RParen) Expression
1889WhileExpression = "while" "(" Expression option(";" Expression) ")" Expression
18901890*/
18911891static AstNode *ast_parse_while_expr(ParseContext *pc, int *token_index, bool mandatory) {
18921892 Token *token = &pc->tokens->at(*token_index);
......@@ -1904,9 +1904,20 @@ static AstNode *ast_parse_while_expr(ParseContext *pc, int *token_index, bool ma
19041904
19051905 ast_eat_token(pc, token_index, TokenIdLParen);
19061906 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
19121923 normalize_parent_ptrs(node);
std/rand.zig+2-5
......@@ -107,12 +107,9 @@ pub struct Rand {
107107fn test_float32() {
108108 var r = Rand.init(42);
109109
110 // TODO for loop with range
111 var i: i32 = 0;
112 while (i < 1000) {
110 {var i: i32 = 0; while (i < 1000; i += 1) {
113111 const val = r.float32();
114112 if (!(val >= 0.0)) unreachable{};
115113 if (!(val < 1.0)) unreachable{};
116 i += 1;
117 }
114 }}
118115}
std/str.zig+1-3
......@@ -2,9 +2,7 @@ const assert = @import("index.zig").assert;
22
33pub fn len(ptr: &const u8) -> isize {
44 var count: isize = 0;
5 while (ptr[count] != 0) {
6 count += 1;
7 }
5 while (ptr[count] != 0; count += 1) {}
86 return count;
97}
108
test/self_hosted.zig+11
......@@ -1258,3 +1258,14 @@ fn pub_enum_test(foo: other.APubEnum) {
12581258fn cast_with_imported_symbol() {
12591259 assert(other.size_t(42) == 42);
12601260}
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}