authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-22 19:54:30-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-06-22 19:54:30-04:00
log44bd0a267096b54ac4dd40af31138bab1919e4d7
tree1f21c21caf7648df1c23e27c53bf0fc54e36f7e8
parent65ef74e2cdc87888d16ad207371cfd3ff8c0dce1
parent8c15cfe3dabe736754b138f16de905e6487bd8b5
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #5662 from shtanton/meta-cast

Adds std.meta.cast and uses it to simplify translate-c

3 files changed, 103 insertions(+), 159 deletions(-)

lib/std/meta.zig+82
......@@ -693,3 +693,85 @@ pub fn Vector(comptime len: u32, comptime child: type) type {
693693 },
694694 });
695695}
696
697/// Given a type and value, cast the value to the type as c would.
698/// This is for translate-c and is not intended for general use.
699pub fn cast(comptime DestType: type, target: var) DestType {
700 const TargetType = @TypeOf(target);
701 switch (@typeInfo(DestType)) {
702 .Pointer => {
703 switch (@typeInfo(TargetType)) {
704 .Int, .ComptimeInt => {
705 return @intToPtr(DestType, target);
706 },
707 .Pointer => |ptr| {
708 return @ptrCast(DestType, @alignCast(ptr.alignment, target));
709 },
710 .Optional => |opt| {
711 if (@typeInfo(opt.child) == .Pointer) {
712 return @ptrCast(DestType, @alignCast(@alignOf(opt.child.Child), target));
713 }
714 },
715 else => {},
716 }
717 },
718 .Optional => |opt| {
719 if (@typeInfo(opt.child) == .Pointer) {
720 switch (@typeInfo(TargetType)) {
721 .Int, .ComptimeInt => {
722 return @intToPtr(DestType, target);
723 },
724 .Pointer => |ptr| {
725 return @ptrCast(DestType, @alignCast(ptr.alignment, target));
726 },
727 .Optional => |target_opt| {
728 if (@typeInfo(target_opt.child) == .Pointer) {
729 return @ptrCast(DestType, @alignCast(@alignOf(target_opt.child.Child), target));
730 }
731 },
732 else => {},
733 }
734 }
735 },
736 .Enum, .EnumLiteral => {
737 if (@typeInfo(TargetType) == .Int or @typeInfo(TargetType) == .ComptimeInt) {
738 return @intToEnum(DestType, target);
739 }
740 },
741 .Int, .ComptimeInt => {
742 switch (@typeInfo(TargetType)) {
743 .Pointer => {
744 return @as(DestType, @ptrToInt(target));
745 },
746 .Optional => |opt| {
747 if (@typeInfo(opt.child) == .Pointer) {
748 return @as(DestType, @ptrToInt(target));
749 }
750 },
751 .Enum, .EnumLiteral => {
752 return @as(DestType, @enumToInt(target));
753 },
754 else => {},
755 }
756 },
757 else => {},
758 }
759 return @as(DestType, target);
760}
761
762test "std.meta.cast" {
763 const E = enum(u2) {
764 Zero,
765 One,
766 Two,
767 };
768
769 var i = @as(i64, 10);
770
771 testing.expect(cast(?*c_void, 0) == @intToPtr(?*c_void, 0));
772 testing.expect(cast(*u8, 16) == @intToPtr(*u8, 16));
773 testing.expect(cast(u64, @as(u32, 10)) == @as(u64, 10));
774 testing.expect(cast(E, 1) == .One);
775 testing.expect(cast(u8, E.Two) == 2);
776 testing.expect(cast(*u64, &i).* == @as(u64, 10));
777}
src-self-hosted/translate_c.zig+13-151
......@@ -5668,161 +5668,23 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
56685668
56695669 const lparen = try appendToken(c, .LParen, "(");
56705670
5671 if (saw_integer_literal) {
5672 //( if (@typeInfo(dest) == .Pointer))
5673 // @intToPtr(dest, x)
5674 //else
5675 // @as(dest, x) )
5676 const if_node = try transCreateNodeIf(c);
5677 const type_info_node = try c.createBuiltinCall("@typeInfo", 1);
5678 type_info_node.params()[0] = inner_node;
5679 type_info_node.rparen_token = try appendToken(c, .LParen, ")");
5680 const cmp_node = try c.arena.create(ast.Node.InfixOp);
5681 cmp_node.* = .{
5682 .op_token = try appendToken(c, .EqualEqual, "=="),
5683 .lhs = &type_info_node.base,
5684 .op = .EqualEqual,
5685 .rhs = try transCreateNodeEnumLiteral(c, "Pointer"),
5686 };
5687 if_node.condition = &cmp_node.base;
5688 _ = try appendToken(c, .RParen, ")");
5689
5690 const int_to_ptr = try c.createBuiltinCall("@intToPtr", 2);
5691 int_to_ptr.params()[0] = inner_node;
5692 int_to_ptr.params()[1] = node_to_cast;
5693 int_to_ptr.rparen_token = try appendToken(c, .RParen, ")");
5694 if_node.body = &int_to_ptr.base;
5695
5696 const else_node = try transCreateNodeElse(c);
5697 if_node.@"else" = else_node;
5698
5699 const as_node = try c.createBuiltinCall("@as", 2);
5700 as_node.params()[0] = inner_node;
5701 as_node.params()[1] = node_to_cast;
5702 as_node.rparen_token = try appendToken(c, .RParen, ")");
5703 else_node.body = &as_node.base;
5704
5705 const group_node = try c.arena.create(ast.Node.GroupedExpression);
5706 group_node.* = .{
5707 .lparen = lparen,
5708 .expr = &if_node.base,
5709 .rparen = try appendToken(c, .RParen, ")"),
5710 };
5711 return &group_node.base;
5712 }
5713
5714 //( if (@typeInfo(@TypeOf(x)) == .Pointer)
5715 // @ptrCast(dest, @alignCast(@alignOf(dest.Child), x))
5716 //else if (@typeInfo(@TypeOf(x)) == .Int and @typeInfo(dest) == .Pointer))
5717 // @intToPtr(dest, x)
5718 //else
5719 // @as(dest, x) )
5720
5721 const if_1 = try transCreateNodeIf(c);
5722 const type_info_1 = try c.createBuiltinCall("@typeInfo", 1);
5723 const type_of_1 = try c.createBuiltinCall("@TypeOf", 1);
5724 type_info_1.params()[0] = &type_of_1.base;
5725 type_of_1.params()[0] = node_to_cast;
5726 type_of_1.rparen_token = try appendToken(c, .RParen, ")");
5727 type_info_1.rparen_token = try appendToken(c, .RParen, ")");
5728
5729 const cmp_1 = try c.arena.create(ast.Node.InfixOp);
5730 cmp_1.* = .{
5731 .op_token = try appendToken(c, .EqualEqual, "=="),
5732 .lhs = &type_info_1.base,
5733 .op = .EqualEqual,
5734 .rhs = try transCreateNodeEnumLiteral(c, "Pointer"),
5735 };
5736 if_1.condition = &cmp_1.base;
5737 _ = try appendToken(c, .RParen, ")");
5738
5739 const period_tok = try appendToken(c, .Period, ".");
5740 const child_ident = try transCreateNodeIdentifier(c, "Child");
5741 const inner_node_child = try c.arena.create(ast.Node.InfixOp);
5742 inner_node_child.* = .{
5743 .op_token = period_tok,
5744 .lhs = inner_node,
5745 .op = .Period,
5746 .rhs = child_ident,
5747 };
5748
5749 const align_of = try c.createBuiltinCall("@alignOf", 1);
5750 align_of.params()[0] = &inner_node_child.base;
5751 align_of.rparen_token = try appendToken(c, .RParen, ")");
5752 // hack to get zig fmt to render a comma in builtin calls
5753 _ = try appendToken(c, .Comma, ",");
5754
5755 const align_cast = try c.createBuiltinCall("@alignCast", 2);
5756 align_cast.params()[0] = &align_of.base;
5757 align_cast.params()[1] = node_to_cast;
5758 align_cast.rparen_token = try appendToken(c, .RParen, ")");
5759
5760 const ptr_cast = try c.createBuiltinCall("@ptrCast", 2);
5761 ptr_cast.params()[0] = inner_node;
5762 ptr_cast.params()[1] = &align_cast.base;
5763 ptr_cast.rparen_token = try appendToken(c, .RParen, ")");
5764 if_1.body = &ptr_cast.base;
5765
5766 const else_1 = try transCreateNodeElse(c);
5767 if_1.@"else" = else_1;
5768
5769 const if_2 = try transCreateNodeIf(c);
5770 const type_info_2 = try c.createBuiltinCall("@typeInfo", 1);
5771 const type_of_2 = try c.createBuiltinCall("@TypeOf", 1);
5772 type_info_2.params()[0] = &type_of_2.base;
5773 type_of_2.params()[0] = node_to_cast;
5774 type_of_2.rparen_token = try appendToken(c, .RParen, ")");
5775 type_info_2.rparen_token = try appendToken(c, .RParen, ")");
5776
5777 const cmp_2 = try c.arena.create(ast.Node.InfixOp);
5778 cmp_2.* = .{
5779 .op_token = try appendToken(c, .EqualEqual, "=="),
5780 .lhs = &type_info_2.base,
5781 .op = .EqualEqual,
5782 .rhs = try transCreateNodeEnumLiteral(c, "Int"),
5783 };
5784 if_2.condition = &cmp_2.base;
5785 const cmp_4 = try c.arena.create(ast.Node.InfixOp);
5786 cmp_4.* = .{
5787 .op_token = try appendToken(c, .Keyword_and, "and"),
5788 .lhs = &cmp_2.base,
5789 .op = .BoolAnd,
5790 .rhs = undefined,
5791 };
5792 const type_info_3 = try c.createBuiltinCall("@typeInfo", 1);
5793 type_info_3.params()[0] = inner_node;
5794 type_info_3.rparen_token = try appendToken(c, .LParen, ")");
5795 const cmp_3 = try c.arena.create(ast.Node.InfixOp);
5796 cmp_3.* = .{
5797 .op_token = try appendToken(c, .EqualEqual, "=="),
5798 .lhs = &type_info_3.base,
5799 .op = .EqualEqual,
5800 .rhs = try transCreateNodeEnumLiteral(c, "Pointer"),
5801 };
5802 cmp_4.rhs = &cmp_3.base;
5803 if_2.condition = &cmp_4.base;
5804 else_1.body = &if_2.base;
5805 _ = try appendToken(c, .RParen, ")");
5806
5807 const int_to_ptr = try c.createBuiltinCall("@intToPtr", 2);
5808 int_to_ptr.params()[0] = inner_node;
5809 int_to_ptr.params()[1] = node_to_cast;
5810 int_to_ptr.rparen_token = try appendToken(c, .RParen, ")");
5811 if_2.body = &int_to_ptr.base;
5812
5813 const else_2 = try transCreateNodeElse(c);
5814 if_2.@"else" = else_2;
5815
5816 const as = try c.createBuiltinCall("@as", 2);
5817 as.params()[0] = inner_node;
5818 as.params()[1] = node_to_cast;
5819 as.rparen_token = try appendToken(c, .RParen, ")");
5820 else_2.body = &as.base;
5671 //(@import("std").meta.cast(dest, x))
5672 const import_fn_call = try c.createBuiltinCall("@import", 1);
5673 const std_node = try transCreateNodeStringLiteral(c, "\"std\"");
5674 import_fn_call.params()[0] = std_node;
5675 import_fn_call.rparen_token = try appendToken(c, .RParen, ")");
5676 const inner_field_access = try transCreateNodeFieldAccess(c, &import_fn_call.base, "meta");
5677 const outer_field_access = try transCreateNodeFieldAccess(c, inner_field_access, "cast");
5678
5679 const cast_fn_call = try c.createCall(outer_field_access, 2);
5680 cast_fn_call.params()[0] = inner_node;
5681 cast_fn_call.params()[1] = node_to_cast;
5682 cast_fn_call.rtoken = try appendToken(c, .RParen, ")");
58215683
58225684 const group_node = try c.arena.create(ast.Node.GroupedExpression);
58235685 group_node.* = .{
58245686 .lparen = lparen,
5825 .expr = &if_1.base,
5687 .expr = &cast_fn_call.base,
58265688 .rparen = try appendToken(c, .RParen, ")"),
58275689 };
58285690 return &group_node.base;
test/translate_c.zig+8-8
......@@ -1473,7 +1473,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
14731473 cases.add("macro pointer cast",
14741474 \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
14751475 , &[_][]const u8{
1476 \\pub const NRF_GPIO = (if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, @alignCast(@alignOf([*c]NRF_GPIO_Type.Child), NRF_GPIO_BASE)) else if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Int and @typeInfo([*c]NRF_GPIO_Type) == .Pointer) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE));
1476 \\pub const NRF_GPIO = (@import("std").meta.cast([*c]NRF_GPIO_Type, NRF_GPIO_BASE));
14771477 });
14781478
14791479 cases.add("basic macro function",
......@@ -2683,11 +2683,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
26832683 \\#define FOO(bar) baz((void *)(baz))
26842684 \\#define BAR (void*) a
26852685 , &[_][]const u8{
2686 \\pub inline fn FOO(bar: var) @TypeOf(baz((if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(?*c_void, @alignCast(@alignOf(?*c_void.Child), baz)) else if (@typeInfo(@TypeOf(baz)) == .Int and @typeInfo(?*c_void) == .Pointer) @intToPtr(?*c_void, baz) else @as(?*c_void, baz)))) {
2687 \\ return baz((if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(?*c_void, @alignCast(@alignOf(?*c_void.Child), baz)) else if (@typeInfo(@TypeOf(baz)) == .Int and @typeInfo(?*c_void) == .Pointer) @intToPtr(?*c_void, baz) else @as(?*c_void, baz)));
2686 \\pub inline fn FOO(bar: var) @TypeOf(baz((@import("std").meta.cast(?*c_void, baz)))) {
2687 \\ return baz((@import("std").meta.cast(?*c_void, baz)));
26882688 \\}
26892689 ,
2690 \\pub const BAR = (if (@typeInfo(@TypeOf(a)) == .Pointer) @ptrCast(?*c_void, @alignCast(@alignOf(?*c_void.Child), a)) else if (@typeInfo(@TypeOf(a)) == .Int and @typeInfo(?*c_void) == .Pointer) @intToPtr(?*c_void, a) else @as(?*c_void, a));
2690 \\pub const BAR = (@import("std").meta.cast(?*c_void, a));
26912691 });
26922692
26932693 cases.add("macro conditional operator",
......@@ -2905,8 +2905,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
29052905 \\#define DefaultScreen(dpy) (((_XPrivDisplay)(dpy))->default_screen)
29062906 \\
29072907 , &[_][]const u8{
2908 \\pub inline fn DefaultScreen(dpy: var) @TypeOf((if (@typeInfo(@TypeOf(dpy)) == .Pointer) @ptrCast(_XPrivDisplay, @alignCast(@alignOf(_XPrivDisplay.Child), dpy)) else if (@typeInfo(@TypeOf(dpy)) == .Int and @typeInfo(_XPrivDisplay) == .Pointer) @intToPtr(_XPrivDisplay, dpy) else @as(_XPrivDisplay, dpy)).*.default_screen) {
2909 \\ return (if (@typeInfo(@TypeOf(dpy)) == .Pointer) @ptrCast(_XPrivDisplay, @alignCast(@alignOf(_XPrivDisplay.Child), dpy)) else if (@typeInfo(@TypeOf(dpy)) == .Int and @typeInfo(_XPrivDisplay) == .Pointer) @intToPtr(_XPrivDisplay, dpy) else @as(_XPrivDisplay, dpy)).*.default_screen;
2908 \\pub inline fn DefaultScreen(dpy: var) @TypeOf((@import("std").meta.cast(_XPrivDisplay, dpy)).*.default_screen) {
2909 \\ return (@import("std").meta.cast(_XPrivDisplay, dpy)).*.default_screen;
29102910 \\}
29112911 });
29122912
......@@ -2914,9 +2914,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
29142914 \\#define NULL ((void*)0)
29152915 \\#define FOO ((int)0x8000)
29162916 , &[_][]const u8{
2917 \\pub const NULL = (if (@typeInfo(?*c_void) == .Pointer) @intToPtr(?*c_void, 0) else @as(?*c_void, 0));
2917 \\pub const NULL = (@import("std").meta.cast(?*c_void, 0));
29182918 ,
2919 \\pub const FOO = (if (@typeInfo(c_int) == .Pointer) @intToPtr(c_int, 0x8000) else @as(c_int, 0x8000));
2919 \\pub const FOO = (@import("std").meta.cast(c_int, 0x8000));
29202920 });
29212921
29222922 if (std.Target.current.abi == .msvc) {