| 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 | 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 | 1127 | /// For a given function type, returns a tuple type which fields will |
| 1098 | 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 | 4431 | |
| 4432 | 4432 | switch (m.list[m.i].id) { |
| 4433 | 4433 | .IntegerLiteral => |suffix| { |
| 4434 | var radix: []const u8 = "decimal"; | |
| 4434 | 4435 | if (lit_bytes.len > 2 and lit_bytes[0] == '0') { |
| 4435 | 4436 | switch (lit_bytes[1]) { |
| 4436 | 4437 | '0'...'7' => { |
| 4437 | 4438 | // Octal |
| 4438 | 4439 | lit_bytes = try std.fmt.allocPrint(c.arena, "0o{s}", .{lit_bytes}); |
| 4440 | radix = "octal"; | |
| 4439 | 4441 | }, |
| 4440 | 4442 | 'X' => { |
| 4441 | 4443 | // Hexadecimal with capital X, valid in C but not in Zig |
| 4442 | 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 | 4450 | else => {}, |
| 4445 | 4451 | } |
| 4446 | 4452 | } |
| 4447 | 4453 | |
| 4448 | if (suffix == .none) { | |
| 4449 | return transCreateNodeNumber(c, lit_bytes, .int); | |
| 4450 | } | |
| 4451 | ||
| 4452 | 4454 | const type_node = try Tag.type.create(c.arena, switch (suffix) { |
| 4455 | .none => "c_int", | |
| 4453 | 4456 | .u => "c_uint", |
| 4454 | 4457 | .l => "c_long", |
| 4455 | 4458 | .lu => "c_ulong", |
| 4456 | 4459 | .ll => "c_longlong", |
| 4457 | 4460 | .llu => "c_ulonglong", |
| 4458 | else => unreachable, | |
| 4461 | .f => unreachable, | |
| 4459 | 4462 | }); |
| 4460 | 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 | 4466 | .lu, .ll => 2, |
| 4463 | 4467 | .llu => 3, |
| 4464 | else => unreachable, | |
| 4468 | .f => unreachable, | |
| 4465 | 4469 | }]; |
| 4466 | const rhs = try transCreateNodeNumber(c, lit_bytes, .int); | |
| 4467 | return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = rhs }); | |
| 4470 | ||
| 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 | 4497 | .FloatLiteral => |suffix| { |
| 4470 | 4498 | if (lit_bytes[0] == '.') |
src/translate_c/ast.zig+29| ... | ... | @@ -39,6 +39,7 @@ pub const Node = extern union { |
| 39 | 39 | float_literal, |
| 40 | 40 | string_literal, |
| 41 | 41 | char_literal, |
| 42 | enum_literal, | |
| 42 | 43 | identifier, |
| 43 | 44 | @"if", |
| 44 | 45 | /// if (!operand) break; |
| ... | ... | @@ -117,6 +118,7 @@ pub const Node = extern union { |
| 117 | 118 | /// @intCast(lhs, rhs) |
| 118 | 119 | int_cast, |
| 119 | 120 | /// @rem(lhs, rhs) |
| 121 | std_meta_promoteIntLiteral, | |
| 120 | 122 | rem, |
| 121 | 123 | /// @divTrunc(lhs, rhs) |
| 122 | 124 | div_trunc, |
| ... | ... | @@ -312,6 +314,7 @@ pub const Node = extern union { |
| 312 | 314 | .float_literal, |
| 313 | 315 | .string_literal, |
| 314 | 316 | .char_literal, |
| 317 | .enum_literal, | |
| 315 | 318 | .identifier, |
| 316 | 319 | .warning, |
| 317 | 320 | .type, |
| ... | ... | @@ -328,6 +331,7 @@ pub const Node = extern union { |
| 328 | 331 | .tuple => Payload.TupleInit, |
| 329 | 332 | .container_init => Payload.ContainerInit, |
| 330 | 333 | .std_meta_cast => Payload.Infix, |
| 334 | .std_meta_promoteIntLiteral => Payload.PromoteIntLiteral, | |
| 331 | 335 | .block => Payload.Block, |
| 332 | 336 | .c_pointer, .single_pointer => Payload.Pointer, |
| 333 | 337 | .array_type => Payload.Array, |
| ... | ... | @@ -651,6 +655,15 @@ pub const Payload = struct { |
| 651 | 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 | 669 | /// Converts the nodes into a Zig ast. |
| ... | ... | @@ -821,6 +834,11 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { |
| 821 | 834 | const import_node = try renderStdImport(c, "meta", "cast"); |
| 822 | 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 | 842 | .std_meta_sizeof => { |
| 825 | 843 | const payload = node.castTag(.std_meta_sizeof).?.data; |
| 826 | 844 | const import_node = try renderStdImport(c, "meta", "sizeof"); |
| ... | ... | @@ -988,6 +1006,15 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { |
| 988 | 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 | 1018 | .fail_decl => { |
| 992 | 1019 | const payload = node.castTag(.fail_decl).?.data; |
| 993 | 1020 | // pub const name = @compileError(msg); |
| ... | ... | @@ -1982,11 +2009,13 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { |
| 1982 | 2009 | .typeof, |
| 1983 | 2010 | .std_meta_sizeof, |
| 1984 | 2011 | .std_meta_cast, |
| 2012 | .std_meta_promoteIntLiteral, | |
| 1985 | 2013 | .std_mem_zeroinit, |
| 1986 | 2014 | .integer_literal, |
| 1987 | 2015 | .float_literal, |
| 1988 | 2016 | .string_literal, |
| 1989 | 2017 | .char_literal, |
| 2018 | .enum_literal, | |
| 1990 | 2019 | .identifier, |
| 1991 | 2020 | .field_access, |
| 1992 | 2021 | .ptr_cast, |