| ... | @@ -4658,51 +4658,197 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n | ... | @@ -4658,51 +4658,197 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 4658 | assert(node->type == NodeTypeWhileExpr); | 4658 | assert(node->type == NodeTypeWhileExpr); |
| 4659 | | 4659 | |
| 4660 | AstNode *continue_expr_node = node->data.while_expr.continue_expr; | 4660 | AstNode *continue_expr_node = node->data.while_expr.continue_expr; |
| | 4661 | AstNode *else_node = node->data.while_expr.else_node; |
| 4661 | | 4662 | |
| 4662 | IrBasicBlock *cond_block = ir_build_basic_block(irb, scope, "WhileCond"); | 4663 | IrBasicBlock *cond_block = ir_build_basic_block(irb, scope, "WhileCond"); |
| 4663 | IrBasicBlock *body_block = ir_build_basic_block(irb, scope, "WhileBody"); | 4664 | IrBasicBlock *body_block = ir_build_basic_block(irb, scope, "WhileBody"); |
| 4664 | IrBasicBlock *continue_block = continue_expr_node ? | 4665 | IrBasicBlock *continue_block = continue_expr_node ? |
| 4665 | ir_build_basic_block(irb, scope, "WhileContinue") : cond_block; | 4666 | ir_build_basic_block(irb, scope, "WhileContinue") : cond_block; |
| 4666 | IrBasicBlock *end_block = ir_build_basic_block(irb, scope, "WhileEnd"); | 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 | IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, | 4671 | IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, |
| 4669 | ir_should_inline(irb->exec, scope) || node->data.while_expr.is_inline); | 4672 | ir_should_inline(irb->exec, scope) || node->data.while_expr.is_inline); |
| 4670 | ir_build_br(irb, scope, node, cond_block, is_comptime); | 4673 | ir_build_br(irb, scope, node, cond_block, is_comptime); |
| 4671 | | 4674 | |
| 4672 | if (continue_expr_node) { | 4675 | Buf *var_symbol = node->data.while_expr.var_symbol; |
| 4673 | ir_set_cursor_at_end(irb, continue_block); | 4676 | Buf *err_symbol = node->data.while_expr.err_symbol; |
| 4674 | IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, scope); | 4677 | if (err_symbol != nullptr) { |
| 4675 | if (expr_result == irb->codegen->invalid_instruction) | 4678 | ir_set_cursor_at_end(irb, cond_block); |
| 4676 | return expr_result; | 4679 | |
| 4677 | if (!instr_is_unreachable(expr_result)) | 4680 | Scope *payload_scope; |
| 4678 | ir_mark_gen(ir_build_br(irb, scope, node, cond_block, is_comptime)); | 4681 | AstNode *symbol_node = node; // TODO make more accurate |
| 4679 | } | 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); | 4733 | // TODO make it an error to write to error variable |
| 4682 | IrInstruction *cond_val = ir_gen_node(irb, node->data.while_expr.condition, scope); | 4734 | AstNode *err_symbol_node = else_node; // TODO make more accurate |
| 4683 | if (cond_val == irb->codegen->invalid_instruction) | 4735 | VariableTableEntry *err_var = ir_create_var(irb, err_symbol_node, scope, err_symbol, |
| 4684 | return cond_val; | 4736 | true, false, false, is_comptime); |
| 4685 | if (!instr_is_unreachable(cond_val)) { | 4737 | Scope *err_scope = err_var->child_scope; |
| 4686 | ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, cond_val, | 4738 | IrInstruction *err_var_value = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr); |
| 4687 | body_block, end_block, is_comptime)); | 4739 | ir_build_var_decl(irb, err_scope, symbol_node, err_var, nullptr, err_var_value); |
| 4688 | } | 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(); | 4803 | ir_set_cursor_at_end(irb, end_block); |
| 4693 | loop_stack_item->break_block = end_block; | 4804 | return ir_build_const_void(irb, scope, node); |
| 4694 | loop_stack_item->continue_block = continue_block; | 4805 | } else { |
| 4695 | loop_stack_item->is_comptime = is_comptime; | 4806 | if (continue_expr_node) { |
| 4696 | IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, scope); | 4807 | ir_set_cursor_at_end(irb, continue_block); |
| 4697 | if (body_result == irb->codegen->invalid_instruction) | 4808 | IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, scope); |
| 4698 | return body_result; | 4809 | if (expr_result == irb->codegen->invalid_instruction) |
| 4699 | irb->loop_stack.pop(); | 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)) | 4841 | IrInstruction *else_result = ir_gen_node(irb, else_node, scope); |
| 4702 | ir_mark_gen(ir_build_br(irb, scope, node, continue_block, is_comptime)); | 4842 | if (else_result == irb->codegen->invalid_instruction) |
| 4703 | ir_set_cursor_at_end(irb, end_block); | 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 | static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node) { | 4854 | static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node) { |