| ... | @@ -12,6 +12,11 @@ | ... | @@ -12,6 +12,11 @@ |
| 12 | | 12 | |
| 13 | #include <string.h> | 13 | #include <string.h> |
| 14 | | 14 | |
| | 15 | struct TypeDef { |
| | 16 | Buf alias; |
| | 17 | Buf target; |
| | 18 | }; |
| | 19 | |
| 15 | struct Arg { | 20 | struct Arg { |
| 16 | Buf name; | 21 | Buf name; |
| 17 | Buf *type; | 22 | Buf *type; |
| ... | @@ -25,11 +30,26 @@ struct Fn { | ... | @@ -25,11 +30,26 @@ struct Fn { |
| 25 | bool is_variadic; | 30 | bool is_variadic; |
| 26 | }; | 31 | }; |
| 27 | | 32 | |
| | 33 | struct Field { |
| | 34 | Buf name; |
| | 35 | Buf *type; |
| | 36 | }; |
| | 37 | |
| | 38 | struct Struct { |
| | 39 | Buf name; |
| | 40 | ZigList<Field*> fields; |
| | 41 | bool have_def; |
| | 42 | }; |
| | 43 | |
| 28 | struct ParseH { | 44 | struct ParseH { |
| 29 | CXTranslationUnit tu; | 45 | CXTranslationUnit tu; |
| 30 | FILE *f; | 46 | FILE *f; |
| 31 | ZigList<Fn *> fn_list; | 47 | ZigList<Fn *> fn_list; |
| | 48 | ZigList<Struct *> struct_list; |
| | 49 | ZigList<TypeDef *> type_def_list; |
| | 50 | ZigList<Struct *> incomplete_struct_list; |
| 32 | Fn *cur_fn; | 51 | Fn *cur_fn; |
| | 52 | Struct *cur_struct; |
| 33 | int arg_index; | 53 | int arg_index; |
| 34 | int cur_indent; | 54 | int cur_indent; |
| 35 | CXSourceRange range; | 55 | CXSourceRange range; |
| ... | @@ -38,6 +58,16 @@ struct ParseH { | ... | @@ -38,6 +58,16 @@ struct ParseH { |
| 38 | | 58 | |
| 39 | static const int indent_size = 4; | 59 | static const int indent_size = 4; |
| 40 | | 60 | |
| | 61 | static 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 | |
| 41 | static bool str_has_prefix(const char *str, const char *prefix) { | 71 | static bool str_has_prefix(const char *str, const char *prefix) { |
| 42 | while (*prefix) { | 72 | while (*prefix) { |
| 43 | if (*str && *str == *prefix) { | 73 | if (*str && *str == *prefix) { |
| ... | @@ -81,6 +111,24 @@ static void print_location(ParseH *p) { | ... | @@ -81,6 +111,24 @@ static void print_location(ParseH *p) { |
| 81 | fprintf(stderr, "%s line %u, column %u\n", clang_getCString(file_name), line, column); | 111 | fprintf(stderr, "%s line %u, column %u\n", clang_getCString(file_name), line, column); |
| 82 | } | 112 | } |
| 83 | | 113 | |
| | 114 | static 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 | |
| 84 | static Buf *to_zig_type(ParseH *p, CXType raw_type) { | 132 | static Buf *to_zig_type(ParseH *p, CXType raw_type) { |
| 85 | if (raw_type.kind == CXType_Unexposed) { | 133 | if (raw_type.kind == CXType_Unexposed) { |
| 86 | CXType canonical = clang_getCanonicalType(raw_type); | 134 | CXType canonical = clang_getCanonicalType(raw_type); |
| ... | @@ -94,15 +142,16 @@ static Buf *to_zig_type(ParseH *p, CXType raw_type) { | ... | @@ -94,15 +142,16 @@ static Buf *to_zig_type(ParseH *p, CXType raw_type) { |
| 94 | case CXType_Unexposed: | 142 | case CXType_Unexposed: |
| 95 | zig_unreachable(); | 143 | zig_unreachable(); |
| 96 | case CXType_Void: | 144 | case CXType_Void: |
| 97 | return buf_create_from_str("void"); | 145 | zig_panic("void type encountered"); |
| 98 | case CXType_Bool: | 146 | case CXType_Bool: |
| 99 | return buf_create_from_str("bool"); | 147 | return buf_create_from_str("bool"); |
| 100 | case CXType_SChar: | 148 | 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"); |
| 102 | case CXType_Char_U: | 152 | case CXType_Char_U: |
| 103 | case CXType_Char_S: | 153 | case CXType_Char_S: |
| 104 | case CXType_UChar: | 154 | return buf_create_from_str("c_char"); |
| 105 | return buf_create_from_str("u8"); | | |
| 106 | case CXType_WChar: | 155 | case CXType_WChar: |
| 107 | print_location(p); | 156 | print_location(p); |
| 108 | zig_panic("TODO wchar"); | 157 | zig_panic("TODO wchar"); |
| ... | @@ -153,7 +202,12 @@ static Buf *to_zig_type(ParseH *p, CXType raw_type) { | ... | @@ -153,7 +202,12 @@ static Buf *to_zig_type(ParseH *p, CXType raw_type) { |
| 153 | case CXType_Pointer: | 202 | case CXType_Pointer: |
| 154 | { | 203 | { |
| 155 | CXType pointee_type = clang_getPointeeType(raw_type); | 204 | 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 | } |
| 157 | if (clang_isConstQualifiedType(pointee_type)) { | 211 | if (clang_isConstQualifiedType(pointee_type)) { |
| 158 | return buf_sprintf("*const %s", buf_ptr(pointee_buf)); | 212 | return buf_sprintf("*const %s", buf_ptr(pointee_buf)); |
| 159 | } else { | 213 | } else { |
| ... | @@ -192,7 +246,11 @@ static Buf *to_zig_type(ParseH *p, CXType raw_type) { | ... | @@ -192,7 +246,11 @@ static Buf *to_zig_type(ParseH *p, CXType raw_type) { |
| 192 | } else { | 246 | } else { |
| 193 | CXCursor typedef_cursor = clang_getTypeDeclaration(raw_type); | 247 | CXCursor typedef_cursor = clang_getTypeDeclaration(raw_type); |
| 194 | CXType underlying_type = clang_getTypedefDeclUnderlyingType(typedef_cursor); | 248 | 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 | } |
| 196 | } | 254 | } |
| 197 | } | 255 | } |
| 198 | case CXType_ConstantArray: | 256 | case CXType_ConstantArray: |
| ... | @@ -205,7 +263,7 @@ static Buf *to_zig_type(ParseH *p, CXType raw_type) { | ... | @@ -205,7 +263,7 @@ static Buf *to_zig_type(ParseH *p, CXType raw_type) { |
| 205 | case CXType_FunctionProto: | 263 | case CXType_FunctionProto: |
| 206 | fprintf(stderr, "warning: TODO function proto\n"); | 264 | fprintf(stderr, "warning: TODO function proto\n"); |
| 207 | print_location(p); | 265 | print_location(p); |
| 208 | return buf_create_from_str("*const u8"); | 266 | return buf_create_from_str("u8"); |
| 209 | case CXType_FunctionNoProto: | 267 | case CXType_FunctionNoProto: |
| 210 | print_location(p); | 268 | print_location(p); |
| 211 | zig_panic("TODO function no proto"); | 269 | zig_panic("TODO function no proto"); |
| ... | @@ -277,6 +335,51 @@ static enum CXChildVisitResult visit_fn_children(CXCursor cursor, CXCursor paren | ... | @@ -277,6 +335,51 @@ static enum CXChildVisitResult visit_fn_children(CXCursor cursor, CXCursor paren |
| 277 | } | 335 | } |
| 278 | } | 336 | } |
| 279 | | 337 | |
| | 338 | static 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 | |
| | 361 | static 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 | |
| 280 | | 383 | |
| 281 | static enum CXChildVisitResult fn_visitor(CXCursor cursor, CXCursor parent, CXClientData client_data) { | 384 | static enum CXChildVisitResult fn_visitor(CXCursor cursor, CXCursor parent, CXClientData client_data) { |
| 282 | ParseH *p = (ParseH*)client_data; | 385 | ParseH *p = (ParseH*)client_data; |
| ... | @@ -306,7 +409,9 @@ static enum CXChildVisitResult fn_visitor(CXCursor cursor, CXCursor parent, CXCl | ... | @@ -306,7 +409,9 @@ static enum CXChildVisitResult fn_visitor(CXCursor cursor, CXCursor parent, CXCl |
| 306 | p->cur_fn->is_variadic = clang_isFunctionTypeVariadic(fn_type); | 409 | p->cur_fn->is_variadic = clang_isFunctionTypeVariadic(fn_type); |
| 307 | | 410 | |
| 308 | CXType return_type = clang_getResultType(fn_type); | 411 | 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 | } |
| 310 | | 415 | |
| 311 | buf_init_from_str(&p->cur_fn->name, clang_getCString(name)); | 416 | buf_init_from_str(&p->cur_fn->name, clang_getCString(name)); |
| 312 | | 417 | |
| ... | @@ -330,7 +435,44 @@ static enum CXChildVisitResult fn_visitor(CXCursor cursor, CXCursor parent, CXCl | ... | @@ -330,7 +435,44 @@ static enum CXChildVisitResult fn_visitor(CXCursor cursor, CXCursor parent, CXCl |
| 330 | case CXCursor_CompoundStmt: | 435 | case CXCursor_CompoundStmt: |
| 331 | case CXCursor_FieldDecl: | 436 | case CXCursor_FieldDecl: |
| 332 | case CXCursor_TypedefDecl: | 437 | 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 | } |
| 334 | default: | 476 | default: |
| 335 | return CXChildVisit_Recurse; | 477 | return CXChildVisit_Recurse; |
| 336 | } | 478 | } |
| ... | @@ -401,6 +543,44 @@ void parse_h_file(const char *target_path, ZigList<const char *> *clang_argv, FI | ... | @@ -401,6 +543,44 @@ void parse_h_file(const char *target_path, ZigList<const char *> *clang_argv, FI |
| 401 | CXCursor cursor = clang_getTranslationUnitCursor(p->tu); | 543 | CXCursor cursor = clang_getTranslationUnitCursor(p->tu); |
| 402 | clang_visitChildren(cursor, fn_visitor, p); | 544 | clang_visitChildren(cursor, fn_visitor, p); |
| 403 | | 545 | |
| | 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 | |
| 404 | if (p->fn_list.length) { | 584 | if (p->fn_list.length) { |
| 405 | fprintf(f, "extern {\n"); | 585 | fprintf(f, "extern {\n"); |
| 406 | p->cur_indent += indent_size; | 586 | p->cur_indent += indent_size; |
| ... | @@ -419,11 +599,12 @@ void parse_h_file(const char *target_path, ZigList<const char *> *clang_argv, FI | ... | @@ -419,11 +599,12 @@ void parse_h_file(const char *target_path, ZigList<const char *> *clang_argv, FI |
| 419 | fprintf(p->f, "..."); | 599 | fprintf(p->f, "..."); |
| 420 | } | 600 | } |
| 421 | fprintf(p->f, ")"); | 601 | fprintf(p->f, ")"); |
| 422 | if (!buf_eql_str(fn->return_type, "void")) { | 602 | if (fn->return_type) { |
| 423 | fprintf(p->f, " -> %s", buf_ptr(fn->return_type)); | 603 | fprintf(p->f, " -> %s", buf_ptr(fn->return_type)); |
| 424 | } | 604 | } |
| 425 | fprintf(p->f, ";\n"); | 605 | fprintf(p->f, ";\n"); |
| 426 | } | 606 | } |
| | 607 | p->cur_indent -= indent_size; |
| 427 | fprintf(f, "}\n"); | 608 | fprintf(f, "}\n"); |
| 428 | } | 609 | } |
| 429 | } | 610 | } |