| author | |
| committer | |
| log | a25307c0a1b45d0c7b83158349fbc57626baf656 |
| tree | 3a7035c0f54e29298f8f7330239db6fea5097556 |
| parent | 04364c45cefbba9451af202ceab5ae528cc8bbaa |
closes #1399 files changed, 69 insertions(+), 16 deletions(-)
doc/langref.md+1-1| ... | ... | @@ -79,7 +79,7 @@ SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" "Symbol" "|") Exp |
| 79 | 79 | |
| 80 | 80 | SwitchItem = Expression | (Expression "..." Expression) |
| 81 | 81 | |
| 82 | WhileExpression = "while" "(" Expression ")" Expression | |
| 82 | WhileExpression = "while" "(" Expression option(";" Expression) ")" Expression | |
| 83 | 83 | |
| 84 | 84 | ForExpression = "for" "(" Expression ")" option("|" "Symbol" option("," "Symbol") "|") Expression |
| 85 | 85 |
src/all_types.hpp+1| ... | ... | @@ -486,6 +486,7 @@ struct AstNodeIfVarExpr { |
| 486 | 486 | |
| 487 | 487 | struct AstNodeWhileExpr { |
| 488 | 488 | AstNode *condition; |
| 489 | AstNode *continue_expr; | |
| 489 | 490 | AstNode *body; |
| 490 | 491 | |
| 491 | 492 | // populated by semantic analyzer |
src/analyze.cpp+5| ... | ... | @@ -3507,10 +3507,15 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, |
| 3507 | 3507 | |
| 3508 | 3508 | AstNode *condition_node = node->data.while_expr.condition; |
| 3509 | 3509 | AstNode *while_body_node = node->data.while_expr.body; |
| 3510 | AstNode **continue_expr_node = &node->data.while_expr.continue_expr; | |
| 3510 | 3511 | |
| 3511 | 3512 | TypeTableEntry *condition_type = analyze_expression(g, import, context, |
| 3512 | 3513 | g->builtin_types.entry_bool, condition_node); |
| 3513 | 3514 | |
| 3515 | if (*continue_expr_node) { | |
| 3516 | analyze_expression(g, import, context, g->builtin_types.entry_void, *continue_expr_node); | |
| 3517 | } | |
| 3518 | ||
| 3514 | 3519 | BlockContext *child_context = new_block_context(node, context); |
| 3515 | 3520 | child_context->parent_loop_node = node; |
| 3516 | 3521 |
src/codegen.cpp+28-4| ... | ... | @@ -2282,12 +2282,16 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) { |
| 2282 | 2282 | assert(node->data.while_expr.condition); |
| 2283 | 2283 | assert(node->data.while_expr.body); |
| 2284 | 2284 | |
| 2285 | AstNode *continue_expr_node = node->data.while_expr.continue_expr; | |
| 2286 | ||
| 2285 | 2287 | bool condition_always_true = node->data.while_expr.condition_always_true; |
| 2286 | 2288 | bool contains_break = node->data.while_expr.contains_break; |
| 2287 | 2289 | if (condition_always_true) { |
| 2288 | 2290 | // generate a forever loop |
| 2289 | 2291 | |
| 2290 | 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 | 2295 | LLVMBasicBlockRef end_block = nullptr; |
| 2292 | 2296 | if (contains_break) { |
| 2293 | 2297 | end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileEnd"); |
| ... | ... | @@ -2296,16 +2300,25 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) { |
| 2296 | 2300 | add_debug_source_node(g, node); |
| 2297 | 2301 | LLVMBuildBr(g->builder, body_block); |
| 2298 | 2302 | |
| 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 | 2312 | LLVMPositionBuilderAtEnd(g->builder, body_block); |
| 2300 | 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 | 2315 | gen_expr(g, node->data.while_expr.body); |
| 2303 | 2316 | g->break_block_stack.pop(); |
| 2304 | 2317 | g->continue_block_stack.pop(); |
| 2305 | 2318 | |
| 2306 | 2319 | if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) { |
| 2307 | 2320 | add_debug_source_node(g, node); |
| 2308 | LLVMBuildBr(g->builder, body_block); | |
| 2321 | LLVMBuildBr(g->builder, continue_block); | |
| 2309 | 2322 | } |
| 2310 | 2323 | |
| 2311 | 2324 | if (contains_break) { |
| ... | ... | @@ -2316,11 +2329,22 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) { |
| 2316 | 2329 | |
| 2317 | 2330 | LLVMBasicBlockRef cond_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileCond"); |
| 2318 | 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 | 2334 | LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileEnd"); |
| 2320 | 2335 | |
| 2321 | 2336 | add_debug_source_node(g, node); |
| 2322 | 2337 | LLVMBuildBr(g->builder, cond_block); |
| 2323 | 2338 | |
| 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 | 2348 | LLVMPositionBuilderAtEnd(g->builder, cond_block); |
| 2325 | 2349 | LLVMValueRef cond_val = gen_expr(g, node->data.while_expr.condition); |
| 2326 | 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 | 2352 | |
| 2329 | 2353 | LLVMPositionBuilderAtEnd(g->builder, body_block); |
| 2330 | 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 | 2356 | gen_expr(g, node->data.while_expr.body); |
| 2333 | 2357 | g->break_block_stack.pop(); |
| 2334 | 2358 | g->continue_block_stack.pop(); |
| 2335 | 2359 | if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) { |
| 2336 | 2360 | add_debug_source_node(g, node); |
| 2337 | LLVMBuildBr(g->builder, cond_block); | |
| 2361 | LLVMBuildBr(g->builder, continue_block); | |
| 2338 | 2362 | } |
| 2339 | 2363 | |
| 2340 | 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 | 1014 | |
| 1015 | 1015 | AstNode *cond_node = node->data.while_expr.condition; |
| 1016 | 1016 | AstNode *body_node = node->data.while_expr.body; |
| 1017 | AstNode *continue_expr_node = node->data.while_expr.continue_expr; | |
| 1017 | 1018 | |
| 1018 | 1019 | EvalScope *my_scope = allocate<EvalScope>(1); |
| 1019 | 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 | 1031 | ConstExprValue body_val = {0}; |
| 1031 | 1032 | if (eval_expr(ef, body_node, &body_val)) return true; |
| 1032 | 1033 | |
| 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 | 1039 | ef->root->branches_used += 1; |
| 1034 | 1040 | } |
| 1035 | 1041 |
src/parser.cpp+14-3| ... | ... | @@ -1886,7 +1886,7 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, int *token_index, bool |
| 1886 | 1886 | } |
| 1887 | 1887 | |
| 1888 | 1888 | /* |
| 1889 | WhileExpression : token(While) token(LParen) Expression token(RParen) Expression | |
| 1889 | WhileExpression = "while" "(" Expression option(";" Expression) ")" Expression | |
| 1890 | 1890 | */ |
| 1891 | 1891 | static AstNode *ast_parse_while_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 1892 | 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 | 1904 | |
| 1905 | 1905 | ast_eat_token(pc, token_index, TokenIdLParen); |
| 1906 | 1906 | node->data.while_expr.condition = ast_parse_expression(pc, token_index, true); |
| 1907 | ast_eat_token(pc, token_index, TokenIdRParen); | |
| 1908 | 1907 | |
| 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 | } | |
| 1910 | 1921 | |
| 1911 | 1922 | |
| 1912 | 1923 | normalize_parent_ptrs(node); |
std/rand.zig+2-5| ... | ... | @@ -107,12 +107,9 @@ pub struct Rand { |
| 107 | 107 | fn test_float32() { |
| 108 | 108 | var r = Rand.init(42); |
| 109 | 109 | |
| 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) { | |
| 113 | 111 | const val = r.float32(); |
| 114 | 112 | if (!(val >= 0.0)) unreachable{}; |
| 115 | 113 | if (!(val < 1.0)) unreachable{}; |
| 116 | i += 1; | |
| 117 | } | |
| 114 | }} | |
| 118 | 115 | } |
std/str.zig+1-3| ... | ... | @@ -2,9 +2,7 @@ const assert = @import("index.zig").assert; |
| 2 | 2 | |
| 3 | 3 | pub fn len(ptr: &const u8) -> isize { |
| 4 | 4 | var count: isize = 0; |
| 5 | while (ptr[count] != 0) { | |
| 6 | count += 1; | |
| 7 | } | |
| 5 | while (ptr[count] != 0; count += 1) {} | |
| 8 | 6 | return count; |
| 9 | 7 | } |
| 10 | 8 |
test/self_hosted.zig+11| ... | ... | @@ -1258,3 +1258,14 @@ fn pub_enum_test(foo: other.APubEnum) { |
| 1258 | 1258 | fn cast_with_imported_symbol() { |
| 1259 | 1259 | assert(other.size_t(42) == 42); |
| 1260 | 1260 | } |
| 1261 | ||
| 1262 | ||
| 1263 | #attribute("test") | |
| 1264 | fn 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 | } |