Commit 66163692ad

Andrew Kelley <superjoe30@gmail.com>
2016-04-23 06:43:48
parseh: support anonymous enums and enums with initializers
1 parent 8187396
src/ast_render.cpp
@@ -523,7 +523,8 @@ static void render_node(AstRender *ar, AstNode *node) {
                 AstNode *lhs = node->data.field_access_expr.struct_expr;
                 Buf *rhs = &node->data.field_access_expr.field_name;
                 render_node(ar, lhs);
-                fprintf(ar->f, ".%s", buf_ptr(rhs));
+                fprintf(ar->f, ".");
+                print_symbol(ar, rhs);
                 break;
             }
         case NodeTypeUse:
src/parseh.cpp
@@ -42,6 +42,7 @@ struct Context {
     HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> struct_type_table;
     HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> struct_decl_table;
     HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> enum_type_table;
+    HashMap<const void *, TypeTableEntry *, ptr_hash, ptr_eq> decl_table;
     HashMap<Buf *, bool, buf_hash, buf_eql_buf> fn_table;
     HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> macro_table;
     SourceManager *source_manager;
@@ -58,6 +59,7 @@ static TypeTableEntry *resolve_qual_type_with_table(Context *c, QualType qt, con
 
 static TypeTableEntry *resolve_qual_type(Context *c, QualType qt, const Decl *decl);
 static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_decl);
+static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl);
 
 
 __attribute__ ((format (printf, 3, 4)))
