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"...@@ -45,7 +45,7 @@ TypeExpr = PrefixOpExpression | "var"
4545
46BlockOrExpression = Block | Expression46BlockOrExpression = Block | Expression
4747
48Expression = ReturnExpression | AssignmentExpression48Expression = ReturnExpression | BreakExpression | AssignmentExpression
4949
50AsmExpression = "asm" option("volatile") "(" String option(AsmOutput) ")"50AsmExpression = "asm" option("volatile") "(" String option(AsmOutput) ")"
5151
...@@ -79,12 +79,14 @@ SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" option("*") Symbo...@@ -79,12 +79,14 @@ SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" option("*") Symbo
7979
80SwitchItem = Expression | (Expression "..." Expression)80SwitchItem = Expression | (Expression "..." Expression)
8181
82ForExpression(body) = "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body82ForExpression(body) = "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body option("else" BlockExpression(body))
8383
84BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression84BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression
8585
86ReturnExpression = option("%") "return" option(Expression)86ReturnExpression = option("%") "return" option(Expression)
8787
88BreakExpression = "break" option(Expression)
89
88Defer(body) = option("%") "defer" body90Defer(body) = option("%") "defer" body
8991
90IfExpression(body) = "if" "(" Expression ")" body option("else" BlockExpression(body))92IfExpression(body) = "if" "(" Expression ")" body option("else" BlockExpression(body))
...@@ -151,7 +153,7 @@ GotoExpression = "goto" Symbol...@@ -151,7 +153,7 @@ GotoExpression = "goto" Symbol
151153
152GroupedExpression = "(" Expression ")"154GroupedExpression = "(" Expression ")"
153155
154KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "this" | "unreachable"156KeywordLiteral = "true" | "false" | "null" | "continue" | "undefined" | "error" | "this" | "unreachable"
155157
156ContainerDecl = option("extern" | "packed") ("struct" | "enum" | "union") "{" many(ContainerMember) "}"158ContainerDecl = option("extern" | "packed") ("struct" | "enum" | "union") "{" many(ContainerMember) "}"
157```159```
src/all_types.hpp+2
...@@ -623,6 +623,7 @@ struct AstNodeForExpr {...@@ -623,6 +623,7 @@ struct AstNodeForExpr {
623 AstNode *elem_node; // always a symbol623 AstNode *elem_node; // always a symbol
624 AstNode *index_node; // always a symbol, might be null624 AstNode *index_node; // always a symbol, might be null
625 AstNode *body;625 AstNode *body;
626 AstNode *else_node; // can be null
626 bool elem_is_ptr;627 bool elem_is_ptr;
627 bool is_inline;628 bool is_inline;
628};629};
...@@ -774,6 +775,7 @@ struct AstNodeBoolLiteral {...@@ -774,6 +775,7 @@ struct AstNodeBoolLiteral {
774};775};
775776
776struct AstNodeBreakExpr {777struct AstNodeBreakExpr {
778 AstNode *expr; // may be null
777};779};
778780
779struct AstNodeContinueExpr {781struct AstNodeContinueExpr {
src/ast_render.cpp+13-5
...@@ -485,6 +485,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -485,6 +485,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
485 }485 }
486 break;486 break;
487 }487 }
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 }
488 case NodeTypeDefer:497 case NodeTypeDefer:
489 {498 {
490 const char *defer_str = defer_string(node->data.defer.kind);499 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) {...@@ -880,11 +889,10 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
880 fprintf(ar->f, "| ");889 fprintf(ar->f, "| ");
881 }890 }
882 render_node_grouped(ar, node->data.for_expr.body);891 render_node_grouped(ar, node->data.for_expr.body);
883 break;892 if (node->data.for_expr.else_node) {
884 }893 fprintf(ar->f, " else");
885 case NodeTypeBreak:894 render_node_grouped(ar, node->data.for_expr.else_node);
886 {895 }
887 fprintf(ar->f, "break");
888 break;896 break;
889 }897 }
890 case NodeTypeContinue:898 case NodeTypeContinue:
src/ir.cpp+104-27
...@@ -22,6 +22,8 @@ struct LoopStackItem {...@@ -22,6 +22,8 @@ struct LoopStackItem {
22 IrBasicBlock *break_block;22 IrBasicBlock *break_block;
23 IrBasicBlock *continue_block;23 IrBasicBlock *continue_block;
24 IrInstruction *is_comptime;24 IrInstruction *is_comptime;
25 ZigList<IrInstruction *> *incoming_values;
26 ZigList<IrBasicBlock *> *incoming_blocks;
25};27};
2628
27struct IrBuilder {29struct IrBuilder {
...@@ -56,6 +58,18 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *sc...@@ -56,6 +58,18 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *sc
56static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction);58static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction);
57static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, TypeTableEntry *expected_type);59static 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
59ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {73ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {
60 assert(const_val->type->id == TypeTableEntryIdPointer);74 assert(const_val->type->id == TypeTableEntryIdPointer);
61 assert(const_val->special == ConstValSpecialStatic);75 assert(const_val->special == ConstValSpecialStatic);
...@@ -4693,6 +4707,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n...@@ -4693,6 +4707,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
4693 return err_val_ptr;4707 return err_val_ptr;
4694 IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr);4708 IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr);
4695 IrInstruction *is_err = ir_build_test_err(irb, scope, node->data.while_expr.condition, err_val);4709 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));
4696 if (!instr_is_unreachable(is_err)) {4712 if (!instr_is_unreachable(is_err)) {
4697 ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_err,4713 ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_err,
4698 else_block, body_block, is_comptime));4714 else_block, body_block, is_comptime));
...@@ -4706,10 +4722,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n...@@ -4706,10 +4722,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
4706 var_ptr_value : ir_build_load_ptr(irb, payload_scope, symbol_node, var_ptr_value);4722 var_ptr_value : ir_build_load_ptr(irb, payload_scope, symbol_node, var_ptr_value);
4707 ir_build_var_decl(irb, payload_scope, symbol_node, payload_var, nullptr, var_value);4723 ir_build_var_decl(irb, payload_scope, symbol_node, payload_var, nullptr, var_value);
4708 }4724 }
4709 LoopStackItem *loop_stack_item = irb->loop_stack.add_one();4725 ZigList<IrInstruction *> incoming_values = {0};
4710 loop_stack_item->break_block = end_block;4726 ZigList<IrBasicBlock *> incoming_blocks = {0};
4711 loop_stack_item->continue_block = continue_block;4727 add_loop_stack_item(irb, end_block, continue_block, is_comptime, &incoming_blocks, &incoming_values);
4712 loop_stack_item->is_comptime = is_comptime;
4713 IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, payload_scope);4728 IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, payload_scope);
4714 if (body_result == irb->codegen->invalid_instruction)4729 if (body_result == irb->codegen->invalid_instruction)
4715 return body_result;4730 return body_result;
...@@ -4727,6 +4742,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n...@@ -4727,6 +4742,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
4727 ir_mark_gen(ir_build_br(irb, payload_scope, node, cond_block, is_comptime));4742 ir_mark_gen(ir_build_br(irb, payload_scope, node, cond_block, is_comptime));
4728 }4743 }
47294744
4745 IrInstruction *else_result = nullptr;
4730 if (else_node) {4746 if (else_node) {
4731 ir_set_cursor_at_end(irb, else_block);4747 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...@@ -4738,15 +4754,23 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
4738 IrInstruction *err_var_value = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr);4754 IrInstruction *err_var_value = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr);
4739 ir_build_var_decl(irb, err_scope, symbol_node, err_var, nullptr, err_var_value);4755 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);
4742 if (else_result == irb->codegen->invalid_instruction)4758 if (else_result == irb->codegen->invalid_instruction)
4743 return else_result;4759 return else_result;
4744 if (!instr_is_unreachable(else_result))4760 if (!instr_is_unreachable(else_result))
4745 ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));4761 ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
4746 }4762 }
47474763 IrBasicBlock *after_else_block = irb->current_basic_block;
4748 ir_set_cursor_at_end(irb, end_block);4764 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);
4750 } else if (var_symbol != nullptr) {4774 } else if (var_symbol != nullptr) {
4751 ir_set_cursor_at_end(irb, cond_block);4775 ir_set_cursor_at_end(irb, cond_block);
4752 // TODO make it an error to write to payload variable4776 // 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...@@ -4759,6 +4783,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
4759 return maybe_val_ptr;4783 return maybe_val_ptr;
4760 IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr);4784 IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr);
4761 IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node->data.while_expr.condition, maybe_val);4785 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));
4762 if (!instr_is_unreachable(is_non_null)) {4788 if (!instr_is_unreachable(is_non_null)) {
4763 ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_non_null,4789 ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_non_null,
4764 body_block, else_block, is_comptime));4790 body_block, else_block, is_comptime));
...@@ -4769,10 +4795,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n...@@ -4769,10 +4795,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
4769 IrInstruction *var_value = node->data.while_expr.var_is_ptr ?4795 IrInstruction *var_value = node->data.while_expr.var_is_ptr ?
4770 var_ptr_value : ir_build_load_ptr(irb, child_scope, symbol_node, var_ptr_value);4796 var_ptr_value : ir_build_load_ptr(irb, child_scope, symbol_node, var_ptr_value);
4771 ir_build_var_decl(irb, child_scope, symbol_node, payload_var, nullptr, var_value);4797 ir_build_var_decl(irb, child_scope, symbol_node, payload_var, nullptr, var_value);
4772 LoopStackItem *loop_stack_item = irb->loop_stack.add_one();4798 ZigList<IrInstruction *> incoming_values = {0};
4773 loop_stack_item->break_block = end_block;4799 ZigList<IrBasicBlock *> incoming_blocks = {0};
4774 loop_stack_item->continue_block = continue_block;4800 add_loop_stack_item(irb, end_block, continue_block, is_comptime, &incoming_blocks, &incoming_values);
4775 loop_stack_item->is_comptime = is_comptime;
4776 IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, child_scope);4801 IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, child_scope);
4777 if (body_result == irb->codegen->invalid_instruction)4802 if (body_result == irb->codegen->invalid_instruction)
4778 return body_result;4803 return body_result;
...@@ -4790,18 +4815,27 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n...@@ -4790,18 +4815,27 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
4790 ir_mark_gen(ir_build_br(irb, child_scope, node, cond_block, is_comptime));4815 ir_mark_gen(ir_build_br(irb, child_scope, node, cond_block, is_comptime));
4791 }4816 }
47924817
4818 IrInstruction *else_result = nullptr;
4793 if (else_node) {4819 if (else_node) {
4794 ir_set_cursor_at_end(irb, else_block);4820 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);
4797 if (else_result == irb->codegen->invalid_instruction)4823 if (else_result == irb->codegen->invalid_instruction)
4798 return else_result;4824 return else_result;
4799 if (!instr_is_unreachable(else_result))4825 if (!instr_is_unreachable(else_result))
4800 ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));4826 ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
4801 }4827 }
48024828 IrBasicBlock *after_else_block = irb->current_basic_block;
4803 ir_set_cursor_at_end(irb, end_block);4829 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);
4805 } else {4839 } else {
4806 if (continue_expr_node) {4840 if (continue_expr_node) {
4807 ir_set_cursor_at_end(irb, continue_block);4841 ir_set_cursor_at_end(irb, continue_block);
...@@ -4816,6 +4850,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n...@@ -4816,6 +4850,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
4816 IrInstruction *cond_val = ir_gen_node(irb, node->data.while_expr.condition, scope);4850 IrInstruction *cond_val = ir_gen_node(irb, node->data.while_expr.condition, scope);
4817 if (cond_val == irb->codegen->invalid_instruction)4851 if (cond_val == irb->codegen->invalid_instruction)
4818 return cond_val;4852 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));
4819 if (!instr_is_unreachable(cond_val)) {4855 if (!instr_is_unreachable(cond_val)) {
4820 ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, cond_val,4856 ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, cond_val,
4821 body_block, else_block, is_comptime));4857 body_block, else_block, is_comptime));
...@@ -4823,10 +4859,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n...@@ -4823,10 +4859,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
48234859
4824 ir_set_cursor_at_end(irb, body_block);4860 ir_set_cursor_at_end(irb, body_block);
48254861
4826 LoopStackItem *loop_stack_item = irb->loop_stack.add_one();4862 ZigList<IrInstruction *> incoming_values = {0};
4827 loop_stack_item->break_block = end_block;4863 ZigList<IrBasicBlock *> incoming_blocks = {0};
4828 loop_stack_item->continue_block = continue_block;4864 add_loop_stack_item(irb, end_block, continue_block, is_comptime, &incoming_blocks, &incoming_values);
4829 loop_stack_item->is_comptime = is_comptime;
4830 IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, scope);4865 IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, scope);
4831 if (body_result == irb->codegen->invalid_instruction)4866 if (body_result == irb->codegen->invalid_instruction)
4832 return body_result;4867 return body_result;
...@@ -4835,19 +4870,27 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n...@@ -4835,19 +4870,27 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
4835 if (!instr_is_unreachable(body_result))4870 if (!instr_is_unreachable(body_result))
4836 ir_mark_gen(ir_build_br(irb, scope, node, continue_block, is_comptime));4871 ir_mark_gen(ir_build_br(irb, scope, node, continue_block, is_comptime));
48374872
4873 IrInstruction *else_result = nullptr;
4838 if (else_node) {4874 if (else_node) {
4839 ir_set_cursor_at_end(irb, else_block);4875 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);
4842 if (else_result == irb->codegen->invalid_instruction)4878 if (else_result == irb->codegen->invalid_instruction)
4843 return else_result;4879 return else_result;
4844 if (!instr_is_unreachable(else_result))4880 if (!instr_is_unreachable(else_result))
4845 ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));4881 ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
4846 }4882 }
48474883 IrBasicBlock *after_else_block = irb->current_basic_block;
4848 ir_set_cursor_at_end(irb, end_block);4884 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);
4851 }4894 }
4852}4895}
48534896
...@@ -4858,6 +4901,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo...@@ -4858,6 +4901,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
4858 AstNode *elem_node = node->data.for_expr.elem_node;4901 AstNode *elem_node = node->data.for_expr.elem_node;
4859 AstNode *index_node = node->data.for_expr.index_node;4902 AstNode *index_node = node->data.for_expr.index_node;
4860 AstNode *body_node = node->data.for_expr.body;4903 AstNode *body_node = node->data.for_expr.body;
4904 AstNode *else_node = node->data.for_expr.else_node;
48614905
4862 if (!elem_node) {4906 if (!elem_node) {
4863 add_node_error(irb->codegen, node, buf_sprintf("for loop expression missing element parameter"));4907 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...@@ -4915,6 +4959,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
4915 IrBasicBlock *cond_block = ir_build_basic_block(irb, child_scope, "ForCond");4959 IrBasicBlock *cond_block = ir_build_basic_block(irb, child_scope, "ForCond");
4916 IrBasicBlock *body_block = ir_build_basic_block(irb, child_scope, "ForBody");4960 IrBasicBlock *body_block = ir_build_basic_block(irb, child_scope, "ForBody");
4917 IrBasicBlock *end_block = ir_build_basic_block(irb, child_scope, "ForEnd");4961 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;
4918 IrBasicBlock *continue_block = ir_build_basic_block(irb, child_scope, "ForContinue");4963 IrBasicBlock *continue_block = ir_build_basic_block(irb, child_scope, "ForContinue");
49194964
4920 IrInstruction *len_val = ir_build_array_len(irb, child_scope, node, array_val);4965 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...@@ -4923,7 +4968,9 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
4923 ir_set_cursor_at_end(irb, cond_block);4968 ir_set_cursor_at_end(irb, cond_block);
4924 IrInstruction *index_val = ir_build_load_ptr(irb, child_scope, node, index_ptr);4969 IrInstruction *index_val = ir_build_load_ptr(irb, child_scope, node, index_ptr);
4925 IrInstruction *cond = ir_build_bin_op(irb, child_scope, node, IrBinOpCmpLessThan, index_val, len_val, false);4970 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
4928 ir_set_cursor_at_end(irb, body_block);4975 ir_set_cursor_at_end(irb, body_block);
4929 IrInstruction *elem_ptr = ir_build_elem_ptr(irb, child_scope, node, array_val_ptr, index_val, false);4976 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...@@ -4935,10 +4982,9 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
4935 }4982 }
4936 ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, elem_var_ptr, elem_val));4983 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();4985 ZigList<IrInstruction *> incoming_values = {0};
4939 loop_stack_item->break_block = end_block;4986 ZigList<IrBasicBlock *> incoming_blocks = {0};
4940 loop_stack_item->continue_block = continue_block;4987 add_loop_stack_item(irb, end_block, continue_block, is_comptime, &incoming_blocks, &incoming_values);
4941 loop_stack_item->is_comptime = is_comptime;
4942 IrInstruction *body_result = ir_gen_node(irb, body_node, child_scope);4988 IrInstruction *body_result = ir_gen_node(irb, body_node, child_scope);
4943 irb->loop_stack.pop();4989 irb->loop_stack.pop();
49444990
...@@ -4950,9 +4996,28 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo...@@ -4950,9 +4996,28 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
4950 ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, index_ptr, new_index_val));4996 ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, index_ptr, new_index_val));
4951 ir_build_br(irb, child_scope, node, cond_block, is_comptime);4997 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;
4953 ir_set_cursor_at_end(irb, end_block);5010 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);
4956}5021}
49575022
4958static IrInstruction *ir_gen_this_literal(IrBuilder *irb, Scope *scope, AstNode *node) {5023static 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)...@@ -5512,8 +5577,20 @@ static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *scope, AstNode *node)
5512 is_comptime = loop_stack_item->is_comptime;5577 is_comptime = loop_stack_item->is_comptime;
5513 }5578 }
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
5515 IrBasicBlock *dest_block = loop_stack_item->break_block;5589 IrBasicBlock *dest_block = loop_stack_item->break_block;
5516 ir_gen_defers_for_block(irb, scope, dest_block->scope, false);5590 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);
5517 return ir_build_br(irb, scope, node, dest_block, is_comptime);5594 return ir_build_br(irb, scope, node, dest_block, is_comptime);
5518}5595}
55195596
src/parser.cpp+32-7
...@@ -641,7 +641,7 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b...@@ -641,7 +641,7 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b
641641
642/*642/*
643PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl643PrimaryExpression = 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"
645*/645*/
646static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) {646static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
647 Token *token = &pc->tokens->at(*token_index);647 Token *token = &pc->tokens->at(*token_index);
...@@ -677,10 +677,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo...@@ -677,10 +677,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
677 AstNode *node = ast_create_node(pc, NodeTypeNullLiteral, token);677 AstNode *node = ast_create_node(pc, NodeTypeNullLiteral, token);
678 *token_index += 1;678 *token_index += 1;
679 return node;679 return node;
680 } else if (token->id == TokenIdKeywordBreak) {
681 AstNode *node = ast_create_node(pc, NodeTypeBreak, token);
682 *token_index += 1;
683 return node;
684 } else if (token->id == TokenIdKeywordContinue) {680 } else if (token->id == TokenIdKeywordContinue) {
685 AstNode *node = ast_create_node(pc, NodeTypeContinue, token);681 AstNode *node = ast_create_node(pc, NodeTypeContinue, token);
686 *token_index += 1;682 *token_index += 1;
...@@ -1447,6 +1443,24 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, size_t *token_index) {...@@ -1447,6 +1443,24 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, size_t *token_index) {
1447 return node;1443 return node;
1448}1444}
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
1450/*1464/*
1451Defer(body) = option("%") "defer" body1465Defer(body) = option("%") "defer" body
1452*/1466*/
...@@ -1668,7 +1682,7 @@ static AstNode *ast_parse_symbol(ParseContext *pc, size_t *token_index) {...@@ -1668,7 +1682,7 @@ static AstNode *ast_parse_symbol(ParseContext *pc, size_t *token_index) {
1668}1682}
16691683
1670/*1684/*
1671ForExpression(body) = option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body1685ForExpression(body) = option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body option("else" BlockExpression(body))
1672*/1686*/
1673static AstNode *ast_parse_for_expr(ParseContext *pc, size_t *token_index, bool mandatory) {1687static AstNode *ast_parse_for_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
1674 Token *first_token = &pc->tokens->at(*token_index);1688 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...@@ -1728,6 +1742,13 @@ static AstNode *ast_parse_for_expr(ParseContext *pc, size_t *token_index, bool m
17281742
1729 node->data.for_expr.body = ast_parse_block_or_expression(pc, token_index, true);1743 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
1731 return node;1752 return node;
1732}1753}
17331754
...@@ -1981,7 +2002,7 @@ static AstNode *ast_parse_block_or_expression(ParseContext *pc, size_t *token_in...@@ -1981,7 +2002,7 @@ static AstNode *ast_parse_block_or_expression(ParseContext *pc, size_t *token_in
1981}2002}
19822003
1983/*2004/*
1984Expression = ReturnExpression | AssignmentExpression2005Expression = ReturnExpression | BreakExpression | AssignmentExpression
1985*/2006*/
1986static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool mandatory) {2007static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool mandatory) {
1987 Token *token = &pc->tokens->at(*token_index);2008 Token *token = &pc->tokens->at(*token_index);
...@@ -1990,6 +2011,10 @@ static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool...@@ -1990,6 +2011,10 @@ static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool
1990 if (return_expr)2011 if (return_expr)
1991 return return_expr;2012 return return_expr;
19922013
2014 AstNode *break_expr = ast_parse_break_expr(pc, token_index);
2015 if (break_expr)
2016 return break_expr;
2017
1993 AstNode *ass_expr = ast_parse_ass_expr(pc, token_index, false);2018 AstNode *ass_expr = ast_parse_ass_expr(pc, token_index, false);
1994 if (ass_expr)2019 if (ass_expr)
1995 return ass_expr;2020 return ass_expr;
test/cases/while.zig+61
...@@ -134,3 +134,64 @@ fn getNumberOrNull() -> ?i32 {...@@ -134,3 +134,64 @@ fn getNumberOrNull() -> ?i32 {
134 };134 };
135}135}
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 }