diff options
author | Aleksey Kladov <[email protected]> | 2019-02-20 12:47:32 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-02-20 12:47:32 +0000 |
commit | 5222b8aba3b1c2c68706aacf6869423a8e4fe6d5 (patch) | |
tree | c8a6e999b8ac5f1f29bde86a2e0b3a53466bb369 /crates/ra_syntax/src/parsing/grammar/items | |
parent | 9d0cda4bc84350961f3884e75a1c20e62c449ede (diff) |
move all parsing related bits to a separate module
Diffstat (limited to 'crates/ra_syntax/src/parsing/grammar/items')
-rw-r--r-- | crates/ra_syntax/src/parsing/grammar/items/consts.rs | 21 | ||||
-rw-r--r-- | crates/ra_syntax/src/parsing/grammar/items/nominal.rs | 168 | ||||
-rw-r--r-- | crates/ra_syntax/src/parsing/grammar/items/traits.rs | 137 | ||||
-rw-r--r-- | crates/ra_syntax/src/parsing/grammar/items/use_item.rs | 121 |
4 files changed, 447 insertions, 0 deletions
diff --git a/crates/ra_syntax/src/parsing/grammar/items/consts.rs b/crates/ra_syntax/src/parsing/grammar/items/consts.rs new file mode 100644 index 000000000..5a5852f83 --- /dev/null +++ b/crates/ra_syntax/src/parsing/grammar/items/consts.rs | |||
@@ -0,0 +1,21 @@ | |||
1 | use super::*; | ||
2 | |||
3 | pub(super) fn static_def(p: &mut Parser) { | ||
4 | const_or_static(p, STATIC_KW) | ||
5 | } | ||
6 | |||
7 | pub(super) fn const_def(p: &mut Parser) { | ||
8 | const_or_static(p, CONST_KW) | ||
9 | } | ||
10 | |||
11 | fn const_or_static(p: &mut Parser, kw: SyntaxKind) { | ||
12 | assert!(p.at(kw)); | ||
13 | p.bump(); | ||
14 | p.eat(MUT_KW); // TODO: validator to forbid const mut | ||
15 | name(p); | ||
16 | types::ascription(p); | ||
17 | if p.eat(EQ) { | ||
18 | expressions::expr(p); | ||
19 | } | ||
20 | p.expect(SEMI); | ||
21 | } | ||
diff --git a/crates/ra_syntax/src/parsing/grammar/items/nominal.rs b/crates/ra_syntax/src/parsing/grammar/items/nominal.rs new file mode 100644 index 000000000..ff9b38f9c --- /dev/null +++ b/crates/ra_syntax/src/parsing/grammar/items/nominal.rs | |||
@@ -0,0 +1,168 @@ | |||
1 | use super::*; | ||
2 | |||
3 | pub(super) fn struct_def(p: &mut Parser, kind: SyntaxKind) { | ||
4 | assert!(p.at(STRUCT_KW) || p.at_contextual_kw("union")); | ||
5 | p.bump_remap(kind); | ||
6 | |||
7 | name_r(p, ITEM_RECOVERY_SET); | ||
8 | type_params::opt_type_param_list(p); | ||
9 | match p.current() { | ||
10 | WHERE_KW => { | ||
11 | type_params::opt_where_clause(p); | ||
12 | match p.current() { | ||
13 | SEMI => { | ||
14 | p.bump(); | ||
15 | return; | ||
16 | } | ||
17 | L_CURLY => named_field_def_list(p), | ||
18 | _ => { | ||
19 | //TODO: special case `(` error message | ||
20 | p.error("expected `;` or `{`"); | ||
21 | return; | ||
22 | } | ||
23 | } | ||
24 | } | ||
25 | SEMI if kind == STRUCT_KW => { | ||
26 | p.bump(); | ||
27 | return; | ||
28 | } | ||
29 | L_CURLY => named_field_def_list(p), | ||
30 | L_PAREN if kind == STRUCT_KW => { | ||
31 | pos_field_def_list(p); | ||
32 | // test tuple_struct_where | ||
33 | // struct Test<T>(T) where T: Clone; | ||
34 | // struct Test<T>(T); | ||
35 | type_params::opt_where_clause(p); | ||
36 | p.expect(SEMI); | ||
37 | } | ||
38 | _ if kind == STRUCT_KW => { | ||
39 | p.error("expected `;`, `{`, or `(`"); | ||
40 | return; | ||
41 | } | ||
42 | _ => { | ||
43 | p.error("expected `{`"); | ||
44 | return; | ||
45 | } | ||
46 | } | ||
47 | } | ||
48 | |||
49 | pub(super) fn enum_def(p: &mut Parser) { | ||
50 | assert!(p.at(ENUM_KW)); | ||
51 | p.bump(); | ||
52 | name_r(p, ITEM_RECOVERY_SET); | ||
53 | type_params::opt_type_param_list(p); | ||
54 | type_params::opt_where_clause(p); | ||
55 | if p.at(L_CURLY) { | ||
56 | enum_variant_list(p); | ||
57 | } else { | ||
58 | p.error("expected `{`") | ||
59 | } | ||
60 | } | ||
61 | |||
62 | pub(crate) fn enum_variant_list(p: &mut Parser) { | ||
63 | assert!(p.at(L_CURLY)); | ||
64 | let m = p.start(); | ||
65 | p.bump(); | ||
66 | while !p.at(EOF) && !p.at(R_CURLY) { | ||
67 | if p.at(L_CURLY) { | ||
68 | error_block(p, "expected enum variant"); | ||
69 | continue; | ||
70 | } | ||
71 | let var = p.start(); | ||
72 | attributes::outer_attributes(p); | ||
73 | if p.at(IDENT) { | ||
74 | name(p); | ||
75 | match p.current() { | ||
76 | L_CURLY => named_field_def_list(p), | ||
77 | L_PAREN => pos_field_def_list(p), | ||
78 | EQ => { | ||
79 | p.bump(); | ||
80 | expressions::expr(p); | ||
81 | } | ||
82 | _ => (), | ||
83 | } | ||
84 | var.complete(p, ENUM_VARIANT); | ||
85 | } else { | ||
86 | var.abandon(p); | ||
87 | p.err_and_bump("expected enum variant"); | ||
88 | } | ||
89 | if !p.at(R_CURLY) { | ||
90 | p.expect(COMMA); | ||
91 | } | ||
92 | } | ||
93 | p.expect(R_CURLY); | ||
94 | m.complete(p, ENUM_VARIANT_LIST); | ||
95 | } | ||
96 | |||
97 | pub(crate) fn named_field_def_list(p: &mut Parser) { | ||
98 | assert!(p.at(L_CURLY)); | ||
99 | let m = p.start(); | ||
100 | p.bump(); | ||
101 | while !p.at(R_CURLY) && !p.at(EOF) { | ||
102 | if p.at(L_CURLY) { | ||
103 | error_block(p, "expected field"); | ||
104 | continue; | ||
105 | } | ||
106 | named_field_def(p); | ||
107 | if !p.at(R_CURLY) { | ||
108 | p.expect(COMMA); | ||
109 | } | ||
110 | } | ||
111 | p.expect(R_CURLY); | ||
112 | m.complete(p, NAMED_FIELD_DEF_LIST); | ||
113 | |||
114 | fn named_field_def(p: &mut Parser) { | ||
115 | let m = p.start(); | ||
116 | // test field_attrs | ||
117 | // struct S { | ||
118 | // #[serde(with = "url_serde")] | ||
119 | // pub uri: Uri, | ||
120 | // } | ||
121 | attributes::outer_attributes(p); | ||
122 | opt_visibility(p); | ||
123 | if p.at(IDENT) { | ||
124 | name(p); | ||
125 | p.expect(COLON); | ||
126 | types::type_(p); | ||
127 | m.complete(p, NAMED_FIELD_DEF); | ||
128 | } else { | ||
129 | m.abandon(p); | ||
130 | p.err_and_bump("expected field declaration"); | ||
131 | } | ||
132 | } | ||
133 | } | ||
134 | |||
135 | fn pos_field_def_list(p: &mut Parser) { | ||
136 | assert!(p.at(L_PAREN)); | ||
137 | let m = p.start(); | ||
138 | if !p.expect(L_PAREN) { | ||
139 | return; | ||
140 | } | ||
141 | while !p.at(R_PAREN) && !p.at(EOF) { | ||
142 | let m = p.start(); | ||
143 | // test pos_field_attrs | ||
144 | // struct S ( | ||
145 | // #[serde(with = "url_serde")] | ||
146 | // pub Uri, | ||
147 | // ); | ||
148 | // | ||
149 | // enum S { | ||
150 | // Uri(#[serde(with = "url_serde")] Uri), | ||
151 | // } | ||
152 | attributes::outer_attributes(p); | ||
153 | opt_visibility(p); | ||
154 | if !p.at_ts(types::TYPE_FIRST) { | ||
155 | p.error("expected a type"); | ||
156 | m.complete(p, ERROR); | ||
157 | break; | ||
158 | } | ||
159 | types::type_(p); | ||
160 | m.complete(p, POS_FIELD_DEF); | ||
161 | |||
162 | if !p.at(R_PAREN) { | ||
163 | p.expect(COMMA); | ||
164 | } | ||
165 | } | ||
166 | p.expect(R_PAREN); | ||
167 | m.complete(p, POS_FIELD_DEF_LIST); | ||
168 | } | ||
diff --git a/crates/ra_syntax/src/parsing/grammar/items/traits.rs b/crates/ra_syntax/src/parsing/grammar/items/traits.rs new file mode 100644 index 000000000..d5a8ccd98 --- /dev/null +++ b/crates/ra_syntax/src/parsing/grammar/items/traits.rs | |||
@@ -0,0 +1,137 @@ | |||
1 | use super::*; | ||
2 | |||
3 | // test trait_item | ||
4 | // trait T<U>: Hash + Clone where U: Copy {} | ||
5 | pub(super) fn trait_def(p: &mut Parser) { | ||
6 | assert!(p.at(TRAIT_KW)); | ||
7 | p.bump(); | ||
8 | name_r(p, ITEM_RECOVERY_SET); | ||
9 | type_params::opt_type_param_list(p); | ||
10 | if p.at(COLON) { | ||
11 | type_params::bounds(p); | ||
12 | } | ||
13 | type_params::opt_where_clause(p); | ||
14 | if p.at(L_CURLY) { | ||
15 | trait_item_list(p); | ||
16 | } else { | ||
17 | p.error("expected `{`"); | ||
18 | } | ||
19 | } | ||
20 | |||
21 | // test trait_item_list | ||
22 | // impl F { | ||
23 | // type A: Clone; | ||
24 | // const B: i32; | ||
25 | // fn foo() {} | ||
26 | // fn bar(&self); | ||
27 | // } | ||
28 | pub(crate) fn trait_item_list(p: &mut Parser) { | ||
29 | assert!(p.at(L_CURLY)); | ||
30 | let m = p.start(); | ||
31 | p.bump(); | ||
32 | while !p.at(EOF) && !p.at(R_CURLY) { | ||
33 | if p.at(L_CURLY) { | ||
34 | error_block(p, "expected an item"); | ||
35 | continue; | ||
36 | } | ||
37 | item_or_macro(p, true, ItemFlavor::Trait); | ||
38 | } | ||
39 | p.expect(R_CURLY); | ||
40 | m.complete(p, ITEM_LIST); | ||
41 | } | ||
42 | |||
43 | // test impl_block | ||
44 | // impl Foo {} | ||
45 | pub(super) fn impl_block(p: &mut Parser) { | ||
46 | assert!(p.at(IMPL_KW)); | ||
47 | p.bump(); | ||
48 | if choose_type_params_over_qpath(p) { | ||
49 | type_params::opt_type_param_list(p); | ||
50 | } | ||
51 | |||
52 | // TODO: never type | ||
53 | // impl ! {} | ||
54 | |||
55 | // test impl_block_neg | ||
56 | // impl !Send for X {} | ||
57 | p.eat(EXCL); | ||
58 | impl_type(p); | ||
59 | if p.eat(FOR_KW) { | ||
60 | impl_type(p); | ||
61 | } | ||
62 | type_params::opt_where_clause(p); | ||
63 | if p.at(L_CURLY) { | ||
64 | impl_item_list(p); | ||
65 | } else { | ||
66 | p.error("expected `{`"); | ||
67 | } | ||
68 | } | ||
69 | |||
70 | // test impl_item_list | ||
71 | // impl F { | ||
72 | // type A = i32; | ||
73 | // const B: i32 = 92; | ||
74 | // fn foo() {} | ||
75 | // fn bar(&self) {} | ||
76 | // } | ||
77 | pub(crate) fn impl_item_list(p: &mut Parser) { | ||
78 | assert!(p.at(L_CURLY)); | ||
79 | let m = p.start(); | ||
80 | p.bump(); | ||
81 | // test impl_inner_attributes | ||
82 | // enum F{} | ||
83 | // impl F { | ||
84 | // //! This is a doc comment | ||
85 | // #![doc("This is also a doc comment")] | ||
86 | // } | ||
87 | attributes::inner_attributes(p); | ||
88 | |||
89 | while !p.at(EOF) && !p.at(R_CURLY) { | ||
90 | if p.at(L_CURLY) { | ||
91 | error_block(p, "expected an item"); | ||
92 | continue; | ||
93 | } | ||
94 | item_or_macro(p, true, ItemFlavor::Mod); | ||
95 | } | ||
96 | p.expect(R_CURLY); | ||
97 | m.complete(p, ITEM_LIST); | ||
98 | } | ||
99 | |||
100 | fn choose_type_params_over_qpath(p: &Parser) -> bool { | ||
101 | // There's an ambiguity between generic parameters and qualified paths in impls. | ||
102 | // If we see `<` it may start both, so we have to inspect some following tokens. | ||
103 | // The following combinations can only start generics, | ||
104 | // but not qualified paths (with one exception): | ||
105 | // `<` `>` - empty generic parameters | ||
106 | // `<` `#` - generic parameters with attributes | ||
107 | // `<` (LIFETIME|IDENT) `>` - single generic parameter | ||
108 | // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list | ||
109 | // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds | ||
110 | // `<` (LIFETIME|IDENT) `=` - generic parameter with a default | ||
111 | // The only truly ambiguous case is | ||
112 | // `<` IDENT `>` `::` IDENT ... | ||
113 | // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`) | ||
114 | // because this is what almost always expected in practice, qualified paths in impls | ||
115 | // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment. | ||
116 | if !p.at(L_ANGLE) { | ||
117 | return false; | ||
118 | } | ||
119 | if p.nth(1) == POUND || p.nth(1) == R_ANGLE { | ||
120 | return true; | ||
121 | } | ||
122 | (p.nth(1) == LIFETIME || p.nth(1) == IDENT) | ||
123 | && (p.nth(2) == R_ANGLE || p.nth(2) == COMMA || p.nth(2) == COLON || p.nth(2) == EQ) | ||
124 | } | ||
125 | |||
126 | // test_err impl_type | ||
127 | // impl Type {} | ||
128 | // impl Trait1 for T {} | ||
129 | // impl impl NotType {} | ||
130 | // impl Trait2 for impl NotType {} | ||
131 | pub(crate) fn impl_type(p: &mut Parser) { | ||
132 | if p.at(IMPL_KW) { | ||
133 | p.error("expected trait or type"); | ||
134 | return; | ||
135 | } | ||
136 | types::type_(p); | ||
137 | } | ||
diff --git a/crates/ra_syntax/src/parsing/grammar/items/use_item.rs b/crates/ra_syntax/src/parsing/grammar/items/use_item.rs new file mode 100644 index 000000000..5111d37eb --- /dev/null +++ b/crates/ra_syntax/src/parsing/grammar/items/use_item.rs | |||
@@ -0,0 +1,121 @@ | |||
1 | use super::*; | ||
2 | |||
3 | pub(super) fn use_item(p: &mut Parser) { | ||
4 | assert!(p.at(USE_KW)); | ||
5 | p.bump(); | ||
6 | use_tree(p); | ||
7 | p.expect(SEMI); | ||
8 | } | ||
9 | |||
10 | /// Parse a use 'tree', such as `some::path` in `use some::path;` | ||
11 | /// Note that this is called both by `use_item` and `use_tree_list`, | ||
12 | /// so handles both `some::path::{inner::path}` and `inner::path` in | ||
13 | /// `use some::path::{inner::path};` | ||
14 | fn use_tree(p: &mut Parser) { | ||
15 | let la = p.nth(1); | ||
16 | let m = p.start(); | ||
17 | match (p.current(), la) { | ||
18 | // Finish the use_tree for cases of e.g. | ||
19 | // `use some::path::{self, *};` or `use *;` | ||
20 | // This does not handle cases such as `use some::path::*` | ||
21 | // N.B. in Rust 2015 `use *;` imports all from crate root | ||
22 | // however in Rust 2018 `use *;` errors: ('cannot glob-import all possible crates') | ||
23 | // TODO: Add this error (if not out of scope) | ||
24 | |||
25 | // test use_star | ||
26 | // use *; | ||
27 | // use ::*; | ||
28 | // use some::path::{*}; | ||
29 | // use some::path::{::*}; | ||
30 | (STAR, _) => p.bump(), | ||
31 | (COLONCOLON, STAR) => { | ||
32 | // Parse `use ::*;`, which imports all from the crate root in Rust 2015 | ||
33 | // This is invalid inside a use_tree_list, (e.g. `use some::path::{::*}`) | ||
34 | // but still parses and errors later: ('crate root in paths can only be used in start position') | ||
35 | // TODO: Add this error (if not out of scope) | ||
36 | // In Rust 2018, it is always invalid (see above) | ||
37 | p.bump(); | ||
38 | p.bump(); | ||
39 | } | ||
40 | // Open a use tree list | ||
41 | // Handles cases such as `use {some::path};` or `{inner::path}` in | ||
42 | // `use some::path::{{inner::path}, other::path}` | ||
43 | |||
44 | // test use_tree_list | ||
45 | // use {crate::path::from::root, or::path::from::crate_name}; // Rust 2018 (with a crate named `or`) | ||
46 | // use {path::from::root}; // Rust 2015 | ||
47 | // use ::{some::arbritrary::path}; // Rust 2015 | ||
48 | // use ::{{{crate::export}}}; // Nonsensical but perfectly legal nestnig | ||
49 | (L_CURLY, _) | (COLONCOLON, L_CURLY) => { | ||
50 | if p.at(COLONCOLON) { | ||
51 | p.bump(); | ||
52 | } | ||
53 | use_tree_list(p); | ||
54 | } | ||
55 | // Parse a 'standard' path. | ||
56 | // Also handles aliases (e.g. `use something as something_else`) | ||
57 | |||
58 | // test use_path | ||
59 | // use ::crate_name; // Rust 2018 - All flavours | ||
60 | // use crate_name; // Rust 2018 - Anchored paths | ||
61 | // use item_in_scope_or_crate_name; // Rust 2018 - Uniform Paths | ||
62 | // | ||
63 | // use self::module::Item; | ||
64 | // use crate::Item; | ||
65 | // use self::some::Struct; | ||
66 | // use crate_name::some_item; | ||
67 | _ if paths::is_path_start(p) => { | ||
68 | paths::use_path(p); | ||
69 | match p.current() { | ||
70 | AS_KW => { | ||
71 | // test use_alias | ||
72 | // use some::path as some_name; | ||
73 | // use some::{ | ||
74 | // other::path as some_other_name, | ||
75 | // different::path as different_name, | ||
76 | // yet::another::path, | ||
77 | // running::out::of::synonyms::for_::different::* | ||
78 | // }; | ||
79 | opt_alias(p); | ||
80 | } | ||
81 | COLONCOLON => { | ||
82 | p.bump(); | ||
83 | match p.current() { | ||
84 | STAR => { | ||
85 | p.bump(); | ||
86 | } | ||
87 | // test use_tree_list_after_path | ||
88 | // use crate::{Item}; | ||
89 | // use self::{Item}; | ||
90 | L_CURLY => use_tree_list(p), | ||
91 | _ => { | ||
92 | // is this unreachable? | ||
93 | p.error("expected `{` or `*`"); | ||
94 | } | ||
95 | } | ||
96 | } | ||
97 | _ => (), | ||
98 | } | ||
99 | } | ||
100 | _ => { | ||
101 | m.abandon(p); | ||
102 | p.err_and_bump("expected one of `*`, `::`, `{`, `self`, `super` or an indentifier"); | ||
103 | return; | ||
104 | } | ||
105 | } | ||
106 | m.complete(p, USE_TREE); | ||
107 | } | ||
108 | |||
109 | pub(crate) fn use_tree_list(p: &mut Parser) { | ||
110 | assert!(p.at(L_CURLY)); | ||
111 | let m = p.start(); | ||
112 | p.bump(); | ||
113 | while !p.at(EOF) && !p.at(R_CURLY) { | ||
114 | use_tree(p); | ||
115 | if !p.at(R_CURLY) { | ||
116 | p.expect(COMMA); | ||
117 | } | ||
118 | } | ||
119 | p.expect(R_CURLY); | ||
120 | m.complete(p, USE_TREE_LIST); | ||
121 | } | ||