aboutsummaryrefslogtreecommitdiff
path: root/crates/parser/src/grammar/items
diff options
context:
space:
mode:
authorZac Pullar-Strecker <[email protected]>2020-08-24 10:19:53 +0100
committerZac Pullar-Strecker <[email protected]>2020-08-24 10:20:13 +0100
commit7bbca7a1b3f9293d2f5cc5745199bc5f8396f2f0 (patch)
treebdb47765991cb973b2cd5481a088fac636bd326c /crates/parser/src/grammar/items
parentca464650eeaca6195891199a93f4f76cf3e7e697 (diff)
parente65d48d1fb3d4d91d9dc1148a7a836ff5c9a3c87 (diff)
Merge remote-tracking branch 'upstream/master' into 503-hover-doc-links
Diffstat (limited to 'crates/parser/src/grammar/items')
-rw-r--r--crates/parser/src/grammar/items/adt.rs178
-rw-r--r--crates/parser/src/grammar/items/consts.rs33
-rw-r--r--crates/parser/src/grammar/items/traits.rs131
-rw-r--r--crates/parser/src/grammar/items/use_item.rs132
4 files changed, 474 insertions, 0 deletions
diff --git a/crates/parser/src/grammar/items/adt.rs b/crates/parser/src/grammar/items/adt.rs
new file mode 100644
index 000000000..67c0c5697
--- /dev/null
+++ b/crates/parser/src/grammar/items/adt.rs
@@ -0,0 +1,178 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) fn strukt(p: &mut Parser, m: Marker) {
6 assert!(p.at(T![struct]));
7 p.bump(T![struct]);
8 struct_or_union(p, m, T![struct], STRUCT);
9}
10
11pub(super) fn union(p: &mut Parser, m: Marker) {
12 assert!(p.at_contextual_kw("union"));
13 p.bump_remap(T![union]);
14 struct_or_union(p, m, T![union], UNION);
15}
16
17fn struct_or_union(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) {
18 name_r(p, ITEM_RECOVERY_SET);
19 type_params::opt_generic_param_list(p);
20 match p.current() {
21 T![where] => {
22 type_params::opt_where_clause(p);
23 match p.current() {
24 T![;] => {
25 p.bump(T![;]);
26 }
27 T!['{'] => record_field_list(p),
28 _ => {
29 //FIXME: special case `(` error message
30 p.error("expected `;` or `{`");
31 }
32 }
33 }
34 T![;] if kw == T![struct] => {
35 p.bump(T![;]);
36 }
37 T!['{'] => record_field_list(p),
38 T!['('] if kw == T![struct] => {
39 tuple_field_list(p);
40 // test tuple_struct_where
41 // struct Test<T>(T) where T: Clone;
42 // struct Test<T>(T);
43 type_params::opt_where_clause(p);
44 p.expect(T![;]);
45 }
46 _ if kw == T![struct] => {
47 p.error("expected `;`, `{`, or `(`");
48 }
49 _ => {
50 p.error("expected `{`");
51 }
52 }
53 m.complete(p, def);
54}
55
56pub(super) fn enum_(p: &mut Parser, m: Marker) {
57 assert!(p.at(T![enum]));
58 p.bump(T![enum]);
59 name_r(p, ITEM_RECOVERY_SET);
60 type_params::opt_generic_param_list(p);
61 type_params::opt_where_clause(p);
62 if p.at(T!['{']) {
63 variant_list(p);
64 } else {
65 p.error("expected `{`")
66 }
67 m.complete(p, ENUM);
68}
69
70pub(crate) fn variant_list(p: &mut Parser) {
71 assert!(p.at(T!['{']));
72 let m = p.start();
73 p.bump(T!['{']);
74 while !p.at(EOF) && !p.at(T!['}']) {
75 if p.at(T!['{']) {
76 error_block(p, "expected enum variant");
77 continue;
78 }
79 let var = p.start();
80 attributes::outer_attrs(p);
81 if p.at(IDENT) {
82 name(p);
83 match p.current() {
84 T!['{'] => record_field_list(p),
85 T!['('] => tuple_field_list(p),
86 _ => (),
87 }
88
89 // test variant_discriminant
90 // enum E { X(i32) = 10 }
91 if p.eat(T![=]) {
92 expressions::expr(p);
93 }
94 var.complete(p, VARIANT);
95 } else {
96 var.abandon(p);
97 p.err_and_bump("expected enum variant");
98 }
99 if !p.at(T!['}']) {
100 p.expect(T![,]);
101 }
102 }
103 p.expect(T!['}']);
104 m.complete(p, VARIANT_LIST);
105}
106
107pub(crate) fn record_field_list(p: &mut Parser) {
108 assert!(p.at(T!['{']));
109 let m = p.start();
110 p.bump(T!['{']);
111 while !p.at(T!['}']) && !p.at(EOF) {
112 if p.at(T!['{']) {
113 error_block(p, "expected field");
114 continue;
115 }
116 record_field_def(p);
117 if !p.at(T!['}']) {
118 p.expect(T![,]);
119 }
120 }
121 p.expect(T!['}']);
122 m.complete(p, RECORD_FIELD_LIST);
123
124 fn record_field_def(p: &mut Parser) {
125 let m = p.start();
126 // test record_field_attrs
127 // struct S {
128 // #[serde(with = "url_serde")]
129 // pub uri: Uri,
130 // }
131 attributes::outer_attrs(p);
132 opt_visibility(p);
133 if p.at(IDENT) {
134 name(p);
135 p.expect(T![:]);
136 types::type_(p);
137 m.complete(p, RECORD_FIELD);
138 } else {
139 m.abandon(p);
140 p.err_and_bump("expected field declaration");
141 }
142 }
143}
144
145fn tuple_field_list(p: &mut Parser) {
146 assert!(p.at(T!['(']));
147 let m = p.start();
148 if !p.expect(T!['(']) {
149 return;
150 }
151 while !p.at(T![')']) && !p.at(EOF) {
152 let m = p.start();
153 // test tuple_field_attrs
154 // struct S (
155 // #[serde(with = "url_serde")]
156 // pub Uri,
157 // );
158 //
159 // enum S {
160 // Uri(#[serde(with = "url_serde")] Uri),
161 // }
162 attributes::outer_attrs(p);
163 opt_visibility(p);
164 if !p.at_ts(types::TYPE_FIRST) {
165 p.error("expected a type");
166 m.complete(p, ERROR);
167 break;
168 }
169 types::type_(p);
170 m.complete(p, TUPLE_FIELD);
171
172 if !p.at(T![')']) {
173 p.expect(T![,]);
174 }
175 }
176 p.expect(T![')']);
177 m.complete(p, TUPLE_FIELD_LIST);
178}
diff --git a/crates/parser/src/grammar/items/consts.rs b/crates/parser/src/grammar/items/consts.rs
new file mode 100644
index 000000000..eb7d1f828
--- /dev/null
+++ b/crates/parser/src/grammar/items/consts.rs
@@ -0,0 +1,33 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) fn static_(p: &mut Parser, m: Marker) {
6 const_or_static(p, m, T![static], STATIC)
7}
8
9pub(super) fn konst(p: &mut Parser, m: Marker) {
10 const_or_static(p, m, T![const], CONST)
11}
12
13fn const_or_static(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) {
14 assert!(p.at(kw));
15 p.bump(kw);
16 p.eat(T![mut]); // FIXME: validator to forbid const mut
17
18 // Allow `_` in place of an identifier in a `const`.
19 let is_const_underscore = kw == T![const] && p.eat(T![_]);
20 if !is_const_underscore {
21 name(p);
22 }
23
24 // test_err static_underscore
25 // static _: i32 = 5;
26
27 types::ascription(p);
28 if p.eat(T![=]) {
29 expressions::expr(p);
30 }
31 p.expect(T![;]);
32 m.complete(p, def);
33}
diff --git a/crates/parser/src/grammar/items/traits.rs b/crates/parser/src/grammar/items/traits.rs
new file mode 100644
index 000000000..8394020da
--- /dev/null
+++ b/crates/parser/src/grammar/items/traits.rs
@@ -0,0 +1,131 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5// test trait_item
6// trait T<U>: Hash + Clone where U: Copy {}
7// trait X<U: Debug + Display>: Hash + Clone where U: Copy {}
8pub(super) fn trait_(p: &mut Parser) {
9 assert!(p.at(T![trait]));
10 p.bump(T![trait]);
11 name_r(p, ITEM_RECOVERY_SET);
12 type_params::opt_generic_param_list(p);
13 // test trait_alias
14 // trait Z<U> = T<U>;
15 // trait Z<U> = T<U> where U: Copy;
16 // trait Z<U> = where Self: T<U>;
17 if p.eat(T![=]) {
18 type_params::bounds_without_colon(p);
19 type_params::opt_where_clause(p);
20 p.expect(T![;]);
21 return;
22 }
23 if p.at(T![:]) {
24 type_params::bounds(p);
25 }
26 type_params::opt_where_clause(p);
27 if p.at(T!['{']) {
28 assoc_item_list(p);
29 } else {
30 p.error("expected `{`");
31 }
32}
33
34// test impl_def
35// impl Foo {}
36pub(super) fn impl_(p: &mut Parser) {
37 assert!(p.at(T![impl]));
38 p.bump(T![impl]);
39 if choose_type_params_over_qpath(p) {
40 type_params::opt_generic_param_list(p);
41 }
42
43 // FIXME: never type
44 // impl ! {}
45
46 // test impl_def_neg
47 // impl !Send for X {}
48 p.eat(T![!]);
49 impl_type(p);
50 if p.eat(T![for]) {
51 impl_type(p);
52 }
53 type_params::opt_where_clause(p);
54 if p.at(T!['{']) {
55 assoc_item_list(p);
56 } else {
57 p.error("expected `{`");
58 }
59}
60
61// test impl_item_list
62// impl F {
63// type A = i32;
64// const B: i32 = 92;
65// fn foo() {}
66// fn bar(&self) {}
67// }
68pub(crate) fn assoc_item_list(p: &mut Parser) {
69 assert!(p.at(T!['{']));
70 let m = p.start();
71 p.bump(T!['{']);
72 // test impl_inner_attributes
73 // enum F{}
74 // impl F {
75 // //! This is a doc comment
76 // #![doc("This is also a doc comment")]
77 // }
78 attributes::inner_attrs(p);
79
80 while !p.at(EOF) && !p.at(T!['}']) {
81 if p.at(T!['{']) {
82 error_block(p, "expected an item");
83 continue;
84 }
85 item_or_macro(p, true);
86 }
87 p.expect(T!['}']);
88 m.complete(p, ASSOC_ITEM_LIST);
89}
90
91// test impl_type_params
92// impl<const N: u32> Bar<N> {}
93fn choose_type_params_over_qpath(p: &Parser) -> bool {
94 // There's an ambiguity between generic parameters and qualified paths in impls.
95 // If we see `<` it may start both, so we have to inspect some following tokens.
96 // The following combinations can only start generics,
97 // but not qualified paths (with one exception):
98 // `<` `>` - empty generic parameters
99 // `<` `#` - generic parameters with attributes
100 // `<` `const` - const generic parameters
101 // `<` (LIFETIME|IDENT) `>` - single generic parameter
102 // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list
103 // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds
104 // `<` (LIFETIME|IDENT) `=` - generic parameter with a default
105 // The only truly ambiguous case is
106 // `<` IDENT `>` `::` IDENT ...
107 // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`)
108 // because this is what almost always expected in practice, qualified paths in impls
109 // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment.
110 if !p.at(T![<]) {
111 return false;
112 }
113 if p.nth(1) == T![#] || p.nth(1) == T![>] || p.nth(1) == CONST_KW {
114 return true;
115 }
116 (p.nth(1) == LIFETIME || p.nth(1) == IDENT)
117 && (p.nth(2) == T![>] || p.nth(2) == T![,] || p.nth(2) == T![:] || p.nth(2) == T![=])
118}
119
120// test_err impl_type
121// impl Type {}
122// impl Trait1 for T {}
123// impl impl NotType {}
124// impl Trait2 for impl NotType {}
125pub(crate) fn impl_type(p: &mut Parser) {
126 if p.at(T![impl]) {
127 p.error("expected trait or type");
128 return;
129 }
130 types::type_(p);
131}
diff --git a/crates/parser/src/grammar/items/use_item.rs b/crates/parser/src/grammar/items/use_item.rs
new file mode 100644
index 000000000..20e6a13cf
--- /dev/null
+++ b/crates/parser/src/grammar/items/use_item.rs
@@ -0,0 +1,132 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) fn use_(p: &mut Parser, m: Marker) {
6 assert!(p.at(T![use]));
7 p.bump(T![use]);
8 use_tree(p, true);
9 p.expect(T![;]);
10 m.complete(p, USE);
11}
12
13/// Parse a use 'tree', such as `some::path` in `use some::path;`
14/// Note that this is called both by `use_item` and `use_tree_list`,
15/// so handles both `some::path::{inner::path}` and `inner::path` in
16/// `use some::path::{inner::path};`
17fn use_tree(p: &mut Parser, top_level: bool) {
18 let m = p.start();
19 match p.current() {
20 // Finish the use_tree for cases of e.g.
21 // `use some::path::{self, *};` or `use *;`
22 // This does not handle cases such as `use some::path::*`
23 // N.B. in Rust 2015 `use *;` imports all from crate root
24 // however in Rust 2018 `use *;` errors: ('cannot glob-import all possible crates')
25 // FIXME: Add this error (if not out of scope)
26
27 // test use_star
28 // use *;
29 // use ::*;
30 // use some::path::{*};
31 // use some::path::{::*};
32 T![*] => p.bump(T![*]),
33 T![:] if p.at(T![::]) && p.nth(2) == T![*] => {
34 // Parse `use ::*;`, which imports all from the crate root in Rust 2015
35 // This is invalid inside a use_tree_list, (e.g. `use some::path::{::*}`)
36 // but still parses and errors later: ('crate root in paths can only be used in start position')
37 // FIXME: Add this error (if not out of scope)
38 // In Rust 2018, it is always invalid (see above)
39 p.bump(T![::]);
40 p.bump(T![*]);
41 }
42 // Open a use tree list
43 // Handles cases such as `use {some::path};` or `{inner::path}` in
44 // `use some::path::{{inner::path}, other::path}`
45
46 // test use_tree_list
47 // use {crate::path::from::root, or::path::from::crate_name}; // Rust 2018 (with a crate named `or`)
48 // use {path::from::root}; // Rust 2015
49 // use ::{some::arbritrary::path}; // Rust 2015
50 // use ::{{{root::export}}}; // Nonsensical but perfectly legal nesting
51 T!['{'] => {
52 use_tree_list(p);
53 }
54 T![:] if p.at(T![::]) && p.nth(2) == T!['{'] => {
55 p.bump(T![::]);
56 use_tree_list(p);
57 }
58 // Parse a 'standard' path.
59 // Also handles aliases (e.g. `use something as something_else`)
60
61 // test use_path
62 // use ::crate_name; // Rust 2018 - All flavours
63 // use crate_name; // Rust 2018 - Anchored paths
64 // use item_in_scope_or_crate_name; // Rust 2018 - Uniform Paths
65 //
66 // use self::module::Item;
67 // use crate::Item;
68 // use self::some::Struct;
69 // use crate_name::some_item;
70 _ if paths::is_use_path_start(p) => {
71 paths::use_path(p);
72 match p.current() {
73 T![as] => {
74 // test use_alias
75 // use some::path as some_name;
76 // use some::{
77 // other::path as some_other_name,
78 // different::path as different_name,
79 // yet::another::path,
80 // running::out::of::synonyms::for_::different::*
81 // };
82 // use Trait as _;
83 opt_rename(p);
84 }
85 T![:] if p.at(T![::]) => {
86 p.bump(T![::]);
87 match p.current() {
88 T![*] => {
89 p.bump(T![*]);
90 }
91 // test use_tree_list_after_path
92 // use crate::{Item};
93 // use self::{Item};
94 T!['{'] => use_tree_list(p),
95 _ => {
96 // is this unreachable?
97 p.error("expected `{` or `*`");
98 }
99 }
100 }
101 _ => (),
102 }
103 }
104 _ => {
105 m.abandon(p);
106 let msg = "expected one of `*`, `::`, `{`, `self`, `super` or an identifier";
107 if top_level {
108 p.err_recover(msg, ITEM_RECOVERY_SET);
109 } else {
110 // if we are parsing a nested tree, we have to eat a token to
111 // main balanced `{}`
112 p.err_and_bump(msg);
113 }
114 return;
115 }
116 }
117 m.complete(p, USE_TREE);
118}
119
120pub(crate) fn use_tree_list(p: &mut Parser) {
121 assert!(p.at(T!['{']));
122 let m = p.start();
123 p.bump(T!['{']);
124 while !p.at(EOF) && !p.at(T!['}']) {
125 use_tree(p, false);
126 if !p.at(T!['}']) {
127 p.expect(T![,]);
128 }
129 }
130 p.expect(T!['}']);
131 m.complete(p, USE_TREE_LIST);
132}