diff options
Diffstat (limited to 'src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs')
-rw-r--r-- | src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs new file mode 100644 index 000000000..e7d30516b --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs @@ -0,0 +1,168 @@ +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 } +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); + if p.at(IDENT) { + name(p); + p.expect(T![:]); + types::type_(p); + m.complete(p, RECORD_FIELD); + } else { + m.abandon(p); + p.err_and_bump("expected field declaration"); + } + } +} + +fn tuple_field_list(p: &mut Parser<'_>) { + assert!(p.at(T!['('])); + let m = p.start(); + p.bump(T!['(']); + while !p.at(T![')']) && !p.at(EOF) { + let m = p.start(); + // test tuple_field_attrs + // struct S (#[attr] f32); + attributes::outer_attrs(p); + opt_visibility(p, true); + if !p.at_ts(types::TYPE_FIRST) { + p.error("expected a type"); + m.complete(p, ERROR); + break; + } + types::type_(p); + m.complete(p, TUPLE_FIELD); + + if !p.at(T![')']) { + p.expect(T![,]); + } + } + p.expect(T![')']); + m.complete(p, TUPLE_FIELD_LIST); +} |