Commit 66163692ad
Changed files (5)
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