diff options
Diffstat (limited to 'crates/parser/src/grammar/items')
-rw-r--r-- | crates/parser/src/grammar/items/adt.rs | 178 | ||||
-rw-r--r-- | crates/parser/src/grammar/items/consts.rs | 33 | ||||
-rw-r--r-- | crates/parser/src/grammar/items/traits.rs | 131 | ||||
-rw-r--r-- | crates/parser/src/grammar/items/use_item.rs | 132 |
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 | |||
3 | use super::*; | ||
4 | |||
5 | pub(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 | |||
11 | pub(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 | |||
17 | fn 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 | |||
56 | pub(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 | |||
70 | pub(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 | |||
107 | pub(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 | |||
145 | fn 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 | |||
3 | use super::*; | ||
4 | |||
5 | pub(super) fn static_(p: &mut Parser, m: Marker) { | ||
6 | const_or_static(p, m, T![static], STATIC) | ||
7 | } | ||
8 | |||
9 | pub(super) fn konst(p: &mut Parser, m: Marker) { | ||
10 | const_or_static(p, m, T![const], CONST) | ||
11 | } | ||
12 | |||
13 | fn 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 | |||
3 | use 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 {} | ||
8 | pub(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 {} | ||
36 | pub(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 | // } | ||
68 | pub(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> {} | ||
93 | fn 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 {} | ||
125 | pub(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 | |||
3 | use super::*; | ||
4 | |||
5 | pub(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};` | ||
17 | fn 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 | |||
120 | pub(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 | } | ||