| 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,7 +79,7 @@ SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" "Symbol" "|") Exp |
| 79 | 79 | ||
| 80 | SwitchItem = Expression | (Expression "..." Expression) | 80 | SwitchItem = Expression | (Expression "..." Expression) |
| 81 | 81 | ||
| 82 | WhileExpression = "while" "(" Expression ")" Expression | 82 | WhileExpression = "while" "(" Expression option(";" Expression) ")" Expression |
| 83 | 83 | ||
| 84 | ForExpression = "for" "(" Expression ")" option("|" "Symbol" option("," "Symbol") "|") Expression | 84 | ForExpression = "for" "(" Expression ")" option("|" "Symbol" option("," "Symbol") "|") Expression |
| 85 | 85 |
src/all_types.hpp+1| ... | @@ -486,6 +486,7 @@ struct AstNodeIfVarExpr { | ... | @@ -486,6 +486,7 @@ struct AstNodeIfVarExpr { |
| 486 | 486 | ||
| 487 | struct AstNodeWhileExpr { | 487 | struct AstNodeWhileExpr { |
| 488 | AstNode *condition; | 488 | AstNode *condition; |
| 489 | AstNode *continue_expr; | ||
| 489 | AstNode *body; | 490 | AstNode *body; |
| 490 | 491 | ||
| 491 | // populated by semantic analyzer | 492 | // 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, |
| 3507 | 3507 | ||
| 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; | ||
| 3510 | 3511 | ||
| 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); |
| 3513 | 3514 | ||
| 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; |
| 3516 | 3521 |
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); |
| 2284 | 2284 | ||
| 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 loop | 2290 | // generate a forever loop |
| 2289 | 2291 | ||
| 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); |
| 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 | 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(); |
| 2305 | 2318 | ||
| 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 | } |
| 2310 | 2323 | ||
| 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) { |
| 2316 | 2329 | ||
| 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"); |
| 2320 | 2335 | ||
| 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); |
| 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 | 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) { |
| 2328 | 2352 | ||
| 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 | } |
| 2339 | 2363 | ||
| 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) |
| 1014 | 1014 | ||
| 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; | ||
| 1017 | 1018 | ||
| 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; |
| 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 | ef->root->branches_used += 1; | 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,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 | static AstNode *ast_parse_while_expr(ParseContext *pc, int *token_index, bool mandatory) { | 1891 | static 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 |
| 1904 | 1904 | ||
| 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); | ||
| 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 | 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 { |
| 107 | fn test_float32() { | 107 | fn test_float32() { |
| 108 | var r = Rand.init(42); | 108 | var r = Rand.init(42); |
| 109 | 109 | ||
| 110 | // TODO for loop with range | 110 | {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; |
| 2 | 2 | ||
| 3 | pub fn len(ptr: &const u8) -> isize { | 3 | pub 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 | } |
| 10 | 8 |
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) { |
| 1258 | fn cast_with_imported_symbol() { | 1258 | fn 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") | ||
| 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 | } |