diff --git a/src/translate_c.zig b/src/translate_c.zig index ce8fea7a71ae16c60fbd4eb241f07705a6fef2f2..995ff16b1c1c208573a633775b679a09ce88eed7 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -1871,7 +1871,10 @@ fn transInitListExprRecord( }); } - return Tag.container_init.create(c.arena, try c.arena.dupe(ast.Payload.ContainerInit.Initializer, field_inits.items)); + return Tag.container_init.create(c.arena, .{ + .lhs = ty_node, + .inits = try c.arena.dupe(ast.Payload.ContainerInit.Initializer, field_inits.items), + }); } fn transInitListExprArray( diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig index 014236e002d5bdefb41fe42c5d2814bce0cded2d..b22e61c65e7d4d935a217a7892fffdae087bab83 100644 --- a/src/translate_c/ast.zig +++ b/src/translate_c/ast.zig @@ -520,7 +520,10 @@ pub const Payload = struct { pub const ContainerInit = struct { base: Payload, - data: []Initializer, + data: struct { + lhs: Node, + inits: []Initializer, + }, pub const Initializer = struct { name: []const u8, @@ -1528,20 +1531,250 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { const lhs = try renderNode(c, payload.lhs); return renderFieldAccess(c, lhs, payload.field_name); }, - .tuple, - .@"enum", - .@"struct", - .@"union", - .container_init, - .enum_redecl, - => return c.addNode(.{ - .tag = .identifier, - .main_token = try c.addTokenFmt(.identifier, "@\"TODO {}\"", .{node.tag()}), + .@"struct", .@"union" => return renderRecord(c, node), + .@"enum" => { + const payload = node.castTag(.@"enum").?.data; + const enum_tok = try c.addToken(.keyword_enum, "enum"); + + _ = try c.addToken(.l_brace, "{"); + const members = try c.gpa.alloc(NodeIndex, std.math.max(payload.len + 1, 1)); + defer c.gpa.free(members); + members[0] = 0; + members[1] = 0; + + for (payload) |field, i| { + const name_tok = try c.addIdentifier(field.name); + const value_expr = if (field.value) |some| blk: { + _ = try c.addToken(.equal, "="); + break :blk try renderNode(c, some); + } else 0; + + members[i] = try c.addNode(.{ + .tag = .container_field_init, + .main_token = name_tok, + .data = .{ + .lhs = 0, + .rhs = value_expr, + }, + }); + _ = try c.addToken(.comma, ","); + } + // make non-exhaustive + members[payload.len] = try c.addNode(.{ + .tag = .container_field_init, + .main_token = try c.addIdentifier("_"), + .data = .{ + .lhs = 0, + .rhs = 0, + }, + }); + _ = try c.addToken(.comma, ","); + _ = try c.addToken(.r_brace, "}"); + + if (members.len <= 2) { + return c.addNode(.{ + .tag = .container_decl_two_comma, + .main_token = enum_tok, + .data = .{ + .lhs = members[0], + .rhs = members[1], + }, + }); + } else { + const span = try c.listToSpan(members); + return c.addNode(.{ + .tag = .container_decl_comma, + .main_token = enum_tok, + .data = .{ + .lhs = span.start, + .rhs = span.end, + }, + }); + } + }, + .enum_redecl => { + const payload = node.castTag(.enum_redecl).?.data; + _ = try c.addToken(.keyword_pub, "pub"); + const const_tok = try c.addToken(.keyword_const, "const"); + _ = try c.addIdentifier(payload.enum_val_name); + _ = try c.addToken(.equal, "="); + + const enum_to_int_tok = try c.addToken(.builtin, "@enumToInt"); + _ = try c.addToken(.l_paren, "("); + const enum_name = try c.addNode(.{ + .tag = .identifier, + .main_token = try c.addIdentifier(payload.enum_name), + .data = undefined, + }); + const field_access = try renderFieldAccess(c, enum_name, payload.field_name); + const init_node = try c.addNode(.{ + .tag = .builtin_call_two, + .main_token = enum_to_int_tok, + .data = .{ + .lhs = field_access, + .rhs = 0, + }, + }); + _ = try c.addToken(.r_paren, ")"); + _ = try c.addToken(.semicolon, ";"); + + return c.addNode(.{ + .tag = .simple_var_decl, + .main_token = const_tok, + .data = .{ + .lhs = 0, + .rhs = init_node, + }, + }); + }, + .tuple => { + const payload = node.castTag(.tuple).?.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, 1)); + defer c.gpa.free(inits); + inits[0] = 0; + for (payload) |init, i| { + if (i != 0) _ = try c.addToken(.comma, ","); + inits[i] = try renderNode(c, init); + } + _ = try c.addToken(.r_brace, "}"); + if (payload.len < 3) { + return c.addNode(.{ + .tag = .array_init_dot_two, + .main_token = l_brace, + .data = .{ + .lhs = inits[0], + .rhs = inits[1], + }, + }); + } else { + const span = try c.listToSpan(inits); + return c.addNode(.{ + .tag = .array_init_dot, + .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); + + const l_brace = try c.addToken(.l_brace, "{"); + var inits = try c.gpa.alloc(NodeIndex, std.math.max(payload.inits.len, 1)); + defer c.gpa.free(inits); + inits[0] = 0; + for (payload.inits) |init, i| { + if (i != 0) _ = try c.addToken(.comma, ","); + _ = try c.addToken(.period, "."); + _ = try c.addIdentifier(init.name); + _ = try c.addToken(.equal, "="); + inits[i] = try renderNode(c, init.value); + } + _ = try c.addToken(.r_brace, "}"); + + if (payload.inits.len < 2) { + return c.addNode(.{ + .tag = .struct_init_one, + .main_token = l_brace, + .data = .{ + .lhs = lhs, + .rhs = inits[0], + }, + }); + } else { + const span = try c.listToSpan(inits); + return c.addNode(.{ + .tag = .struct_init, + .main_token = l_brace, + .data = .{ + .lhs = lhs, + .rhs = try c.addExtra(NodeSubRange{ + .start = span.start, + .end = span.end, + }), + }, + }); + } + }, + } +} + +fn renderRecord(c: *Context, node: Node) !NodeIndex { + const payload = @fieldParentPtr(Payload.Record, "base", node.ptr_otherwise).data; + if (payload.is_packed) _ = try c.addToken(.keyword_packed, "packed"); + const kind_tok = if (node.tag() == .@"struct") + try c.addToken(.keyword_struct, "struct") + else + try c.addToken(.keyword_union, "union"); + + _ = try c.addToken(.l_brace, "{"); + const members = try c.gpa.alloc(NodeIndex, std.math.max(payload.fields.len, 2)); + defer c.gpa.free(members); + members[0] = 0; + members[1] = 0; + + for (payload.fields) |field, i| { + const name_tok = try c.addIdentifier(field.name); + _ = try c.addToken(.colon, ":"); + const type_expr = try renderNode(c, field.type); + + const alignment = field.alignment orelse { + members[i] = try c.addNode(.{ + .tag = .container_field_init, + .main_token = name_tok, + .data = .{ + .lhs = type_expr, + .rhs = 0, + }, + }); + _ = try c.addToken(.comma, ","); + continue; + }; + _ = try c.addToken(.keyword_align, "align"); + _ = try c.addToken(.l_paren, "("); + const align_expr = try c.addNode(.{ + .tag = .integer_literal, + .main_token = try c.addTokenFmt(.integer_literal, "{d}", .{alignment}), + .data = undefined, + }); + _ = try c.addToken(.r_paren, ")"); + + members[i] = try c.addNode(.{ + .tag = .container_field_align, + .main_token = name_tok, .data = .{ - .lhs = undefined, - .rhs = undefined, + .lhs = type_expr, + .rhs = align_expr, }, - }), + }); + _ = try c.addToken(.comma, ","); + } + _ = try c.addToken(.r_brace, "}"); + + if (members.len <= 2) { + return c.addNode(.{ + .tag = .container_decl_two_comma, + .main_token = kind_tok, + .data = .{ + .lhs = members[0], + .rhs = members[1], + }, + }); + } else { + const span = try c.listToSpan(members); + return c.addNode(.{ + .tag = .container_decl_comma, + .main_token = kind_tok, + .data = .{ + .lhs = span.start, + .rhs = span.end, + }, + }); } } @@ -1558,50 +1791,37 @@ fn renderFieldAccess(c: *Context, lhs: NodeIndex, field_name: []const u8) !NodeI fn renderArrayInit(c: *Context, lhs: NodeIndex, inits: []const Node) !NodeIndex { const l_brace = try c.addToken(.l_brace, "{"); - const res = switch (inits.len) { - 0 => try c.addNode(.{ - .tag = .struct_init_one, - .main_token = l_brace, - .data = .{ - .lhs = lhs, - .rhs = 0, - }, - }), - 1 => blk: { - const init = try renderNode(c, inits[0]); - break :blk try c.addNode(.{ - .tag = .array_init_one, - .main_token = l_brace, - .data = .{ - .lhs = lhs, - .rhs = init, - }, - }); - }, - else => blk: { - var rendered = try c.gpa.alloc(NodeIndex, inits.len); - defer c.gpa.free(rendered); - - for (inits) |init, i| { - if (i != 0) _ = try c.addToken(.comma, ","); - rendered[i] = try renderNode(c, init); - } - const span = try c.listToSpan(rendered); - break :blk try c.addNode(.{ - .tag = .array_init, - .main_token = l_brace, - .data = .{ - .lhs = lhs, - .rhs = try c.addExtra(NodeSubRange{ - .start = span.start, - .end = span.end, - }), - }, - }); - }, - }; + var rendered = try c.gpa.alloc(NodeIndex, std.math.max(inits.len, 1)); + defer c.gpa.free(rendered); + rendered[0] = 0; + for (inits) |init, i| { + if (i != 0) _ = try c.addToken(.comma, ","); + rendered[i] = try renderNode(c, init); + } _ = try c.addToken(.r_brace, "}"); - return res; + if (inits.len < 2) { + return c.addNode(.{ + .tag = .array_init_one, + .main_token = l_brace, + .data = .{ + .lhs = lhs, + .rhs = rendered[0], + }, + }); + } else { + const span = try c.listToSpan(rendered); + return c.addNode(.{ + .tag = .array_init, + .main_token = l_brace, + .data = .{ + .lhs = lhs, + .rhs = try c.addExtra(NodeSubRange{ + .start = span.start, + .end = span.end, + }), + }, + }); + } } fn renderArrayType(c: *Context, len: usize, elem_type: Node) !NodeIndex {