diff options
Diffstat (limited to 'crates/ra_syntax')
-rw-r--r-- | crates/ra_syntax/Cargo.toml | 4 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar/mod.rs | 5 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar/type_params.rs | 86 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar/types.rs | 13 | ||||
-rw-r--r-- | crates/ra_syntax/src/lib.rs | 3 | ||||
-rw-r--r-- | crates/ra_syntax/tests/data/parser/inline/0113_where_pred_for.rs | 4 | ||||
-rw-r--r-- | crates/ra_syntax/tests/data/parser/inline/0113_where_pred_for.txt | 58 |
7 files changed, 135 insertions, 38 deletions
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml index 043c9bacd..de4b25e67 100644 --- a/crates/ra_syntax/Cargo.toml +++ b/crates/ra_syntax/Cargo.toml | |||
@@ -1,9 +1,11 @@ | |||
1 | [package] | 1 | [package] |
2 | edition = "2018" | 2 | edition = "2015" |
3 | name = "ra_syntax" | 3 | name = "ra_syntax" |
4 | version = "0.1.0" | 4 | version = "0.1.0" |
5 | authors = ["Aleksey Kladov <[email protected]>"] | 5 | authors = ["Aleksey Kladov <[email protected]>"] |
6 | license = "MIT OR Apache-2.0" | 6 | license = "MIT OR Apache-2.0" |
7 | description = "Comment and whitespace preserving parser for the Rust langauge" | ||
8 | repository = "https://github.com/rust-analyzer/rust-analyzer" | ||
7 | 9 | ||
8 | [dependencies] | 10 | [dependencies] |
9 | unicode-xid = "0.1.0" | 11 | unicode-xid = "0.1.0" |
diff --git a/crates/ra_syntax/src/grammar/mod.rs b/crates/ra_syntax/src/grammar/mod.rs index c87564073..95c437983 100644 --- a/crates/ra_syntax/src/grammar/mod.rs +++ b/crates/ra_syntax/src/grammar/mod.rs | |||
@@ -21,6 +21,11 @@ | |||
21 | //! After adding a new inline-test, run `cargo collect-tests` to extract | 21 | //! After adding a new inline-test, run `cargo collect-tests` to extract |
22 | //! it as a standalone text-fixture into `tests/data/parser/inline`, and | 22 | //! it as a standalone text-fixture into `tests/data/parser/inline`, and |
23 | //! run `cargo test` once to create the "gold" value. | 23 | //! run `cargo test` once to create the "gold" value. |
24 | //! | ||
25 | //! Coding convention: rules like `where_clause` always produce either a | ||
26 | //! node or an error, rules like `opt_where_clause` may produce nothing. | ||
27 | //! Non-opt rules typically start with `assert!(p.at(FIRST_TOKEN))`, the | ||
28 | //! caller is responsible for branching on the first token. | ||
24 | mod attributes; | 29 | mod attributes; |
25 | mod expressions; | 30 | mod expressions; |
26 | mod items; | 31 | mod items; |
diff --git a/crates/ra_syntax/src/grammar/type_params.rs b/crates/ra_syntax/src/grammar/type_params.rs index 79f5036b4..68eca0ce8 100644 --- a/crates/ra_syntax/src/grammar/type_params.rs +++ b/crates/ra_syntax/src/grammar/type_params.rs | |||
@@ -4,6 +4,11 @@ pub(super) fn opt_type_param_list(p: &mut Parser) { | |||
4 | if !p.at(L_ANGLE) { | 4 | if !p.at(L_ANGLE) { |
5 | return; | 5 | return; |
6 | } | 6 | } |
7 | type_param_list(p); | ||
8 | } | ||
9 | |||
10 | fn type_param_list(p: &mut Parser) { | ||
11 | assert!(p.at(L_ANGLE)); | ||
7 | let m = p.start(); | 12 | let m = p.start(); |
8 | p.bump(); | 13 | p.bump(); |
9 | 14 | ||
@@ -19,32 +24,32 @@ pub(super) fn opt_type_param_list(p: &mut Parser) { | |||
19 | } | 24 | } |
20 | p.expect(R_ANGLE); | 25 | p.expect(R_ANGLE); |
21 | m.complete(p, TYPE_PARAM_LIST); | 26 | m.complete(p, TYPE_PARAM_LIST); |
27 | } | ||
22 | 28 | ||
23 | fn lifetime_param(p: &mut Parser) { | 29 | fn lifetime_param(p: &mut Parser) { |
24 | assert!(p.at(LIFETIME)); | 30 | assert!(p.at(LIFETIME)); |
25 | let m = p.start(); | 31 | let m = p.start(); |
26 | p.bump(); | 32 | p.bump(); |
27 | if p.at(COLON) { | 33 | if p.at(COLON) { |
28 | lifetime_bounds(p); | 34 | lifetime_bounds(p); |
29 | } | ||
30 | m.complete(p, LIFETIME_PARAM); | ||
31 | } | 35 | } |
36 | m.complete(p, LIFETIME_PARAM); | ||
37 | } | ||
32 | 38 | ||
33 | fn type_param(p: &mut Parser) { | 39 | fn type_param(p: &mut Parser) { |
34 | assert!(p.at(IDENT)); | 40 | assert!(p.at(IDENT)); |
35 | let m = p.start(); | 41 | let m = p.start(); |
36 | name(p); | 42 | name(p); |
37 | if p.at(COLON) { | 43 | if p.at(COLON) { |
38 | bounds(p); | 44 | bounds(p); |
39 | } | ||
40 | // test type_param_default | ||
41 | // struct S<T = i32>; | ||
42 | if p.at(EQ) { | ||
43 | p.bump(); | ||
44 | types::type_(p) | ||
45 | } | ||
46 | m.complete(p, TYPE_PARAM); | ||
47 | } | 45 | } |
46 | // test type_param_default | ||
47 | // struct S<T = i32>; | ||
48 | if p.at(EQ) { | ||
49 | p.bump(); | ||
50 | types::type_(p) | ||
51 | } | ||
52 | m.complete(p, TYPE_PARAM); | ||
48 | } | 53 | } |
49 | 54 | ||
50 | // test type_param_bounds | 55 | // test type_param_bounds |
@@ -99,7 +104,7 @@ pub(super) fn opt_where_clause(p: &mut Parser) { | |||
99 | let m = p.start(); | 104 | let m = p.start(); |
100 | p.bump(); | 105 | p.bump(); |
101 | loop { | 106 | loop { |
102 | if !(paths::is_path_start(p) || p.current() == LIFETIME) { | 107 | if !(paths::is_path_start(p) || p.current() == LIFETIME || p.current() == FOR_KW) { |
103 | break; | 108 | break; |
104 | } | 109 | } |
105 | where_predicate(p); | 110 | where_predicate(p); |
@@ -112,19 +117,30 @@ pub(super) fn opt_where_clause(p: &mut Parser) { | |||
112 | 117 | ||
113 | fn where_predicate(p: &mut Parser) { | 118 | fn where_predicate(p: &mut Parser) { |
114 | let m = p.start(); | 119 | let m = p.start(); |
115 | if p.at(LIFETIME) { | 120 | match p.current() { |
116 | p.eat(LIFETIME); | 121 | LIFETIME => { |
117 | if p.at(COLON) { | 122 | p.bump(); |
118 | lifetime_bounds(p) | 123 | if p.at(COLON) { |
119 | } else { | 124 | lifetime_bounds(p); |
120 | p.error("expected colon") | 125 | } else { |
126 | p.error("expected colon"); | ||
127 | } | ||
121 | } | 128 | } |
122 | } else { | 129 | _ => { |
123 | types::path_type(p); | 130 | // test where_pred_for |
124 | if p.at(COLON) { | 131 | // fn test<F>() |
125 | bounds(p); | 132 | // where |
126 | } else { | 133 | // for<'a> F: Fn(&'a str) |
127 | p.error("expected colon") | 134 | // { } |
135 | if p.at(FOR_KW) { | ||
136 | types::for_binder(p); | ||
137 | } | ||
138 | types::path_type(p); | ||
139 | if p.at(COLON) { | ||
140 | bounds(p); | ||
141 | } else { | ||
142 | p.error("expected colon"); | ||
143 | } | ||
128 | } | 144 | } |
129 | } | 145 | } |
130 | m.complete(p, WHERE_PRED); | 146 | m.complete(p, WHERE_PRED); |
diff --git a/crates/ra_syntax/src/grammar/types.rs b/crates/ra_syntax/src/grammar/types.rs index f308aef89..ed2718e73 100644 --- a/crates/ra_syntax/src/grammar/types.rs +++ b/crates/ra_syntax/src/grammar/types.rs | |||
@@ -188,13 +188,22 @@ fn fn_pointer_type(p: &mut Parser) { | |||
188 | m.complete(p, FN_POINTER_TYPE); | 188 | m.complete(p, FN_POINTER_TYPE); |
189 | } | 189 | } |
190 | 190 | ||
191 | pub(super) fn for_binder(p: &mut Parser) { | ||
192 | assert!(p.at(FOR_KW)); | ||
193 | p.bump(); | ||
194 | if p.at(L_ANGLE) { | ||
195 | type_params::opt_type_param_list(p); | ||
196 | } else { | ||
197 | p.error("expected `<`"); | ||
198 | } | ||
199 | } | ||
200 | |||
191 | // test for_type | 201 | // test for_type |
192 | // type A = for<'a> fn() -> (); | 202 | // type A = for<'a> fn() -> (); |
193 | pub(super) fn for_type(p: &mut Parser) { | 203 | pub(super) fn for_type(p: &mut Parser) { |
194 | assert!(p.at(FOR_KW)); | 204 | assert!(p.at(FOR_KW)); |
195 | let m = p.start(); | 205 | let m = p.start(); |
196 | p.bump(); | 206 | for_binder(p); |
197 | type_params::opt_type_param_list(p); | ||
198 | match p.current() { | 207 | match p.current() { |
199 | FN_KW | UNSAFE_KW | EXTERN_KW => fn_pointer_type(p), | 208 | FN_KW | UNSAFE_KW | EXTERN_KW => fn_pointer_type(p), |
200 | _ if paths::is_path_start(p) => path_type_(p, false), | 209 | _ if paths::is_path_start(p) => path_type_(p, false), |
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index 69a679d04..123002825 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs | |||
@@ -60,6 +60,7 @@ pub use crate::{ | |||
60 | 60 | ||
61 | use crate::yellow::GreenNode; | 61 | use crate::yellow::GreenNode; |
62 | 62 | ||
63 | /// File represents a parse tree for a single Rust file. | ||
63 | #[derive(Clone, Debug, Hash, PartialEq, Eq)] | 64 | #[derive(Clone, Debug, Hash, PartialEq, Eq)] |
64 | pub struct File { | 65 | pub struct File { |
65 | root: SyntaxNode, | 66 | root: SyntaxNode, |
@@ -92,9 +93,11 @@ impl File { | |||
92 | text_utils::replace_range(self.syntax().text().to_string(), edit.delete, &edit.insert); | 93 | text_utils::replace_range(self.syntax().text().to_string(), edit.delete, &edit.insert); |
93 | File::parse(&text) | 94 | File::parse(&text) |
94 | } | 95 | } |
96 | /// Typed AST representation of the parse tree. | ||
95 | pub fn ast(&self) -> ast::Root { | 97 | pub fn ast(&self) -> ast::Root { |
96 | ast::Root::cast(self.syntax()).unwrap() | 98 | ast::Root::cast(self.syntax()).unwrap() |
97 | } | 99 | } |
100 | /// Untyped homogeneous representation of the parse tree. | ||
98 | pub fn syntax(&self) -> SyntaxNodeRef { | 101 | pub fn syntax(&self) -> SyntaxNodeRef { |
99 | self.root.borrowed() | 102 | self.root.borrowed() |
100 | } | 103 | } |
diff --git a/crates/ra_syntax/tests/data/parser/inline/0113_where_pred_for.rs b/crates/ra_syntax/tests/data/parser/inline/0113_where_pred_for.rs new file mode 100644 index 000000000..b448c6178 --- /dev/null +++ b/crates/ra_syntax/tests/data/parser/inline/0113_where_pred_for.rs | |||
@@ -0,0 +1,4 @@ | |||
1 | fn test<F>() | ||
2 | where | ||
3 | for<'a> F: Fn(&'a str) | ||
4 | { } | ||
diff --git a/crates/ra_syntax/tests/data/parser/inline/0113_where_pred_for.txt b/crates/ra_syntax/tests/data/parser/inline/0113_where_pred_for.txt new file mode 100644 index 000000000..08aacc77a --- /dev/null +++ b/crates/ra_syntax/tests/data/parser/inline/0113_where_pred_for.txt | |||
@@ -0,0 +1,58 @@ | |||
1 | ROOT@[0; 49) | ||
2 | FN_DEF@[0; 48) | ||
3 | FN_KW@[0; 2) | ||
4 | WHITESPACE@[2; 3) | ||
5 | NAME@[3; 7) | ||
6 | IDENT@[3; 7) "test" | ||
7 | TYPE_PARAM_LIST@[7; 10) | ||
8 | L_ANGLE@[7; 8) | ||
9 | TYPE_PARAM@[8; 9) | ||
10 | NAME@[8; 9) | ||
11 | IDENT@[8; 9) "F" | ||
12 | R_ANGLE@[9; 10) | ||
13 | PARAM_LIST@[10; 12) | ||
14 | L_PAREN@[10; 11) | ||
15 | R_PAREN@[11; 12) | ||
16 | WHITESPACE@[12; 13) | ||
17 | WHERE_CLAUSE@[13; 44) | ||
18 | WHERE_KW@[13; 18) | ||
19 | WHITESPACE@[18; 22) | ||
20 | WHERE_PRED@[22; 44) | ||
21 | FOR_KW@[22; 25) | ||
22 | TYPE_PARAM_LIST@[25; 29) | ||
23 | L_ANGLE@[25; 26) | ||
24 | LIFETIME_PARAM@[26; 28) | ||
25 | LIFETIME@[26; 28) "'a" | ||
26 | R_ANGLE@[28; 29) | ||
27 | WHITESPACE@[29; 30) | ||
28 | PATH_TYPE@[30; 31) | ||
29 | PATH@[30; 31) | ||
30 | PATH_SEGMENT@[30; 31) | ||
31 | NAME_REF@[30; 31) | ||
32 | IDENT@[30; 31) "F" | ||
33 | COLON@[31; 32) | ||
34 | WHITESPACE@[32; 33) | ||
35 | PATH_TYPE@[33; 44) | ||
36 | PATH@[33; 44) | ||
37 | PATH_SEGMENT@[33; 44) | ||
38 | NAME_REF@[33; 35) | ||
39 | IDENT@[33; 35) "Fn" | ||
40 | PARAM_LIST@[35; 44) | ||
41 | L_PAREN@[35; 36) | ||
42 | PARAM@[36; 43) | ||
43 | REFERENCE_TYPE@[36; 43) | ||
44 | AMP@[36; 37) | ||
45 | LIFETIME@[37; 39) "'a" | ||
46 | WHITESPACE@[39; 40) | ||
47 | PATH_TYPE@[40; 43) | ||
48 | PATH@[40; 43) | ||
49 | PATH_SEGMENT@[40; 43) | ||
50 | NAME_REF@[40; 43) | ||
51 | IDENT@[40; 43) "str" | ||
52 | R_PAREN@[43; 44) | ||
53 | WHITESPACE@[44; 45) | ||
54 | BLOCK@[45; 48) | ||
55 | L_CURLY@[45; 46) | ||
56 | WHITESPACE@[46; 47) | ||
57 | R_CURLY@[47; 48) | ||
58 | WHITESPACE@[48; 49) | ||