@@ -4658,51 +4658,197 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
4658
4658
assert(node->type == NodeTypeWhileExpr);
4659
4659
4660
4660
AstNode *continue_expr_node = node->data.while_expr.continue_expr;
4661
+ AstNode *else_node = node->data.while_expr.else_node;
4661
4662
4662
4663
IrBasicBlock *cond_block = ir_build_basic_block(irb, scope, "WhileCond");
4663
4664
IrBasicBlock *body_block = ir_build_basic_block(irb, scope, "WhileBody");
4664
4665
IrBasicBlock *continue_block = continue_expr_node ?
4665
4666
ir_build_basic_block(irb, scope, "WhileContinue") : cond_block;
4666
4667
IrBasicBlock *end_block = ir_build_basic_block(irb, scope, "WhileEnd");
4668
+ IrBasicBlock *else_block = else_node ?
4669
+ ir_build_basic_block(irb, scope, "WhileElse") : end_block;
4667
4670
4668
4671
IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node,
4669
4672
ir_should_inline(irb->exec, scope) || node->data.while_expr.is_inline);
4670
4673
ir_build_br(irb, scope, node, cond_block, is_comptime);
4671
4674
4672
- if (continue_expr_node) {
4673
- ir_set_cursor_at_end(irb, continue_block);
4674
- IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, scope);
4675
- if (expr_result == irb->codegen->invalid_instruction)
4676
- return expr_result;
4677
- if (!instr_is_unreachable(expr_result))
4678
- ir_mark_gen(ir_build_br(irb, scope, node, cond_block, is_comptime));
4679
- }
4675
+ Buf *var_symbol = node->data.while_expr.var_symbol;
4676
+ Buf *err_symbol = node->data.while_expr.err_symbol;
4677
+ if (err_symbol != nullptr) {
4678
+ ir_set_cursor_at_end(irb, cond_block);
4679
+
4680
+ Scope *payload_scope;
4681
+ AstNode *symbol_node = node; // TODO make more accurate
4682
+ VariableTableEntry *payload_var;
4683
+ if (var_symbol) {
4684
+ // TODO make it an error to write to payload variable
4685
+ payload_var = ir_create_var(irb, symbol_node, scope, var_symbol,
4686
+ true, false, false, is_comptime);
4687
+ payload_scope = payload_var->child_scope;
4688
+ } else {
4689
+ payload_scope = scope;
4690
+ }
4691
+ IrInstruction *err_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, scope, LVAL_PTR);
4692
+ if (err_val_ptr == irb->codegen->invalid_instruction)
4693
+ return err_val_ptr;
4694
+ 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);
4696
+ if (!instr_is_unreachable(is_err)) {
4697
+ ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_err,
4698
+ else_block, body_block, is_comptime));
4699
+ }
4700
+
4701
+ ir_set_cursor_at_end(irb, body_block);
4702
+ if (var_symbol) {
4703
+ IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, payload_scope, symbol_node,
4704
+ err_val_ptr, false);
4705
+ IrInstruction *var_value = node->data.while_expr.var_is_ptr ?
4706
+ 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);
4708
+ }
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;
4713
+ IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, payload_scope);
4714
+ if (body_result == irb->codegen->invalid_instruction)
4715
+ return body_result;
4716
+ irb->loop_stack.pop();
4717
+
4718
+ if (!instr_is_unreachable(body_result))
4719
+ ir_mark_gen(ir_build_br(irb, payload_scope, node, continue_block, is_comptime));
4720
+
4721
+ if (continue_expr_node) {
4722
+ ir_set_cursor_at_end(irb, continue_block);
4723
+ IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, payload_scope);
4724
+ if (expr_result == irb->codegen->invalid_instruction)
4725
+ return expr_result;
4726
+ if (!instr_is_unreachable(expr_result))
4727
+ ir_mark_gen(ir_build_br(irb, payload_scope, node, cond_block, is_comptime));
4728
+ }
4729
+
4730
+ if (else_node) {
4731
+ ir_set_cursor_at_end(irb, else_block);
4680
4732
4681
- ir_set_cursor_at_end(irb, cond_block);
4682
- IrInstruction *cond_val = ir_gen_node(irb, node->data.while_expr.condition, scope);
4683
- if (cond_val == irb->codegen->invalid_instruction)
4684
- return cond_val;
4685
- if (!instr_is_unreachable(cond_val)) {
4686
- ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, cond_val,
4687
- body_block, end_block, is_comptime));
4688
- }
4733
+ // TODO make it an error to write to error variable
4734
+ AstNode *err_symbol_node = else_node; // TODO make more accurate
4735
+ VariableTableEntry *err_var = ir_create_var(irb, err_symbol_node, scope, err_symbol,
4736
+ true, false, false, is_comptime);
4737
+ Scope *err_scope = err_var->child_scope;
4738
+ 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);
4740
+
4741
+ IrInstruction *else_result = ir_gen_node(irb, else_node, err_scope);
4742
+ if (else_result == irb->codegen->invalid_instruction)
4743
+ return else_result;
4744
+ if (!instr_is_unreachable(else_result))
4745
+ ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
4746
+ }
4747
+
4748
+ ir_set_cursor_at_end(irb, end_block);
4749
+ return ir_build_const_void(irb, scope, node);
4750
+ } else if (var_symbol != nullptr) {
4751
+ ir_set_cursor_at_end(irb, cond_block);
4752
+ // TODO make it an error to write to payload variable
4753
+ AstNode *symbol_node = node; // TODO make more accurate
4754
+ VariableTableEntry *payload_var = ir_create_var(irb, symbol_node, scope, var_symbol,
4755
+ true, false, false, is_comptime);
4756
+ Scope *child_scope = payload_var->child_scope;
4757
+ IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, scope, LVAL_PTR);
4758
+ if (maybe_val_ptr == irb->codegen->invalid_instruction)
4759
+ return maybe_val_ptr;
4760
+ 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);
4762
+ 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,
4764
+ body_block, else_block, is_comptime));
4765
+ }
4766
+
4767
+ ir_set_cursor_at_end(irb, body_block);
4768
+ IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, child_scope, symbol_node, maybe_val_ptr, false);
4769
+ 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);
4771
+ 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;
4776
+ IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, child_scope);
4777
+ if (body_result == irb->codegen->invalid_instruction)
4778
+ return body_result;
4779
+ irb->loop_stack.pop();
4780
+
4781
+ if (!instr_is_unreachable(body_result))
4782
+ ir_mark_gen(ir_build_br(irb, child_scope, node, continue_block, is_comptime));
4783
+
4784
+ if (continue_expr_node) {
4785
+ ir_set_cursor_at_end(irb, continue_block);
4786
+ IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, child_scope);
4787
+ if (expr_result == irb->codegen->invalid_instruction)
4788
+ return expr_result;
4789
+ if (!instr_is_unreachable(expr_result))
4790
+ ir_mark_gen(ir_build_br(irb, child_scope, node, cond_block, is_comptime));
4791
+ }
4792
+
4793
+ if (else_node) {
4794
+ ir_set_cursor_at_end(irb, else_block);
4689
4795
4690
- ir_set_cursor_at_end(irb, body_block);
4796
+ IrInstruction *else_result = ir_gen_node(irb, else_node, scope);
4797
+ if (else_result == irb->codegen->invalid_instruction)
4798
+ return else_result;
4799
+ if (!instr_is_unreachable(else_result))
4800
+ ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
4801
+ }
4691
4802
4692
- LoopStackItem *loop_stack_item = irb->loop_stack.add_one();
4693
- loop_stack_item->break_block = end_block;
4694
- loop_stack_item->continue_block = continue_block;
4695
- loop_stack_item->is_comptime = is_comptime;
4696
- IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, scope);
4697
- if (body_result == irb->codegen->invalid_instruction)
4698
- return body_result;
4699
- irb->loop_stack.pop();
4803
+ ir_set_cursor_at_end(irb, end_block);
4804
+ return ir_build_const_void(irb, scope, node);
4805
+ } else {
4806
+ if (continue_expr_node) {
4807
+ ir_set_cursor_at_end(irb, continue_block);
4808
+ IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, scope);
4809
+ if (expr_result == irb->codegen->invalid_instruction)
4810
+ return expr_result;
4811
+ if (!instr_is_unreachable(expr_result))
4812
+ ir_mark_gen(ir_build_br(irb, scope, node, cond_block, is_comptime));
4813
+ }
4814
+
4815
+ ir_set_cursor_at_end(irb, cond_block);
4816
+ IrInstruction *cond_val = ir_gen_node(irb, node->data.while_expr.condition, scope);
4817
+ if (cond_val == irb->codegen->invalid_instruction)
4818
+ return cond_val;
4819
+ if (!instr_is_unreachable(cond_val)) {
4820
+ ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, cond_val,
4821
+ body_block, else_block, is_comptime));
4822
+ }
4823
+
4824
+ ir_set_cursor_at_end(irb, body_block);
4825
+
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;
4830
+ IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, scope);
4831
+ if (body_result == irb->codegen->invalid_instruction)
4832
+ return body_result;
4833
+ irb->loop_stack.pop();
4834
+
4835
+ if (!instr_is_unreachable(body_result))
4836
+ ir_mark_gen(ir_build_br(irb, scope, node, continue_block, is_comptime));
4837
+
4838
+ if (else_node) {
4839
+ ir_set_cursor_at_end(irb, else_block);
4700
4840
4701
- if (!instr_is_unreachable(body_result))
4702
- ir_mark_gen(ir_build_br(irb, scope, node, continue_block, is_comptime));
4703
- ir_set_cursor_at_end(irb, end_block);
4841
+ IrInstruction *else_result = ir_gen_node(irb, else_node, scope);
4842
+ if (else_result == irb->codegen->invalid_instruction)
4843
+ return else_result;
4844
+ if (!instr_is_unreachable(else_result))
4845
+ ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
4846
+ }
4704
4847
4705
- return ir_build_const_void(irb, scope, node);
4848
+ ir_set_cursor_at_end(irb, end_block);
4849
+
4850
+ return ir_build_const_void(irb, scope, node);
4851
+ }
4706
4852
}
4707
4853
4708
4854
static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
0 commit comments