authorgravatar for 14938807+xackus@users.noreply.github.comxackus <14938807+xackus@users.noreply.github.com> 2021-06-12 15:54:39+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-06-13 16:47:42+03:00
logaa83cbb69737fbf8567c100340e476b5e38f0c84
tree5a96e2a519f1a1dd4fc55d980ed4d7cbccdf3a8d
parent46b9e061e07700ad1372ed2e9d2af9a29f24d76c

translate-c: better typename parsing


2 files changed, 164 insertions(+), 93 deletions(-)

src/translate_c.zig+151-92
......@@ -280,6 +280,8 @@ pub const Context = struct {
280280 opaque_demotes: std.AutoHashMapUnmanaged(usize, void) = .{},
281281 /// Table of unnamed enums and records that are child types of typedefs.
282282 unnamed_typedefs: std.AutoHashMapUnmanaged(usize, []const u8) = .{},
283 /// Needed to decide if we are parsing a typename
284 typedefs: std.StringArrayHashMapUnmanaged(void) = .{},
283285
284286 /// This one is different than the root scope's name table. This contains
285287 /// a list of names that we found by visiting all the top level decls without
......@@ -348,6 +350,7 @@ pub fn translate(
348350 context.global_names.deinit(gpa);
349351 context.opaque_demotes.deinit(gpa);
350352 context.unnamed_typedefs.deinit(gpa);
353 context.typedefs.deinit(gpa);
351354 context.global_scope.deinit();
352355 }
353356
......@@ -461,6 +464,7 @@ fn declVisitorNamesOnly(c: *Context, decl: *const clang.Decl) Error!void {
461464 result.value_ptr.* = name;
462465 // Put this typedef in the decl_table to avoid redefinitions.
463466 try c.decl_table.putNoClobber(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), name);
467 try c.typedefs.put(c.gpa, name, {});
464468 }
465469 }
466470}
......@@ -792,6 +796,8 @@ fn transTypeDef(c: *Context, scope: *Scope, typedef_decl: *const clang.TypedefNa
792796 // TODO https://github.com/ziglang/zig/issues/3756
793797 // TODO https://github.com/ziglang/zig/issues/1802
794798 var name: []const u8 = if (isZigPrimitiveType(bare_name)) try std.fmt.allocPrint(c.arena, "{s}_{d}", .{ bare_name, c.getMangle() }) else bare_name;
799 try c.typedefs.put(c.gpa, name, {});
800
795801 if (builtin_typedef_map.get(name)) |builtin| {
796802 return c.decl_table.putNoClobber(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), builtin);
797803 }
......@@ -5303,56 +5309,6 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
53035309 .IntegerLiteral, .FloatLiteral => {
53045310 return parseCNumLit(c, m);
53055311 },
5306 // eventually this will be replaced by std.c.parse which will handle these correctly
5307 .Keyword_void => return Tag.type.create(c.arena, "c_void"),
5308 .Keyword_bool => return Tag.type.create(c.arena, "bool"),
5309 .Keyword_double => return Tag.type.create(c.arena, "f64"),
5310 .Keyword_long => return Tag.type.create(c.arena, "c_long"),
5311 .Keyword_int => return Tag.type.create(c.arena, "c_int"),
5312 .Keyword_float => return Tag.type.create(c.arena, "f32"),
5313 .Keyword_short => return Tag.type.create(c.arena, "c_short"),
5314 .Keyword_char => return Tag.type.create(c.arena, "u8"),
5315 .Keyword_unsigned => if (m.next()) |t| switch (t) {
5316 .Keyword_char => return Tag.type.create(c.arena, "u8"),
5317 .Keyword_short => return Tag.type.create(c.arena, "c_ushort"),
5318 .Keyword_int => return Tag.type.create(c.arena, "c_uint"),
5319 .Keyword_long => if (m.peek() != null and m.peek().? == .Keyword_long) {
5320 _ = m.next();
5321 return Tag.type.create(c.arena, "c_ulonglong");
5322 } else return Tag.type.create(c.arena, "c_ulong"),
5323 else => {
5324 m.i -= 1;
5325 return Tag.type.create(c.arena, "c_uint");
5326 },
5327 } else {
5328 return Tag.type.create(c.arena, "c_uint");
5329 },
5330 .Keyword_signed => if (m.next()) |t| switch (t) {
5331 .Keyword_char => return Tag.type.create(c.arena, "i8"),
5332 .Keyword_short => return Tag.type.create(c.arena, "c_short"),
5333 .Keyword_int => return Tag.type.create(c.arena, "c_int"),
5334 .Keyword_long => if (m.peek() != null and m.peek().? == .Keyword_long) {
5335 _ = m.next();
5336 return Tag.type.create(c.arena, "c_longlong");
5337 } else return Tag.type.create(c.arena, "c_long"),
5338 else => {
5339 m.i -= 1;
5340 return Tag.type.create(c.arena, "c_int");
5341 },
5342 } else {
5343 return Tag.type.create(c.arena, "c_int");
5344 },
5345 .Keyword_enum, .Keyword_struct, .Keyword_union => {
5346 // struct Foo will be declared as struct_Foo by transRecordDecl
5347 const next_id = m.next().?;
5348 if (next_id != .Identifier) {
5349 try m.fail(c, "unable to translate C expr: expected Identifier instead got: {s}", .{@tagName(next_id)});
5350 return error.ParseError;
5351 }
5352
5353 const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ slice, m.slice() });
5354 return Tag.identifier.create(c.arena, name);
5355 },
53565312 .Identifier => {
53575313 const mangled_name = scope.getAlias(slice);
53585314 if (mem.startsWith(u8, mangled_name, "__builtin_") and !isBuiltinDefined(mangled_name)) {
......@@ -5369,37 +5325,15 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
53695325 try m.fail(c, "unable to translate C expr: expected ')' instead got: {s}", .{@tagName(next_id)});
53705326 return error.ParseError;
53715327 }
5372 var saw_l_paren = false;
5373 var saw_integer_literal = false;
5374 switch (m.peek().?) {
5375 // (type)(to_cast)
5376 .LParen => {
5377 saw_l_paren = true;
5378 _ = m.next();
5379 },
5380 // (type)sizeof(x)
5381 .Keyword_sizeof,
5382 // (type)alignof(x)
5383 .Keyword_alignof,
5384 // (type)identifier
5385 .Identifier,
5386 => {},
5387 // (type)integer
5388 .IntegerLiteral => {
5389 saw_integer_literal = true;
5390 },
5391 else => return inner_node,
5392 }
5393 const node_to_cast = try parseCExpr(c, m, scope);
5394
5395 if (saw_l_paren and m.next().? != .RParen) {
5396 try m.fail(c, "unable to translate C expr: expected ')'", .{});
5397 return error.ParseError;
5398 }
5399
5400 return Tag.std_meta_cast.create(c.arena, .{ .lhs = inner_node, .rhs = node_to_cast });
5328 return inner_node;
54015329 },
54025330 else => {
5331 // for handling type macros (EVIL)
5332 // TODO maybe detect and treat type macros as typedefs in parseCSpecifierQualifierList?
5333 m.i -= 1;
5334 if (try parseCTypeName(c, m, scope)) |type_name| {
5335 return type_name;
5336 }
54035337 try m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(tok)});
54045338 return error.ParseError;
54055339 },
......@@ -5605,7 +5539,7 @@ fn parseCAddSubExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
56055539}
56065540
56075541fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5608 var node = try parseCUnaryExpr(c, m, scope);
5542 var node = try parseCCastExpr(c, m, scope);
56095543 while (true) {
56105544 switch (m.next().?) {
56115545 .Asterisk => {
......@@ -5633,18 +5567,18 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
56335567 } else {
56345568 // expr * expr
56355569 const lhs = try macroBoolToInt(c, node);
5636 const rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
5570 const rhs = try macroBoolToInt(c, try parseCCastExpr(c, m, scope));
56375571 node = try Tag.mul.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
56385572 }
56395573 },
56405574 .Slash => {
56415575 const lhs = try macroBoolToInt(c, node);
5642 const rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
5576 const rhs = try macroBoolToInt(c, try parseCCastExpr(c, m, scope));
56435577 node = try Tag.div.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
56445578 },
56455579 .Percent => {
56465580 const lhs = try macroBoolToInt(c, node);
5647 const rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
5581 const rhs = try macroBoolToInt(c, try parseCCastExpr(c, m, scope));
56485582 node = try Tag.mod.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
56495583 },
56505584 else => {
......@@ -5655,8 +5589,133 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
56555589 }
56565590}
56575591
5658fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5659 var node = try parseCPrimaryExpr(c, m, scope);
5592fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5593 switch (m.next().?) {
5594 .LParen => {
5595 if (try parseCTypeName(c, m, scope)) |type_name| {
5596 if (m.next().? != .RParen) {
5597 try m.fail(c, "unable to translate C expr: expected ')'", .{});
5598 return error.ParseError;
5599 }
5600 if (m.peek().? == .LBrace) {
5601 // initializer list
5602 return parseCPostfixExpr(c, m, scope, type_name);
5603 }
5604 const node_to_cast = try parseCCastExpr(c, m, scope);
5605 return Tag.std_meta_cast.create(c.arena, .{ .lhs = type_name, .rhs = node_to_cast });
5606 }
5607 },
5608 else => {},
5609 }
5610 m.i -= 1;
5611 return parseCUnaryExpr(c, m, scope);
5612}
5613
5614fn parseCTypeName(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!?Node {
5615 if (try parseCSpecifierQualifierList(c, m, scope)) |node| {
5616 return try parseCAbstractDeclarator(c, m, scope, node);
5617 } else {
5618 return null;
5619 }
5620}
5621
5622fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!?Node {
5623 switch (m.next().?) {
5624 .Identifier => {
5625 const mangled_name = scope.getAlias(m.slice());
5626 if (c.typedefs.contains(mangled_name)) {
5627 return try Tag.identifier.create(c.arena, builtin_typedef_map.get(mangled_name) orelse mangled_name);
5628 }
5629 },
5630 // eventually this will be replaced by std.c.parse which will handle these correctly
5631 .Keyword_void => return try Tag.type.create(c.arena, "c_void"),
5632 .Keyword_bool => return try Tag.type.create(c.arena, "bool"),
5633 .Keyword_double => return try Tag.type.create(c.arena, "f64"),
5634 .Keyword_long => return try Tag.type.create(c.arena, "c_long"),
5635 .Keyword_int => return try Tag.type.create(c.arena, "c_int"),
5636 .Keyword_float => return try Tag.type.create(c.arena, "f32"),
5637 .Keyword_short => return try Tag.type.create(c.arena, "c_short"),
5638 .Keyword_char => return try Tag.type.create(c.arena, "u8"),
5639 .Keyword_unsigned => if (m.next()) |t| switch (t) {
5640 .Keyword_char => return try Tag.type.create(c.arena, "u8"),
5641 .Keyword_short => return try Tag.type.create(c.arena, "c_ushort"),
5642 .Keyword_int => return try Tag.type.create(c.arena, "c_uint"),
5643 .Keyword_long => if (m.peek() != null and m.peek().? == .Keyword_long) {
5644 _ = m.next();
5645 return try Tag.type.create(c.arena, "c_ulonglong");
5646 } else return try Tag.type.create(c.arena, "c_ulong"),
5647 else => {
5648 m.i -= 1;
5649 return try Tag.type.create(c.arena, "c_uint");
5650 },
5651 } else {
5652 return try Tag.type.create(c.arena, "c_uint");
5653 },
5654 .Keyword_signed => if (m.next()) |t| switch (t) {
5655 .Keyword_char => return try Tag.type.create(c.arena, "i8"),
5656 .Keyword_short => return try Tag.type.create(c.arena, "c_short"),
5657 .Keyword_int => return try Tag.type.create(c.arena, "c_int"),
5658 .Keyword_long => if (m.peek() != null and m.peek().? == .Keyword_long) {
5659 _ = m.next();
5660 return try Tag.type.create(c.arena, "c_longlong");
5661 } else return try Tag.type.create(c.arena, "c_long"),
5662 else => {
5663 m.i -= 1;
5664 return try Tag.type.create(c.arena, "c_int");
5665 },
5666 } else {
5667 return try Tag.type.create(c.arena, "c_int");
5668 },
5669 .Keyword_enum, .Keyword_struct, .Keyword_union => {
5670 // struct Foo will be declared as struct_Foo by transRecordDecl
5671 const slice = m.slice();
5672 const next_id = m.next().?;
5673 if (next_id != .Identifier) {
5674 try m.fail(c, "unable to translate C expr: expected Identifier instead got: {s}", .{@tagName(next_id)});
5675 return error.ParseError;
5676 }
5677
5678 const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ slice, m.slice() });
5679 return try Tag.identifier.create(c.arena, name);
5680 },
5681 .Keyword_complex => {}, // TODO
5682 else => {},
5683 }
5684
5685 m.i -= 1;
5686 return null;
5687}
5688
5689fn parseCAbstractDeclarator(c: *Context, m: *MacroCtx, scope: *Scope, node: Node) ParseError!Node {
5690 switch (m.next().?) {
5691 .Asterisk => {
5692 // last token of `node`
5693 const prev_id = m.list[m.i - 1].id;
5694
5695 if (prev_id == .Keyword_void) {
5696 const ptr = try Tag.single_pointer.create(c.arena, .{
5697 .is_const = false,
5698 .is_volatile = false,
5699 .elem_type = node,
5700 });
5701 return Tag.optional_type.create(c.arena, ptr);
5702 } else {
5703 return Tag.c_pointer.create(c.arena, .{
5704 .is_const = false,
5705 .is_volatile = false,
5706 .elem_type = node,
5707 });
5708 }
5709 },
5710 else => {
5711 m.i -= 1;
5712 return node;
5713 },
5714 }
5715}
5716
5717fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node) ParseError!Node {
5718 var node = type_name orelse try parseCPrimaryExpr(c, m, scope);
56605719 while (true) {
56615720 switch (m.next().?) {
56625721 .Period => {
......@@ -5776,24 +5835,24 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
57765835fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
57775836 switch (m.next().?) {
57785837 .Bang => {
5779 const operand = try macroIntToBool(c, try parseCUnaryExpr(c, m, scope));
5838 const operand = try macroIntToBool(c, try parseCCastExpr(c, m, scope));
57805839 return Tag.not.create(c.arena, operand);
57815840 },
57825841 .Minus => {
5783 const operand = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
5842 const operand = try macroBoolToInt(c, try parseCCastExpr(c, m, scope));
57845843 return Tag.negate.create(c.arena, operand);
57855844 },
5786 .Plus => return try parseCUnaryExpr(c, m, scope),
5845 .Plus => return try parseCCastExpr(c, m, scope),
57875846 .Tilde => {
5788 const operand = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
5847 const operand = try macroBoolToInt(c, try parseCCastExpr(c, m, scope));
57895848 return Tag.bit_not.create(c.arena, operand);
57905849 },
57915850 .Asterisk => {
5792 const operand = try parseCUnaryExpr(c, m, scope);
5851 const operand = try parseCCastExpr(c, m, scope);
57935852 return Tag.deref.create(c.arena, operand);
57945853 },
57955854 .Ampersand => {
5796 const operand = try parseCUnaryExpr(c, m, scope);
5855 const operand = try parseCCastExpr(c, m, scope);
57975856 return Tag.address_of.create(c.arena, operand);
57985857 },
57995858 .Keyword_sizeof => {
......@@ -5834,7 +5893,7 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
58345893 },
58355894 else => {
58365895 m.i -= 1;
5837 return try parseCPostfixExpr(c, m, scope);
5896 return try parseCPostfixExpr(c, m, scope, null);
58385897 },
58395898 }
58405899}
test/translate_c.zig+13-1
......@@ -238,7 +238,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
238238 });
239239
240240 cases.add("use cast param as macro fn return type",
241 \\#define MEM_PHYSICAL_TO_K0(x) (void*)((u32)(x) + SYS_BASE_CACHED)
241 \\#include <stdint.h>
242 \\#define MEM_PHYSICAL_TO_K0(x) (void*)((uint32_t)(x) + SYS_BASE_CACHED)
242243 , &[_][]const u8{
243244 \\pub inline fn MEM_PHYSICAL_TO_K0(x: anytype) ?*c_void {
244245 \\ return @import("std").meta.cast(?*c_void, @import("std").meta.cast(u32, x) + SYS_BASE_CACHED);
......@@ -1878,6 +1879,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
18781879 });
18791880
18801881 cases.add("macro pointer cast",
1882 \\typedef struct { int dummy; } NRF_GPIO_Type;
18811883 \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
18821884 , &[_][]const u8{
18831885 \\pub const NRF_GPIO = @import("std").meta.cast([*c]NRF_GPIO_Type, NRF_GPIO_BASE);
......@@ -3175,6 +3177,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
31753177 });
31763178
31773179 cases.add("macro cast",
3180 \\#include <stdint.h>
31783181 \\#define FOO(bar) baz((void *)(baz))
31793182 \\#define BAR (void*) a
31803183 \\#define BAZ (uint32_t)(2)
......@@ -3633,4 +3636,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
36333636 \\ return foo.static.x;
36343637 \\}
36353638 });
3639
3640 cases.add("macro with nontrivial cast",
3641 \\#define MAP_FAILED ((void *) -1)
3642 \\typedef long long LONG_PTR;
3643 \\#define INVALID_HANDLE_VALUE ((void *)(LONG_PTR)-1)
3644 , &[_][]const u8{
3645 \\pub const MAP_FAILED = @import("std").meta.cast(?*c_void, -@as(c_int, 1));
3646 \\pub const INVALID_HANDLE_VALUE = @import("std").meta.cast(?*c_void, @import("std").meta.cast(LONG_PTR, -@as(c_int, 1)));
3647 });
36363648}