diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2016-01-28 15:41:12 -0700 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2016-01-28 15:41:12 -0700 |
| commit | ed3117a77fffa424e7f902059a7bf3a52f758bfc (patch) | |
| tree | f74d9b0bdd6b574daf54de1dfdcafb4e3c9bcdf3 | |
| parent | 47c3a30310b142dea390afaf4063a8b078a34f0d (diff) | |
| download | zig-ed3117a77fffa424e7f902059a7bf3a52f758bfc.tar.gz zig-ed3117a77fffa424e7f902059a7bf3a52f758bfc.zip | |
parseh understands elaborated structs and enums
| -rw-r--r-- | src/parseh.cpp | 161 | ||||
| -rw-r--r-- | test/run_tests.cpp | 24 |
2 files changed, 132 insertions, 53 deletions
diff --git a/src/parseh.cpp b/src/parseh.cpp index 01969f366c..9b640f5ec3 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -27,12 +27,18 @@ struct Context { VisibMod visib_mod; bool have_c_void_decl_node; AstNode *root; - HashMap<Buf *, bool, buf_hash, buf_eql_buf> type_table; + HashMap<Buf *, bool, buf_hash, buf_eql_buf> root_type_table; + HashMap<Buf *, bool, buf_hash, buf_eql_buf> struct_type_table; + HashMap<Buf *, bool, buf_hash, buf_eql_buf> enum_type_table; HashMap<Buf *, bool, buf_hash, buf_eql_buf> fn_table; SourceManager *source_manager; ZigList<AstNode *> aliases; }; +static AstNode *make_qual_type_node(Context *c, QualType qt, const Decl *decl); +static AstNode *make_qual_type_node_with_table(Context *c, QualType qt, const Decl *decl, + HashMap<Buf *, bool, buf_hash, buf_eql_buf> *type_table); + __attribute__ ((format (printf, 3, 4))) static void emit_warning(Context *c, const Decl *decl, const char *format, ...) { if (!c->warnings_on) { @@ -59,8 +65,6 @@ static void emit_warning(Context *c, const Decl *decl, const char *format, ...) fprintf(stderr, "%s:%u:%u: warning: %s\n", buf_ptr(path), line, column, buf_ptr(msg)); } -static AstNode *make_qual_type_node(Context *c, QualType qt, const Decl *decl); - static AstNode *create_node(Context *c, NodeType type) { AstNode *node = allocate<AstNode>(1); node->type = type; @@ -129,7 +133,7 @@ static AstNode *add_typedef_node(Context *c, Buf *new_name, AstNode *target_node } AstNode *node = create_var_decl_node(c, buf_ptr(new_name), target_node); - c->type_table.put(new_name, true); + c->root_type_table.put(new_name, true); c->root->data.root.top_level_decls.append(node); return node; } @@ -157,7 +161,9 @@ static AstNode *pointer_to_type(Context *c, AstNode *type_node, bool is_const) { return create_prefix_node(c, PrefixOpMaybe, child_node); } -static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl) { +static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl, + HashMap<Buf *, bool, buf_hash, buf_eql_buf> *type_table) +{ switch (ty->getTypeClass()) { case Type::Builtin: { @@ -258,7 +264,7 @@ static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl) { } else if (buf_eql_str(type_name, "uintptr_t")) { return create_symbol_node(c, "usize"); } else { - auto entry = c->type_table.maybe_get(type_name); + auto entry = type_table->maybe_get(type_name); if (entry) { return create_symbol_node(c, buf_ptr(type_name)); } else { @@ -267,13 +273,63 @@ static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl) { } } case Type::Elaborated: - emit_warning(c, decl, "ignoring elaborated type"); - return nullptr; + { + const ElaboratedType *elaborated_ty = static_cast<const ElaboratedType*>(ty); + switch (elaborated_ty->getKeyword()) { + case ETK_Struct: + return make_qual_type_node_with_table(c, elaborated_ty->getNamedType(), + decl, &c->struct_type_table); + case ETK_Enum: + return make_qual_type_node_with_table(c, elaborated_ty->getNamedType(), + decl, &c->enum_type_table); + case ETK_Interface: + case ETK_Union: + case ETK_Class: + case ETK_Typename: + case ETK_None: + emit_warning(c, decl, "unsupported elaborated type"); + return nullptr; + } + } case Type::FunctionProto: emit_warning(c, decl, "ignoring function type"); return nullptr; case Type::Record: + { + const RecordType *record_ty = static_cast<const RecordType*>(ty); + Buf *record_name = buf_create_from_str(decl_name(record_ty->getDecl())); + if (type_table->maybe_get(record_name)) { + const char *prefix_str; + if (type_table == &c->enum_type_table) { + prefix_str = "enum_"; + } else if (type_table == &c->struct_type_table) { + prefix_str = "struct_"; + } else { + prefix_str = ""; + } + return create_symbol_node(c, buf_ptr(buf_sprintf("%s%s", prefix_str, buf_ptr(record_name)))); + } else { + return nullptr; + } + } 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 (type_table->maybe_get(record_name)) { + const char *prefix_str; + if (type_table == &c->enum_type_table) { + prefix_str = "enum_"; + } else if (type_table == &c->struct_type_table) { + prefix_str = "struct_"; + } else { + prefix_str = ""; + } + return create_symbol_node(c, buf_ptr(buf_sprintf("%s%s", prefix_str, buf_ptr(record_name)))); + } else { + return nullptr; + } + } case Type::BlockPointer: case Type::LValueReference: case Type::RValueReference: @@ -314,8 +370,14 @@ static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl) { } } +static AstNode *make_qual_type_node_with_table(Context *c, QualType qt, const Decl *decl, + HashMap<Buf *, bool, buf_hash, buf_eql_buf> *type_table) +{ + return make_type_node(c, qt.getTypePtr(), decl, type_table); +} + static AstNode *make_qual_type_node(Context *c, QualType qt, const Decl *decl) { - return make_type_node(c, qt.getTypePtr(), decl); + return make_qual_type_node_with_table(c, qt, decl, &c->root_type_table); } static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { @@ -334,7 +396,6 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { node->data.fn_proto.is_var_args = fn_decl->isVariadic(); int arg_count = fn_decl->getNumParams(); - bool all_ok = true; for (int i = 0; i < arg_count; i += 1) { const ParmVarDecl *param = fn_decl->getParamDecl(i); AstNode *param_decl_node = create_node(c, NodeTypeParamDecl); @@ -347,8 +408,9 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { param_decl_node->data.param_decl.is_noalias = qt.isRestrictQualified(); param_decl_node->data.param_decl.type = make_qual_type_node(c, qt, fn_decl); if (!param_decl_node->data.param_decl.type) { - all_ok = false; - break; + emit_warning(c, param, "skipping function %s, unresolved param type\n", + buf_ptr(&node->data.fn_proto.name)); + return; } normalize_parent_ptrs(param_decl_node); @@ -362,11 +424,8 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { } if (!node->data.fn_proto.return_type) { - all_ok = false; - } - if (!all_ok) { - // not all the types could be resolved, so we give up on the function decl - emit_warning(c, fn_decl, "skipping function %s\n", buf_ptr(&node->data.fn_proto.name)); + emit_warning(c, fn_decl, "skipping function %s, unresolved return type\n", + buf_ptr(&node->data.fn_proto.name)); return; } @@ -404,13 +463,10 @@ static void add_alias(Context *c, const char *new_name, const char *target_name) } static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) { - Buf bare_name = BUF_INIT; - buf_init_from_str(&bare_name, decl_name(enum_decl)); - - Buf *type_name = buf_alloc(); - buf_appendf(type_name, "enum_%s", buf_ptr(&bare_name)); + Buf *bare_name = buf_create_from_str(decl_name(enum_decl)); + Buf *full_type_name = buf_sprintf("enum_%s", buf_ptr(bare_name)); - if (c->type_table.maybe_get(type_name)) { + if (c->enum_type_table.maybe_get(bare_name)) { // we've already seen it return; } @@ -419,13 +475,13 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) { if (!enum_def) { // this is a type that we can point to but that's it, same as `struct Foo;`. - add_typedef_node(c, type_name, create_symbol_node(c, "u8")); - add_alias(c, buf_ptr(&bare_name), buf_ptr(type_name)); + add_typedef_node(c, full_type_name, create_symbol_node(c, "u8")); + add_alias(c, buf_ptr(bare_name), buf_ptr(full_type_name)); return; } AstNode *node = create_node(c, NodeTypeStructDecl); - buf_init_from_buf(&node->data.struct_decl.name, type_name); + buf_init_from_buf(&node->data.struct_decl.name, full_type_name); node->data.struct_decl.kind = ContainerKindEnum; node->data.struct_decl.visib_mod = VisibModExport; @@ -439,7 +495,7 @@ 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(type_name)); + emit_warning(c, enum_const, "skipping enum %s - has init expression\n", buf_ptr(bare_name)); return; } Buf enum_val_name = BUF_INIT; @@ -447,8 +503,8 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) { Buf field_name = BUF_INIT; - 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 (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])) { buf_init_from_buf(&field_name, slice); } else { @@ -463,13 +519,12 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) { node->data.struct_decl.fields.append(field_node); // in C each enum value is in the global namespace. so we put them there too. - AstNode *field_access_node = create_field_access_node(c, buf_ptr(type_name), - buf_ptr(&field_name)); + 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->type_table.put(type_name, true); + c->enum_type_table.put(bare_name, true); normalize_parent_ptrs(node); c->root->data.root.top_level_decls.append(node); @@ -481,17 +536,20 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) { // 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(type_name)); + add_alias(c, buf_ptr(bare_name), buf_ptr(full_type_name)); } static void visit_record_decl(Context *c, const RecordDecl *record_decl) { - Buf bare_name = BUF_INIT; - buf_init_from_str(&bare_name, decl_name(record_decl)); + Buf *bare_name = buf_create_from_str(decl_name(record_decl)); + + if (!record_decl->isStruct()) { + emit_warning(c, record_decl, "skipping record %s, not a struct", buf_ptr(bare_name)); + return; + } - Buf *type_name = buf_alloc(); - buf_appendf(type_name, "struct_%s", buf_ptr(&bare_name)); + Buf *full_type_name = buf_sprintf("struct_%s", buf_ptr(bare_name)); - if (c->type_table.maybe_get(type_name)) { + if (c->struct_type_table.maybe_get(bare_name)) { // we've already seen it return; } @@ -499,18 +557,13 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) { RecordDecl *record_def = record_decl->getDefinition(); if (!record_def) { // this is a type that we can point to but that's it, such as `struct Foo;`. - add_typedef_node(c, type_name, create_symbol_node(c, "u8")); - add_alias(c, buf_ptr(&bare_name), buf_ptr(type_name)); - return; - } - - if (!record_def->isStruct()) { - emit_warning(c, record_decl, "skipping record %s, not a struct", buf_ptr(&bare_name)); + add_typedef_node(c, full_type_name, create_symbol_node(c, "u8")); + add_alias(c, buf_ptr(bare_name), buf_ptr(full_type_name)); return; } AstNode *node = create_node(c, NodeTypeStructDecl); - buf_init_from_buf(&node->data.struct_decl.name, type_name); + buf_init_from_buf(&node->data.struct_decl.name, full_type_name); node->data.struct_decl.kind = ContainerKindStruct; node->data.struct_decl.visib_mod = VisibModExport; @@ -523,13 +576,13 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) { const FieldDecl *field_decl = *it; if (field_decl->isBitField()) { - emit_warning(c, field_decl, "skipping struct %s - has bitfield\n", buf_ptr(&bare_name)); + emit_warning(c, field_decl, "skipping struct %s - has bitfield\n", buf_ptr(bare_name)); return; } AstNode *type_node = make_qual_type_node(c, field_decl->getType(), field_decl); if (!type_node) { - emit_warning(c, field_decl, "skipping struct %s - unhandled type\n", buf_ptr(&bare_name)); + emit_warning(c, field_decl, "skipping struct %s - unhandled type\n", buf_ptr(bare_name)); return; } @@ -537,13 +590,13 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) { node->data.struct_decl.fields.append(field_node); } - c->type_table.put(type_name, true); + c->struct_type_table.put(bare_name, true); normalize_parent_ptrs(node); c->root->data.root.top_level_decls.append(node); // make an alias without the "struct_" 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(type_name)); + add_alias(c, buf_ptr(bare_name), buf_ptr(full_type_name)); } static bool decl_visitor(void *context, const Decl *decl) { @@ -574,7 +627,7 @@ static void render_aliases(Context *c) { AstNode *alias_node = c->aliases.at(i); assert(alias_node->type == NodeTypeVariableDeclaration); Buf *name = &alias_node->data.variable_declaration.symbol; - if (c->type_table.maybe_get(name)) { + if (c->root_type_table.maybe_get(name)) { continue; } if (c->fn_table.maybe_get(name)) { @@ -618,8 +671,10 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, c->import = import; c->errors = errors; c->visib_mod = VisibModPub; - c->type_table.init(32); - c->fn_table.init(32); + c->root_type_table.init(16); + c->enum_type_table.init(16); + c->struct_type_table.init(16); + c->fn_table.init(16); char *ZIG_PARSEH_CFLAGS = getenv("ZIG_PARSEH_CFLAGS"); if (ZIG_PARSEH_CFLAGS) { diff --git a/test/run_tests.cpp b/test/run_tests.cpp index e30200c200..afd7635caa 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -1839,6 +1839,30 @@ struct Foo { y: ?&u8, } pub const Foo = struct_Foo;)OUTPUT"); + + add_parseh_case("qualified struct and enum", R"SOURCE( +struct Foo { + int x; + int y; +}; +enum Bar { + BarA, + BarB, +}; +void func(struct Foo *a, enum Bar **b); + )SOURCE", R"OUTPUT(export struct struct_Foo { + x: c_int, + y: c_int, +} +export enum enum_Bar { + A, + B, +} +pub const BarA = enum_Bar.A; +pub const BarB = enum_Bar.B; +pub extern fn func(a: ?&struct_Foo, b: ?&?&enum_Bar); +pub const Foo = struct_Foo; +pub const Bar = enum_Bar;)OUTPUT"); } static void print_compiler_invocation(TestCase *test_case) { |
