| ... | ... | @@ -4711,109 +4711,120 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp |
| 4711 | 4711 | |
| 4712 | 4712 | static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *instruction) { |
| 4713 | 4713 | IrInstruction *op1 = instruction->op1->other; |
| 4714 | | if (op1->type_entry->id == TypeTableEntryIdInvalid) |
| 4714 | TypeTableEntry *op1_canon_type = get_underlying_type(op1->type_entry); |
| 4715 | if (op1_canon_type->id == TypeTableEntryIdInvalid) |
| 4715 | 4716 | return ira->codegen->builtin_types.entry_invalid; |
| 4716 | 4717 | |
| 4717 | 4718 | IrInstruction *op2 = instruction->op2->other; |
| 4718 | | if (op2->type_entry->id == TypeTableEntryIdInvalid) |
| 4719 | TypeTableEntry *op2_canon_type = get_underlying_type(op2->type_entry); |
| 4720 | if (op2_canon_type->id == TypeTableEntryIdInvalid) |
| 4719 | 4721 | return ira->codegen->builtin_types.entry_invalid; |
| 4720 | 4722 | |
| 4721 | | // AstNode **op1 = node->data.bin_op_expr.op1->parent_field; |
| 4722 | | // AstNode **op2 = node->data.bin_op_expr.op2->parent_field; |
| 4723 | | // |
| 4724 | | // TypeTableEntry *op1_type = analyze_expression(g, import, context, nullptr, *op1); |
| 4725 | | // TypeTableEntry *child_type; |
| 4726 | | // if (op1_type->id == TypeTableEntryIdInvalid) { |
| 4727 | | // return g->builtin_types.entry_invalid; |
| 4728 | | // } else if (op1_type->id == TypeTableEntryIdArray) { |
| 4729 | | // child_type = op1_type->data.array.child_type; |
| 4730 | | // } else if (op1_type->id == TypeTableEntryIdPointer && |
| 4731 | | // op1_type->data.pointer.child_type == g->builtin_types.entry_u8) { |
| 4732 | | // child_type = op1_type->data.pointer.child_type; |
| 4733 | | // } else { |
| 4734 | | // add_node_error(g, *op1, buf_sprintf("expected array or C string literal, found '%s'", |
| 4735 | | // buf_ptr(&op1_type->name))); |
| 4736 | | // return g->builtin_types.entry_invalid; |
| 4737 | | // } |
| 4738 | | // |
| 4739 | | // TypeTableEntry *op2_type = analyze_expression(g, import, context, nullptr, *op2); |
| 4740 | | // |
| 4741 | | // if (op2_type->id == TypeTableEntryIdInvalid) { |
| 4742 | | // return g->builtin_types.entry_invalid; |
| 4743 | | // } else if (op2_type->id == TypeTableEntryIdArray) { |
| 4744 | | // if (op2_type->data.array.child_type != child_type) { |
| 4745 | | // add_node_error(g, *op2, buf_sprintf("expected array of type '%s', found '%s'", |
| 4746 | | // buf_ptr(&child_type->name), |
| 4747 | | // buf_ptr(&op2_type->name))); |
| 4748 | | // return g->builtin_types.entry_invalid; |
| 4749 | | // } |
| 4750 | | // } else if (op2_type->id == TypeTableEntryIdPointer && |
| 4751 | | // op2_type->data.pointer.child_type == g->builtin_types.entry_u8) { |
| 4752 | | // } else { |
| 4753 | | // add_node_error(g, *op2, buf_sprintf("expected array or C string literal, found '%s'", |
| 4754 | | // buf_ptr(&op2_type->name))); |
| 4755 | | // return g->builtin_types.entry_invalid; |
| 4756 | | // } |
| 4757 | | // |
| 4758 | | // ConstExprValue *op1_val = &get_resolved_expr(*op1)->const_val; |
| 4759 | | // ConstExprValue *op2_val = &get_resolved_expr(*op2)->const_val; |
| 4760 | | // |
| 4761 | | // AstNode *bad_node; |
| 4762 | | // if (!op1_val->ok) { |
| 4763 | | // bad_node = *op1; |
| 4764 | | // } else if (!op2_val->ok) { |
| 4765 | | // bad_node = *op2; |
| 4766 | | // } else { |
| 4767 | | // bad_node = nullptr; |
| 4768 | | // } |
| 4769 | | // if (bad_node) { |
| 4770 | | // add_node_error(g, bad_node, buf_sprintf("array concatenation requires constant expression")); |
| 4771 | | // return g->builtin_types.entry_invalid; |
| 4772 | | // } |
| 4773 | | // |
| 4774 | | // ConstExprValue *const_val = &get_resolved_expr(node)->const_val; |
| 4775 | | // const_val->ok = true; |
| 4776 | | // const_val->depends_on_compile_var = op1_val->depends_on_compile_var || |
| 4777 | | // op2_val->depends_on_compile_var; |
| 4778 | | // |
| 4779 | | // if (op1_type->id == TypeTableEntryIdArray) { |
| 4780 | | // uint64_t new_len = op1_type->data.array.len + op2_type->data.array.len; |
| 4781 | | // const_val->data.x_array.fields = allocate<ConstExprValue*>(new_len); |
| 4782 | | // uint64_t next_index = 0; |
| 4783 | | // for (uint64_t i = 0; i < op1_type->data.array.len; i += 1, next_index += 1) { |
| 4784 | | // const_val->data.x_array.fields[next_index] = op1_val->data.x_array.fields[i]; |
| 4785 | | // } |
| 4786 | | // for (uint64_t i = 0; i < op2_type->data.array.len; i += 1, next_index += 1) { |
| 4787 | | // const_val->data.x_array.fields[next_index] = op2_val->data.x_array.fields[i]; |
| 4788 | | // } |
| 4789 | | // return get_array_type(g, child_type, new_len); |
| 4790 | | // } else if (op1_type->id == TypeTableEntryIdPointer) { |
| 4791 | | // if (!op1_val->data.x_ptr.is_c_str) { |
| 4792 | | // add_node_error(g, *op1, |
| 4793 | | // buf_sprintf("expected array or C string literal, found '%s'", |
| 4794 | | // buf_ptr(&op1_type->name))); |
| 4795 | | // return g->builtin_types.entry_invalid; |
| 4796 | | // } else if (!op2_val->data.x_ptr.is_c_str) { |
| 4797 | | // add_node_error(g, *op2, |
| 4798 | | // buf_sprintf("expected array or C string literal, found '%s'", |
| 4799 | | // buf_ptr(&op2_type->name))); |
| 4800 | | // return g->builtin_types.entry_invalid; |
| 4801 | | // } |
| 4802 | | // const_val->data.x_ptr.is_c_str = true; |
| 4803 | | // const_val->data.x_ptr.len = op1_val->data.x_ptr.len + op2_val->data.x_ptr.len - 1; |
| 4804 | | // const_val->data.x_ptr.ptr = allocate<ConstExprValue*>(const_val->data.x_ptr.len); |
| 4805 | | // uint64_t next_index = 0; |
| 4806 | | // for (uint64_t i = 0; i < op1_val->data.x_ptr.len - 1; i += 1, next_index += 1) { |
| 4807 | | // const_val->data.x_ptr.ptr[next_index] = op1_val->data.x_ptr.ptr[i]; |
| 4808 | | // } |
| 4809 | | // for (uint64_t i = 0; i < op2_val->data.x_ptr.len; i += 1, next_index += 1) { |
| 4810 | | // const_val->data.x_ptr.ptr[next_index] = op2_val->data.x_ptr.ptr[i]; |
| 4811 | | // } |
| 4812 | | // return op1_type; |
| 4813 | | // } else { |
| 4814 | | // zig_unreachable(); |
| 4815 | | // } |
| 4816 | | zig_panic("TODO"); |
| 4723 | ConstExprValue *op1_val = ir_resolve_const(ira, op1); |
| 4724 | if (!op1_val) |
| 4725 | return ira->codegen->builtin_types.entry_invalid; |
| 4726 | |
| 4727 | ConstExprValue *op2_val = ir_resolve_const(ira, op2); |
| 4728 | if (!op2_val) |
| 4729 | return ira->codegen->builtin_types.entry_invalid; |
| 4730 | |
| 4731 | ConstExprValue *op1_array_val; |
| 4732 | size_t op1_array_index; |
| 4733 | size_t op1_array_end; |
| 4734 | TypeTableEntry *child_type; |
| 4735 | if (op1_canon_type->id == TypeTableEntryIdArray) { |
| 4736 | child_type = op1_canon_type->data.array.child_type; |
| 4737 | op1_array_val = op1_val; |
| 4738 | op1_array_index = 0; |
| 4739 | op1_array_end = op1_val->data.x_array.size; |
| 4740 | } else if (op1_canon_type->id == TypeTableEntryIdPointer && |
| 4741 | op1_canon_type->data.pointer.child_type == ira->codegen->builtin_types.entry_u8 && |
| 4742 | op1_val->data.x_ptr.special == ConstPtrSpecialCStr) |
| 4743 | { |
| 4744 | child_type = op1_canon_type->data.pointer.child_type; |
| 4745 | op1_array_val = op1_val->data.x_ptr.base_ptr; |
| 4746 | op1_array_index = op1_val->data.x_ptr.index; |
| 4747 | op1_array_end = op1_array_val->data.x_array.size - 1; |
| 4748 | } else { |
| 4749 | ir_add_error(ira, op1, |
| 4750 | buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op1->type_entry->name))); |
| 4751 | // TODO if meta_type is type decl, add note pointing to type decl declaration |
| 4752 | return ira->codegen->builtin_types.entry_invalid; |
| 4753 | } |
| 4754 | |
| 4755 | ConstExprValue *op2_array_val; |
| 4756 | size_t op2_array_index; |
| 4757 | size_t op2_array_end; |
| 4758 | if (op2_canon_type->id == TypeTableEntryIdArray) { |
| 4759 | if (op2_canon_type->data.array.child_type != child_type) { |
| 4760 | ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", |
| 4761 | buf_ptr(&child_type->name), |
| 4762 | buf_ptr(&op2->type_entry->name))); |
| 4763 | return ira->codegen->builtin_types.entry_invalid; |
| 4764 | } |
| 4765 | op2_array_val = op2_val; |
| 4766 | op2_array_index = 0; |
| 4767 | op2_array_end = op2_array_val->data.x_array.size; |
| 4768 | } else if (op2_canon_type->id == TypeTableEntryIdPointer && |
| 4769 | op2_canon_type->data.pointer.child_type == ira->codegen->builtin_types.entry_u8 && |
| 4770 | op2_val->data.x_ptr.special == ConstPtrSpecialCStr) |
| 4771 | { |
| 4772 | if (child_type != ira->codegen->builtin_types.entry_u8) { |
| 4773 | ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", |
| 4774 | buf_ptr(&child_type->name), |
| 4775 | buf_ptr(&op2->type_entry->name))); |
| 4776 | return ira->codegen->builtin_types.entry_invalid; |
| 4777 | } |
| 4778 | op2_array_val = op2_val->data.x_ptr.base_ptr; |
| 4779 | op2_array_index = op2_val->data.x_ptr.index; |
| 4780 | op2_array_end = op2_array_val->data.x_array.size - 1; |
| 4781 | } else { |
| 4782 | ir_add_error(ira, op2, |
| 4783 | buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op1->type_entry->name))); |
| 4784 | // TODO if meta_type is type decl, add note pointing to type decl declaration |
| 4785 | return ira->codegen->builtin_types.entry_invalid; |
| 4786 | } |
| 4787 | |
| 4788 | bool depends_on_compile_var = op1->static_value.depends_on_compile_var || op2->static_value.depends_on_compile_var; |
| 4789 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var); |
| 4790 | |
| 4791 | TypeTableEntry *result_type; |
| 4792 | ConstExprValue *out_array_val; |
| 4793 | size_t new_len = (op1_array_end - op1_array_index) + (op2_array_end - op2_array_index); |
| 4794 | if (op1_canon_type->id == TypeTableEntryIdArray || op2_canon_type->id == TypeTableEntryIdArray) { |
| 4795 | result_type = get_array_type(ira->codegen, child_type, new_len); |
| 4796 | |
| 4797 | out_array_val = out_val; |
| 4798 | } else { |
| 4799 | result_type = get_pointer_to_type(ira->codegen, child_type, true); |
| 4800 | |
| 4801 | out_array_val = allocate<ConstExprValue>(1); |
| 4802 | out_array_val->special = ConstValSpecialStatic; |
| 4803 | out_val->data.x_ptr.base_ptr = out_array_val; |
| 4804 | out_val->data.x_ptr.index = 0; |
| 4805 | out_val->data.x_ptr.special = ConstPtrSpecialCStr; |
| 4806 | |
| 4807 | new_len += 1; // null byte |
| 4808 | } |
| 4809 | out_array_val->data.x_array.elements = allocate<ConstExprValue>(new_len); |
| 4810 | out_array_val->data.x_array.size = new_len; |
| 4811 | |
| 4812 | size_t next_index = 0; |
| 4813 | for (size_t i = op1_array_index; i < op1_array_end; i += 1, next_index += 1) { |
| 4814 | out_array_val->data.x_array.elements[next_index] = op1_array_val->data.x_array.elements[i]; |
| 4815 | } |
| 4816 | for (size_t i = op2_array_index; i < op2_array_end; i += 1, next_index += 1) { |
| 4817 | out_array_val->data.x_array.elements[next_index] = op2_array_val->data.x_array.elements[i]; |
| 4818 | } |
| 4819 | if (next_index < new_len) { |
| 4820 | ConstExprValue *null_byte = &out_array_val->data.x_array.elements[next_index]; |
| 4821 | null_byte->special = ConstValSpecialStatic; |
| 4822 | bignum_init_unsigned(&null_byte->data.x_bignum, 0); |
| 4823 | next_index += 1; |
| 4824 | } |
| 4825 | assert(next_index == new_len); |
| 4826 | |
| 4827 | return result_type; |
| 4817 | 4828 | } |
| 4818 | 4829 | |
| 4819 | 4830 | static TypeTableEntry *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp *instruction) { |