| author | |
| committer | |
| log | 679910ecec5cb8d77cbb599ce5df9459615e2d50 |
| tree | 4a47a31015f91168cbaee4b0faa2895c685f0c09 |
| parent | 9cd038d73a174706ec0a51ab9db0c04b095e019d |
3 files changed, 96 insertions(+), 9 deletions(-)
lib/std/meta.zig+30| ... | @@ -1094,6 +1094,36 @@ test "sizeof" { | ... | @@ -1094,6 +1094,36 @@ test "sizeof" { |
| 1094 | testing.expect(sizeof(c_void) == 1); | 1094 | testing.expect(sizeof(c_void) == 1); |
| 1095 | } | 1095 | } |
| 1096 | 1096 | ||
| 1097 | pub const CIntLiteralRadix = enum { decimal, octal, hexadecimal }; | ||
| 1098 | |||
| 1099 | fn PromoteIntLiteralReturnType(comptime SuffixType: type, comptime target: comptime_int, comptime radix: CIntLiteralRadix) type { | ||
| 1100 | const signed_decimal = [_]type{ c_int, c_long, c_longlong }; | ||
| 1101 | const signed_oct_hex = [_]type{ c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong }; | ||
| 1102 | const unsigned = [_]type{ c_uint, c_ulong, c_ulonglong }; | ||
| 1103 | |||
| 1104 | const list: []const type = if (@typeInfo(SuffixType).Int.signedness == .unsigned) | ||
| 1105 | &unsigned | ||
| 1106 | else if (radix == .decimal) | ||
| 1107 | &signed_decimal | ||
| 1108 | else | ||
| 1109 | &signed_oct_hex; | ||
| 1110 | |||
| 1111 | var pos = mem.indexOfScalar(type, list, SuffixType).?; | ||
| 1112 | |||
| 1113 | while (pos < list.len) : (pos += 1) { | ||
| 1114 | if (target >= math.minInt(list[pos]) and target <= math.maxInt(list[pos])) { | ||
| 1115 | return list[pos]; | ||
| 1116 | } | ||
| 1117 | } | ||
| 1118 | @compileError("Integer literal does not fit in compatible types"); | ||
| 1119 | } | ||
| 1120 | |||
| 1121 | /// Promote the type of an integer literal until it fits as C would. | ||
| 1122 | /// This is for translate-c and is not intended for general use. | ||
| 1123 | pub fn promoteIntLiteral(comptime SuffixType: type, comptime target: comptime_int, comptime radix: CIntLiteralRadix) PromoteIntLiteralReturnType(SuffixType, target, radix) { | ||
| 1124 | return @as(PromoteIntLiteralReturnType(SuffixType, target, radix), target); | ||
| 1125 | } | ||
| 1126 | |||
| 1097 | /// For a given function type, returns a tuple type which fields will | 1127 | /// For a given function type, returns a tuple type which fields will |
| 1098 | /// correspond to the argument types. | 1128 | /// correspond to the argument types. |
| 1099 | /// | 1129 | /// |
src/translate_c.zig+37-9| ... | @@ -4431,40 +4431,68 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node { | ... | @@ -4431,40 +4431,68 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node { |
| 4431 | 4431 | ||
| 4432 | switch (m.list[m.i].id) { | 4432 | switch (m.list[m.i].id) { |
| 4433 | .IntegerLiteral => |suffix| { | 4433 | .IntegerLiteral => |suffix| { |
| 4434 | var radix: []const u8 = "decimal"; | ||
| 4434 | if (lit_bytes.len > 2 and lit_bytes[0] == '0') { | 4435 | if (lit_bytes.len > 2 and lit_bytes[0] == '0') { |
| 4435 | switch (lit_bytes[1]) { | 4436 | switch (lit_bytes[1]) { |
| 4436 | '0'...'7' => { | 4437 | '0'...'7' => { |
| 4437 | // Octal | 4438 | // Octal |
| 4438 | lit_bytes = try std.fmt.allocPrint(c.arena, "0o{s}", .{lit_bytes}); | 4439 | lit_bytes = try std.fmt.allocPrint(c.arena, "0o{s}", .{lit_bytes}); |
| 4440 | radix = "octal"; | ||
| 4439 | }, | 4441 | }, |
| 4440 | 'X' => { | 4442 | 'X' => { |
| 4441 | // Hexadecimal with capital X, valid in C but not in Zig | 4443 | // Hexadecimal with capital X, valid in C but not in Zig |
| 4442 | lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}", .{lit_bytes[2..]}); | 4444 | lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}", .{lit_bytes[2..]}); |
| 4445 | radix = "hexadecimal"; | ||
| 4446 | }, | ||
| 4447 | 'x' => { | ||
| 4448 | radix = "hexadecimal"; | ||
| 4443 | }, | 4449 | }, |
| 4444 | else => {}, | 4450 | else => {}, |
| 4445 | } | 4451 | } |
| 4446 | } | 4452 | } |
| 4447 | 4453 | ||
| 4448 | if (suffix == .none) { | ||
| 4449 | return transCreateNodeNumber(c, lit_bytes, .int); | ||
| 4450 | } | ||
| 4451 | |||
| 4452 | const type_node = try Tag.type.create(c.arena, switch (suffix) { | 4454 | const type_node = try Tag.type.create(c.arena, switch (suffix) { |
| 4455 | .none => "c_int", | ||
| 4453 | .u => "c_uint", | 4456 | .u => "c_uint", |
| 4454 | .l => "c_long", | 4457 | .l => "c_long", |
| 4455 | .lu => "c_ulong", | 4458 | .lu => "c_ulong", |
| 4456 | .ll => "c_longlong", | 4459 | .ll => "c_longlong", |
| 4457 | .llu => "c_ulonglong", | 4460 | .llu => "c_ulonglong", |
| 4458 | else => unreachable, | 4461 | .f => unreachable, |
| 4459 | }); | 4462 | }); |
| 4460 | lit_bytes = lit_bytes[0 .. lit_bytes.len - switch (suffix) { | 4463 | lit_bytes = lit_bytes[0 .. lit_bytes.len - switch (suffix) { |
| 4461 | .u, .l => @as(u8, 1), | 4464 | .none => @as(u8, 0), |
| 4465 | .u, .l => 1, | ||
| 4462 | .lu, .ll => 2, | 4466 | .lu, .ll => 2, |
| 4463 | .llu => 3, | 4467 | .llu => 3, |
| 4464 | else => unreachable, | 4468 | .f => unreachable, |
| 4465 | }]; | 4469 | }]; |
| 4466 | const rhs = try transCreateNodeNumber(c, lit_bytes, .int); | 4470 | |
| 4467 | return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = rhs }); | 4471 | const value = std.fmt.parseInt(i128, lit_bytes, 0) catch math.maxInt(i128); |
| 4472 | |||
| 4473 | // make the output less noisy by skipping promoteIntLiteral where | ||
| 4474 | // it's guaranteed to not be required because of C standard type constraints | ||
| 4475 | const guaranteed_to_fit = switch (suffix) { | ||
| 4476 | .none => if (math.cast(i16, value)) |_| true else |_| false, | ||
| 4477 | .u => if (math.cast(u16, value)) |_| true else |_| false, | ||
| 4478 | .l => if (math.cast(i32, value)) |_| true else |_| false, | ||
| 4479 | .lu => if (math.cast(u32, value)) |_| true else |_| false, | ||
| 4480 | .ll => if (math.cast(i64, value)) |_| true else |_| false, | ||
| 4481 | .llu => if (math.cast(u64, value)) |_| true else |_| false, | ||
| 4482 | .f => unreachable, | ||
| 4483 | }; | ||
| 4484 | |||
| 4485 | const literal_node = try transCreateNodeNumber(c, lit_bytes, .int); | ||
| 4486 | |||
| 4487 | if (guaranteed_to_fit) { | ||
| 4488 | return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = literal_node }); | ||
| 4489 | } else { | ||
| 4490 | return Tag.std_meta_promoteIntLiteral.create(c.arena, .{ | ||
| 4491 | .type = type_node, | ||
| 4492 | .value = literal_node, | ||
| 4493 | .radix = try Tag.enum_literal.create(c.arena, radix), | ||
| 4494 | }); | ||
| 4495 | } | ||
| 4468 | }, | 4496 | }, |
| 4469 | .FloatLiteral => |suffix| { | 4497 | .FloatLiteral => |suffix| { |
| 4470 | if (lit_bytes[0] == '.') | 4498 | if (lit_bytes[0] == '.') |
src/translate_c/ast.zig+29| ... | @@ -39,6 +39,7 @@ pub const Node = extern union { | ... | @@ -39,6 +39,7 @@ pub const Node = extern union { |
| 39 | float_literal, | 39 | float_literal, |
| 40 | string_literal, | 40 | string_literal, |
| 41 | char_literal, | 41 | char_literal, |
| 42 | enum_literal, | ||
| 42 | identifier, | 43 | identifier, |
| 43 | @"if", | 44 | @"if", |
| 44 | /// if (!operand) break; | 45 | /// if (!operand) break; |
| ... | @@ -117,6 +118,7 @@ pub const Node = extern union { | ... | @@ -117,6 +118,7 @@ pub const Node = extern union { |
| 117 | /// @intCast(lhs, rhs) | 118 | /// @intCast(lhs, rhs) |
| 118 | int_cast, | 119 | int_cast, |
| 119 | /// @rem(lhs, rhs) | 120 | /// @rem(lhs, rhs) |
| 121 | std_meta_promoteIntLiteral, | ||
| 120 | rem, | 122 | rem, |
| 121 | /// @divTrunc(lhs, rhs) | 123 | /// @divTrunc(lhs, rhs) |
| 122 | div_trunc, | 124 | div_trunc, |
| ... | @@ -312,6 +314,7 @@ pub const Node = extern union { | ... | @@ -312,6 +314,7 @@ pub const Node = extern union { |
| 312 | .float_literal, | 314 | .float_literal, |
| 313 | .string_literal, | 315 | .string_literal, |
| 314 | .char_literal, | 316 | .char_literal, |
| 317 | .enum_literal, | ||
| 315 | .identifier, | 318 | .identifier, |
| 316 | .warning, | 319 | .warning, |
| 317 | .type, | 320 | .type, |
| ... | @@ -328,6 +331,7 @@ pub const Node = extern union { | ... | @@ -328,6 +331,7 @@ pub const Node = extern union { |
| 328 | .tuple => Payload.TupleInit, | 331 | .tuple => Payload.TupleInit, |
| 329 | .container_init => Payload.ContainerInit, | 332 | .container_init => Payload.ContainerInit, |
| 330 | .std_meta_cast => Payload.Infix, | 333 | .std_meta_cast => Payload.Infix, |
| 334 | .std_meta_promoteIntLiteral => Payload.PromoteIntLiteral, | ||
| 331 | .block => Payload.Block, | 335 | .block => Payload.Block, |
| 332 | .c_pointer, .single_pointer => Payload.Pointer, | 336 | .c_pointer, .single_pointer => Payload.Pointer, |
| 333 | .array_type => Payload.Array, | 337 | .array_type => Payload.Array, |
| ... | @@ -651,6 +655,15 @@ pub const Payload = struct { | ... | @@ -651,6 +655,15 @@ pub const Payload = struct { |
| 651 | field_name: []const u8, | 655 | field_name: []const u8, |
| 652 | }, | 656 | }, |
| 653 | }; | 657 | }; |
| 658 | |||
| 659 | pub const PromoteIntLiteral = struct { | ||
| 660 | base: Payload, | ||
| 661 | data: struct { | ||
| 662 | value: Node, | ||
| 663 | type: Node, | ||
| 664 | radix: Node, | ||
| 665 | }, | ||
| 666 | }; | ||
| 654 | }; | 667 | }; |
| 655 | 668 | ||
| 656 | /// Converts the nodes into a Zig ast. | 669 | /// Converts the nodes into a Zig ast. |
| ... | @@ -821,6 +834,11 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { | ... | @@ -821,6 +834,11 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { |
| 821 | const import_node = try renderStdImport(c, "meta", "cast"); | 834 | const import_node = try renderStdImport(c, "meta", "cast"); |
| 822 | return renderCall(c, import_node, &.{ payload.lhs, payload.rhs }); | 835 | return renderCall(c, import_node, &.{ payload.lhs, payload.rhs }); |
| 823 | }, | 836 | }, |
| 837 | .std_meta_promoteIntLiteral => { | ||
| 838 | const payload = node.castTag(.std_meta_promoteIntLiteral).?.data; | ||
| 839 | const import_node = try renderStdImport(c, "meta", "promoteIntLiteral"); | ||
| 840 | return renderCall(c, import_node, &.{ payload.type, payload.value, payload.radix }); | ||
| 841 | }, | ||
| 824 | .std_meta_sizeof => { | 842 | .std_meta_sizeof => { |
| 825 | const payload = node.castTag(.std_meta_sizeof).?.data; | 843 | const payload = node.castTag(.std_meta_sizeof).?.data; |
| 826 | const import_node = try renderStdImport(c, "meta", "sizeof"); | 844 | const import_node = try renderStdImport(c, "meta", "sizeof"); |
| ... | @@ -988,6 +1006,15 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { | ... | @@ -988,6 +1006,15 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { |
| 988 | .data = undefined, | 1006 | .data = undefined, |
| 989 | }); | 1007 | }); |
| 990 | }, | 1008 | }, |
| 1009 | .enum_literal => { | ||
| 1010 | const payload = node.castTag(.enum_literal).?.data; | ||
| 1011 | _ = try c.addToken(.period, "."); | ||
| 1012 | return c.addNode(.{ | ||
| 1013 | .tag = .enum_literal, | ||
| 1014 | .main_token = try c.addToken(.identifier, payload), | ||
| 1015 | .data = undefined, | ||
| 1016 | }); | ||
| 1017 | }, | ||
| 991 | .fail_decl => { | 1018 | .fail_decl => { |
| 992 | const payload = node.castTag(.fail_decl).?.data; | 1019 | const payload = node.castTag(.fail_decl).?.data; |
| 993 | // pub const name = @compileError(msg); | 1020 | // pub const name = @compileError(msg); |
| ... | @@ -1982,11 +2009,13 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { | ... | @@ -1982,11 +2009,13 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { |
| 1982 | .typeof, | 2009 | .typeof, |
| 1983 | .std_meta_sizeof, | 2010 | .std_meta_sizeof, |
| 1984 | .std_meta_cast, | 2011 | .std_meta_cast, |
| 2012 | .std_meta_promoteIntLiteral, | ||
| 1985 | .std_mem_zeroinit, | 2013 | .std_mem_zeroinit, |
| 1986 | .integer_literal, | 2014 | .integer_literal, |
| 1987 | .float_literal, | 2015 | .float_literal, |
| 1988 | .string_literal, | 2016 | .string_literal, |
| 1989 | .char_literal, | 2017 | .char_literal, |
| 2018 | .enum_literal, | ||
| 1990 | .identifier, | 2019 | .identifier, |
| 1991 | .field_access, | 2020 | .field_access, |
| 1992 | .ptr_cast, | 2021 | .ptr_cast, |