Caller must have already verified the first token.
fn expectContainerDeclAuto(p: *Parse) !Node.Index
fn expectContainerDeclAuto(p: *Parse) !Node.Index {
const main_token = p.nextToken();
const arg_expr = switch (p.tokenTag(main_token)) {
.keyword_opaque => null,
.keyword_struct, .keyword_enum => blk: {
if (p.eatToken(.l_paren)) |_| {
const expr = try p.expectExpr();
_ = try p.expectToken(.r_paren);
break :blk expr;
} else {
break :blk null;
}
},
.keyword_union => blk: {
if (p.eatToken(.l_paren)) |_| {
if (p.eatToken(.keyword_enum)) |_| {
if (p.eatToken(.l_paren)) |_| {
const enum_tag_expr = try p.expectExpr();
_ = try p.expectToken(.r_paren);
_ = try p.expectToken(.r_paren);
_ = try p.expectToken(.l_brace);
const members = try p.parseContainerMembers();
const members_span = try members.toSpan(p);
_ = try p.expectToken(.r_brace);
return try p.addNode(.{
.tag = switch (members.trailing) {
true => .tagged_union_enum_tag_trailing,
false => .tagged_union_enum_tag,
},
.main_token = main_token,
.data = .{ .node_and_extra = .{
enum_tag_expr,
try p.addExtra(members_span),
} },
});
} else {
_ = try p.expectToken(.r_paren);
_ = try p.expectToken(.l_brace);
const members = try p.parseContainerMembers();
_ = try p.expectToken(.r_brace);
if (members.len <= 2) {
return try p.addNode(.{
.tag = switch (members.trailing) {
true => .tagged_union_two_trailing,
false => .tagged_union_two,
},
.main_token = main_token,
.data = members.data,
});
} else {
const span = try members.toSpan(p);
return try p.addNode(.{
.tag = switch (members.trailing) {
true => .tagged_union_trailing,
false => .tagged_union,
},
.main_token = main_token,
.data = .{ .extra_range = span },
});
}
}
} else {
const expr = try p.expectExpr();
_ = try p.expectToken(.r_paren);
break :blk expr;
}
} else {
break :blk null;
}
},
else => {
p.tok_i -= 1;
return p.fail(.expected_container);
},
};
_ = try p.expectToken(.l_brace);
const members = try p.parseContainerMembers();
_ = try p.expectToken(.r_brace);
if (arg_expr == null) {
if (members.len <= 2) {
return try p.addNode(.{
.tag = switch (members.trailing) {
true => .container_decl_two_trailing,
false => .container_decl_two,
},
.main_token = main_token,
.data = members.data,
});
} else {
const span = try members.toSpan(p);
return try p.addNode(.{
.tag = switch (members.trailing) {
true => .container_decl_trailing,
false => .container_decl,
},
.main_token = main_token,
.data = .{ .extra_range = span },
});
}
} else {
const span = try members.toSpan(p);
return try p.addNode(.{
.tag = switch (members.trailing) {
true => .container_decl_arg_trailing,
false => .container_decl_arg,
},
.main_token = main_token,
.data = .{ .node_and_extra = .{
arg_expr.?,
try p.addExtra(Node.SubRange{
.start = span.start,
.end = span.end,
}),
} },
});
}
}