blob: a37569614028afa9c3def05d7606669b82446d76 [file] [log] [blame]
use crate::grammar::attributes::ATTRIBUTE_FIRST;
use super::*;
// test struct_item
// struct S {}
pub(super) fn strukt(p: &mut Parser<'_>, m: Marker) {
p.bump(T![struct]);
struct_or_union(p, m, true);
}
// test union_item
// struct U { i: i32, f: f32 }
pub(super) fn union(p: &mut Parser<'_>, m: Marker) {
assert!(p.at_contextual_kw(T![union]));
p.bump_remap(T![union]);
struct_or_union(p, m, false);
}
fn struct_or_union(p: &mut Parser<'_>, m: Marker, is_struct: bool) {
name_r(p, ITEM_RECOVERY_SET);
generic_params::opt_generic_param_list(p);
match p.current() {
T![where] => {
generic_params::opt_where_clause(p);
match p.current() {
T![;] => p.bump(T![;]),
T!['{'] => record_field_list(p),
_ => {
//FIXME: special case `(` error message
p.error("expected `;` or `{`");
}
}
}
T!['{'] => record_field_list(p),
// test unit_struct
// struct S;
T![;] if is_struct => {
p.bump(T![;]);
}
// test tuple_struct
// struct S(String, usize);
T!['('] if is_struct => {
tuple_field_list(p);
// test tuple_struct_where
// struct S<T>(T) where T: Clone;
generic_params::opt_where_clause(p);
p.expect(T![;]);
}
_ => p.error(if is_struct { "expected `;`, `{`, or `(`" } else { "expected `{`" }),
}
m.complete(p, if is_struct { STRUCT } else { UNION });
}
pub(super) fn enum_(p: &mut Parser<'_>, m: Marker) {
p.bump(T![enum]);
name_r(p, ITEM_RECOVERY_SET);
generic_params::opt_generic_param_list(p);
generic_params::opt_where_clause(p);
if p.at(T!['{']) {
variant_list(p);
} else {
p.error("expected `{`");
}
m.complete(p, ENUM);
}
pub(crate) fn variant_list(p: &mut Parser<'_>) {
assert!(p.at(T!['{']));
let m = p.start();
p.bump(T!['{']);
while !p.at(EOF) && !p.at(T!['}']) {
if p.at(T!['{']) {
error_block(p, "expected enum variant");
continue;
}
variant(p);
if !p.at(T!['}']) {
p.expect(T![,]);
}
}
p.expect(T!['}']);
m.complete(p, VARIANT_LIST);
fn variant(p: &mut Parser<'_>) {
let m = p.start();
attributes::outer_attrs(p);
if p.at(IDENT) {
name(p);
match p.current() {
T!['{'] => record_field_list(p),
T!['('] => tuple_field_list(p),
_ => (),
}
// test variant_discriminant
// enum E { X(i32) = 10 }
if p.eat(T![=]) {
expressions::expr(p);
}
m.complete(p, VARIANT);
} else {
m.abandon(p);
p.err_and_bump("expected enum variant");
}
}
}
// test record_field_list
// struct S { a: i32, b: f32, unsafe c: u8 }
pub(crate) fn record_field_list(p: &mut Parser<'_>) {
assert!(p.at(T!['{']));
let m = p.start();
p.bump(T!['{']);
while !p.at(T!['}']) && !p.at(EOF) {
if p.at(T!['{']) {
error_block(p, "expected field");
continue;
}
record_field(p);
if !p.at(T!['}']) {
p.expect(T![,]);
}
}
p.expect(T!['}']);
m.complete(p, RECORD_FIELD_LIST);
fn record_field(p: &mut Parser<'_>) {
let m = p.start();
// test record_field_attrs
// struct S { #[attr] f: f32 }
attributes::outer_attrs(p);
opt_visibility(p, false);
p.eat(T![unsafe]);
if p.at(IDENT) {
name(p);
p.expect(T![:]);
types::type_(p);
// test record_field_default_values
// struct S { f: f32 = 0.0 }
if p.eat(T![=]) {
expressions::expr(p);
}
m.complete(p, RECORD_FIELD);
} else {
m.abandon(p);
p.err_and_bump("expected field declaration");
}
}
}
const TUPLE_FIELD_FIRST: TokenSet =
types::TYPE_FIRST.union(ATTRIBUTE_FIRST).union(VISIBILITY_FIRST);
// test_err tuple_field_list_recovery
// struct S(struct S;
// struct S(A,,B);
fn tuple_field_list(p: &mut Parser<'_>) {
assert!(p.at(T!['(']));
let m = p.start();
delimited(
p,
T!['('],
T![')'],
T![,],
|| "expected tuple field".into(),
TUPLE_FIELD_FIRST,
|p| {
let m = p.start();
// test tuple_field_attrs
// struct S (#[attr] f32);
attributes::outer_attrs(p);
let has_vis = opt_visibility(p, true);
if !p.at_ts(types::TYPE_FIRST) {
p.error("expected a type");
if has_vis {
m.complete(p, ERROR);
} else {
m.abandon(p);
}
return false;
}
types::type_(p);
m.complete(p, TUPLE_FIELD);
true
},
);
m.complete(p, TUPLE_FIELD_LIST);
}