aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/parsing/grammar/items
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/parsing/grammar/items')
-rw-r--r--crates/ra_syntax/src/parsing/grammar/items/consts.rs21
-rw-r--r--crates/ra_syntax/src/parsing/grammar/items/nominal.rs168
-rw-r--r--crates/ra_syntax/src/parsing/grammar/items/traits.rs137
-rw-r--r--crates/ra_syntax/src/parsing/grammar/items/use_item.rs121
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 @@
1use super::*;
2
3pub(super) fn static_def(p: &mut Parser) {
4 const_or_static(p, STATIC_KW)
5}
6
7pub(super) fn const_def(p: &mut Parser) {
8 const_or_static(p, CONST_KW)
9}
10
11fn 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 @@
1use super::*;
2
3pub(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
49pub(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
62pub(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
97pub(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
135fn 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 @@
1use super::*;
2
3// test trait_item
4// trait T<U>: Hash + Clone where U: Copy {}
5pub(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// }
28pub(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 {}
45pub(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// }
77pub(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
100fn 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 {}
131pub(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 @@
1use super::*;
2
3pub(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};`
14fn 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
109pub(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}