| author | |
| committer | |
| log | f0a43cfda9bcfcbefb24cac3ef01c5c745022c58 |
| tree | 6e1ad0d4b16713078f40bf235aebbef09f8b196d |
| parent | 826c7f06a3cebdf15d88e5228e705974b215bcd4 |
3 files changed, 87 insertions(+), 29 deletions(-)
src/analyze.cpp+39-16| ... | ... | @@ -235,17 +235,53 @@ static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, ui |
| 235 | 235 | } |
| 236 | 236 | } |
| 237 | 237 | |
| 238 | static void unknown_size_array_type_common_init(CodeGen *g, TypeTableEntry *child_type, | |
| 239 | bool is_const, TypeTableEntry *entry) | |
| 240 | { | |
| 241 | TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const); | |
| 242 | ||
| 243 | unsigned element_count = 2; | |
| 244 | entry->size_in_bits = g->pointer_size_bytes * 2 * 8; | |
| 245 | entry->align_in_bits = g->pointer_size_bytes * 8; | |
| 246 | entry->data.structure.is_packed = false; | |
| 247 | entry->data.structure.is_unknown_size_array = true; | |
| 248 | entry->data.structure.field_count = element_count; | |
| 249 | entry->data.structure.fields = allocate<TypeStructField>(element_count); | |
| 250 | entry->data.structure.fields[0].name = buf_create_from_str("ptr"); | |
| 251 | entry->data.structure.fields[0].type_entry = pointer_type; | |
| 252 | entry->data.structure.fields[0].src_index = 0; | |
| 253 | entry->data.structure.fields[0].gen_index = 0; | |
| 254 | entry->data.structure.fields[1].name = buf_create_from_str("len"); | |
| 255 | entry->data.structure.fields[1].type_entry = g->builtin_types.entry_usize; | |
| 256 | entry->data.structure.fields[1].src_index = 1; | |
| 257 | entry->data.structure.fields[1].gen_index = 1; | |
| 258 | } | |
| 259 | ||
| 238 | 260 | static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) { |
| 239 | 261 | assert(child_type->id != TypeTableEntryIdInvalid); |
| 240 | 262 | TypeTableEntry **parent_pointer = &child_type->unknown_size_array_parent[(is_const ? 1 : 0)]; |
| 263 | ||
| 241 | 264 | if (*parent_pointer) { |
| 242 | 265 | return *parent_pointer; |
| 266 | } else if (is_const) { | |
| 267 | TypeTableEntry *var_peer = get_unknown_size_array_type(g, child_type, false); | |
| 268 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct); | |
| 269 | ||
| 270 | buf_resize(&entry->name, 0); | |
| 271 | buf_appendf(&entry->name, "[]const %s", buf_ptr(&child_type->name)); | |
| 272 | ||
| 273 | unknown_size_array_type_common_init(g, child_type, is_const, entry); | |
| 274 | ||
| 275 | entry->type_ref = var_peer->type_ref; | |
| 276 | entry->di_type = var_peer->di_type; | |
| 277 | ||
| 278 | *parent_pointer = entry; | |
| 279 | return entry; | |
| 243 | 280 | } else { |
| 244 | 281 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct); |
| 245 | 282 | |
| 246 | const char *const_str = is_const ? "const " : ""; | |
| 247 | 283 | buf_resize(&entry->name, 0); |
| 248 | buf_appendf(&entry->name, "[]%s%s", const_str, buf_ptr(&child_type->name)); | |
| 284 | buf_appendf(&entry->name, "[]%s", buf_ptr(&child_type->name)); | |
| 249 | 285 | entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&entry->name)); |
| 250 | 286 | |
| 251 | 287 | TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const); |
| ... | ... | @@ -257,20 +293,7 @@ static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, TypeTableEntry *c |
| 257 | 293 | }; |
| 258 | 294 | LLVMStructSetBody(entry->type_ref, element_types, element_count, false); |
| 259 | 295 | |
| 260 | entry->size_in_bits = g->pointer_size_bytes * 2 * 8; | |
| 261 | entry->align_in_bits = g->pointer_size_bytes * 8; | |
| 262 | entry->data.structure.is_packed = false; | |
| 263 | entry->data.structure.is_unknown_size_array = true; | |
| 264 | entry->data.structure.field_count = element_count; | |
| 265 | entry->data.structure.fields = allocate<TypeStructField>(element_count); | |
| 266 | entry->data.structure.fields[0].name = buf_create_from_str("ptr"); | |
| 267 | entry->data.structure.fields[0].type_entry = pointer_type; | |
| 268 | entry->data.structure.fields[0].src_index = 0; | |
| 269 | entry->data.structure.fields[0].gen_index = 0; | |
| 270 | entry->data.structure.fields[1].name = buf_create_from_str("len"); | |
| 271 | entry->data.structure.fields[1].type_entry = g->builtin_types.entry_usize; | |
| 272 | entry->data.structure.fields[1].src_index = 1; | |
| 273 | entry->data.structure.fields[1].gen_index = 1; | |
| 296 | unknown_size_array_type_common_init(g, child_type, is_const, entry); | |
| 274 | 297 | |
| 275 | 298 | LLVMZigDIType *di_element_types[] = { |
| 276 | 299 | pointer_type->di_type, |
src/codegen.cpp+33-13| ... | ... | @@ -150,6 +150,13 @@ static TypeTableEntry *get_expr_type(AstNode *node) { |
| 150 | 150 | return expr->type_entry; |
| 151 | 151 | } |
| 152 | 152 | |
| 153 | static bool handle_is_ptr(TypeTableEntry *type_entry) { | |
| 154 | return type_entry->id == TypeTableEntryIdStruct || | |
| 155 | (type_entry->id == TypeTableEntryIdEnum && type_entry->data.enumeration.gen_field_count != 0) || | |
| 156 | type_entry->id == TypeTableEntryIdMaybe || | |
| 157 | type_entry->id == TypeTableEntryIdArray; | |
| 158 | } | |
| 159 | ||
| 153 | 160 | static LLVMValueRef gen_number_literal_raw(CodeGen *g, AstNode *source_node, |
| 154 | 161 | NumLitCodeGen *codegen_num_lit, AstNodeNumberLiteral *num_lit_node) |
| 155 | 162 | { |
| ... | ... | @@ -681,12 +688,27 @@ static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) { |
| 681 | 688 | } |
| 682 | 689 | } |
| 683 | 690 | |
| 691 | ||
| 684 | 692 | static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) { |
| 685 | 693 | assert(node->type == NodeTypeArrayAccessExpr); |
| 686 | 694 | |
| 687 | 695 | LLVMValueRef ptr = gen_array_ptr(g, node); |
| 696 | TypeTableEntry *child_type; | |
| 697 | TypeTableEntry *array_type = get_expr_type(node->data.array_access_expr.array_ref_expr); | |
| 698 | if (array_type->id == TypeTableEntryIdPointer) { | |
| 699 | child_type = array_type->data.pointer.child_type; | |
| 700 | } else if (array_type->id == TypeTableEntryIdStruct) { | |
| 701 | assert(array_type->data.structure.is_unknown_size_array); | |
| 702 | TypeTableEntry *child_ptr_type = array_type->data.structure.fields[0].type_entry; | |
| 703 | assert(child_ptr_type->id == TypeTableEntryIdPointer); | |
| 704 | child_type = child_ptr_type->data.pointer.child_type; | |
| 705 | } else if (array_type->id == TypeTableEntryIdArray) { | |
| 706 | child_type = array_type->data.array.child_type; | |
| 707 | } else { | |
| 708 | zig_unreachable(); | |
| 709 | } | |
| 688 | 710 | |
| 689 | if (is_lvalue || !ptr) { | |
| 711 | if (is_lvalue || !ptr || handle_is_ptr(child_type)) { | |
| 690 | 712 | return ptr; |
| 691 | 713 | } else { |
| 692 | 714 | add_debug_source_node(g, node); |
| ... | ... | @@ -1142,10 +1164,7 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) { |
| 1142 | 1164 | static LLVMValueRef gen_struct_memcpy(CodeGen *g, AstNode *source_node, LLVMValueRef src, LLVMValueRef dest, |
| 1143 | 1165 | TypeTableEntry *type_entry) |
| 1144 | 1166 | { |
| 1145 | assert(type_entry->id == TypeTableEntryIdStruct || | |
| 1146 | type_entry->id == TypeTableEntryIdMaybe || | |
| 1147 | (type_entry->id == TypeTableEntryIdEnum && type_entry->data.enumeration.gen_field_count != 0) || | |
| 1148 | type_entry->id == TypeTableEntryIdArray); | |
| 1167 | assert(handle_is_ptr(type_entry)); | |
| 1149 | 1168 | |
| 1150 | 1169 | LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); |
| 1151 | 1170 | |
| ... | ... | @@ -1168,11 +1187,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType b |
| 1168 | 1187 | LLVMValueRef target_ref, LLVMValueRef value, |
| 1169 | 1188 | TypeTableEntry *op1_type, TypeTableEntry *op2_type) |
| 1170 | 1189 | { |
| 1171 | if (op1_type->id == TypeTableEntryIdStruct || | |
| 1172 | (op1_type->id == TypeTableEntryIdEnum && op1_type->data.enumeration.gen_field_count != 0) || | |
| 1173 | op1_type->id == TypeTableEntryIdMaybe || | |
| 1174 | op1_type->id == TypeTableEntryIdArray) | |
| 1175 | { | |
| 1190 | if (handle_is_ptr(op1_type)) { | |
| 1176 | 1191 | assert(op1_type == op2_type); |
| 1177 | 1192 | assert(bin_op == BinOpTypeAssign); |
| 1178 | 1193 | |
| ... | ... | @@ -1632,8 +1647,10 @@ static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) { |
| 1632 | 1647 | |
| 1633 | 1648 | add_debug_source_node(g, field_node); |
| 1634 | 1649 | LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, type_struct_field->gen_index, ""); |
| 1635 | LLVMValueRef value = gen_expr(g, field_node->data.struct_val_field.expr); | |
| 1636 | LLVMBuildStore(g->builder, value, field_ptr); | |
| 1650 | AstNode *expr_node = field_node->data.struct_val_field.expr; | |
| 1651 | LLVMValueRef value = gen_expr(g, expr_node); | |
| 1652 | gen_assign_raw(g, field_node, BinOpTypeAssign, field_ptr, value, | |
| 1653 | type_struct_field->type_entry, get_expr_type(expr_node)); | |
| 1637 | 1654 | } |
| 1638 | 1655 | |
| 1639 | 1656 | return tmp_struct_ptr; |
| ... | ... | @@ -1651,6 +1668,8 @@ static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) { |
| 1651 | 1668 | int field_count = type_entry->data.array.len; |
| 1652 | 1669 | assert(field_count == node->data.container_init_expr.entries.length); |
| 1653 | 1670 | |
| 1671 | TypeTableEntry *child_type = type_entry->data.array.child_type; | |
| 1672 | ||
| 1654 | 1673 | for (int i = 0; i < field_count; i += 1) { |
| 1655 | 1674 | AstNode *field_node = node->data.container_init_expr.entries.at(i); |
| 1656 | 1675 | LLVMValueRef elem_val = gen_expr(g, field_node); |
| ... | ... | @@ -1661,7 +1680,8 @@ static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) { |
| 1661 | 1680 | }; |
| 1662 | 1681 | add_debug_source_node(g, field_node); |
| 1663 | 1682 | LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP(g->builder, tmp_array_ptr, indices, 2, ""); |
| 1664 | LLVMBuildStore(g->builder, elem_val, elem_ptr); | |
| 1683 | gen_assign_raw(g, field_node, BinOpTypeAssign, elem_ptr, elem_val, | |
| 1684 | child_type, get_expr_type(field_node)); | |
| 1665 | 1685 | } |
| 1666 | 1686 | |
| 1667 | 1687 | return tmp_array_ptr; |
test/run_tests.cpp+15| ... | ... | @@ -1121,6 +1121,21 @@ pub fn main(args: [][]u8) i32 => { |
| 1121 | 1121 | return 0; |
| 1122 | 1122 | } |
| 1123 | 1123 | )SOURCE", "OK\n"); |
| 1124 | ||
| 1125 | add_simple_case("nested arrays", R"SOURCE( | |
| 1126 | import "std.zig"; | |
| 1127 | ||
| 1128 | pub fn main(args: [][]u8) i32 => { | |
| 1129 | const array_of_strings = [][]u8 {"hello", "this", "is", "my", "thing"}; | |
| 1130 | var i: @typeof(array_of_strings.len) = 0; | |
| 1131 | while (i < array_of_strings.len) { | |
| 1132 | print_str(array_of_strings[i]); | |
| 1133 | print_str("\n"); | |
| 1134 | i += 1; | |
| 1135 | } | |
| 1136 | return 0; | |
| 1137 | } | |
| 1138 | )SOURCE", "hello\nthis\nis\nmy\nthing\n"); | |
| 1124 | 1139 | } |
| 1125 | 1140 | |
| 1126 | 1141 |