| ... | @@ -371,13 +371,13 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { | ... | @@ -371,13 +371,13 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { |
| 371 | return visitFnDecl(c, @ptrCast(*const ZigClangFunctionDecl, decl)); | 371 | return visitFnDecl(c, @ptrCast(*const ZigClangFunctionDecl, decl)); |
| 372 | }, | 372 | }, |
| 373 | .Typedef => { | 373 | .Typedef => { |
| 374 | return resolveTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl)); | 374 | _ = try transTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl)); |
| 375 | }, | 375 | }, |
| 376 | .Enum => { | 376 | .Enum => { |
| 377 | _ = try transEnumDecl(c, @ptrCast(*const ZigClangEnumDecl, decl)); | 377 | _ = try transEnumDecl(c, @ptrCast(*const ZigClangEnumDecl, decl)); |
| 378 | }, | 378 | }, |
| 379 | .Record => { | 379 | .Record => { |
| 380 | return resolveRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl)); | 380 | _ = try transRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl)); |
| 381 | }, | 381 | }, |
| 382 | .Var => { | 382 | .Var => { |
| 383 | return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl)); | 383 | return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl)); |
| ... | @@ -541,10 +541,9 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { | ... | @@ -541,10 +541,9 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 541 | return addTopLevelDecl(c, checked_name, &node.base); | 541 | return addTopLevelDecl(c, checked_name, &node.base); |
| 542 | } | 542 | } |
| 543 | | 543 | |
| 544 | fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Error!void { | 544 | fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Error!?*ast.Node { |
| 545 | if (c.decl_table.contains( | 545 | if (c.decl_table.get(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)))) |kv| |
| 546 | @ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), | 546 | return try transCreateNodeIdentifier(c, kv.value); // Avoid processing this decl twice |
| 547 | )) return; // Avoid processing this decl twice | | |
| 548 | const rp = makeRestorePoint(c); | 547 | const rp = makeRestorePoint(c); |
| 549 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); | 548 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); |
| 550 | const const_tok = try appendToken(c, .Keyword_const, "const"); | 549 | const const_tok = try appendToken(c, .Keyword_const, "const"); |
| ... | @@ -558,29 +557,40 @@ fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Err | ... | @@ -558,29 +557,40 @@ fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Err |
| 558 | const typedef_loc = ZigClangTypedefNameDecl_getLocation(typedef_decl); | 557 | const typedef_loc = ZigClangTypedefNameDecl_getLocation(typedef_decl); |
| 559 | node.init_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) { | 558 | node.init_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) { |
| 560 | error.UnsupportedType => { | 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 | error.OutOfMemory => |e| return e, | 563 | error.OutOfMemory => |e| return e, |
| 564 | }; | 564 | }; |
| 565 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); | 565 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); |
| 566 | try addTopLevelDecl(c, typedef_name, &node.base); | 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 | fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*ast.Node { |
| 570 | if (c.decl_table.contains(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) return; // Avoid processing this decl twice | 571 | if (c.decl_table.get(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) |kv| |
| 571 | const rp = makeRestorePoint(c); | 572 | return try transCreateNodeIdentifier(c, kv.value); // Avoid processing this decl twice |
| 572 | | 573 | const record_loc = ZigClangRecordDecl_getLocation(record_decl); |
| 573 | const bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl))); | | |
| 574 | | 574 | |
| 575 | const container_kind_name = if (ZigClangRecordDecl_isUnion(record_decl)) | 575 | var bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl))); |
| 576 | "union" | 576 | var is_unnamed = false; |
| 577 | else if (ZigClangRecordDecl_isStruct(record_decl)) | 577 | if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0) { |
| 578 | "struct" | 578 | bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()}); |
| 579 | else | 579 | is_unnamed = true; |
| 580 | return emitWarning(c, ZigClangRecordDecl_getLocation(record_decl), "record {} is not a struct or union", .{bare_name}); | 580 | } |
| 581 | | 581 | |
| 582 | if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0) | 582 | var container_kind_name: []const u8 = undefined; |
| 583 | return; | 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 | const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name }); | 595 | const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name }); |
| 586 | _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name); | 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,16 +598,211 @@ fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error! |
| 588 | const node = try transCreateNodeVarDecl(c, true, true, name); | 598 | const node = try transCreateNodeVarDecl(c, true, true, name); |
| 589 | | 599 | |
| 590 | node.eq_token = try appendToken(c, .Equal, "="); | 600 | node.eq_token = try appendToken(c, .Equal, "="); |
| 591 | node.init_node = transRecordDecl(c, record_decl) catch |err| switch (err) { | 601 | |
| 592 | error.UnsupportedType => { | 602 | var semicolon: ast.TokenIndex = undefined; |
| 593 | return failDecl(c, ZigClangRecordDecl_getLocation(record_decl), name, "unable to resolve record type", .{}); | 603 | node.init_node = blk: { |
| 594 | }, | 604 | const rp = makeRestorePoint(c); |
| 595 | error.OutOfMemory => |e| return e, | 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 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); | 781 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); |
| 598 | | 782 | |
| 599 | try addTopLevelDecl(c, name, &node.base); | 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 | fn createAlias(c: *Context, alias: var) !void { | 808 | fn createAlias(c: *Context, alias: var) !void { |
| ... | @@ -1452,7 +1657,6 @@ fn transSwitch( | ... | @@ -1452,7 +1657,6 @@ fn transSwitch( |
| 1452 | switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}"); | 1657 | switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}"); |
| 1453 | return &switch_scope.pending_block.base; | 1658 | return &switch_scope.pending_block.base; |
| 1454 | } | 1659 | } |
| 1455 | | | |
| 1456 | | 1660 | |
| 1457 | fn transCase( | 1661 | fn transCase( |
| 1458 | rp: RestorePoint, | 1662 | rp: RestorePoint, |
| ... | @@ -1675,222 +1879,6 @@ fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSou | ... | @@ -1675,222 +1879,6 @@ fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSou |
| 1675 | return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc); | 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 | fn isCBuiltinType(qt: ZigClangQualType, kind: ZigClangBuiltinTypeKind) bool { | 1882 | fn isCBuiltinType(qt: ZigClangQualType, kind: ZigClangBuiltinTypeKind) bool { |
| 1895 | const c_type = qualTypeCanon(qt); | 1883 | const c_type = qualTypeCanon(qt); |
| 1896 | if (ZigClangType_getTypeClass(c_type) != .Builtin) | 1884 | if (ZigClangType_getTypeClass(c_type) != .Builtin) |
| ... | @@ -2591,7 +2579,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour | ... | @@ -2591,7 +2579,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour |
| 2591 | else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}), | 2579 | else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}), |
| 2592 | }); | 2580 | }); |
| 2593 | }, | 2581 | }, |
| 2594 | .FunctionProto => { | 2582 | .FunctionProto, .FunctionNoProto => { |
| 2595 | const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty); | 2583 | const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty); |
| 2596 | const fn_proto = try transFnProto(rp, null, fn_proto_ty, source_loc, null, false); | 2584 | const fn_proto = try transFnProto(rp, null, fn_proto_ty, source_loc, null, false); |
| 2597 | return &fn_proto.base; | 2585 | return &fn_proto.base; |
| ... | @@ -2666,24 +2654,15 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour | ... | @@ -2666,24 +2654,15 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour |
| 2666 | const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty); | 2654 | const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty); |
| 2667 | | 2655 | |
| 2668 | const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); | 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))); | 2657 | return (try transTypeDef(rp.c, typedef_decl)) orelse |
| 2670 | return transCreateNodeIdentifier(rp.c, typedef_name); | 2658 | revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to translate typedef declaration", .{}); |
| 2671 | }, | 2659 | }, |
| 2672 | .Record => { | 2660 | .Record => { |
| 2673 | const record_ty = @ptrCast(*const ZigClangRecordType, ty); | 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 | const record_decl = ZigClangRecordType_getDecl(record_ty); | 2663 | const record_decl = ZigClangRecordType_getDecl(record_ty); |
| 2683 | if (try getContainerName(rp, record_decl)) |name| | 2664 | return (try transRecordDecl(rp.c, record_decl)) orelse |
| 2684 | return transCreateNodeIdentifier(rp.c, name) | 2665 | revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to resolve record declaration", .{}); |
| 2685 | else | | |
| 2686 | return transRecordDecl(rp.c, record_decl); | | |
| 2687 | }, | 2666 | }, |
| 2688 | .Enum => { | 2667 | .Enum => { |
| 2689 | const enum_ty = @ptrCast(*const ZigClangEnumType, ty); | 2668 | const enum_ty = @ptrCast(*const ZigClangEnumType, ty); |
| ... | @@ -2704,6 +2683,10 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour | ... | @@ -2704,6 +2683,10 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour |
| 2704 | const attributed_ty = @ptrCast(*const ZigClangAttributedType, ty); | 2683 | const attributed_ty = @ptrCast(*const ZigClangAttributedType, ty); |
| 2705 | return transQualType(rp, ZigClangAttributedType_getEquivalentType(attributed_ty), source_loc); | 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 | else => { | 2690 | else => { |
| 2708 | const type_name = rp.c.str(ZigClangType_getTypeClassName(ty)); | 2691 | const type_name = rp.c.str(ZigClangType_getTypeClassName(ty)); |
| 2709 | return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{}'", .{type_name}); | 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,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 | fn isCVoid(qt: ZigClangQualType) bool { | 2697 | fn isCVoid(qt: ZigClangQualType) bool { |
| 2731 | const ty = ZigClangQualType_getTypePtr(qt); | 2698 | const ty = ZigClangQualType_getTypePtr(qt); |
| 2732 | if (ZigClangType_getTypeClass(ty) == .Builtin) { | 2699 | if (ZigClangType_getTypeClass(ty) == .Builtin) { |
| ... | @@ -2909,14 +2876,13 @@ fn finishTransFnProto( | ... | @@ -2909,14 +2876,13 @@ fn finishTransFnProto( |
| 2909 | }; | 2876 | }; |
| 2910 | | 2877 | |
| 2911 | const fn_proto = try rp.c.a().create(ast.Node.FnProto); | 2878 | const fn_proto = try rp.c.a().create(ast.Node.FnProto); |
| 2912 | fn_proto.* = ast.Node.FnProto{ | 2879 | fn_proto.* = .{ |
| 2913 | .base = ast.Node{ .id = ast.Node.Id.FnProto }, | | |
| 2914 | .doc_comments = null, | 2880 | .doc_comments = null, |
| 2915 | .visib_token = pub_tok, | 2881 | .visib_token = pub_tok, |
| 2916 | .fn_token = fn_tok, | 2882 | .fn_token = fn_tok, |
| 2917 | .name_token = name_tok, | 2883 | .name_token = name_tok, |
| 2918 | .params = fn_params, | 2884 | .params = fn_params, |
| 2919 | .return_type = ast.Node.FnProto.ReturnType{ .Explicit = return_type_node }, | 2885 | .return_type = .{ .Explicit = return_type_node }, |
| 2920 | .var_args_token = null, // TODO this field is broken in the AST data model | 2886 | .var_args_token = null, // TODO this field is broken in the AST data model |
| 2921 | .extern_export_inline_token = extern_export_inline_tok, | 2887 | .extern_export_inline_token = extern_export_inline_tok, |
| 2922 | .cc_token = cc_tok, | 2888 | .cc_token = cc_tok, |