authorgravatar for charlie@shtanton.comCharlie Stanton <charlie@shtanton.com> 2020-06-21 18:24:59+01:00
committergravatar for charlie@shtanton.comCharlie Stanton <charlie@shtanton.com> 2020-06-21 18:24:59+01:00
log6f475130098a5913b485828c72cb47ab8146f9ea
tree37d5dab2ab5ced8681e8f9e18ed65cd82e9495ec
parent56220449abcbbb0e308e0eadeb2e0e7c8a9e4cba

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


3 files changed, 118 insertions(+), 157 deletions(-)

lib/std/meta.zig+95
...@@ -693,3 +693,98 @@ pub fn Vector(comptime len: u32, comptime child: type) type {...@@ -693,3 +693,98 @@ pub fn Vector(comptime len: u32, comptime child: type) type {
693 },693 },
694 });694 });
695}695}
696
697/// Given a type and value, cast the value to the type as c would
698pub fn cast(comptime DestType: type, target: var) DestType {
699 const TargetType = @TypeOf(target);
700 switch (@typeInfo(DestType)) {
701 .Pointer => |_| {
702 switch (@typeInfo(TargetType)) {
703 .Int => |_| {
704 return @intToPtr(DestType, target);
705 },
706 .ComptimeInt => |_| {
707 return @intToPtr(DestType, target);
708 },
709 .Pointer => |ptr| {
710 return @ptrCast(DestType, @alignCast(ptr.alignment, target));
711 },
712 .Optional => |opt| {
713 if (@typeInfo(opt.child) == .Pointer) {
714 return @ptrCast(DestType, @alignCast(@alignOf(opt.child.Child), target));
715 }
716 },
717 else => {},
718 }
719 },
720 .Optional => |opt| {
721 if (@typeInfo(opt.child) == .Pointer) {
722 switch (@typeInfo(TargetType)) {
723 .Int => |_| {
724 return @intToPtr(DestType, target);
725 },
726 .ComptimeInt => |_| {
727 return @intToPtr(DestType, target);
728 },
729 .Pointer => |ptr| {
730 return @ptrCast(DestType, @alignCast(ptr.alignment, target));
731 },
732 .Optional => |target_opt| {
733 if (@typeInfo(target_opt.child) == .Pointer) {
734 return @ptrCast(DestType, @alignCast(@alignOf(target_opt.child.Child), target));
735 }
736 },
737 else => {},
738 }
739 }
740 },
741 .Enum => |_| {
742 if (@typeInfo(TargetType) == .Int or @typeInfo(TargetType) == .ComptimeInt) {
743 return @intToEnum(DestType, target);
744 }
745 },
746 .EnumLiteral => |_| {
747 if (@typeInfo(TargetType) == .Int or @typeInfo(TargetType) == .ComptimeInt) {
748 return @intToEnum(DestType, target);
749 }
750 },
751 .Int => |_| {
752 switch (@typeInfo(TargetType)) {
753 .Pointer => |_| {
754 return @as(DestType, @ptrToInt(target));
755 },
756 .Optional => |opt| {
757 if (@typeInfo(opt.child) == .Pointer) {
758 return @as(DestType, @ptrToInt(target));
759 }
760 },
761 .Enum => |_| {
762 return @as(DestType, @enumToInt(target));
763 },
764 .EnumLiteral => |_| {
765 return @as(DestType, @enumToInt(target));
766 },
767 else => {},
768 }
769 },
770 else => {},
771 }
772 return @as(DestType, target);
773}
774
775test "std.meta.cast" {
776 const E = enum(u2) {
777 Zero,
778 One,
779 Two,
780 };
781
782 var i = @as(i64, 10);
783
784 testing.expect(cast(?*c_void, 0) == @intToPtr(?*c_void, 0));
785 testing.expect(cast(*u8, 16) == @intToPtr(*u8, 16));
786 testing.expect(cast(u64, @as(u32, 10)) == @as(u64, 10));
787 testing.expect(cast(E, 1) == .One);
788 testing.expect(cast(u8, E.Two) == 2);
789 testing.expect(cast(*u64, &i).* == @as(u64, 10));
790}
src-self-hosted/translate_c.zig+15-149
...@@ -5668,161 +5668,27 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5668,161 +5668,27 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
56685668
5669 const lparen = try appendToken(c, .LParen, "(");5669 const lparen = try appendToken(c, .LParen, "(");
56705670
5671 if (saw_integer_literal) {5671 //(@import("std").meta.cast(dest, x))
5672 //( if (@typeInfo(dest) == .Pointer))5672 const import_fn_call = try c.createBuiltinCall("@import", 1);
5673 // @intToPtr(dest, x)5673 const std_token = try appendToken(c, .StringLiteral, "\"std\"");
5674 //else5674 const std_node = try c.arena.create(ast.Node.StringLiteral);
5675 // @as(dest, x) )5675 std_node.* = .{
5676 const if_node = try transCreateNodeIf(c);5676 .token = std_token,
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 };5677 };
5678 import_fn_call.params()[0] = &std_node.base;
5679 import_fn_call.rparen_token = try appendToken(c, .RParen, ")");
5680 const inner_field_access = try transCreateNodeFieldAccess(c, &import_fn_call.base, "meta");
5681 const outer_field_access = try transCreateNodeFieldAccess(c, inner_field_access, "cast");
57485682
5749 const align_of = try c.createBuiltinCall("@alignOf", 1);5683 const cast_fn_call = try c.createCall(outer_field_access, 2);
5750 align_of.params()[0] = &inner_node_child.base;5684 cast_fn_call.params()[0] = inner_node;
5751 align_of.rparen_token = try appendToken(c, .RParen, ")");5685 cast_fn_call.params()[1] = node_to_cast;
5752 // hack to get zig fmt to render a comma in builtin calls5686 cast_fn_call.rtoken = try appendToken(c, .RParen, ")");
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;
58215687
5822 const group_node = try c.arena.create(ast.Node.GroupedExpression);5688 const group_node = try c.arena.create(ast.Node.GroupedExpression);
5823 group_node.* = .{5689 group_node.* = .{
5824 .lparen = lparen,5690 .lparen = lparen,
5825 .expr = &if_1.base,5691 .expr = &cast_fn_call.base,
5826 .rparen = try appendToken(c, .RParen, ")"),5692 .rparen = try appendToken(c, .RParen, ")"),
5827 };5693 };
5828 return &group_node.base;5694 return &group_node.base;
test/translate_c.zig+8-8
...@@ -1473,7 +1473,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1473,7 +1473,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1473 cases.add("macro pointer cast",1473 cases.add("macro pointer cast",
1474 \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)1474 \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
1475 , &[_][]const u8{1475 , &[_][]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));
1477 });1477 });
14781478
1479 cases.add("basic macro function",1479 cases.add("basic macro function",
...@@ -2683,11 +2683,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2683,11 +2683,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2683 \\#define FOO(bar) baz((void *)(baz))2683 \\#define FOO(bar) baz((void *)(baz))
2684 \\#define BAR (void*) a2684 \\#define BAR (void*) a
2685 , &[_][]const u8{2685 , &[_][]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)))) {2686 \\pub inline fn FOO(bar: var) @TypeOf(baz((@import("std").meta.cast(?*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)));2687 \\ return baz((@import("std").meta.cast(?*c_void, baz)));
2688 \\}2688 \\}
2689 ,2689 ,
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));
2691 });2691 });
26922692
2693 cases.add("macro conditional operator",2693 cases.add("macro conditional operator",
...@@ -2905,8 +2905,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2905,8 +2905,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2905 \\#define DefaultScreen(dpy) (((_XPrivDisplay)(dpy))->default_screen)2905 \\#define DefaultScreen(dpy) (((_XPrivDisplay)(dpy))->default_screen)
2906 \\2906 \\
2907 , &[_][]const u8{2907 , &[_][]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) {2908 \\pub inline fn DefaultScreen(dpy: var) @TypeOf((@import("std").meta.cast(_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;2909 \\ return (@import("std").meta.cast(_XPrivDisplay, dpy)).*.default_screen;
2910 \\}2910 \\}
2911 });2911 });
29122912
...@@ -2914,9 +2914,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2914,9 +2914,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2914 \\#define NULL ((void*)0)2914 \\#define NULL ((void*)0)
2915 \\#define FOO ((int)0x8000)2915 \\#define FOO ((int)0x8000)
2916 , &[_][]const u8{2916 , &[_][]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));
2918 ,2918 ,
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));
2920 });2920 });
29212921
2922 if (std.Target.current.abi == .msvc) {2922 if (std.Target.current.abi == .msvc) {