diff --git a/src/translate_c.zig b/src/translate_c.zig index b46274375..db29007a9 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -4813,8 +4813,11 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { const br = blk_last.castTag(.break_val).?; break :blk br.data.val; } else expr; - const return_type = if (typeof_arg.castTag(.std_meta_cast)) |some| + + const return_type = if (typeof_arg.castTag(.std_meta_cast) orelse typeof_arg.castTag(.std_mem_zeroinit)) |some| some.data.lhs + else if (typeof_arg.castTag(.std_mem_zeroes)) |some| + some.data else try Tag.typeof.create(c.arena, typeof_arg); @@ -4932,6 +4935,7 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node { } }, .FloatLiteral => |suffix| { + if (suffix != .none) lit_bytes = lit_bytes[0 .. lit_bytes.len - 1]; const dot_index = mem.indexOfScalar(u8, lit_bytes, '.').?; if (dot_index == 0) { lit_bytes = try std.fmt.allocPrint(c.arena, "0{s}", .{lit_bytes}); @@ -4943,15 +4947,16 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node { lit_bytes[dot_index + 1 ..], }); } - if (suffix == .none) { + + if (suffix == .none) return transCreateNodeNumber(c, lit_bytes, .float); - } + const type_node = try Tag.type.create(c.arena, switch (suffix) { .f => "f32", .l => "c_longdouble", else => unreachable, }); - const rhs = try transCreateNodeNumber(c, lit_bytes[0 .. lit_bytes.len - 1], .float); + const rhs = try transCreateNodeNumber(c, lit_bytes, .float); return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = rhs }); }, else => unreachable, @@ -5540,6 +5545,42 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { } }, .LBrace => { + // Check for designated field initializers + if (m.peek().? == .Period) { + var init_vals = std.ArrayList(ast.Payload.ContainerInitDot.Initializer).init(c.gpa); + defer init_vals.deinit(); + + while (true) { + if (m.next().? != .Period) { + try m.fail(c, "unable to translate C expr: expected '.'", .{}); + return error.ParseError; + } + if (m.next().? != .Identifier) { + try m.fail(c, "unable to translate C expr: expected identifier", .{}); + return error.ParseError; + } + const name = m.slice(); + if (m.next().? != .Equal) { + try m.fail(c, "unable to translate C expr: expected '='", .{}); + return error.ParseError; + } + + const val = try parseCCondExpr(c, m, scope); + try init_vals.append(.{ .name = name, .value = val }); + switch (m.next().?) { + .Comma => {}, + .RBrace => break, + else => { + try m.fail(c, "unable to translate C expr: expected ',' or '}}'", .{}); + return error.ParseError; + }, + } + } + const tuple_node = try Tag.container_init_dot.create(c.arena, try c.arena.dupe(ast.Payload.ContainerInitDot.Initializer, init_vals.items)); + node = try Tag.std_mem_zeroinit.create(c.arena, .{ .lhs = node, .rhs = tuple_node }); + continue; + } + var init_vals = std.ArrayList(Node).init(c.gpa); defer init_vals.deinit(); diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig index 0ea997e17..11ea5bda0 100644 --- a/src/translate_c/ast.zig +++ b/src/translate_c/ast.zig @@ -71,6 +71,7 @@ pub const Node = extern union { array_init, tuple, container_init, + container_init_dot, std_meta_cast, /// _ = operand; discard, @@ -332,6 +333,7 @@ pub const Node = extern union { .ptr_cast, .div_exact, .byte_offset_of, + .std_meta_cast, => Payload.BinOp, .integer_literal, @@ -354,7 +356,7 @@ pub const Node = extern union { .@"struct", .@"union" => Payload.Record, .tuple => Payload.TupleInit, .container_init => Payload.ContainerInit, - .std_meta_cast => Payload.Infix, + .container_init_dot => Payload.ContainerInitDot, .std_meta_promoteIntLiteral => Payload.PromoteIntLiteral, .block => Payload.Block, .c_pointer, .single_pointer => Payload.Pointer, @@ -448,14 +450,6 @@ pub const Node = extern union { pub const Payload = struct { tag: Node.Tag, - pub const Infix = struct { - base: Payload, - data: struct { - lhs: Node, - rhs: Node, - }, - }; - pub const Value = struct { base: Payload, data: []const u8, @@ -600,6 +594,16 @@ pub const Payload = struct { }; }; + pub const ContainerInitDot = struct { + base: Payload, + data: []Initializer, + + pub const Initializer = struct { + name: []const u8, + value: Node, + }; + }; + pub const Block = struct { base: Payload, data: struct { @@ -1893,6 +1897,44 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { }); } }, + .container_init_dot => { + const payload = node.castTag(.container_init_dot).?.data; + _ = try c.addToken(.period, "."); + const l_brace = try c.addToken(.l_brace, "{"); + var inits = try c.gpa.alloc(NodeIndex, std.math.max(payload.len, 2)); + defer c.gpa.free(inits); + inits[0] = 0; + inits[1] = 0; + for (payload) |init, i| { + _ = try c.addToken(.period, "."); + _ = try c.addIdentifier(init.name); + _ = try c.addToken(.equal, "="); + inits[i] = try renderNode(c, init.value); + _ = try c.addToken(.comma, ","); + } + _ = try c.addToken(.r_brace, "}"); + + if (payload.len < 3) { + return c.addNode(.{ + .tag = .struct_init_dot_two_comma, + .main_token = l_brace, + .data = .{ + .lhs = inits[0], + .rhs = inits[1], + }, + }); + } else { + const span = try c.listToSpan(inits); + return c.addNode(.{ + .tag = .struct_init_dot_comma, + .main_token = l_brace, + .data = .{ + .lhs = span.start, + .rhs = span.end, + }, + }); + } + }, .container_init => { const payload = node.castTag(.container_init).?.data; const lhs = try renderNode(c, payload.lhs); @@ -2257,6 +2299,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { .array_init, .tuple, .container_init, + .container_init_dot, .block, => return c.addNode(.{ .tag = .grouped_expression, diff --git a/test/translate_c.zig b/test/translate_c.zig index 8a9705e87..09db156d5 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -336,6 +336,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ int i1; \\} boom_t; \\#define FOO ((boom_t){1}) + \\typedef struct { float x; } MyCStruct; + \\#define A(_x) (MyCStruct) { .x = (_x) } + \\#define B A(0.f) , &[_][]const u8{ \\pub const struct_Color = extern struct { \\ r: u8, @@ -357,6 +360,18 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const boom_t = struct_boom_t; , \\pub const FOO = @import("std").mem.zeroInit(boom_t, .{@as(c_int, 1)}); + , + \\pub const MyCStruct = extern struct { + \\ x: f32, + \\}; + , + \\pub inline fn A(_x: anytype) MyCStruct { + \\ return @import("std").mem.zeroInit(MyCStruct, .{ + \\ .x = _x, + \\ }); + \\} + , + \\pub const B = A(@as(f32, 0.0)); }); cases.add("complex switch",