feature. See also
. The project being documented here (as the example) is the Zig library itself.
ast.renderContainer
fn renderContainer(c: *Context, node: Node) !NodeIndex
File
Code
fn renderContainer(c: *Context, node: Node) !NodeIndex {
const payload = @as(*Payload.Container, @alignCast(@fieldParentPtr("base", node.ptr_otherwise))).data;
if (payload.layout == .@"packed")
_ = try c.addToken(.keyword_packed, "packed")
else if (payload.layout == .@"extern")
_ = try c.addToken(.keyword_extern, "extern");
const kind_tok = if (node.tag() == .@"struct")
try c.addToken(.keyword_struct, "struct")
else if (node.tag() == .@"union")
try c.addToken(.keyword_union, "union")
else if (node.tag() == .@"opaque")
try c.addToken(.keyword_opaque, "opaque")
else
unreachable;
_ = try c.addToken(.l_brace, "{");
const num_decls = payload.decls.len;
const total_members = payload.fields.len + num_decls;
const members = try c.gpa.alloc(NodeIndex, total_members);
defer c.gpa.free(members);
for (payload.fields, 0..) |field, i| {
const name_tok = try c.addTokenFmt(.identifier, "{f}", .{std.zig.fmtIdFlags(field.name, .{ .allow_primitive = true })});
_ = try c.addToken(.colon, ":");
const type_expr = try renderNode(c, field.type);
const align_expr_opt = if (field.alignment) |alignment| blk: {
_ = try c.addToken(.keyword_align, "align");
_ = try c.addToken(.l_paren, "(");
const align_expr = try c.addNode(.{
.tag = .number_literal,
.main_token = try c.addTokenFmt(.number_literal, "{d}", .{alignment}),
.data = undefined,
});
_ = try c.addToken(.r_paren, ")");
break :blk align_expr;
} else null;
const value_expr_opt = if (field.default_value) |value| blk: {
_ = try c.addToken(.equal, "=");
break :blk try renderNode(c, value);
} else null;
if (align_expr_opt) |align_expr| {
if (value_expr_opt) |value_expr| {
members[i] = try c.addNode(.{
.tag = .container_field,
.main_token = name_tok,
.data = .{ .node_and_extra = .{
type_expr,
try c.addExtra(std.zig.Ast.Node.ContainerField{
.align_expr = align_expr,
.value_expr = value_expr,
}),
} },
});
} else {
members[i] = try c.addNode(.{
.tag = .container_field_align,
.main_token = name_tok,
.data = .{ .node_and_node = .{
type_expr,
align_expr,
} },
});
}
} else {
members[i] = try c.addNode(.{
.tag = .container_field_init,
.main_token = name_tok,
.data = .{ .node_and_opt_node = .{
type_expr,
.fromOptional(value_expr_opt),
} },
});
}
_ = try c.addToken(.comma, ",");
}
for (members[payload.fields.len..], payload.decls) |*member, decl| {
member.* = try renderNode(c, decl);
}
const trailing = switch (c.tokens.items(.tag)[c.tokens.len - 1]) {
.comma, .semicolon => true,
else => false,
};
_ = try c.addToken(.r_brace, "}");
if (total_members == 0) {
return c.addNode(.{
.tag = .container_decl_two,
.main_token = kind_tok,
.data = .{ .opt_node_and_opt_node = .{
.none, .none,
} },
});
} else if (total_members <= 2) {
return c.addNode(.{
.tag = if (trailing) .container_decl_two_trailing else .container_decl_two,
.main_token = kind_tok,
.data = .{ .opt_node_and_opt_node = .{
if (members.len >= 1) members[0].toOptional() else .none,
if (members.len >= 2) members[1].toOptional() else .none,
} },
});
} else {
const span = try c.listToSpan(members);
return c.addNode(.{
.tag = if (trailing) .container_decl_trailing else .container_decl,
.main_token = kind_tok,
.data = .{ .extra_range = span },
});
}
}