authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-05-04 12:43:11-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-05-04 12:43:11-04:00
logb6a679c0edd74d996bd0c1769cf4b161b4d42c4d
treeb9b90568cb38ec6edaa1fa094b8da18575144a08
parent0454e610bf8627537855ce96e922dfbe7322e4a1

implement else on loops and break can give an expression

closes #357

6 files changed, 217 insertions(+), 42 deletions(-)

doc/langref.md+5-3
......@@ -45,7 +45,7 @@ TypeExpr = PrefixOpExpression | "var"
4545
4646BlockOrExpression = Block | Expression
4747
48Expression = ReturnExpression | AssignmentExpression
48Expression = ReturnExpression | BreakExpression | AssignmentExpression
4949
5050AsmExpression = "asm" option("volatile") "(" String option(AsmOutput) ")"
5151
......@@ -79,12 +79,14 @@ SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" option("*") Symbo
7979
8080SwitchItem = Expression | (Expression "..." Expression)
8181
82ForExpression(body) = "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body
82ForExpression(body) = "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body option("else" BlockExpression(body))
8383
8484BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression
8585
8686ReturnExpression = option("%") "return" option(Expression)
8787
88BreakExpression = "break" option(Expression)
89
8890Defer(body) = option("%") "defer" body
8991
9092IfExpression(body) = "if" "(" Expression ")" body option("else" BlockExpression(body))
......@@ -151,7 +153,7 @@ GotoExpression = "goto" Symbol
151153
152154GroupedExpression = "(" Expression ")"
153155
154KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "this" | "unreachable"
156KeywordLiteral = "true" | "false" | "null" | "continue" | "undefined" | "error" | "this" | "unreachable"
155157
156158ContainerDecl = option("extern" | "packed") ("struct" | "enum" | "union") "{" many(ContainerMember) "}"
157159```
src/all_types.hpp+2
......@@ -623,6 +623,7 @@ struct AstNodeForExpr {
623623 AstNode *elem_node; // always a symbol
624624 AstNode *index_node; // always a symbol, might be null
625625 AstNode *body;
626 AstNode *else_node; // can be null
626627 bool elem_is_ptr;
627628 bool is_inline;
628629};
......@@ -774,6 +775,7 @@ struct AstNodeBoolLiteral {
774775};
775776
776777struct AstNodeBreakExpr {
778 AstNode *expr; // may be null
777779};
778780
779781struct AstNodeContinueExpr {
src/ast_render.cpp+13-5
......@@ -485,6 +485,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
485485 }
486486 break;
487487 }
488 case NodeTypeBreak:
489 {
490 fprintf(ar->f, "break");
491 if (node->data.break_expr.expr) {
492 fprintf(ar->f, " ");
493 render_node_grouped(ar, node->data.break_expr.expr);
494 }
495 break;
496 }
488497 case NodeTypeDefer:
489498 {
490499 const char *defer_str = defer_string(node->data.defer.kind);
......@@ -880,11 +889,10 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
880889 fprintf(ar->f, "| ");
881890 }
882891 render_node_grouped(ar, node->data.for_expr.body);
883 break;
884 }
885 case NodeTypeBreak:
886 {
887 fprintf(ar->f, "break");
892 if (node->data.for_expr.else_node) {
893 fprintf(ar->f, " else");
894 render_node_grouped(ar, node->data.for_expr.else_node);
895 }
888896 break;
889897 }
890898 case NodeTypeContinue:
src/ir.cpp+104-27
......@@ -22,6 +22,8 @@ struct LoopStackItem {
2222 IrBasicBlock *break_block;
2323 IrBasicBlock *continue_block;
2424 IrInstruction *is_comptime;
25 ZigList<IrInstruction *> *incoming_values;
26 ZigList<IrBasicBlock *> *incoming_blocks;
2527};
2628
2729struct IrBuilder {
......@@ -56,6 +58,18 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *sc
5658static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction);
5759static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, TypeTableEntry *expected_type);
5860
61static LoopStackItem *add_loop_stack_item(IrBuilder *irb, IrBasicBlock *break_block, IrBasicBlock *continue_block,
62 IrInstruction *is_comptime, ZigList<IrBasicBlock *> *incoming_blocks, ZigList<IrInstruction *> *incoming_values)
63{
64 LoopStackItem *loop_stack_item = irb->loop_stack.add_one();
65 loop_stack_item->break_block = break_block;
66 loop_stack_item->continue_block = continue_block;
67 loop_stack_item->is_comptime = is_comptime;
68 loop_stack_item->incoming_blocks = incoming_blocks;
69 loop_stack_item->incoming_values = incoming_values;
70 return loop_stack_item;
71}
72
5973ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {
6074 assert(const_val->type->id == TypeTableEntryIdPointer);
6175 assert(const_val->special == ConstValSpecialStatic);
......@@ -4693,6 +4707,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
46934707 return err_val_ptr;
46944708 IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr);
46954709 IrInstruction *is_err = ir_build_test_err(irb, scope, node->data.while_expr.condition, err_val);
4710 IrBasicBlock *after_cond_block = irb->current_basic_block;
4711 IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));
46964712 if (!instr_is_unreachable(is_err)) {
46974713 ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_err,
46984714 else_block, body_block, is_comptime));
......@@ -4706,10 +4722,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
47064722 var_ptr_value : ir_build_load_ptr(irb, payload_scope, symbol_node, var_ptr_value);
47074723 ir_build_var_decl(irb, payload_scope, symbol_node, payload_var, nullptr, var_value);
47084724 }
4709 LoopStackItem *loop_stack_item = irb->loop_stack.add_one();
4710 loop_stack_item->break_block = end_block;
4711 loop_stack_item->continue_block = continue_block;
4712 loop_stack_item->is_comptime = is_comptime;
4725 ZigList<IrInstruction *> incoming_values = {0};
4726 ZigList<IrBasicBlock *> incoming_blocks = {0};
4727 add_loop_stack_item(irb, end_block, continue_block, is_comptime, &incoming_blocks, &incoming_values);
47134728 IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, payload_scope);
47144729 if (body_result == irb->codegen->invalid_instruction)
47154730 return body_result;
......@@ -4727,6 +4742,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
47274742 ir_mark_gen(ir_build_br(irb, payload_scope, node, cond_block, is_comptime));
47284743 }
47294744
4745 IrInstruction *else_result = nullptr;
47304746 if (else_node) {
47314747 ir_set_cursor_at_end(irb, else_block);
47324748
......@@ -4738,15 +4754,23 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
47384754 IrInstruction *err_var_value = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr);
47394755 ir_build_var_decl(irb, err_scope, symbol_node, err_var, nullptr, err_var_value);
47404756
4741 IrInstruction *else_result = ir_gen_node(irb, else_node, err_scope);
4757 else_result = ir_gen_node(irb, else_node, err_scope);
47424758 if (else_result == irb->codegen->invalid_instruction)
47434759 return else_result;
47444760 if (!instr_is_unreachable(else_result))
47454761 ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
47464762 }
4747
4763 IrBasicBlock *after_else_block = irb->current_basic_block;
47484764 ir_set_cursor_at_end(irb, end_block);
4749 return ir_build_const_void(irb, scope, node);
4765 if (else_result) {
4766 incoming_blocks.append(after_else_block);
4767 incoming_values.append(else_result);
4768 } else {
4769 incoming_blocks.append(after_cond_block);
4770 incoming_values.append(void_else_result);
4771 }
4772
4773 return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
47504774 } else if (var_symbol != nullptr) {
47514775 ir_set_cursor_at_end(irb, cond_block);
47524776 // TODO make it an error to write to payload variable
......@@ -4759,6 +4783,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
47594783 return maybe_val_ptr;
47604784 IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr);
47614785 IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node->data.while_expr.condition, maybe_val);
4786 IrBasicBlock *after_cond_block = irb->current_basic_block;
4787 IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));
47624788 if (!instr_is_unreachable(is_non_null)) {
47634789 ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_non_null,
47644790 body_block, else_block, is_comptime));
......@@ -4769,10 +4795,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
47694795 IrInstruction *var_value = node->data.while_expr.var_is_ptr ?
47704796 var_ptr_value : ir_build_load_ptr(irb, child_scope, symbol_node, var_ptr_value);
47714797 ir_build_var_decl(irb, child_scope, symbol_node, payload_var, nullptr, var_value);
4772 LoopStackItem *loop_stack_item = irb->loop_stack.add_one();
4773 loop_stack_item->break_block = end_block;
4774 loop_stack_item->continue_block = continue_block;
4775 loop_stack_item->is_comptime = is_comptime;
4798 ZigList<IrInstruction *> incoming_values = {0};
4799 ZigList<IrBasicBlock *> incoming_blocks = {0};
4800 add_loop_stack_item(irb, end_block, continue_block, is_comptime, &incoming_blocks, &incoming_values);
47764801 IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, child_scope);
47774802 if (body_result == irb->codegen->invalid_instruction)
47784803 return body_result;
......@@ -4790,18 +4815,27 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
47904815 ir_mark_gen(ir_build_br(irb, child_scope, node, cond_block, is_comptime));
47914816 }
47924817
4818 IrInstruction *else_result = nullptr;
47934819 if (else_node) {
47944820 ir_set_cursor_at_end(irb, else_block);
47954821
4796 IrInstruction *else_result = ir_gen_node(irb, else_node, scope);
4822 else_result = ir_gen_node(irb, else_node, scope);
47974823 if (else_result == irb->codegen->invalid_instruction)
47984824 return else_result;
47994825 if (!instr_is_unreachable(else_result))
48004826 ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
48014827 }
4802
4828 IrBasicBlock *after_else_block = irb->current_basic_block;
48034829 ir_set_cursor_at_end(irb, end_block);
4804 return ir_build_const_void(irb, scope, node);
4830 if (else_result) {
4831 incoming_blocks.append(after_else_block);
4832 incoming_values.append(else_result);
4833 } else {
4834 incoming_blocks.append(after_cond_block);
4835 incoming_values.append(void_else_result);
4836 }
4837
4838 return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
48054839 } else {
48064840 if (continue_expr_node) {
48074841 ir_set_cursor_at_end(irb, continue_block);
......@@ -4816,6 +4850,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
48164850 IrInstruction *cond_val = ir_gen_node(irb, node->data.while_expr.condition, scope);
48174851 if (cond_val == irb->codegen->invalid_instruction)
48184852 return cond_val;
4853 IrBasicBlock *after_cond_block = irb->current_basic_block;
4854 IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));
48194855 if (!instr_is_unreachable(cond_val)) {
48204856 ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, cond_val,
48214857 body_block, else_block, is_comptime));
......@@ -4823,10 +4859,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
48234859
48244860 ir_set_cursor_at_end(irb, body_block);
48254861
4826 LoopStackItem *loop_stack_item = irb->loop_stack.add_one();
4827 loop_stack_item->break_block = end_block;
4828 loop_stack_item->continue_block = continue_block;
4829 loop_stack_item->is_comptime = is_comptime;
4862 ZigList<IrInstruction *> incoming_values = {0};
4863 ZigList<IrBasicBlock *> incoming_blocks = {0};
4864 add_loop_stack_item(irb, end_block, continue_block, is_comptime, &incoming_blocks, &incoming_values);
48304865 IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, scope);
48314866 if (body_result == irb->codegen->invalid_instruction)
48324867 return body_result;
......@@ -4835,19 +4870,27 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
48354870 if (!instr_is_unreachable(body_result))
48364871 ir_mark_gen(ir_build_br(irb, scope, node, continue_block, is_comptime));
48374872
4873 IrInstruction *else_result = nullptr;
48384874 if (else_node) {
48394875 ir_set_cursor_at_end(irb, else_block);
48404876
4841 IrInstruction *else_result = ir_gen_node(irb, else_node, scope);
4877 else_result = ir_gen_node(irb, else_node, scope);
48424878 if (else_result == irb->codegen->invalid_instruction)
48434879 return else_result;
48444880 if (!instr_is_unreachable(else_result))
48454881 ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
48464882 }
4847
4883 IrBasicBlock *after_else_block = irb->current_basic_block;
48484884 ir_set_cursor_at_end(irb, end_block);
4885 if (else_result) {
4886 incoming_blocks.append(after_else_block);
4887 incoming_values.append(else_result);
4888 } else {
4889 incoming_blocks.append(after_cond_block);
4890 incoming_values.append(void_else_result);
4891 }
48494892
4850 return ir_build_const_void(irb, scope, node);
4893 return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
48514894 }
48524895}
48534896
......@@ -4858,6 +4901,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
48584901 AstNode *elem_node = node->data.for_expr.elem_node;
48594902 AstNode *index_node = node->data.for_expr.index_node;
48604903 AstNode *body_node = node->data.for_expr.body;
4904 AstNode *else_node = node->data.for_expr.else_node;
48614905
48624906 if (!elem_node) {
48634907 add_node_error(irb->codegen, node, buf_sprintf("for loop expression missing element parameter"));
......@@ -4915,6 +4959,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
49154959 IrBasicBlock *cond_block = ir_build_basic_block(irb, child_scope, "ForCond");
49164960 IrBasicBlock *body_block = ir_build_basic_block(irb, child_scope, "ForBody");
49174961 IrBasicBlock *end_block = ir_build_basic_block(irb, child_scope, "ForEnd");
4962 IrBasicBlock *else_block = else_node ? ir_build_basic_block(irb, child_scope, "ForElse") : end_block;
49184963 IrBasicBlock *continue_block = ir_build_basic_block(irb, child_scope, "ForContinue");
49194964
49204965 IrInstruction *len_val = ir_build_array_len(irb, child_scope, node, array_val);
......@@ -4923,7 +4968,9 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
49234968 ir_set_cursor_at_end(irb, cond_block);
49244969 IrInstruction *index_val = ir_build_load_ptr(irb, child_scope, node, index_ptr);
49254970 IrInstruction *cond = ir_build_bin_op(irb, child_scope, node, IrBinOpCmpLessThan, index_val, len_val, false);
4926 ir_mark_gen(ir_build_cond_br(irb, child_scope, node, cond, body_block, end_block, is_comptime));
4971 IrBasicBlock *after_cond_block = irb->current_basic_block;
4972 IrInstruction *void_else_value = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, parent_scope, node));
4973 ir_mark_gen(ir_build_cond_br(irb, child_scope, node, cond, body_block, else_block, is_comptime));
49274974
49284975 ir_set_cursor_at_end(irb, body_block);
49294976 IrInstruction *elem_ptr = ir_build_elem_ptr(irb, child_scope, node, array_val_ptr, index_val, false);
......@@ -4935,10 +4982,9 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
49354982 }
49364983 ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, elem_var_ptr, elem_val));
49374984
4938 LoopStackItem *loop_stack_item = irb->loop_stack.add_one();
4939 loop_stack_item->break_block = end_block;
4940 loop_stack_item->continue_block = continue_block;
4941 loop_stack_item->is_comptime = is_comptime;
4985 ZigList<IrInstruction *> incoming_values = {0};
4986 ZigList<IrBasicBlock *> incoming_blocks = {0};
4987 add_loop_stack_item(irb, end_block, continue_block, is_comptime, &incoming_blocks, &incoming_values);
49424988 IrInstruction *body_result = ir_gen_node(irb, body_node, child_scope);
49434989 irb->loop_stack.pop();
49444990
......@@ -4950,9 +4996,28 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
49504996 ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, index_ptr, new_index_val));
49514997 ir_build_br(irb, child_scope, node, cond_block, is_comptime);
49524998
4999 IrInstruction *else_result = nullptr;
5000 if (else_node) {
5001 ir_set_cursor_at_end(irb, else_block);
5002
5003 else_result = ir_gen_node(irb, else_node, parent_scope);
5004 if (else_result == irb->codegen->invalid_instruction)
5005 return else_result;
5006 if (!instr_is_unreachable(else_result))
5007 ir_mark_gen(ir_build_br(irb, parent_scope, node, end_block, is_comptime));
5008 }
5009 IrBasicBlock *after_else_block = irb->current_basic_block;
49535010 ir_set_cursor_at_end(irb, end_block);
4954 return ir_build_const_void(irb, child_scope, node);
49555011
5012 if (else_result) {
5013 incoming_blocks.append(after_else_block);
5014 incoming_values.append(else_result);
5015 } else {
5016 incoming_blocks.append(after_cond_block);
5017 incoming_values.append(void_else_value);
5018 }
5019
5020 return ir_build_phi(irb, parent_scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
49565021}
49575022
49585023static IrInstruction *ir_gen_this_literal(IrBuilder *irb, Scope *scope, AstNode *node) {
......@@ -5512,8 +5577,20 @@ static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *scope, AstNode *node)
55125577 is_comptime = loop_stack_item->is_comptime;
55135578 }
55145579
5580 IrInstruction *result_value;
5581 if (node->data.break_expr.expr) {
5582 result_value = ir_gen_node(irb, node->data.break_expr.expr, scope);
5583 if (result_value == irb->codegen->invalid_instruction)
5584 return irb->codegen->invalid_instruction;
5585 } else {
5586 result_value = ir_build_const_void(irb, scope, node);
5587 }
5588
55155589 IrBasicBlock *dest_block = loop_stack_item->break_block;
55165590 ir_gen_defers_for_block(irb, scope, dest_block->scope, false);
5591
5592 loop_stack_item->incoming_blocks->append(irb->current_basic_block);
5593 loop_stack_item->incoming_values->append(result_value);
55175594 return ir_build_br(irb, scope, node, dest_block, is_comptime);
55185595}
55195596
src/parser.cpp+32-7
......@@ -641,7 +641,7 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b
641641
642642/*
643643PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl
644KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "this" | "unreachable"
644KeywordLiteral = "true" | "false" | "null" | "continue" | "undefined" | "error" | "this" | "unreachable"
645645*/
646646static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
647647 Token *token = &pc->tokens->at(*token_index);
......@@ -677,10 +677,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
677677 AstNode *node = ast_create_node(pc, NodeTypeNullLiteral, token);
678678 *token_index += 1;
679679 return node;
680 } else if (token->id == TokenIdKeywordBreak) {
681 AstNode *node = ast_create_node(pc, NodeTypeBreak, token);
682 *token_index += 1;
683 return node;
684680 } else if (token->id == TokenIdKeywordContinue) {
685681 AstNode *node = ast_create_node(pc, NodeTypeContinue, token);
686682 *token_index += 1;
......@@ -1447,6 +1443,24 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, size_t *token_index) {
14471443 return node;
14481444}
14491445
1446/*
1447BreakExpression : "break" option(Expression)
1448*/
1449static AstNode *ast_parse_break_expr(ParseContext *pc, size_t *token_index) {
1450 Token *token = &pc->tokens->at(*token_index);
1451
1452 if (token->id == TokenIdKeywordBreak) {
1453 *token_index += 1;
1454 } else {
1455 return nullptr;
1456 }
1457
1458 AstNode *node = ast_create_node(pc, NodeTypeBreak, token);
1459 node->data.break_expr.expr = ast_parse_expression(pc, token_index, false);
1460
1461 return node;
1462}
1463
14501464/*
14511465Defer(body) = option("%") "defer" body
14521466*/
......@@ -1668,7 +1682,7 @@ static AstNode *ast_parse_symbol(ParseContext *pc, size_t *token_index) {
16681682}
16691683
16701684/*
1671ForExpression(body) = option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body
1685ForExpression(body) = option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body option("else" BlockExpression(body))
16721686*/
16731687static AstNode *ast_parse_for_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
16741688 Token *first_token = &pc->tokens->at(*token_index);
......@@ -1728,6 +1742,13 @@ static AstNode *ast_parse_for_expr(ParseContext *pc, size_t *token_index, bool m
17281742
17291743 node->data.for_expr.body = ast_parse_block_or_expression(pc, token_index, true);
17301744
1745 Token *else_tok = &pc->tokens->at(*token_index);
1746 if (else_tok->id == TokenIdKeywordElse) {
1747 *token_index += 1;
1748
1749 node->data.for_expr.else_node = ast_parse_block_or_expression(pc, token_index, true);
1750 }
1751
17311752 return node;
17321753}
17331754
......@@ -1981,7 +2002,7 @@ static AstNode *ast_parse_block_or_expression(ParseContext *pc, size_t *token_in
19812002}
19822003
19832004/*
1984Expression = ReturnExpression | AssignmentExpression
2005Expression = ReturnExpression | BreakExpression | AssignmentExpression
19852006*/
19862007static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool mandatory) {
19872008 Token *token = &pc->tokens->at(*token_index);
......@@ -1990,6 +2011,10 @@ static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool
19902011 if (return_expr)
19912012 return return_expr;
19922013
2014 AstNode *break_expr = ast_parse_break_expr(pc, token_index);
2015 if (break_expr)
2016 return break_expr;
2017
19932018 AstNode *ass_expr = ast_parse_ass_expr(pc, token_index, false);
19942019 if (ass_expr)
19952020 return ass_expr;
test/cases/while.zig+61
......@@ -134,3 +134,64 @@ fn getNumberOrNull() -> ?i32 {
134134 };
135135}
136136
137test "while on nullable with else result follow else prong" {
138 const result = while (returnNull()) |value| {
139 break value;
140 } else {
141 i32(2)
142 };
143 assert(result == 2);
144}
145
146test "while on nullable with else result follow break prong" {
147 const result = while (returnMaybe(10)) |value| {
148 break value;
149 } else {
150 i32(2)
151 };
152 assert(result == 10);
153}
154
155test "while on error union with else result follow else prong" {
156 const result = while (returnError()) |value| {
157 break value;
158 } else |err| {
159 i32(2)
160 };
161 assert(result == 2);
162}
163
164test "while on error union with else result follow break prong" {
165 const result = while (returnSuccess(10)) |value| {
166 break value;
167 } else |err| {
168 i32(2)
169 };
170 assert(result == 10);
171}
172
173test "while on bool with else result follow else prong" {
174 const result = while (returnFalse()) {
175 break i32(10);
176 } else {
177 i32(2)
178 };
179 assert(result == 2);
180}
181
182test "while on bool with else result follow break prong" {
183 const result = while (returnTrue()) {
184 break i32(10);
185 } else {
186 i32(2)
187 };
188 assert(result == 10);
189}
190
191fn returnNull() -> ?i32 { null }
192fn returnMaybe(x: i32) -> ?i32 { x }
193error YouWantedAnError;
194fn returnError() -> %i32 { error.YouWantedAnError }
195fn returnSuccess(x: i32) -> %i32 { x }
196fn returnFalse() -> bool { false }
197fn returnTrue() -> bool { true }