| ... | @@ -2770,6 +2770,7 @@ static TypeTableEntry *resolve_expr_const_val_as_c_string_lit(CodeGen *g, AstNod | ... | @@ -2770,6 +2770,7 @@ static TypeTableEntry *resolve_expr_const_val_as_c_string_lit(CodeGen *g, AstNod |
| 2770 | int len_with_null = buf_len(str) + 1; | 2770 | int len_with_null = buf_len(str) + 1; |
| 2771 | expr->const_val.data.x_ptr.ptr = allocate<ConstExprValue*>(len_with_null); | 2771 | expr->const_val.data.x_ptr.ptr = allocate<ConstExprValue*>(len_with_null); |
| 2772 | expr->const_val.data.x_ptr.len = len_with_null; | 2772 | expr->const_val.data.x_ptr.len = len_with_null; |
| | 2773 | expr->const_val.data.x_ptr.is_c_str = true; |
| 2773 | | 2774 | |
| 2774 | ConstExprValue *all_chars = allocate<ConstExprValue>(len_with_null); | 2775 | ConstExprValue *all_chars = allocate<ConstExprValue>(len_with_null); |
| 2775 | for (int i = 0; i < buf_len(str); i += 1) { | 2776 | for (int i = 0; i < buf_len(str); i += 1) { |
| ... | @@ -2974,7 +2975,7 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) { | ... | @@ -2974,7 +2975,7 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) { |
| 2974 | case BinOpTypeDiv: | 2975 | case BinOpTypeDiv: |
| 2975 | case BinOpTypeMod: | 2976 | case BinOpTypeMod: |
| 2976 | case BinOpTypeUnwrapMaybe: | 2977 | case BinOpTypeUnwrapMaybe: |
| 2977 | case BinOpTypeStrCat: | 2978 | case BinOpTypeArrayCat: |
| 2978 | case BinOpTypeArrayMult: | 2979 | case BinOpTypeArrayMult: |
| 2979 | zig_unreachable(); | 2980 | zig_unreachable(); |
| 2980 | } | 2981 | } |
| ... | @@ -3379,19 +3380,42 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -3379,19 +3380,42 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, |
| 3379 | return g->builtin_types.entry_invalid; | 3380 | return g->builtin_types.entry_invalid; |
| 3380 | } | 3381 | } |
| 3381 | } | 3382 | } |
| 3382 | case BinOpTypeStrCat: | 3383 | case BinOpTypeArrayCat: |
| 3383 | { | 3384 | { |
| 3384 | AstNode **op1 = node->data.bin_op_expr.op1->parent_field; | 3385 | AstNode **op1 = node->data.bin_op_expr.op1->parent_field; |
| 3385 | AstNode **op2 = node->data.bin_op_expr.op2->parent_field; | 3386 | AstNode **op2 = node->data.bin_op_expr.op2->parent_field; |
| 3386 | | 3387 | |
| 3387 | TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true); | 3388 | TypeTableEntry *op1_type = analyze_expression(g, import, context, nullptr, *op1); |
| | 3389 | TypeTableEntry *child_type; |
| | 3390 | if (op1_type->id == TypeTableEntryIdInvalid) { |
| | 3391 | return g->builtin_types.entry_invalid; |
| | 3392 | } else if (op1_type->id == TypeTableEntryIdArray) { |
| | 3393 | child_type = op1_type->data.array.child_type; |
| | 3394 | } else if (op1_type->id == TypeTableEntryIdPointer && |
| | 3395 | op1_type->data.pointer.child_type == g->builtin_types.entry_u8) { |
| | 3396 | child_type = op1_type->data.pointer.child_type; |
| | 3397 | } else { |
| | 3398 | add_node_error(g, *op1, buf_sprintf("expected array or C string literal, got '%s'", |
| | 3399 | buf_ptr(&op1_type->name))); |
| | 3400 | return g->builtin_types.entry_invalid; |
| | 3401 | } |
| 3388 | | 3402 | |
| 3389 | TypeTableEntry *op1_type = analyze_expression(g, import, context, str_type, *op1); | 3403 | TypeTableEntry *op2_type = analyze_expression(g, import, context, nullptr, *op2); |
| 3390 | TypeTableEntry *op2_type = analyze_expression(g, import, context, str_type, *op2); | | |
| 3391 | | 3404 | |
| 3392 | if (op1_type->id == TypeTableEntryIdInvalid || | 3405 | if (op2_type->id == TypeTableEntryIdInvalid) { |
| 3393 | op2_type->id == TypeTableEntryIdInvalid) | 3406 | return g->builtin_types.entry_invalid; |
| 3394 | { | 3407 | } else if (op2_type->id == TypeTableEntryIdArray) { |
| | 3408 | if (op2_type->data.array.child_type != child_type) { |
| | 3409 | add_node_error(g, *op2, buf_sprintf("expected array of type '%s', got '%s'", |
| | 3410 | buf_ptr(&child_type->name), |
| | 3411 | buf_ptr(&op2_type->name))); |
| | 3412 | return g->builtin_types.entry_invalid; |
| | 3413 | } |
| | 3414 | } else if (op2_type->id == TypeTableEntryIdPointer && |
| | 3415 | op2_type->data.pointer.child_type == g->builtin_types.entry_u8) { |
| | 3416 | } else { |
| | 3417 | add_node_error(g, *op2, buf_sprintf("expected array or C string literal, got '%s'", |
| | 3418 | buf_ptr(&op2_type->name))); |
| 3395 | return g->builtin_types.entry_invalid; | 3419 | return g->builtin_types.entry_invalid; |
| 3396 | } | 3420 | } |
| 3397 | | 3421 | |
| ... | @@ -3407,41 +3431,52 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -3407,41 +3431,52 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, |
| 3407 | bad_node = nullptr; | 3431 | bad_node = nullptr; |
| 3408 | } | 3432 | } |
| 3409 | if (bad_node) { | 3433 | if (bad_node) { |
| 3410 | add_node_error(g, bad_node, buf_sprintf("string concatenation requires constant expression")); | 3434 | add_node_error(g, bad_node, buf_sprintf("array concatenation requires constant expression")); |
| 3411 | return g->builtin_types.entry_invalid; | 3435 | return g->builtin_types.entry_invalid; |
| 3412 | } | 3436 | } |
| | 3437 | |
| 3413 | ConstExprValue *const_val = &get_resolved_expr(node)->const_val; | 3438 | ConstExprValue *const_val = &get_resolved_expr(node)->const_val; |
| 3414 | const_val->ok = true; | 3439 | const_val->ok = true; |
| 3415 | const_val->depends_on_compile_var = op1_val->depends_on_compile_var || | 3440 | const_val->depends_on_compile_var = op1_val->depends_on_compile_var || |
| 3416 | op2_val->depends_on_compile_var; | 3441 | op2_val->depends_on_compile_var; |
| 3417 | | 3442 | |
| 3418 | ConstExprValue *all_fields = allocate<ConstExprValue>(2); | 3443 | if (op1_type->id == TypeTableEntryIdArray) { |
| 3419 | ConstExprValue *ptr_field = &all_fields[0]; | 3444 | uint64_t new_len = op1_type->data.array.len + op2_type->data.array.len; |
| 3420 | ConstExprValue *len_field = &all_fields[1]; | 3445 | const_val->data.x_array.fields = allocate<ConstExprValue*>(new_len); |
| 3421 | | 3446 | uint64_t next_index = 0; |
| 3422 | const_val->data.x_struct.fields = allocate<ConstExprValue*>(2); | 3447 | for (uint64_t i = 0; i < op1_type->data.array.len; i += 1, next_index += 1) { |
| 3423 | const_val->data.x_struct.fields[0] = ptr_field; | 3448 | const_val->data.x_array.fields[next_index] = op1_val->data.x_array.fields[i]; |
| 3424 | const_val->data.x_struct.fields[1] = len_field; | 3449 | } |
| 3425 | | 3450 | for (uint64_t i = 0; i < op2_type->data.array.len; i += 1, next_index += 1) { |
| 3426 | len_field->ok = true; | 3451 | const_val->data.x_array.fields[next_index] = op2_val->data.x_array.fields[i]; |
| 3427 | uint64_t op1_len = op1_val->data.x_struct.fields[1]->data.x_bignum.data.x_uint; | 3452 | } |
| 3428 | uint64_t op2_len = op2_val->data.x_struct.fields[1]->data.x_bignum.data.x_uint; | 3453 | return get_array_type(g, child_type, new_len); |
| 3429 | uint64_t len = op1_len + op2_len; | 3454 | } else if (op1_type->id == TypeTableEntryIdPointer) { |
| 3430 | bignum_init_unsigned(&len_field->data.x_bignum, len); | 3455 | if (!op1_val->data.x_ptr.is_c_str) { |
| 3431 | | 3456 | add_node_error(g, *op1, |
| 3432 | ptr_field->ok = true; | 3457 | buf_sprintf("expected array or C string literal, got '%s'", |
| 3433 | ptr_field->data.x_ptr.ptr = allocate<ConstExprValue*>(len); | 3458 | buf_ptr(&op1_type->name))); |
| 3434 | ptr_field->data.x_ptr.len = len; | 3459 | return g->builtin_types.entry_invalid; |
| 3435 | | 3460 | } else if (!op2_val->data.x_ptr.is_c_str) { |
| 3436 | uint64_t i = 0; | 3461 | add_node_error(g, *op2, |
| 3437 | for (uint64_t op1_i = 0; op1_i < op1_len; op1_i += 1, i += 1) { | 3462 | buf_sprintf("expected array or C string literal, got '%s'", |
| 3438 | ptr_field->data.x_ptr.ptr[i] = op1_val->data.x_struct.fields[0]->data.x_ptr.ptr[op1_i]; | 3463 | buf_ptr(&op2_type->name))); |
| 3439 | } | 3464 | return g->builtin_types.entry_invalid; |
| 3440 | for (uint64_t op2_i = 0; op2_i < op2_len; op2_i += 1, i += 1) { | 3465 | } |
| 3441 | ptr_field->data.x_ptr.ptr[i] = op2_val->data.x_struct.fields[0]->data.x_ptr.ptr[op2_i]; | 3466 | const_val->data.x_ptr.is_c_str = true; |
| | 3467 | const_val->data.x_ptr.len = op1_val->data.x_ptr.len + op2_val->data.x_ptr.len - 1; |
| | 3468 | const_val->data.x_ptr.ptr = allocate<ConstExprValue*>(const_val->data.x_ptr.len); |
| | 3469 | uint64_t next_index = 0; |
| | 3470 | for (uint64_t i = 0; i < op1_val->data.x_ptr.len - 1; i += 1, next_index += 1) { |
| | 3471 | const_val->data.x_ptr.ptr[next_index] = op1_val->data.x_ptr.ptr[i]; |
| | 3472 | } |
| | 3473 | for (uint64_t i = 0; i < op2_val->data.x_ptr.len; i += 1, next_index += 1) { |
| | 3474 | const_val->data.x_ptr.ptr[next_index] = op2_val->data.x_ptr.ptr[i]; |
| | 3475 | } |
| | 3476 | return op1_type; |
| | 3477 | } else { |
| | 3478 | zig_unreachable(); |
| 3442 | } | 3479 | } |
| 3443 | | | |
| 3444 | return str_type; | | |
| 3445 | } | 3480 | } |
| 3446 | case BinOpTypeArrayMult: | 3481 | case BinOpTypeArrayMult: |
| 3447 | return analyze_array_mult(g, import, context, expected_type, node); | 3482 | return analyze_array_mult(g, import, context, expected_type, node); |