@@ -292,6 +294,7 @@ static const char *decl_name(const Decl *decl) {
 
 static AstNode *add_typedef_node(Context *c, TypeTableEntry *type_decl) {
     assert(type_decl);
+    assert(type_decl->id == TypeTableEntryIdTypeDecl);
 
     AstNode *node = create_type_decl_node(c, buf_ptr(&type_decl->name),
             make_type_node(c, type_decl->data.type_decl.child_type));
@@ -310,6 +313,26 @@ static AstNode *add_const_var_node(Context *c, Buf *name, TypeTableEntry *type_e
     return node;
 }
 
+static AstNode *create_ap_num_lit_node(Context *c, const Decl *source_decl,
+        const llvm::APSInt &aps_int)
+{
+    if (aps_int.isSigned()) {
+        if (aps_int > INT64_MAX || aps_int < INT64_MIN) {
+            emit_warning(c, source_decl, "integer overflow\n");
+            return nullptr;
+        } else {
+            return create_num_lit_signed(c, aps_int.getExtValue());
+        }
+    } else {
+        if (aps_int > INT64_MAX) {
+            emit_warning(c, source_decl, "integer overflow\n");
+            return nullptr;
+        } else {
+            return create_num_lit_unsigned(c, aps_int.getExtValue());
+        }
+    }
+}
+
 static bool is_c_void_type(Context *c, TypeTableEntry *type_entry) {
     while (type_entry->id == TypeTableEntryIdTypeDecl) {
         if (type_entry == c->codegen->builtin_types.entry_c_void) {
@@ -586,18 +609,7 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const
         case Type::Enum:
             {
                 const EnumType *enum_ty = static_cast<const EnumType*>(ty);
-                Buf *record_name = buf_create_from_str(decl_name(enum_ty->getDecl()));
-                if (buf_len(record_name) == 0) {
-                    emit_warning(c, decl, "unhandled anonymous enum");
-                    return c->codegen->builtin_types.entry_invalid;
-                }
-
-                auto entry = type_table->maybe_get(record_name);
-                if (!entry) {
-                    return c->codegen->builtin_types.entry_invalid;
-                }
-
-                return entry->value;
+                return resolve_enum_decl(c, enum_ty->getDecl());
             }
         case Type::ConstantArray:
             {
@@ -759,36 +771,45 @@ static void add_alias(Context *c, const char *new_name, const char *target_name)
     c->aliases.append(alias_node);
 }
 
-static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) {
+static void replace_with_fwd_decl(Context *c, TypeTableEntry *struct_type, Buf *full_type_name) {
+    unsigned line = c->source_node ? c->source_node->line : 0;
+    LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugForwardDeclType(c->codegen->dbuilder,
+        LLVMZigTag_DW_structure_type(), buf_ptr(full_type_name), 
+        LLVMZigFileToScope(c->import->di_file), c->import->di_file, line);
+
+    LLVMZigReplaceTemporary(c->codegen->dbuilder, struct_type->di_type, replacement_di_type);
+    struct_type->di_type = replacement_di_type;
+}
+
+static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
+    auto existing_entry = c->decl_table.maybe_get((void*)enum_decl);
+    if (existing_entry) {
+        return existing_entry->value;
+    }
+
     const char *raw_name = decl_name(enum_decl);
-    // we have no interest in top level anonymous enums since they're
-    // not exposing anything.
+
+    Buf *bare_name;
     if (raw_name[0] == 0) {
-        return;
+        bare_name = buf_sprintf("anon_$%" PRIu32, get_next_node_index(c));
+    } else {
+        bare_name = buf_create_from_str(raw_name);
     }
 
-    Buf *bare_name = buf_create_from_str(raw_name);
     Buf *full_type_name = buf_sprintf("enum_%s", buf_ptr(bare_name));
 
-    if (c->enum_type_table.maybe_get(bare_name)) {
-        // we've already seen it
-        return;
-    }
-
     const EnumDecl *enum_def = enum_decl->getDefinition();
-
     if (!enum_def) {
-        TypeTableEntry *typedecl_type = get_typedecl_type(c->codegen, buf_ptr(full_type_name),
-                c->codegen->builtin_types.entry_u8);
-        c->enum_type_table.put(bare_name, typedecl_type);
+        TypeTableEntry *enum_type = get_partial_container_type(c->codegen, c->import,
+                ContainerKindEnum, c->source_node, buf_ptr(full_type_name));
+        c->enum_type_table.put(bare_name, enum_type);
+        c->decl_table.put(enum_decl, enum_type);
+        replace_with_fwd_decl(c, enum_type, full_type_name);
 
-        // this is a type that we can point to but that's it, same as `struct Foo;`.
-        add_typedef_node(c, typedecl_type);
-        add_alias(c, buf_ptr(bare_name), buf_ptr(full_type_name));
-        return;
+        return enum_type;
     }
 
-    // count and validate
+    bool pure_enum = true;
     uint32_t field_count = 0;
     for (auto it = enum_def->enumerator_begin(),
               it_end = enum_def->enumerator_end();
@@ -796,120 +817,156 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) {
     {
         const EnumConstantDecl *enum_const = *it;
         if (enum_const->getInitExpr()) {
-            emit_warning(c, enum_const, "skipping enum %s - has init expression\n", buf_ptr(bare_name));
-            return;
+            pure_enum = false;
         }
     }
 
-    TypeTableEntry *enum_type = get_partial_container_type(c->codegen, c->import,
-            ContainerKindEnum, c->source_node, buf_ptr(full_type_name));
-
-    enum_type->data.enumeration.gen_field_count = 0;
-    enum_type->data.enumeration.complete = true;
+    TypeTableEntry *tag_type_entry = resolve_qual_type(c, enum_decl->getIntegerType(), enum_decl);
 
-    TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(c->codegen, field_count);
-    enum_type->data.enumeration.tag_type = tag_type_entry;
+    if (pure_enum) {
+        TypeTableEntry *enum_type = get_partial_container_type(c->codegen, c->import,
+                ContainerKindEnum, c->source_node, buf_ptr(full_type_name));
+        c->enum_type_table.put(bare_name, enum_type);
+        c->decl_table.put(enum_decl, enum_type);
 
-    c->enum_type_table.put(bare_name, enum_type);
-    // make an alias without the "enum_" prefix. this will get emitted at the
-    // end if it doesn't conflict with anything else
-    add_alias(c, buf_ptr(bare_name), buf_ptr(full_type_name));
+        enum_type->data.enumeration.gen_field_count = 0;
+        enum_type->data.enumeration.complete = true;
+        enum_type->data.enumeration.tag_type = tag_type_entry;
 
-    enum_type->data.enumeration.field_count = field_count;
-    enum_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);
-    LLVMZigDIEnumerator **di_enumerators = allocate<LLVMZigDIEnumerator*>(field_count);
+        enum_type->data.enumeration.field_count = field_count;
+        enum_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);
+        LLVMZigDIEnumerator **di_enumerators = allocate<LLVMZigDIEnumerator*>(field_count);
 
-    ZigList<AstNode *> var_decls = {0};
-    uint32_t i = 0;
-    for (auto it = enum_def->enumerator_begin(),
-              it_end = enum_def->enumerator_end();
-              it != it_end; ++it, i += 1)
-    {
-        const EnumConstantDecl *enum_const = *it;
+        uint32_t i = 0;
+        for (auto it = enum_def->enumerator_begin(),
+                it_end = enum_def->enumerator_end();
+                it != it_end; ++it, i += 1)
+        {
+            const EnumConstantDecl *enum_const = *it;
 
-        Buf *enum_val_name = buf_create_from_str(decl_name(enum_const));
-        Buf *field_name;
-        if (buf_starts_with_buf(enum_val_name, bare_name)) {
-            Buf *slice = buf_slice(enum_val_name, buf_len(bare_name), buf_len(enum_val_name));
-            if (valid_symbol_starter(buf_ptr(slice)[0])) {
-                field_name = slice;
+            Buf *enum_val_name = buf_create_from_str(decl_name(enum_const));
+            Buf *field_name;
+            if (buf_starts_with_buf(enum_val_name, bare_name)) {
+                field_name = buf_slice(enum_val_name, buf_len(bare_name), buf_len(enum_val_name));
             } else {
-                field_name = buf_sprintf("_%s", buf_ptr(slice));
+                field_name = enum_val_name;
             }
-        } else {
-            field_name = enum_val_name;
+
+            TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
+            type_enum_field->name = field_name;
+            type_enum_field->type_entry = c->codegen->builtin_types.entry_void;
+            type_enum_field->value = i;
+
+            di_enumerators[i] = LLVMZigCreateDebugEnumerator(c->codegen->dbuilder, buf_ptr(type_enum_field->name), i);
+
+
+            // in C each enum value is in the global namespace. so we put them there too.
+            // at this point we can rely on the enum emitting successfully
+            AstNode *field_access_node = create_field_access_node(c, buf_ptr(full_type_name), buf_ptr(field_name));
+            AstNode *var_node = create_var_decl_node(c, buf_ptr(enum_val_name), field_access_node);
+            c->root->data.root.top_level_decls.append(var_node);
+
+            c->global_value_table.put(enum_val_name, {enum_type, true});
         }
 
-        TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
-        type_enum_field->name = field_name;
-        type_enum_field->type_entry = c->codegen->builtin_types.entry_void;
-        type_enum_field->value = i;
+        // create llvm type for root struct
+        enum_type->type_ref = tag_type_entry->type_ref;
 
-        di_enumerators[i] = LLVMZigCreateDebugEnumerator(c->codegen->dbuilder, buf_ptr(type_enum_field->name), i);
+        // create debug type for tag
+        unsigned line = c->source_node ? (c->source_node->line + 1) : 0;
+        uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(c->codegen->target_data_ref, enum_type->type_ref);
+        uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(c->codegen->target_data_ref, enum_type->type_ref);
+        LLVMZigDIType *tag_di_type = LLVMZigCreateDebugEnumerationType(c->codegen->dbuilder,
+                LLVMZigFileToScope(c->import->di_file), buf_ptr(bare_name),
+                c->import->di_file, line,
+                debug_size_in_bits,
+                debug_align_in_bits,
+                di_enumerators, field_count, tag_type_entry->di_type, "");
 
+        LLVMZigReplaceTemporary(c->codegen->dbuilder, enum_type->di_type, tag_di_type);
+        enum_type->di_type = tag_di_type;
 
-        // in C each enum value is in the global namespace. so we put them there too.
-        // at this point we can rely on the enum emitting successfully
-        AstNode *field_access_node = create_field_access_node(c, buf_ptr(full_type_name), buf_ptr(field_name));
-        AstNode *var_node = create_var_decl_node(c, buf_ptr(enum_val_name), field_access_node);
-        var_decls.append(var_node);
-        c->global_value_table.put(enum_val_name, {enum_type, true});
-    }
+        return enum_type;
+    } else {
+        TypeTableEntry *enum_type = get_typedecl_type(c->codegen, buf_ptr(full_type_name), tag_type_entry);
+        c->enum_type_table.put(bare_name, enum_type);
+        c->decl_table.put(enum_decl, enum_type);
 
-    // create llvm type for root struct
-    enum_type->type_ref = tag_type_entry->type_ref;
+        // add variables for all the values with enum_type
+        for (auto it = enum_def->enumerator_begin(),
+                it_end = enum_def->enumerator_end();
+                it != it_end; ++it)
+        {
+            const EnumConstantDecl *enum_const = *it;
+            AstNode *num_lit_node = create_ap_num_lit_node(c, enum_decl, enum_const->getInitVal());
+            if (!num_lit_node) {
+                return c->codegen->builtin_types.entry_invalid;
+            }
 
-    // create debug type for tag
-    unsigned line = c->source_node ? (c->source_node->line + 1) : 0;
-    uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(c->codegen->target_data_ref, enum_type->type_ref);
-    uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(c->codegen->target_data_ref, enum_type->type_ref);
-    LLVMZigDIType *tag_di_type = LLVMZigCreateDebugEnumerationType(c->codegen->dbuilder,
-            LLVMZigFileToScope(c->import->di_file), buf_ptr(bare_name),
-            c->import->di_file, line,
-            debug_size_in_bits,
-            debug_align_in_bits,
-            di_enumerators, field_count, tag_type_entry->di_type, "");
+            Buf *enum_val_name = buf_create_from_str(decl_name(enum_const));
 
-    LLVMZigReplaceTemporary(c->codegen->dbuilder, enum_type->di_type, tag_di_type);
-    enum_type->di_type = tag_di_type;
+            AstNode *type_node = make_type_node(c, enum_type);
+            AstNode *var_decl_node = create_typed_var_decl_node(c, true, buf_ptr(enum_val_name),
+                    type_node, num_lit_node);
 
-    //////////
+            c->root->data.root.top_level_decls.append(var_decl_node);
+            c->global_value_table.put(enum_val_name, {enum_type, true});
 
-    // now create top level decl for the type
-    AstNode *enum_node = create_node(c, NodeTypeStructDecl);
-    buf_init_from_buf(&enum_node->data.struct_decl.name, full_type_name);
-    enum_node->data.struct_decl.kind = ContainerKindEnum;
-    enum_node->data.struct_decl.top_level_decl.visib_mod = VisibModExport;
-    enum_node->data.struct_decl.type_entry = enum_type;
+        }
 
-    for (uint32_t i = 0; i < field_count; i += 1) {
-        TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
-        AstNode *type_node = make_type_node(c, type_enum_field->type_entry);
-        AstNode *field_node = create_struct_field_node(c, buf_ptr(type_enum_field->name), type_node);
-        enum_node->data.struct_decl.fields.append(field_node);
+        return enum_type;
     }
+}
 
-    normalize_parent_ptrs(enum_node);
-    c->root->data.root.top_level_decls.append(enum_node);
+static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) {
+    TypeTableEntry *enum_type = resolve_enum_decl(c, enum_decl);
 
-    for (int i = 0; i < var_decls.length; i += 1) {
-        AstNode *var_node = var_decls.at(i);
-        c->root->data.root.top_level_decls.append(var_node);
+    if (enum_type->id == TypeTableEntryIdInvalid) {
+        return;
     }
 
-}
+    // make an alias without the "enum_" prefix. this will get emitted at the
+    // end if it doesn't conflict with anything else
+    if (decl_name(enum_decl)[0] != 0) {
+        add_alias(c, decl_name(enum_decl), buf_ptr(&enum_type->name));
+    }
 
-static void replace_with_fwd_decl(Context *c, TypeTableEntry *struct_type, Buf *full_type_name) {
-    unsigned line = c->source_node ? c->source_node->line : 0;
-    LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugForwardDeclType(c->codegen->dbuilder,
-        LLVMZigTag_DW_structure_type(), buf_ptr(full_type_name), 
-        LLVMZigFileToScope(c->import->di_file), c->import->di_file, line);
+    if (enum_type->id == TypeTableEntryIdEnum) {
+        if (enum_type->data.enumeration.complete) {
+            // now create top level decl for the type
+            AstNode *enum_node = create_node(c, NodeTypeStructDecl);
+            buf_init_from_buf(&enum_node->data.struct_decl.name, &enum_type->name);
+            enum_node->data.struct_decl.kind = ContainerKindEnum;
+            enum_node->data.struct_decl.top_level_decl.visib_mod = VisibModExport;
+            enum_node->data.struct_decl.type_entry = enum_type;
+
+            for (uint32_t i = 0; i < enum_type->data.enumeration.field_count; i += 1) {
+                TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
+                AstNode *type_node = make_type_node(c, type_enum_field->type_entry);
+                AstNode *field_node = create_struct_field_node(c, buf_ptr(type_enum_field->name), type_node);
+                enum_node->data.struct_decl.fields.append(field_node);
+            }
 
-    LLVMZigReplaceTemporary(c->codegen->dbuilder, struct_type->di_type, replacement_di_type);
-    struct_type->di_type = replacement_di_type;
+            normalize_parent_ptrs(enum_node);
+            c->root->data.root.top_level_decls.append(enum_node);
+        } else {
+            TypeTableEntry *typedecl_type = get_typedecl_type(c->codegen, buf_ptr(&enum_type->name),
+                    c->codegen->builtin_types.entry_u8);
+            add_typedef_node(c, typedecl_type);
+        }
+    } else if (enum_type->id == TypeTableEntryIdTypeDecl) {
+        add_typedef_node(c, enum_type);
+    } else {
+        zig_unreachable();
+    }
 }
 
 static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_decl) {
+    auto existing_entry = c->decl_table.maybe_get((void*)record_decl);
+    if (existing_entry) {
+        return existing_entry->value;
+    }
+
     const char *raw_name = decl_name(record_decl);
 
     if (!record_decl->isStruct()) {
@@ -922,11 +979,6 @@ static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_
         bare_name = buf_sprintf("anon_$%" PRIu32, get_next_node_index(c));
     } else {
         bare_name = buf_create_from_str(raw_name);
-
-        auto existing_entry = c->struct_type_table.maybe_get(bare_name);
-        if (existing_entry) {
-            return existing_entry->value;
-        }
     }
 
     Buf *full_type_name = buf_sprintf("struct_%s", buf_ptr(bare_name));
@@ -936,6 +988,7 @@ static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_
             ContainerKindStruct, c->source_node, buf_ptr(full_type_name));
 
     c->struct_type_table.put(bare_name, struct_type);
+    c->decl_table.put(record_decl, struct_type);
 
     RecordDecl *record_def = record_decl->getDefinition();
     unsigned line = c->source_node ? c->source_node->line : 0;
@@ -1125,23 +1178,9 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) {
                             "ignoring variable '%s' - int initializer for non int type\n", buf_ptr(name));
                         return;
                     }
-                    llvm::APSInt aps_int = ap_value->getInt();
-                    if (aps_int.isSigned()) {
-                        if (aps_int > INT64_MAX || aps_int < INT64_MIN) {
-                            emit_warning(c, var_decl,
-                                "ignoring variable '%s' - initializer overflow\n", buf_ptr(name));
-                            return;
-                        } else {
-                            init_node = create_num_lit_signed(c, aps_int.getExtValue());
-                        }
-                    } else {
-                        if (aps_int > UINT64_MAX) {
-                            emit_warning(c, var_decl,
-                                "ignoring variable '%s' - initializer overflow\n", buf_ptr(name));
-                            return;
-                        } else {
-                            init_node = create_num_lit_unsigned(c, aps_int.getExtValue());
-                        }
+                    init_node = create_ap_num_lit_node(c, var_decl, ap_value->getInt());
+                    if (!init_node) {
+                        return;
                     }
                     break;
                 }
@@ -1360,7 +1399,7 @@ static void process_preprocessor_entities(Context *c, ASTUnit &unit) {
             case PreprocessedEntity::MacroDefinitionKind:
                 {
                     MacroDefinitionRecord *macro = static_cast<MacroDefinitionRecord *>(entity);
-                    const char *name = macro->getName()->getNameStart();
+                    const char *raw_name = macro->getName()->getNameStart();
                     SourceRange range = macro->getSourceRange();
                     SourceLocation begin_loc = range.getBegin();
                     SourceLocation end_loc = range.getEnd();
@@ -1370,9 +1409,13 @@ static void process_preprocessor_entities(Context *c, ASTUnit &unit) {
                         // we don't care about such things
                         continue;
                     }
+                    Buf *name = buf_create_from_str(raw_name);
+                    if (name_exists(c, name)) {
+                        continue;
+                    }
 
                     const char *end_c = c->source_manager->getCharacterData(end_loc);
-                    process_macro(c, &ctok, buf_create_from_str(name), end_c);
+                    process_macro(c, &ctok, name, end_c);
                 }
         }
     }
@@ -1408,6 +1451,7 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch
     c->enum_type_table.init(8);
     c->struct_type_table.init(8);
     c->struct_decl_table.init(8);
+    c->decl_table.init(8);
     c->fn_table.init(8);
     c->macro_table.init(8);
     c->codegen = codegen;
src/util.cpp
@@ -34,3 +34,11 @@ uint32_t uint64_hash(uint64_t i) {
 bool uint64_eq(uint64_t a, uint64_t b) {
     return a == b;
 }
+
+uint32_t ptr_hash(const void *ptr) {
+    return ((uintptr_t)ptr) % UINT32_MAX;
+}
+
+bool ptr_eq(const void *a, const void *b) {
+    return a == b;
+}
src/util.hpp
@@ -83,5 +83,7 @@ uint32_t int_hash(int i);
 bool int_eq(int a, int b);
 uint32_t uint64_hash(uint64_t i);
 bool uint64_eq(uint64_t a, uint64_t b);
+uint32_t ptr_hash(const void *ptr);
+bool ptr_eq(const void *a, const void *b);
 
 #endif
test/run_tests.cpp
@@ -1244,15 +1244,14 @@ enum Foo {
     FooB,
     Foo1,
 };
-    )SOURCE", 1, R"OUTPUT(export enum enum_Foo {
+    )SOURCE", 3, R"(export enum enum_Foo {
     A,
     B,
-    _1,
-}
-pub const FooA = enum_Foo.A;
+    @"1",
+})", R"(pub const FooA = enum_Foo.A;
 pub const FooB = enum_Foo.B;
-pub const Foo1 = enum_Foo._1;)OUTPUT",
-            R"OUTPUT(pub const Foo = enum_Foo;)OUTPUT");
+pub const Foo1 = enum_Foo.@"1";)",
+            R"(pub const Foo = enum_Foo;)");
 
     add_parseh_case("restrict -> noalias", R"SOURCE(
 void foo(void *restrict bar, void *restrict);
@@ -1279,15 +1278,14 @@ enum Bar {
     BarB,
 };
 void func(struct Foo *a, enum Bar **b);
-    )SOURCE", 3, R"OUTPUT(export struct struct_Foo {
+    )SOURCE", 5, R"OUTPUT(export struct struct_Foo {
     x: c_int,
     y: c_int,
-}
+})OUTPUT", R"OUTPUT(
 export enum enum_Bar {
     A,
     B,
-}
-pub const BarA = enum_Bar.A;
+})OUTPUT", R"OUTPUT(pub const BarA = enum_Bar.A;
 pub const BarB = enum_Bar.B;)OUTPUT",
             "pub extern fn func(a: ?&struct_Foo, b: ?&?&enum_Bar);",
     R"OUTPUT(pub const Foo = struct_Foo;
@@ -1325,12 +1323,6 @@ pub extern fn some_func(foo: ?&struct_Foo, x: c_int) -> ?&struct_Foo;)OUTPUT",
     )SOURCE", 1, R"OUTPUT(pub const CHANNEL_COUNT = 24;)OUTPUT");
 
 
-    add_parseh_case("overide previous #define", R"SOURCE(
-#define A_CHAR 'a'
-#define A_CHAR 'b'
-    )SOURCE", 1, "pub const A_CHAR = 'b';");
-
-
     add_parseh_case("#define referencing another #define", R"SOURCE(
 #define THING2 THING1
 #define THING1 1234