| ... | ... | @@ -371,13 +371,13 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { |
| 371 | 371 | return visitFnDecl(c, @ptrCast(*const ZigClangFunctionDecl, decl)); |
| 372 | 372 | }, |
| 373 | 373 | .Typedef => { |
| 374 | | return resolveTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl)); |
| 374 | _ = try transTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl)); |
| 375 | 375 | }, |
| 376 | 376 | .Enum => { |
| 377 | 377 | _ = try transEnumDecl(c, @ptrCast(*const ZigClangEnumDecl, decl)); |
| 378 | 378 | }, |
| 379 | 379 | .Record => { |
| 380 | | return resolveRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl)); |
| 380 | _ = try transRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl)); |
| 381 | 381 | }, |
| 382 | 382 | .Var => { |
| 383 | 383 | return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl)); |
| ... | ... | @@ -541,10 +541,9 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 541 | 541 | return addTopLevelDecl(c, checked_name, &node.base); |
| 542 | 542 | } |
| 543 | 543 | |
| 544 | | fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Error!void { |
| 545 | | if (c.decl_table.contains( |
| 546 | | @ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), |
| 547 | | )) return; // Avoid processing this decl twice |
| 544 | fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Error!?*ast.Node { |
| 545 | if (c.decl_table.get(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)))) |kv| |
| 546 | return try transCreateNodeIdentifier(c, kv.value); // Avoid processing this decl twice |
| 548 | 547 | const rp = makeRestorePoint(c); |
| 549 | 548 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); |
| 550 | 549 | const const_tok = try appendToken(c, .Keyword_const, "const"); |
| ... | ... | @@ -558,29 +557,40 @@ fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Err |
| 558 | 557 | const typedef_loc = ZigClangTypedefNameDecl_getLocation(typedef_decl); |
| 559 | 558 | node.init_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) { |
| 560 | 559 | error.UnsupportedType => { |
| 561 | | return failDecl(c, typedef_loc, typedef_name, "unable to resolve typedef child type", .{}); |
| 560 | try failDecl(c, typedef_loc, typedef_name, "unable to resolve typedef child type", .{}); |
| 561 | return null; |
| 562 | 562 | }, |
| 563 | 563 | error.OutOfMemory => |e| return e, |
| 564 | 564 | }; |
| 565 | 565 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); |
| 566 | 566 | try addTopLevelDecl(c, typedef_name, &node.base); |
| 567 | return transCreateNodeIdentifier(c, typedef_name); |
| 567 | 568 | } |
| 568 | 569 | |
| 569 | | fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!void { |
| 570 | | if (c.decl_table.contains(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) return; // Avoid processing this decl twice |
| 571 | | const rp = makeRestorePoint(c); |
| 572 | | |
| 573 | | const bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl))); |
| 570 | fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*ast.Node { |
| 571 | if (c.decl_table.get(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) |kv| |
| 572 | return try transCreateNodeIdentifier(c, kv.value); // Avoid processing this decl twice |
| 573 | const record_loc = ZigClangRecordDecl_getLocation(record_decl); |
| 574 | 574 | |
| 575 | | const container_kind_name = if (ZigClangRecordDecl_isUnion(record_decl)) |
| 576 | | "union" |
| 577 | | else if (ZigClangRecordDecl_isStruct(record_decl)) |
| 578 | | "struct" |
| 579 | | else |
| 580 | | return emitWarning(c, ZigClangRecordDecl_getLocation(record_decl), "record {} is not a struct or union", .{bare_name}); |
| 575 | var bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl))); |
| 576 | var is_unnamed = false; |
| 577 | if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0) { |
| 578 | bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()}); |
| 579 | is_unnamed = true; |
| 580 | } |
| 581 | 581 | |
| 582 | | if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0) |
| 583 | | return; |
| 582 | var container_kind_name: []const u8 = undefined; |
| 583 | var container_kind: std.zig.Token.Id = undefined; |
| 584 | if (ZigClangRecordDecl_isUnion(record_decl)) { |
| 585 | container_kind_name = "union"; |
| 586 | container_kind = .Keyword_union; |
| 587 | } else if (ZigClangRecordDecl_isStruct(record_decl)) { |
| 588 | container_kind_name = "struct"; |
| 589 | container_kind = .Keyword_struct; |
| 590 | } else { |
| 591 | try emitWarning(c, record_loc, "record {} is not a struct or union", .{bare_name}); |
| 592 | return null; |
| 593 | } |
| 584 | 594 | |
| 585 | 595 | const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name }); |
| 586 | 596 | _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name); |
| ... | ... | @@ -588,16 +598,211 @@ fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error! |
| 588 | 598 | const node = try transCreateNodeVarDecl(c, true, true, name); |
| 589 | 599 | |
| 590 | 600 | node.eq_token = try appendToken(c, .Equal, "="); |
| 591 | | node.init_node = transRecordDecl(c, record_decl) catch |err| switch (err) { |
| 592 | | error.UnsupportedType => { |
| 593 | | return failDecl(c, ZigClangRecordDecl_getLocation(record_decl), name, "unable to resolve record type", .{}); |
| 594 | | }, |
| 595 | | error.OutOfMemory => |e| return e, |
| 601 | |
| 602 | var semicolon: ast.TokenIndex = undefined; |
| 603 | node.init_node = blk: { |
| 604 | const rp = makeRestorePoint(c); |
| 605 | const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse { |
| 606 | const opaque = try transCreateNodeOpaqueType(c); |
| 607 | semicolon = try appendToken(c, .Semicolon, ";"); |
| 608 | break :blk opaque; |
| 609 | }; |
| 610 | |
| 611 | const extern_tok = try appendToken(c, .Keyword_extern, "extern"); |
| 612 | const container_tok = try appendToken(c, container_kind, container_kind_name); |
| 613 | const lbrace_token = try appendToken(c, .LBrace, "{"); |
| 614 | |
| 615 | const container_node = try c.a().create(ast.Node.ContainerDecl); |
| 616 | container_node.* = .{ |
| 617 | .layout_token = extern_tok, |
| 618 | .kind_token = container_tok, |
| 619 | .init_arg_expr = .None, |
| 620 | .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()), |
| 621 | .lbrace_token = lbrace_token, |
| 622 | .rbrace_token = undefined, |
| 623 | }; |
| 624 | |
| 625 | var it = ZigClangRecordDecl_field_begin(record_def); |
| 626 | const end_it = ZigClangRecordDecl_field_end(record_def); |
| 627 | while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) { |
| 628 | const field_decl = ZigClangRecordDecl_field_iterator_deref(it); |
| 629 | const field_loc = ZigClangFieldDecl_getLocation(field_decl); |
| 630 | |
| 631 | if (ZigClangFieldDecl_isBitField(field_decl)) { |
| 632 | const opaque = try transCreateNodeOpaqueType(c); |
| 633 | semicolon = try appendToken(c, .Semicolon, ";"); |
| 634 | try emitWarning(c, field_loc, "{} demoted to opaque type - has bitfield", .{container_kind_name}); |
| 635 | break :blk opaque; |
| 636 | } |
| 637 | |
| 638 | const field_name = try appendIdentifier(c, try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl)))); |
| 639 | _ = try appendToken(c, .Colon, ":"); |
| 640 | const field_type = transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc) catch |err| switch (err) { |
| 641 | error.UnsupportedType => { |
| 642 | try failDecl(c, record_loc, name, "unable to translate {} member type", .{container_kind_name}); |
| 643 | return null; |
| 644 | }, |
| 645 | else => |e| return e, |
| 646 | }; |
| 647 | |
| 648 | const field_node = try c.a().create(ast.Node.ContainerField); |
| 649 | field_node.* = .{ |
| 650 | .doc_comments = null, |
| 651 | .comptime_token = null, |
| 652 | .name_token = field_name, |
| 653 | .type_expr = field_type, |
| 654 | .value_expr = null, |
| 655 | .align_expr = null, |
| 656 | }; |
| 657 | |
| 658 | try container_node.fields_and_decls.push(&field_node.base); |
| 659 | _ = try appendToken(c, .Comma, ","); |
| 660 | } |
| 661 | container_node.rbrace_token = try appendToken(c, .RBrace, "}"); |
| 662 | semicolon = try appendToken(c, .Semicolon, ";"); |
| 663 | break :blk &container_node.base; |
| 596 | 664 | }; |
| 665 | node.semicolon_token = semicolon; |
| 666 | |
| 667 | try addTopLevelDecl(c, name, &node.base); |
| 668 | if (!is_unnamed) |
| 669 | try c.alias_list.push(.{ .alias = bare_name, .name = name }); |
| 670 | return transCreateNodeIdentifier(c, name); |
| 671 | } |
| 672 | |
| 673 | fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.Node { |
| 674 | if (c.decl_table.get(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)))) |name| |
| 675 | return try transCreateNodeIdentifier(c, name.value); // Avoid processing this decl twice |
| 676 | const rp = makeRestorePoint(c); |
| 677 | const enum_loc = ZigClangEnumDecl_getLocation(enum_decl); |
| 678 | |
| 679 | var bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_decl))); |
| 680 | var is_unnamed = false; |
| 681 | if (bare_name.len == 0) { |
| 682 | bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()}); |
| 683 | is_unnamed = true; |
| 684 | } |
| 685 | |
| 686 | const name = try std.fmt.allocPrint(c.a(), "enum_{}", .{bare_name}); |
| 687 | _ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name); |
| 688 | const node = try transCreateNodeVarDecl(c, true, true, name); |
| 689 | node.eq_token = try appendToken(c, .Equal, "="); |
| 690 | |
| 691 | node.init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: { |
| 692 | var pure_enum = true; |
| 693 | var it = ZigClangEnumDecl_enumerator_begin(enum_def); |
| 694 | var end_it = ZigClangEnumDecl_enumerator_end(enum_def); |
| 695 | while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) { |
| 696 | const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it); |
| 697 | if (ZigClangEnumConstantDecl_getInitExpr(enum_const)) |_| { |
| 698 | pure_enum = false; |
| 699 | break; |
| 700 | } |
| 701 | } |
| 702 | |
| 703 | const extern_tok = try appendToken(c, .Keyword_extern, "extern"); |
| 704 | const container_tok = try appendToken(c, .Keyword_enum, "enum"); |
| 705 | |
| 706 | const container_node = try c.a().create(ast.Node.ContainerDecl); |
| 707 | container_node.* = .{ |
| 708 | .layout_token = extern_tok, |
| 709 | .kind_token = container_tok, |
| 710 | .init_arg_expr = .None, |
| 711 | .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()), |
| 712 | .lbrace_token = undefined, |
| 713 | .rbrace_token = undefined, |
| 714 | }; |
| 715 | |
| 716 | const int_type = ZigClangEnumDecl_getIntegerType(enum_decl); |
| 717 | |
| 718 | // TODO only emit this tag type if the enum tag type is not the default. |
| 719 | // I don't know what the default is, need to figure out how clang is deciding. |
| 720 | // it appears to at least be different across gcc/msvc |
| 721 | if (!isCBuiltinType(int_type, .UInt) and |
| 722 | !isCBuiltinType(int_type, .Int)) |
| 723 | { |
| 724 | _ = try appendToken(c, .LParen, "("); |
| 725 | container_node.init_arg_expr = .{ |
| 726 | .Type = transQualType(rp, int_type, enum_loc) catch |err| switch (err) { |
| 727 | error.UnsupportedType => { |
| 728 | try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{}); |
| 729 | return null; |
| 730 | }, |
| 731 | else => |e| return e, |
| 732 | }, |
| 733 | }; |
| 734 | _ = try appendToken(c, .RParen, ")"); |
| 735 | } |
| 736 | |
| 737 | container_node.lbrace_token = try appendToken(c, .LBrace, "{"); |
| 738 | |
| 739 | it = ZigClangEnumDecl_enumerator_begin(enum_def); |
| 740 | end_it = ZigClangEnumDecl_enumerator_end(enum_def); |
| 741 | while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) { |
| 742 | const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it); |
| 743 | |
| 744 | const enum_val_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_const))); |
| 745 | |
| 746 | const field_name = if (!is_unnamed and std.mem.startsWith(u8, enum_val_name, bare_name)) |
| 747 | enum_val_name[bare_name.len..] |
| 748 | else |
| 749 | enum_val_name; |
| 750 | |
| 751 | const field_name_tok = try appendIdentifier(c, field_name); |
| 752 | |
| 753 | const int_node = if (!pure_enum) blk: { |
| 754 | _ = try appendToken(c, .Colon, "="); |
| 755 | break :blk try transCreateNodeAPInt(c, ZigClangEnumConstantDecl_getInitVal(enum_const)); |
| 756 | } else |
| 757 | null; |
| 758 | |
| 759 | const field_node = try c.a().create(ast.Node.ContainerField); |
| 760 | field_node.* = .{ |
| 761 | .doc_comments = null, |
| 762 | .comptime_token = null, |
| 763 | .name_token = field_name_tok, |
| 764 | .type_expr = null, |
| 765 | .value_expr = int_node, |
| 766 | .align_expr = null, |
| 767 | }; |
| 768 | |
| 769 | try container_node.fields_and_decls.push(&field_node.base); |
| 770 | _ = try appendToken(c, .Comma, ","); |
| 771 | // In C each enum value is in the global namespace. So we put them there too. |
| 772 | // At this point we can rely on the enum emitting successfully. |
| 773 | try addEnumTopLevel(c, name, field_name, enum_val_name); |
| 774 | } |
| 775 | container_node.rbrace_token = try appendToken(c, .RBrace, "}"); |
| 776 | |
| 777 | break :blk &container_node.base; |
| 778 | } else |
| 779 | try transCreateNodeOpaqueType(c); |
| 780 | |
| 597 | 781 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); |
| 598 | 782 | |
| 599 | 783 | try addTopLevelDecl(c, name, &node.base); |
| 600 | | try c.alias_list.push(.{ .alias = bare_name, .name = name }); |
| 784 | if (!is_unnamed) |
| 785 | try c.alias_list.push(.{ .alias = bare_name, .name = name }); |
| 786 | return transCreateNodeIdentifier(c, name); |
| 787 | } |
| 788 | |
| 789 | fn addEnumTopLevel(c: *Context, enum_name: []const u8, field_name: []const u8, enum_val_name: []const u8) !void { |
| 790 | const node = try transCreateNodeVarDecl(c, true, true, enum_val_name); |
| 791 | node.eq_token = try appendToken(c, .Equal, "="); |
| 792 | const enum_ident = try transCreateNodeIdentifier(c, enum_name); |
| 793 | const period_tok = try appendToken(c, .Period, "."); |
| 794 | const field_ident = try transCreateNodeIdentifier(c, field_name); |
| 795 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); |
| 796 | |
| 797 | const field_access_node = try c.a().create(ast.Node.InfixOp); |
| 798 | field_access_node.* = .{ |
| 799 | .op_token = period_tok, |
| 800 | .lhs = enum_ident, |
| 801 | .op = .Period, |
| 802 | .rhs = field_ident, |
| 803 | }; |
| 804 | node.init_node = &field_access_node.base; |
| 805 | try addTopLevelDecl(c, field_name, &node.base); |
| 601 | 806 | } |
| 602 | 807 | |
| 603 | 808 | fn createAlias(c: *Context, alias: var) !void { |
| ... | ... | @@ -1452,7 +1657,6 @@ fn transSwitch( |
| 1452 | 1657 | switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}"); |
| 1453 | 1658 | return &switch_scope.pending_block.base; |
| 1454 | 1659 | } |
| 1455 | | |
| 1456 | 1660 | |
| 1457 | 1661 | fn transCase( |
| 1458 | 1662 | rp: RestorePoint, |
| ... | ... | @@ -1675,222 +1879,6 @@ fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSou |
| 1675 | 1879 | return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc); |
| 1676 | 1880 | } |
| 1677 | 1881 | |
| 1678 | | fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) TypeError!*ast.Node { |
| 1679 | | const rp = makeRestorePoint(c); |
| 1680 | | |
| 1681 | | const record_loc = ZigClangRecordDecl_getLocation(record_decl); |
| 1682 | | |
| 1683 | | var container_kind_name: []const u8 = undefined; |
| 1684 | | var container_kind: std.zig.Token.Id = undefined; |
| 1685 | | |
| 1686 | | if (ZigClangRecordDecl_isUnion(record_decl)) { |
| 1687 | | container_kind_name = "union"; |
| 1688 | | container_kind = .Keyword_union; |
| 1689 | | } else if (ZigClangRecordDecl_isStruct(record_decl)) { |
| 1690 | | container_kind_name = "struct"; |
| 1691 | | container_kind = .Keyword_struct; |
| 1692 | | } else { |
| 1693 | | return revertAndWarn( |
| 1694 | | rp, |
| 1695 | | error.UnsupportedType, |
| 1696 | | record_loc, |
| 1697 | | "unsupported record type", |
| 1698 | | .{}, |
| 1699 | | ); |
| 1700 | | } |
| 1701 | | |
| 1702 | | const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse { |
| 1703 | | return transCreateNodeOpaqueType(c); |
| 1704 | | }; |
| 1705 | | |
| 1706 | | const extern_tok = try appendToken(c, .Keyword_extern, "extern"); |
| 1707 | | const container_tok = try appendToken(c, container_kind, container_kind_name); |
| 1708 | | const lbrace_token = try appendToken(c, .LBrace, "{"); |
| 1709 | | |
| 1710 | | const container_node = try c.a().create(ast.Node.ContainerDecl); |
| 1711 | | container_node.* = .{ |
| 1712 | | .layout_token = extern_tok, |
| 1713 | | .kind_token = container_tok, |
| 1714 | | .init_arg_expr = .None, |
| 1715 | | .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()), |
| 1716 | | .lbrace_token = lbrace_token, |
| 1717 | | .rbrace_token = undefined, |
| 1718 | | }; |
| 1719 | | |
| 1720 | | var it = ZigClangRecordDecl_field_begin(record_def); |
| 1721 | | const end_it = ZigClangRecordDecl_field_end(record_def); |
| 1722 | | while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) { |
| 1723 | | const field_decl = ZigClangRecordDecl_field_iterator_deref(it); |
| 1724 | | const field_loc = ZigClangFieldDecl_getLocation(field_decl); |
| 1725 | | |
| 1726 | | if (ZigClangFieldDecl_isBitField(field_decl)) { |
| 1727 | | rp.activate(); |
| 1728 | | const node = try transCreateNodeOpaqueType(c); |
| 1729 | | try emitWarning(c, field_loc, "{} demoted to opaque type - has bitfield", .{container_kind_name}); |
| 1730 | | return node; |
| 1731 | | } |
| 1732 | | |
| 1733 | | const field_name = try appendIdentifier(c, try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl)))); |
| 1734 | | _ = try appendToken(c, .Colon, ":"); |
| 1735 | | const field_type = try transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc); |
| 1736 | | |
| 1737 | | const field_node = try c.a().create(ast.Node.ContainerField); |
| 1738 | | field_node.* = .{ |
| 1739 | | .doc_comments = null, |
| 1740 | | .comptime_token = null, |
| 1741 | | .name_token = field_name, |
| 1742 | | .type_expr = field_type, |
| 1743 | | .value_expr = null, |
| 1744 | | .align_expr = null, |
| 1745 | | }; |
| 1746 | | |
| 1747 | | try container_node.fields_and_decls.push(&field_node.base); |
| 1748 | | _ = try appendToken(c, .Comma, ","); |
| 1749 | | } |
| 1750 | | |
| 1751 | | container_node.rbrace_token = try appendToken(c, .RBrace, "}"); |
| 1752 | | return &container_node.base; |
| 1753 | | } |
| 1754 | | |
| 1755 | | fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.Node { |
| 1756 | | if (c.decl_table.get(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)))) |name| |
| 1757 | | return try transCreateNodeIdentifier(c, name.value); // Avoid processing this decl twice |
| 1758 | | const rp = makeRestorePoint(c); |
| 1759 | | const enum_loc = ZigClangEnumDecl_getLocation(enum_decl); |
| 1760 | | |
| 1761 | | var bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_decl))); |
| 1762 | | var is_unnamed = false; |
| 1763 | | if (bare_name.len == 0) { |
| 1764 | | bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()}); |
| 1765 | | is_unnamed = true; |
| 1766 | | } |
| 1767 | | |
| 1768 | | const name = try std.fmt.allocPrint(c.a(), "enum_{}", .{bare_name}); |
| 1769 | | _ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name); |
| 1770 | | const node = try transCreateNodeVarDecl(c, true, true, name); |
| 1771 | | node.eq_token = try appendToken(c, .Equal, "="); |
| 1772 | | |
| 1773 | | node.init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: { |
| 1774 | | var pure_enum = true; |
| 1775 | | var it = ZigClangEnumDecl_enumerator_begin(enum_def); |
| 1776 | | var end_it = ZigClangEnumDecl_enumerator_end(enum_def); |
| 1777 | | while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) { |
| 1778 | | const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it); |
| 1779 | | if (ZigClangEnumConstantDecl_getInitExpr(enum_const)) |_| { |
| 1780 | | pure_enum = false; |
| 1781 | | break; |
| 1782 | | } |
| 1783 | | } |
| 1784 | | |
| 1785 | | const extern_tok = try appendToken(c, .Keyword_extern, "extern"); |
| 1786 | | const container_tok = try appendToken(c, .Keyword_enum, "enum"); |
| 1787 | | |
| 1788 | | const container_node = try c.a().create(ast.Node.ContainerDecl); |
| 1789 | | container_node.* = .{ |
| 1790 | | .layout_token = extern_tok, |
| 1791 | | .kind_token = container_tok, |
| 1792 | | .init_arg_expr = .None, |
| 1793 | | .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()), |
| 1794 | | .lbrace_token = undefined, |
| 1795 | | .rbrace_token = undefined, |
| 1796 | | }; |
| 1797 | | |
| 1798 | | const int_type = ZigClangEnumDecl_getIntegerType(enum_decl); |
| 1799 | | |
| 1800 | | // TODO only emit this tag type if the enum tag type is not the default. |
| 1801 | | // I don't know what the default is, need to figure out how clang is deciding. |
| 1802 | | // it appears to at least be different across gcc/msvc |
| 1803 | | if (!isCBuiltinType(int_type, .UInt) and |
| 1804 | | !isCBuiltinType(int_type, .Int)) |
| 1805 | | { |
| 1806 | | _ = try appendToken(c, .LParen, "("); |
| 1807 | | container_node.init_arg_expr = .{ |
| 1808 | | .Type = transQualType(rp, int_type, enum_loc) catch |err| switch (err) { |
| 1809 | | error.UnsupportedType => { |
| 1810 | | if (is_unnamed) { |
| 1811 | | try emitWarning(c, enum_loc, "unable to translate enum tag type", .{}); |
| 1812 | | } else { |
| 1813 | | try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{}); |
| 1814 | | } |
| 1815 | | return null; |
| 1816 | | }, |
| 1817 | | else => |e| return e, |
| 1818 | | }, |
| 1819 | | }; |
| 1820 | | _ = try appendToken(c, .RParen, ")"); |
| 1821 | | } |
| 1822 | | |
| 1823 | | container_node.lbrace_token = try appendToken(c, .LBrace, "{"); |
| 1824 | | |
| 1825 | | it = ZigClangEnumDecl_enumerator_begin(enum_def); |
| 1826 | | end_it = ZigClangEnumDecl_enumerator_end(enum_def); |
| 1827 | | while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) { |
| 1828 | | const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it); |
| 1829 | | |
| 1830 | | const enum_val_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_const))); |
| 1831 | | |
| 1832 | | const field_name = if (!is_unnamed and std.mem.startsWith(u8, enum_val_name, bare_name)) |
| 1833 | | enum_val_name[bare_name.len..] |
| 1834 | | else |
| 1835 | | enum_val_name; |
| 1836 | | |
| 1837 | | const field_name_tok = try appendIdentifier(c, field_name); |
| 1838 | | |
| 1839 | | const int_node = if (!pure_enum) blk: { |
| 1840 | | _ = try appendToken(c, .Colon, "="); |
| 1841 | | break :blk try transCreateNodeAPInt(c, ZigClangEnumConstantDecl_getInitVal(enum_const)); |
| 1842 | | } else |
| 1843 | | null; |
| 1844 | | |
| 1845 | | const field_node = try c.a().create(ast.Node.ContainerField); |
| 1846 | | field_node.* = .{ |
| 1847 | | .doc_comments = null, |
| 1848 | | .comptime_token = null, |
| 1849 | | .name_token = field_name_tok, |
| 1850 | | .type_expr = null, |
| 1851 | | .value_expr = int_node, |
| 1852 | | .align_expr = null, |
| 1853 | | }; |
| 1854 | | |
| 1855 | | try container_node.fields_and_decls.push(&field_node.base); |
| 1856 | | _ = try appendToken(c, .Comma, ","); |
| 1857 | | // In C each enum value is in the global namespace. So we put them there too. |
| 1858 | | // At this point we can rely on the enum emitting successfully. |
| 1859 | | try addEnumTopLevel(c, name, field_name, enum_val_name); |
| 1860 | | } |
| 1861 | | container_node.rbrace_token = try appendToken(c, .RBrace, "}"); |
| 1862 | | |
| 1863 | | break :blk &container_node.base; |
| 1864 | | } else |
| 1865 | | try transCreateNodeOpaqueType(c); |
| 1866 | | |
| 1867 | | node.semicolon_token = try appendToken(c, .Semicolon, ";"); |
| 1868 | | |
| 1869 | | try addTopLevelDecl(c, name, &node.base); |
| 1870 | | if (!is_unnamed) |
| 1871 | | try c.alias_list.push(.{ .alias = bare_name, .name = name }); |
| 1872 | | return transCreateNodeIdentifier(c, name); |
| 1873 | | } |
| 1874 | | |
| 1875 | | fn addEnumTopLevel(c: *Context, enum_name: []const u8, field_name: []const u8, enum_val_name: []const u8) !void { |
| 1876 | | const node = try transCreateNodeVarDecl(c, true, true, enum_val_name); |
| 1877 | | node.eq_token = try appendToken(c, .Equal, "="); |
| 1878 | | const enum_ident = try transCreateNodeIdentifier(c, enum_name); |
| 1879 | | const period_tok = try appendToken(c, .Period, "."); |
| 1880 | | const field_ident = try transCreateNodeIdentifier(c, field_name); |
| 1881 | | node.semicolon_token = try appendToken(c, .Semicolon, ";"); |
| 1882 | | |
| 1883 | | const field_access_node = try c.a().create(ast.Node.InfixOp); |
| 1884 | | field_access_node.* = .{ |
| 1885 | | .op_token = period_tok, |
| 1886 | | .lhs = enum_ident, |
| 1887 | | .op = .Period, |
| 1888 | | .rhs = field_ident, |
| 1889 | | }; |
| 1890 | | node.init_node = &field_access_node.base; |
| 1891 | | try addTopLevelDecl(c, field_name, &node.base); |
| 1892 | | } |
| 1893 | | |
| 1894 | 1882 | fn isCBuiltinType(qt: ZigClangQualType, kind: ZigClangBuiltinTypeKind) bool { |
| 1895 | 1883 | const c_type = qualTypeCanon(qt); |
| 1896 | 1884 | if (ZigClangType_getTypeClass(c_type) != .Builtin) |
| ... | ... | @@ -2591,7 +2579,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour |
| 2591 | 2579 | else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}), |
| 2592 | 2580 | }); |
| 2593 | 2581 | }, |
| 2594 | | .FunctionProto => { |
| 2582 | .FunctionProto, .FunctionNoProto => { |
| 2595 | 2583 | const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty); |
| 2596 | 2584 | const fn_proto = try transFnProto(rp, null, fn_proto_ty, source_loc, null, false); |
| 2597 | 2585 | return &fn_proto.base; |
| ... | ... | @@ -2666,24 +2654,15 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour |
| 2666 | 2654 | const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty); |
| 2667 | 2655 | |
| 2668 | 2656 | const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); |
| 2669 | | const typedef_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl))); |
| 2670 | | return transCreateNodeIdentifier(rp.c, typedef_name); |
| 2657 | return (try transTypeDef(rp.c, typedef_decl)) orelse |
| 2658 | revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to translate typedef declaration", .{}); |
| 2671 | 2659 | }, |
| 2672 | 2660 | .Record => { |
| 2673 | 2661 | const record_ty = @ptrCast(*const ZigClangRecordType, ty); |
| 2674 | 2662 | |
| 2675 | | // TODO this sould get the name from decl_table |
| 2676 | | // struct Foo { |
| 2677 | | // struct Bar{ |
| 2678 | | // int b; |
| 2679 | | // }; |
| 2680 | | // struct Bar c; |
| 2681 | | // }; |
| 2682 | 2663 | const record_decl = ZigClangRecordType_getDecl(record_ty); |
| 2683 | | if (try getContainerName(rp, record_decl)) |name| |
| 2684 | | return transCreateNodeIdentifier(rp.c, name) |
| 2685 | | else |
| 2686 | | return transRecordDecl(rp.c, record_decl); |
| 2664 | return (try transRecordDecl(rp.c, record_decl)) orelse |
| 2665 | revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to resolve record declaration", .{}); |
| 2687 | 2666 | }, |
| 2688 | 2667 | .Enum => { |
| 2689 | 2668 | const enum_ty = @ptrCast(*const ZigClangEnumType, ty); |
| ... | ... | @@ -2704,6 +2683,10 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour |
| 2704 | 2683 | const attributed_ty = @ptrCast(*const ZigClangAttributedType, ty); |
| 2705 | 2684 | return transQualType(rp, ZigClangAttributedType_getEquivalentType(attributed_ty), source_loc); |
| 2706 | 2685 | }, |
| 2686 | .MacroQualified => { |
| 2687 | const macroqualified_ty = @ptrCast(*const ZigClangMacroQualifiedType, ty); |
| 2688 | return transQualType(rp, ZigClangMacroQualifiedType_getModifiedType(macroqualified_ty), source_loc); |
| 2689 | }, |
| 2707 | 2690 | else => { |
| 2708 | 2691 | const type_name = rp.c.str(ZigClangType_getTypeClassName(ty)); |
| 2709 | 2692 | return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{}'", .{type_name}); |
| ... | ... | @@ -2711,22 +2694,6 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour |
| 2711 | 2694 | } |
| 2712 | 2695 | } |
| 2713 | 2696 | |
| 2714 | | fn getContainerName(rp: RestorePoint, record_decl: *const ZigClangRecordDecl) !?[]const u8 { |
| 2715 | | const bare_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl))); |
| 2716 | | |
| 2717 | | const container_kind_name = if (ZigClangRecordDecl_isUnion(record_decl)) |
| 2718 | | "union" |
| 2719 | | else if (ZigClangRecordDecl_isStruct(record_decl)) |
| 2720 | | "struct" |
| 2721 | | else |
| 2722 | | return revertAndWarn(rp, error.UnsupportedType, ZigClangRecordDecl_getLocation(record_decl), "record {} is not a struct or union", .{bare_name}); |
| 2723 | | |
| 2724 | | if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0) |
| 2725 | | return null; |
| 2726 | | |
| 2727 | | return try std.fmt.allocPrint(rp.c.a(), "{}_{}", .{ container_kind_name, bare_name }); |
| 2728 | | } |
| 2729 | | |
| 2730 | 2697 | fn isCVoid(qt: ZigClangQualType) bool { |
| 2731 | 2698 | const ty = ZigClangQualType_getTypePtr(qt); |
| 2732 | 2699 | if (ZigClangType_getTypeClass(ty) == .Builtin) { |
| ... | ... | @@ -2909,14 +2876,13 @@ fn finishTransFnProto( |
| 2909 | 2876 | }; |
| 2910 | 2877 | |
| 2911 | 2878 | const fn_proto = try rp.c.a().create(ast.Node.FnProto); |
| 2912 | | fn_proto.* = ast.Node.FnProto{ |
| 2913 | | .base = ast.Node{ .id = ast.Node.Id.FnProto }, |
| 2879 | fn_proto.* = .{ |
| 2914 | 2880 | .doc_comments = null, |
| 2915 | 2881 | .visib_token = pub_tok, |
| 2916 | 2882 | .fn_token = fn_tok, |
| 2917 | 2883 | .name_token = name_tok, |
| 2918 | 2884 | .params = fn_params, |
| 2919 | | .return_type = ast.Node.FnProto.ReturnType{ .Explicit = return_type_node }, |
| 2885 | .return_type = .{ .Explicit = return_type_node }, |
| 2920 | 2886 | .var_args_token = null, // TODO this field is broken in the AST data model |
| 2921 | 2887 | .extern_export_inline_token = extern_export_inline_tok, |
| 2922 | 2888 | .cc_token = cc_tok, |