authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-08 23:12:36-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-08 23:22:25-07:00
log4eff5f114b463ddd887665129f2e1d29b0f13b7f
tree10535aff8fa5cdb95c57f595537167d471d4c705
parentface8d65a85e9b6184d9eb7c3d5b345090350b27

parseh: better results for stdio.h


1 files changed, 191 insertions(+), 10 deletions(-)

src/parseh.cpp+191-10
......@@ -12,6 +12,11 @@
1212
1313#include <string.h>
1414
15struct TypeDef {
16 Buf alias;
17 Buf target;
18};
19
1520struct Arg {
1621 Buf name;
1722 Buf *type;
......@@ -25,11 +30,26 @@ struct Fn {
2530 bool is_variadic;
2631};
2732
33struct Field {
34 Buf name;
35 Buf *type;
36};
37
38struct Struct {
39 Buf name;
40 ZigList<Field*> fields;
41 bool have_def;
42};
43
2844struct ParseH {
2945 CXTranslationUnit tu;
3046 FILE *f;
3147 ZigList<Fn *> fn_list;
48 ZigList<Struct *> struct_list;
49 ZigList<TypeDef *> type_def_list;
50 ZigList<Struct *> incomplete_struct_list;
3251 Fn *cur_fn;
52 Struct *cur_struct;
3353 int arg_index;
3454 int cur_indent;
3555 CXSourceRange range;
......@@ -38,6 +58,16 @@ struct ParseH {
3858
3959static const int indent_size = 4;
4060
61static bool have_struct_def(ParseH *p, Buf *name) {
62 for (int i = 0; i < p->struct_list.length; i += 1) {
63 Struct *struc = p->struct_list.at(i);
64 if (struc->fields.length > 0 && buf_eql_buf(&struc->name, name)) {
65 return true;
66 }
67 }
68 return false;
69}
70
4171static bool str_has_prefix(const char *str, const char *prefix) {
4272 while (*prefix) {
4373 if (*str && *str == *prefix) {
......@@ -81,6 +111,24 @@ static void print_location(ParseH *p) {
81111 fprintf(stderr, "%s line %u, column %u\n", clang_getCString(file_name), line, column);
82112}
83113
114static bool resolves_to_void(ParseH *p, CXType raw_type) {
115 if (raw_type.kind == CXType_Unexposed) {
116 CXType canonical = clang_getCanonicalType(raw_type);
117 if (canonical.kind == CXType_Unexposed)
118 zig_panic("clang C api insufficient");
119 else
120 return resolves_to_void(p, canonical);
121 }
122 if (raw_type.kind == CXType_Void) {
123 return true;
124 } else if (raw_type.kind == CXType_Typedef) {
125 CXCursor typedef_cursor = clang_getTypeDeclaration(raw_type);
126 CXType underlying_type = clang_getTypedefDeclUnderlyingType(typedef_cursor);
127 return resolves_to_void(p, underlying_type);
128 }
129 return false;
130}
131
84132static Buf *to_zig_type(ParseH *p, CXType raw_type) {
85133 if (raw_type.kind == CXType_Unexposed) {
86134 CXType canonical = clang_getCanonicalType(raw_type);
......@@ -94,15 +142,16 @@ static Buf *to_zig_type(ParseH *p, CXType raw_type) {
94142 case CXType_Unexposed:
95143 zig_unreachable();
96144 case CXType_Void:
97 return buf_create_from_str("void");
145 zig_panic("void type encountered");
98146 case CXType_Bool:
99147 return buf_create_from_str("bool");
100148 case CXType_SChar:
101 return buf_create_from_str("i8");
149 return buf_create_from_str("c_schar");
150 case CXType_UChar:
151 return buf_create_from_str("c_uchar");
102152 case CXType_Char_U:
103153 case CXType_Char_S:
104 case CXType_UChar:
105 return buf_create_from_str("u8");
154 return buf_create_from_str("c_char");
106155 case CXType_WChar:
107156 print_location(p);
108157 zig_panic("TODO wchar");
......@@ -153,7 +202,12 @@ static Buf *to_zig_type(ParseH *p, CXType raw_type) {
153202 case CXType_Pointer:
154203 {
155204 CXType pointee_type = clang_getPointeeType(raw_type);
156 Buf *pointee_buf = to_zig_type(p, pointee_type);
205 Buf *pointee_buf;
206 if (resolves_to_void(p, pointee_type)) {
207 pointee_buf = buf_create_from_str("u8");
208 } else {
209 pointee_buf = to_zig_type(p, pointee_type);
210 }
157211 if (clang_isConstQualifiedType(pointee_type)) {
158212 return buf_sprintf("*const %s", buf_ptr(pointee_buf));
159213 } else {
......@@ -192,7 +246,11 @@ static Buf *to_zig_type(ParseH *p, CXType raw_type) {
192246 } else {
193247 CXCursor typedef_cursor = clang_getTypeDeclaration(raw_type);
194248 CXType underlying_type = clang_getTypedefDeclUnderlyingType(typedef_cursor);
195 return to_zig_type(p, underlying_type);
249 if (resolves_to_void(p, underlying_type)) {
250 return buf_create_from_str("u8");
251 } else {
252 return buf_create_from_str(name);
253 }
196254 }
197255 }
198256 case CXType_ConstantArray:
......@@ -205,7 +263,7 @@ static Buf *to_zig_type(ParseH *p, CXType raw_type) {
205263 case CXType_FunctionProto:
206264 fprintf(stderr, "warning: TODO function proto\n");
207265 print_location(p);
208 return buf_create_from_str("*const u8");
266 return buf_create_from_str("u8");
209267 case CXType_FunctionNoProto:
210268 print_location(p);
211269 zig_panic("TODO function no proto");
......@@ -277,6 +335,51 @@ static enum CXChildVisitResult visit_fn_children(CXCursor cursor, CXCursor paren
277335 }
278336}
279337
338static enum CXChildVisitResult visit_struct_children(CXCursor cursor, CXCursor parent, CXClientData client_data) {
339 ParseH *p = (ParseH*)client_data;
340 enum CXCursorKind kind = clang_getCursorKind(cursor);
341
342 switch (kind) {
343 case CXCursor_FieldDecl:
344 {
345 assert(p->cur_struct);
346 CXString name = clang_getCursorSpelling(cursor);
347 Field *field = allocate<Field>(1);
348 buf_init_from_str(&field->name, clang_getCString(name));
349 CXType cursor_type = clang_getCursorType(cursor);
350 field->type = to_zig_type(p, cursor_type);
351
352 p->cur_struct->fields.append(field);
353
354 return CXChildVisit_Continue;
355 }
356 default:
357 return CXChildVisit_Recurse;
358 }
359}
360
361static bool handle_struct_cursor(ParseH *p, CXCursor cursor, const char *name, bool expect_name) {
362 p->cur_struct = allocate<Struct>(1);
363
364 buf_init_from_str(&p->cur_struct->name, name);
365
366 bool got_name = (buf_len(&p->cur_struct->name) != 0);
367 if (expect_name != got_name)
368 return false;
369
370 clang_visitChildren(cursor, visit_struct_children, p);
371
372 if (p->cur_struct->fields.length > 0) {
373 p->struct_list.append(p->cur_struct);
374 } else {
375 p->incomplete_struct_list.append(p->cur_struct);
376 }
377
378 p->cur_struct = nullptr;
379
380 return true;
381}
382
280383
281384static enum CXChildVisitResult fn_visitor(CXCursor cursor, CXCursor parent, CXClientData client_data) {
282385 ParseH *p = (ParseH*)client_data;
......@@ -306,7 +409,9 @@ static enum CXChildVisitResult fn_visitor(CXCursor cursor, CXCursor parent, CXCl
306409 p->cur_fn->is_variadic = clang_isFunctionTypeVariadic(fn_type);
307410
308411 CXType return_type = clang_getResultType(fn_type);
309 p->cur_fn->return_type = to_zig_type(p, return_type);
412 if (!resolves_to_void(p, return_type)) {
413 p->cur_fn->return_type = to_zig_type(p, return_type);
414 }
310415
311416 buf_init_from_str(&p->cur_fn->name, clang_getCString(name));
312417
......@@ -330,7 +435,44 @@ static enum CXChildVisitResult fn_visitor(CXCursor cursor, CXCursor parent, CXCl
330435 case CXCursor_CompoundStmt:
331436 case CXCursor_FieldDecl:
332437 case CXCursor_TypedefDecl:
333 return CXChildVisit_Continue;
438 {
439 CXType underlying_type = clang_getTypedefDeclUnderlyingType(cursor);
440
441 if (resolves_to_void(p, underlying_type)) {
442 return CXChildVisit_Continue;
443 }
444
445 if (underlying_type.kind == CXType_Unexposed) {
446 underlying_type = clang_getCanonicalType(underlying_type);
447 }
448 bool skip_typedef;
449 if (underlying_type.kind == CXType_Unexposed) {
450 fprintf(stderr, "warning: unexposed type\n");
451 print_location(p);
452 skip_typedef = true;
453 } else if (underlying_type.kind == CXType_Record) {
454 CXCursor decl_cursor = clang_getTypeDeclaration(underlying_type);
455 skip_typedef = handle_struct_cursor(p, decl_cursor, clang_getCString(name), false);
456 } else {
457 skip_typedef = false;
458 }
459
460 if (!skip_typedef) {
461 CXType typedef_type = clang_getCursorType(cursor);
462 TypeDef *type_def = allocate<TypeDef>(1);
463 buf_init_from_str(&type_def->alias, prefixes_stripped(typedef_type));
464 buf_init_from_buf(&type_def->target, to_zig_type(p, underlying_type));
465 p->type_def_list.append(type_def);
466 }
467
468 return CXChildVisit_Continue;
469 }
470 case CXCursor_StructDecl:
471 {
472 handle_struct_cursor(p, cursor, clang_getCString(name), true);
473
474 return CXChildVisit_Continue;
475 }
334476 default:
335477 return CXChildVisit_Recurse;
336478 }
......@@ -401,6 +543,44 @@ void parse_h_file(const char *target_path, ZigList<const char *> *clang_argv, FI
401543 CXCursor cursor = clang_getTranslationUnitCursor(p->tu);
402544 clang_visitChildren(cursor, fn_visitor, p);
403545
546 for (int struct_i = 0; struct_i < p->struct_list.length; struct_i += 1) {
547 Struct *struc = p->struct_list.at(struct_i);
548 fprintf(f, "struct %s {\n", buf_ptr(&struc->name));
549 p->cur_indent += indent_size;
550 for (int field_i = 0; field_i < struc->fields.length; field_i += 1) {
551 Field *field = struc->fields.at(field_i);
552 print_indent(p);
553 fprintf(f, "%s: %s,\n", buf_ptr(&field->name), buf_ptr(field->type));
554 }
555
556 p->cur_indent -= indent_size;
557 fprintf(f, "}\n\n");
558 }
559
560 int total_typedef_count = p->type_def_list.length;
561 for (int i = 0; i < p->incomplete_struct_list.length; i += 1) {
562 Struct *struc = p->incomplete_struct_list.at(i);
563 struc->have_def = have_struct_def(p, &struc->name);
564 total_typedef_count += (int)!struc->have_def;
565 }
566
567 if (total_typedef_count) {
568 for (int i = 0; i < p->incomplete_struct_list.length; i += 1) {
569 Struct *struc = p->incomplete_struct_list.at(i);
570 if (struc->have_def)
571 continue;
572
573 fprintf(f, "struct %s;\n", buf_ptr(&struc->name));
574 }
575
576 for (int type_def_i = 0; type_def_i < p->type_def_list.length; type_def_i += 1) {
577 TypeDef *type_def = p->type_def_list.at(type_def_i);
578 fprintf(f, "type %s = %s;\n", buf_ptr(&type_def->alias), buf_ptr(&type_def->target));
579 }
580
581 fprintf(f, "\n");
582 }
583
404584 if (p->fn_list.length) {
405585 fprintf(f, "extern {\n");
406586 p->cur_indent += indent_size;
......@@ -419,11 +599,12 @@ void parse_h_file(const char *target_path, ZigList<const char *> *clang_argv, FI
419599 fprintf(p->f, "...");
420600 }
421601 fprintf(p->f, ")");
422 if (!buf_eql_str(fn->return_type, "void")) {
602 if (fn->return_type) {
423603 fprintf(p->f, " -> %s", buf_ptr(fn->return_type));
424604 }
425605 fprintf(p->f, ";\n");
426606 }
607 p->cur_indent -= indent_size;
427608 fprintf(f, "}\n");
428609 }
429610}