aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_parser/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_parser/src')
-rw-r--r--crates/ra_parser/src/grammar.rs12
-rw-r--r--crates/ra_parser/src/grammar/expressions.rs6
-rw-r--r--crates/ra_parser/src/grammar/items.rs20
-rw-r--r--crates/ra_parser/src/grammar/paths.rs15
-rw-r--r--crates/ra_parser/src/grammar/patterns.rs8
-rw-r--r--crates/ra_parser/src/grammar/type_params.rs11
-rw-r--r--crates/ra_parser/src/grammar/types.rs16
-rw-r--r--crates/ra_parser/src/parser.rs15
-rw-r--r--crates/ra_parser/src/syntax_kind.rs5
9 files changed, 68 insertions, 40 deletions
diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs
index be0cd5661..caedeead0 100644
--- a/crates/ra_parser/src/grammar.rs
+++ b/crates/ra_parser/src/grammar.rs
@@ -18,9 +18,10 @@
18//! // fn foo() {} 18//! // fn foo() {}
19//! ``` 19//! ```
20//! 20//!
21//! After adding a new inline-test, run `cargo collect-tests` to extract 21//! After adding a new inline-test, run `cargo xtask codegen` to
22//! it as a standalone text-fixture into `tests/data/parser/inline`, and 22//! extract it as a standalone text-fixture into
23//! run `cargo test` once to create the "gold" value. 23//! `crates/ra_syntax/test_data/parser/`, and run `cargo test` once to
24//! create the "gold" value.
24//! 25//!
25//! Coding convention: rules like `where_clause` always produce either a 26//! Coding convention: rules like `where_clause` always produce either a
26//! node or an error, rules like `opt_where_clause` may produce nothing. 27//! node or an error, rules like `opt_where_clause` may produce nothing.
@@ -72,10 +73,7 @@ pub(crate) mod fragments {
72 // Parse a meta item , which excluded [], e.g : #[ MetaItem ] 73 // Parse a meta item , which excluded [], e.g : #[ MetaItem ]
73 pub(crate) fn meta_item(p: &mut Parser) { 74 pub(crate) fn meta_item(p: &mut Parser) {
74 fn is_delimiter(p: &mut Parser) -> bool { 75 fn is_delimiter(p: &mut Parser) -> bool {
75 match p.current() { 76 matches!(p.current(), T!['{'] | T!['('] | T!['['])
76 T!['{'] | T!['('] | T!['['] => true,
77 _ => false,
78 }
79 } 77 }
80 78
81 if is_delimiter(p) { 79 if is_delimiter(p) {
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs
index d6e8df32a..6e72eea66 100644
--- a/crates/ra_parser/src/grammar/expressions.rs
+++ b/crates/ra_parser/src/grammar/expressions.rs
@@ -50,10 +50,8 @@ fn expr_no_struct(p: &mut Parser) {
50} 50}
51 51
52fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool { 52fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool {
53 match kind { 53 let forbid = matches!(kind, BIN_EXPR | RANGE_EXPR);
54 BIN_EXPR | RANGE_EXPR | IF_EXPR => false, 54 !forbid
55 _ => true,
56 }
57} 55}
58 56
59pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) { 57pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) {
diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs
index 67a924de5..97642bc24 100644
--- a/crates/ra_parser/src/grammar/items.rs
+++ b/crates/ra_parser/src/grammar/items.rs
@@ -118,7 +118,22 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul
118 && p.at_contextual_kw("default") 118 && p.at_contextual_kw("default")
119 && (match p.nth(1) { 119 && (match p.nth(1) {
120 T![impl] => true, 120 T![impl] => true,
121 T![fn] | T![type] => { 121 T![unsafe] => {
122 // test default_unsafe_impl
123 // default unsafe impl Foo {}
124
125 // test default_unsafe_fn
126 // impl T for Foo {
127 // default unsafe fn foo() {}
128 // }
129 if p.nth(2) == T![impl] || p.nth(2) == T![fn] {
130 p.bump_remap(T![default]);
131 p.bump(T![unsafe]);
132 has_mods = true;
133 }
134 false
135 }
136 T![fn] | T![type] | T![const] => {
122 if let ItemFlavor::Mod = flavor { 137 if let ItemFlavor::Mod = flavor {
123 true 138 true
124 } else { 139 } else {
@@ -198,6 +213,9 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul
198 // default type T = Bar; 213 // default type T = Bar;
199 // default fn foo() {} 214 // default fn foo() {}
200 // } 215 // }
216 T![const] => {
217 consts::const_def(p, m);
218 }
201 219
202 // test unsafe_default_impl 220 // test unsafe_default_impl
203 // unsafe default impl Foo {} 221 // unsafe default impl Foo {}
diff --git a/crates/ra_parser/src/grammar/paths.rs b/crates/ra_parser/src/grammar/paths.rs
index 332acc1a0..b503af1dc 100644
--- a/crates/ra_parser/src/grammar/paths.rs
+++ b/crates/ra_parser/src/grammar/paths.rs
@@ -3,7 +3,7 @@
3use super::*; 3use super::*;
4 4
5pub(super) const PATH_FIRST: TokenSet = 5pub(super) const PATH_FIRST: TokenSet =
6 token_set![IDENT, SELF_KW, SUPER_KW, CRATE_KW, COLON, L_ANGLE]; 6 token_set![IDENT, T![self], T![super], T![crate], T![:], T![<]];
7 7
8pub(super) fn is_path_start(p: &Parser) -> bool { 8pub(super) fn is_path_start(p: &Parser) -> bool {
9 is_use_path_start(p) || p.at(T![<]) 9 is_use_path_start(p) || p.at(T![<])
@@ -41,10 +41,7 @@ fn path(p: &mut Parser, mode: Mode) {
41 path_segment(p, mode, true); 41 path_segment(p, mode, true);
42 let mut qual = path.complete(p, PATH); 42 let mut qual = path.complete(p, PATH);
43 loop { 43 loop {
44 let use_tree = match p.nth(2) { 44 let use_tree = matches!(p.nth(2), T![*] | T!['{']);
45 T![*] | T!['{'] => true,
46 _ => false,
47 };
48 if p.at(T![::]) && !use_tree { 45 if p.at(T![::]) && !use_tree {
49 let path = qual.precede(p); 46 let path = qual.precede(p);
50 p.bump(T![::]); 47 p.bump(T![::]);
@@ -73,8 +70,10 @@ fn path_segment(p: &mut Parser, mode: Mode, first: bool) {
73 } 70 }
74 p.expect(T![>]); 71 p.expect(T![>]);
75 } else { 72 } else {
73 let mut empty = true;
76 if first { 74 if first {
77 p.eat(T![::]); 75 p.eat(T![::]);
76 empty = false;
78 } 77 }
79 match p.current() { 78 match p.current() {
80 IDENT => { 79 IDENT => {
@@ -86,6 +85,12 @@ fn path_segment(p: &mut Parser, mode: Mode, first: bool) {
86 T![self] | T![super] | T![crate] => p.bump_any(), 85 T![self] | T![super] | T![crate] => p.bump_any(),
87 _ => { 86 _ => {
88 p.err_recover("expected identifier", items::ITEM_RECOVERY_SET); 87 p.err_recover("expected identifier", items::ITEM_RECOVERY_SET);
88 if empty {
89 // test_err empty_segment
90 // use crate::;
91 m.abandon(p);
92 return;
93 }
89 } 94 }
90 }; 95 };
91 } 96 }
diff --git a/crates/ra_parser/src/grammar/patterns.rs b/crates/ra_parser/src/grammar/patterns.rs
index 68fb2fc73..427c0eb49 100644
--- a/crates/ra_parser/src/grammar/patterns.rs
+++ b/crates/ra_parser/src/grammar/patterns.rs
@@ -4,7 +4,7 @@ use super::*;
4 4
5pub(super) const PATTERN_FIRST: TokenSet = expressions::LITERAL_FIRST 5pub(super) const PATTERN_FIRST: TokenSet = expressions::LITERAL_FIRST
6 .union(paths::PATH_FIRST) 6 .union(paths::PATH_FIRST)
7 .union(token_set![BOX_KW, REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE, MINUS, DOT]); 7 .union(token_set![T![box], T![ref], T![mut], T!['('], T!['['], T![&], T![_], T![-], T![.]]);
8 8
9pub(crate) fn pattern(p: &mut Parser) { 9pub(crate) fn pattern(p: &mut Parser) {
10 pattern_r(p, PAT_RECOVERY_SET); 10 pattern_r(p, PAT_RECOVERY_SET);
@@ -88,7 +88,9 @@ fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> {
88 _ => bind_pat(p, true), 88 _ => bind_pat(p, true),
89 }, 89 },
90 90
91 _ if paths::is_use_path_start(p) => path_or_macro_pat(p), 91 // test type_path_in_pattern
92 // fn main() { let <_>::Foo = (); }
93 _ if paths::is_path_start(p) => path_or_macro_pat(p),
92 _ if is_literal_pat_start(p) => literal_pat(p), 94 _ if is_literal_pat_start(p) => literal_pat(p),
93 95
94 T![.] if p.at(T![..]) => dot_dot_pat(p), 96 T![.] if p.at(T![..]) => dot_dot_pat(p),
@@ -138,7 +140,7 @@ fn literal_pat(p: &mut Parser) -> CompletedMarker {
138// let Bar(..) = (); 140// let Bar(..) = ();
139// } 141// }
140fn path_or_macro_pat(p: &mut Parser) -> CompletedMarker { 142fn path_or_macro_pat(p: &mut Parser) -> CompletedMarker {
141 assert!(paths::is_use_path_start(p)); 143 assert!(paths::is_path_start(p));
142 let m = p.start(); 144 let m = p.start();
143 paths::expr_path(p); 145 paths::expr_path(p);
144 let kind = match p.current() { 146 let kind = match p.current() {
diff --git a/crates/ra_parser/src/grammar/type_params.rs b/crates/ra_parser/src/grammar/type_params.rs
index 50e4900c3..d1330d4b9 100644
--- a/crates/ra_parser/src/grammar/type_params.rs
+++ b/crates/ra_parser/src/grammar/type_params.rs
@@ -169,10 +169,7 @@ fn is_where_predicate(p: &mut Parser) -> bool {
169} 169}
170 170
171fn is_where_clause_end(p: &mut Parser) -> bool { 171fn is_where_clause_end(p: &mut Parser) -> bool {
172 match p.current() { 172 matches!(p.current(), T!['{'] | T![;] | T![=])
173 T!['{'] | T![;] | T![=] => true,
174 _ => false,
175 }
176} 173}
177 174
178fn where_predicate(p: &mut Parser) { 175fn where_predicate(p: &mut Parser) {
@@ -191,10 +188,14 @@ fn where_predicate(p: &mut Parser) {
191 } 188 }
192 _ => { 189 _ => {
193 // test where_pred_for 190 // test where_pred_for
194 // fn test<F>() 191 // fn for_trait<F>()
195 // where 192 // where
196 // for<'a> F: Fn(&'a str) 193 // for<'a> F: Fn(&'a str)
197 // { } 194 // { }
195 if p.at(T![for]) {
196 types::for_binder(p);
197 }
198
198 types::type_(p); 199 types::type_(p);
199 200
200 if p.at(T![:]) { 201 if p.at(T![:]) {
diff --git a/crates/ra_parser/src/grammar/types.rs b/crates/ra_parser/src/grammar/types.rs
index fe1a039cb..9e8e3bd97 100644
--- a/crates/ra_parser/src/grammar/types.rs
+++ b/crates/ra_parser/src/grammar/types.rs
@@ -216,19 +216,21 @@ pub(super) fn for_binder(p: &mut Parser) {
216 216
217// test for_type 217// test for_type
218// type A = for<'a> fn() -> (); 218// type A = for<'a> fn() -> ();
219// fn foo<T>(_t: &T) where for<'a> &'a T: Iterator {} 219// type B = for<'a> unsafe extern "C" fn(&'a ()) -> ();
220// fn bar<T>(_t: &T) where for<'a> &'a mut T: Iterator {} 220// type Obj = for<'a> PartialEq<&'a i32>;
221// fn baz<T>(_t: &T) where for<'a> <&'a T as Baz>::Foo: Iterator {}
222pub(super) fn for_type(p: &mut Parser) { 221pub(super) fn for_type(p: &mut Parser) {
223 assert!(p.at(T![for])); 222 assert!(p.at(T![for]));
224 let m = p.start(); 223 let m = p.start();
225 for_binder(p); 224 for_binder(p);
226 match p.current() { 225 match p.current() {
227 T![fn] | T![unsafe] | T![extern] => fn_pointer_type(p), 226 T![fn] | T![unsafe] | T![extern] => {}
228 T![&] => reference_type(p), 227 // OK: legacy trait object format
229 _ if paths::is_path_start(p) => path_type_(p, false), 228 _ if paths::is_use_path_start(p) => {}
230 _ => p.error("expected a path"), 229 _ => {
230 p.error("expected a function pointer or path");
231 }
231 } 232 }
233 type_no_bounds(p);
232 m.complete(p, FOR_TYPE); 234 m.complete(p, FOR_TYPE);
233} 235}
234 236
diff --git a/crates/ra_parser/src/parser.rs b/crates/ra_parser/src/parser.rs
index 4f59b0a23..d797f2cc9 100644
--- a/crates/ra_parser/src/parser.rs
+++ b/crates/ra_parser/src/parser.rs
@@ -127,17 +127,24 @@ impl<'t> Parser<'t> {
127 127
128 fn at_composite2(&self, n: usize, k1: SyntaxKind, k2: SyntaxKind) -> bool { 128 fn at_composite2(&self, n: usize, k1: SyntaxKind, k2: SyntaxKind) -> bool {
129 let t1 = self.token_source.lookahead_nth(n); 129 let t1 = self.token_source.lookahead_nth(n);
130 if t1.kind != k1 || !t1.is_jointed_to_next {
131 return false;
132 }
130 let t2 = self.token_source.lookahead_nth(n + 1); 133 let t2 = self.token_source.lookahead_nth(n + 1);
131 t1.kind == k1 && t1.is_jointed_to_next && t2.kind == k2 134 t2.kind == k2
132 } 135 }
133 136
134 fn at_composite3(&self, n: usize, k1: SyntaxKind, k2: SyntaxKind, k3: SyntaxKind) -> bool { 137 fn at_composite3(&self, n: usize, k1: SyntaxKind, k2: SyntaxKind, k3: SyntaxKind) -> bool {
135 let t1 = self.token_source.lookahead_nth(n); 138 let t1 = self.token_source.lookahead_nth(n);
139 if t1.kind != k1 || !t1.is_jointed_to_next {
140 return false;
141 }
136 let t2 = self.token_source.lookahead_nth(n + 1); 142 let t2 = self.token_source.lookahead_nth(n + 1);
143 if t2.kind != k2 || !t2.is_jointed_to_next {
144 return false;
145 }
137 let t3 = self.token_source.lookahead_nth(n + 2); 146 let t3 = self.token_source.lookahead_nth(n + 2);
138 (t1.kind == k1 && t1.is_jointed_to_next) 147 t3.kind == k3
139 && (t2.kind == k2 && t2.is_jointed_to_next)
140 && t3.kind == k3
141 } 148 }
142 149
143 /// Checks if the current token is in `kinds`. 150 /// Checks if the current token is in `kinds`.
diff --git a/crates/ra_parser/src/syntax_kind.rs b/crates/ra_parser/src/syntax_kind.rs
index 8d6bd057b..63204436c 100644
--- a/crates/ra_parser/src/syntax_kind.rs
+++ b/crates/ra_parser/src/syntax_kind.rs
@@ -20,9 +20,6 @@ impl From<SyntaxKind> for u16 {
20 20
21impl SyntaxKind { 21impl SyntaxKind {
22 pub fn is_trivia(self) -> bool { 22 pub fn is_trivia(self) -> bool {
23 match self { 23 matches!(self, SyntaxKind::WHITESPACE | SyntaxKind::COMMENT)
24 SyntaxKind::WHITESPACE | SyntaxKind::COMMENT => true,
25 _ => false,
26 }
27 } 24 }
28} 25}