From f0a43cfda9bcfcbefb24cac3ef01c5c745022c58 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 18 Jan 2016 04:34:26 -0700 Subject: [PATCH] fix nested arrays --- src/analyze.cpp | 55 ++++++++++++++++++++++++++++++++-------------- src/codegen.cpp | 46 +++++++++++++++++++++++++++----------- test/run_tests.cpp | 15 +++++++++++++ 3 files changed, 87 insertions(+), 29 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 4a95ab53f..2763b0f68 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -235,17 +235,53 @@ static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, ui } } +static void unknown_size_array_type_common_init(CodeGen *g, TypeTableEntry *child_type, + bool is_const, TypeTableEntry *entry) +{ + TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const); + + unsigned element_count = 2; + entry->size_in_bits = g->pointer_size_bytes * 2 * 8; + entry->align_in_bits = g->pointer_size_bytes * 8; + entry->data.structure.is_packed = false; + entry->data.structure.is_unknown_size_array = true; + entry->data.structure.field_count = element_count; + entry->data.structure.fields = allocate(element_count); + entry->data.structure.fields[0].name = buf_create_from_str("ptr"); + entry->data.structure.fields[0].type_entry = pointer_type; + entry->data.structure.fields[0].src_index = 0; + entry->data.structure.fields[0].gen_index = 0; + entry->data.structure.fields[1].name = buf_create_from_str("len"); + entry->data.structure.fields[1].type_entry = g->builtin_types.entry_usize; + entry->data.structure.fields[1].src_index = 1; + entry->data.structure.fields[1].gen_index = 1; +} + static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) { assert(child_type->id != TypeTableEntryIdInvalid); TypeTableEntry **parent_pointer = &child_type->unknown_size_array_parent[(is_const ? 1 : 0)]; + if (*parent_pointer) { return *parent_pointer; + } else if (is_const) { + TypeTableEntry *var_peer = get_unknown_size_array_type(g, child_type, false); + TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct); + + buf_resize(&entry->name, 0); + buf_appendf(&entry->name, "[]const %s", buf_ptr(&child_type->name)); + + unknown_size_array_type_common_init(g, child_type, is_const, entry); + + entry->type_ref = var_peer->type_ref; + entry->di_type = var_peer->di_type; + + *parent_pointer = entry; + return entry; } else { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct); - const char *const_str = is_const ? "const " : ""; buf_resize(&entry->name, 0); - buf_appendf(&entry->name, "[]%s%s", const_str, buf_ptr(&child_type->name)); + buf_appendf(&entry->name, "[]%s", buf_ptr(&child_type->name)); entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&entry->name)); 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 }; LLVMStructSetBody(entry->type_ref, element_types, element_count, false); - entry->size_in_bits = g->pointer_size_bytes * 2 * 8; - entry->align_in_bits = g->pointer_size_bytes * 8; - entry->data.structure.is_packed = false; - entry->data.structure.is_unknown_size_array = true; - entry->data.structure.field_count = element_count; - entry->data.structure.fields = allocate(element_count); - entry->data.structure.fields[0].name = buf_create_from_str("ptr"); - entry->data.structure.fields[0].type_entry = pointer_type; - entry->data.structure.fields[0].src_index = 0; - entry->data.structure.fields[0].gen_index = 0; - entry->data.structure.fields[1].name = buf_create_from_str("len"); - entry->data.structure.fields[1].type_entry = g->builtin_types.entry_usize; - entry->data.structure.fields[1].src_index = 1; - entry->data.structure.fields[1].gen_index = 1; + unknown_size_array_type_common_init(g, child_type, is_const, entry); LLVMZigDIType *di_element_types[] = { pointer_type->di_type, diff --git a/src/codegen.cpp b/src/codegen.cpp index db9d77088..c6c03175a 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -150,6 +150,13 @@ static TypeTableEntry *get_expr_type(AstNode *node) { return expr->type_entry; } +static bool handle_is_ptr(TypeTableEntry *type_entry) { + return type_entry->id == TypeTableEntryIdStruct || + (type_entry->id == TypeTableEntryIdEnum && type_entry->data.enumeration.gen_field_count != 0) || + type_entry->id == TypeTableEntryIdMaybe || + type_entry->id == TypeTableEntryIdArray; +} + static LLVMValueRef gen_number_literal_raw(CodeGen *g, AstNode *source_node, NumLitCodeGen *codegen_num_lit, AstNodeNumberLiteral *num_lit_node) { @@ -681,12 +688,27 @@ static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) { } } + static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) { assert(node->type == NodeTypeArrayAccessExpr); LLVMValueRef ptr = gen_array_ptr(g, node); + TypeTableEntry *child_type; + TypeTableEntry *array_type = get_expr_type(node->data.array_access_expr.array_ref_expr); + if (array_type->id == TypeTableEntryIdPointer) { + child_type = array_type->data.pointer.child_type; + } else if (array_type->id == TypeTableEntryIdStruct) { + assert(array_type->data.structure.is_unknown_size_array); + TypeTableEntry *child_ptr_type = array_type->data.structure.fields[0].type_entry; + assert(child_ptr_type->id == TypeTableEntryIdPointer); + child_type = child_ptr_type->data.pointer.child_type; + } else if (array_type->id == TypeTableEntryIdArray) { + child_type = array_type->data.array.child_type; + } else { + zig_unreachable(); + } - if (is_lvalue || !ptr) { + if (is_lvalue || !ptr || handle_is_ptr(child_type)) { return ptr; } else { add_debug_source_node(g, node); @@ -1142,10 +1164,7 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) { static LLVMValueRef gen_struct_memcpy(CodeGen *g, AstNode *source_node, LLVMValueRef src, LLVMValueRef dest, TypeTableEntry *type_entry) { - assert(type_entry->id == TypeTableEntryIdStruct || - type_entry->id == TypeTableEntryIdMaybe || - (type_entry->id == TypeTableEntryIdEnum && type_entry->data.enumeration.gen_field_count != 0) || - type_entry->id == TypeTableEntryIdArray); + assert(handle_is_ptr(type_entry)); LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); @@ -1168,11 +1187,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType b LLVMValueRef target_ref, LLVMValueRef value, TypeTableEntry *op1_type, TypeTableEntry *op2_type) { - if (op1_type->id == TypeTableEntryIdStruct || - (op1_type->id == TypeTableEntryIdEnum && op1_type->data.enumeration.gen_field_count != 0) || - op1_type->id == TypeTableEntryIdMaybe || - op1_type->id == TypeTableEntryIdArray) - { + if (handle_is_ptr(op1_type)) { assert(op1_type == op2_type); assert(bin_op == BinOpTypeAssign); @@ -1632,8 +1647,10 @@ static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) { add_debug_source_node(g, field_node); LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, type_struct_field->gen_index, ""); - LLVMValueRef value = gen_expr(g, field_node->data.struct_val_field.expr); - LLVMBuildStore(g->builder, value, field_ptr); + AstNode *expr_node = field_node->data.struct_val_field.expr; + LLVMValueRef value = gen_expr(g, expr_node); + gen_assign_raw(g, field_node, BinOpTypeAssign, field_ptr, value, + type_struct_field->type_entry, get_expr_type(expr_node)); } return tmp_struct_ptr; @@ -1651,6 +1668,8 @@ static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) { int field_count = type_entry->data.array.len; assert(field_count == node->data.container_init_expr.entries.length); + TypeTableEntry *child_type = type_entry->data.array.child_type; + for (int i = 0; i < field_count; i += 1) { AstNode *field_node = node->data.container_init_expr.entries.at(i); LLVMValueRef elem_val = gen_expr(g, field_node); @@ -1661,7 +1680,8 @@ static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) { }; add_debug_source_node(g, field_node); LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP(g->builder, tmp_array_ptr, indices, 2, ""); - LLVMBuildStore(g->builder, elem_val, elem_ptr); + gen_assign_raw(g, field_node, BinOpTypeAssign, elem_ptr, elem_val, + child_type, get_expr_type(field_node)); } return tmp_array_ptr; diff --git a/test/run_tests.cpp b/test/run_tests.cpp index edb9afa0b..f416beb31 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -1121,6 +1121,21 @@ pub fn main(args: [][]u8) i32 => { return 0; } )SOURCE", "OK\n"); + + add_simple_case("nested arrays", R"SOURCE( +import "std.zig"; + +pub fn main(args: [][]u8) i32 => { + const array_of_strings = [][]u8 {"hello", "this", "is", "my", "thing"}; + var i: @typeof(array_of_strings.len) = 0; + while (i < array_of_strings.len) { + print_str(array_of_strings[i]); + print_str("\n"); + i += 1; + } + return 0; +} + )SOURCE", "hello\nthis\nis\nmy\nthing\n"); }