+
+typedef struct type_path_entry_t type_path_entry_t;
+struct type_path_entry_t {
+ type_t *type;
+ ir_initializer_t *initializer;
+ size_t index;
+ declaration_t *compound_entry;
+};
+
+typedef struct type_path_t type_path_t;
+struct type_path_t {
+ type_path_entry_t *path;
+ type_t *top_type;
+ bool invalid;
+};
+
+static __attribute__((unused)) void debug_print_type_path(const type_path_t *path)
+{
+ size_t len = ARR_LEN(path->path);
+
+ for(size_t i = 0; i < len; ++i) {
+ const type_path_entry_t *entry = & path->path[i];
+
+ type_t *type = skip_typeref(entry->type);
+ if(is_type_compound(type)) {
+ fprintf(stderr, ".%s", entry->compound_entry->symbol->string);
+ } else if(is_type_array(type)) {
+ fprintf(stderr, "[%u]", entry->index);
+ } else {
+ fprintf(stderr, "-INVALID-");
+ }
+ }
+ fprintf(stderr, " (");
+ print_type(path->top_type);
+ fprintf(stderr, ")");
+}
+
+static type_path_entry_t *get_type_path_top(const type_path_t *path)
+{
+ size_t len = ARR_LEN(path->path);
+ assert(len > 0);
+ return & path->path[len-1];
+}
+
+static type_path_entry_t *append_to_type_path(type_path_t *path)
+{
+ size_t len = ARR_LEN(path->path);
+ ARR_RESIZE(type_path_entry_t, path->path, len+1);
+
+ type_path_entry_t *result = & path->path[len];
+ memset(result, 0, sizeof(result[0]));
+ return result;
+}
+
+static size_t get_compound_size(const compound_type_t *type)
+{
+ declaration_t *declaration = type->declaration;
+ declaration_t *member = declaration->scope.declarations;
+ size_t size = 0;
+ for( ; member != NULL; member = member->next) {
+ ++size;
+ }
+ /* TODO: cache results? */
+
+ return size;
+}
+
+static ir_initializer_t *get_initializer_entry(type_path_t *path)
+{
+ type_t *orig_top_type = path->top_type;
+ type_t *top_type = skip_typeref(orig_top_type);
+
+ assert(is_type_compound(top_type) || is_type_array(top_type));
+
+ if(ARR_LEN(path->path) == 0) {
+ return NULL;
+ } else {
+ type_path_entry_t *top = get_type_path_top(path);
+ ir_initializer_t *initializer = top->initializer;
+ return get_initializer_compound_value(initializer, top->index);
+ }
+}
+
+static void descend_into_subtype(type_path_t *path)
+{
+ type_t *orig_top_type = path->top_type;
+ type_t *top_type = skip_typeref(orig_top_type);
+
+ assert(is_type_compound(top_type) || is_type_array(top_type));
+
+ ir_initializer_t *initializer = get_initializer_entry(path);
+
+ type_path_entry_t *top = append_to_type_path(path);
+ top->type = top_type;
+
+ size_t len;
+
+ if(is_type_compound(top_type)) {
+ declaration_t *declaration = top_type->compound.declaration;
+ declaration_t *entry = declaration->scope.declarations;
+
+ top->compound_entry = entry;
+ top->index = 0;
+ path->top_type = entry->type;
+ len = get_compound_size(&top_type->compound);
+ } else {
+ assert(is_type_array(top_type));
+ assert(top_type->array.size > 0);
+
+ top->index = 0;
+ path->top_type = top_type->array.element_type;
+ len = top_type->array.size;
+ }
+ if(initializer == NULL
+ || get_initializer_kind(initializer) == IR_INITIALIZER_NULL) {
+ initializer = create_initializer_compound(len);
+ /* we have to set the entry at the 2nd latest path entry... */
+ size_t path_len = ARR_LEN(path->path);
+ assert(path_len >= 1);
+ if(path_len > 1) {
+ type_path_entry_t *entry = & path->path[path_len-2];
+ ir_initializer_t *tinitializer = entry->initializer;
+ set_initializer_compound_value(tinitializer, entry->index,
+ initializer);
+ }
+ }
+ top->initializer = initializer;
+}
+
+static void ascend_from_subtype(type_path_t *path)
+{
+ type_path_entry_t *top = get_type_path_top(path);
+
+ path->top_type = top->type;
+
+ size_t len = ARR_LEN(path->path);
+ ARR_RESIZE(type_path_entry_t, path->path, len-1);
+}
+
+static void walk_designator(type_path_t *path, const designator_t *designator)
+{
+ /* designators start at current object type */
+ ARR_RESIZE(type_path_entry_t, path->path, 1);
+
+ for( ; designator != NULL; designator = designator->next) {
+ type_path_entry_t *top = get_type_path_top(path);
+ type_t *orig_type = top->type;
+ type_t *type = skip_typeref(orig_type);
+
+ if(designator->symbol != NULL) {
+ assert(is_type_compound(type));
+ size_t index = 0;
+ symbol_t *symbol = designator->symbol;
+
+ declaration_t *declaration = type->compound.declaration;
+ declaration_t *iter = declaration->scope.declarations;
+ for( ; iter != NULL; iter = iter->next, ++index) {
+ if(iter->symbol == symbol) {
+ break;
+ }
+ }
+ assert(iter != NULL);
+
+ top->type = orig_type;
+ top->compound_entry = iter;
+ top->index = index;
+ orig_type = iter->type;
+ } else {
+ expression_t *array_index = designator->array_index;
+ assert(designator->array_index != NULL);
+ assert(is_type_array(type));
+ assert(is_type_valid(array_index->base.type));
+
+ long index = fold_constant(array_index);
+ assert(index >= 0);
+#ifndef NDEBUG
+ if(type->array.size_constant == 1) {
+ long array_size = type->array.size;
+ assert(index < array_size);
+ }
+#endif
+
+ top->type = orig_type;
+ top->index = (size_t) index;
+ orig_type = type->array.element_type;
+ }
+ path->top_type = orig_type;
+
+ if(designator->next != NULL) {
+ descend_into_subtype(path);
+ }
+ }
+
+ path->invalid = false;
+}
+
+static void advance_current_object(type_path_t *path)
+{
+ if(path->invalid) {
+ /* TODO: handle this... */
+ panic("invalid initializer in ast2firm (excessive elements)");
+ return;
+ }
+
+ type_path_entry_t *top = get_type_path_top(path);
+
+ type_t *type = skip_typeref(top->type);
+ if(is_type_union(type)) {
+ top->compound_entry = NULL;
+ } else if(is_type_struct(type)) {
+ declaration_t *entry = top->compound_entry;
+
+ top->index++;
+ entry = entry->next;
+ top->compound_entry = entry;
+ if(entry != NULL) {
+ path->top_type = entry->type;
+ return;
+ }
+ } else {
+ assert(is_type_array(type));
+
+ top->index++;
+ if(!type->array.size_constant || top->index < type->array.size) {
+ return;
+ }
+ }
+
+ /* we're past the last member of the current sub-aggregate, try if we
+ * can ascend in the type hierarchy and continue with another subobject */
+ size_t len = ARR_LEN(path->path);
+
+ if(len > 1) {
+ ascend_from_subtype(path);
+ advance_current_object(path);
+ } else {
+ path->invalid = true;
+ }
+}
+
+