aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax')
-rw-r--r--crates/ra_syntax/Cargo.toml4
-rw-r--r--crates/ra_syntax/src/grammar/mod.rs5
-rw-r--r--crates/ra_syntax/src/grammar/type_params.rs86
-rw-r--r--crates/ra_syntax/src/grammar/types.rs13
-rw-r--r--crates/ra_syntax/src/lib.rs3
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0113_where_pred_for.rs4
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0113_where_pred_for.txt58
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]
2edition = "2018" 2edition = "2015"
3name = "ra_syntax" 3name = "ra_syntax"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["Aleksey Kladov <[email protected]>"] 5authors = ["Aleksey Kladov <[email protected]>"]
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7description = "Comment and whitespace preserving parser for the Rust langauge"
8repository = "https://github.com/rust-analyzer/rust-analyzer"
7 9
8[dependencies] 10[dependencies]
9unicode-xid = "0.1.0" 11unicode-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.
24mod attributes; 29mod attributes;
25mod expressions; 30mod expressions;
26mod items; 31mod 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
10fn 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) { 29fn 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) { 39fn 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
113fn where_predicate(p: &mut Parser) { 118fn 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
191pub(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() -> ();
193pub(super) fn for_type(p: &mut Parser) { 203pub(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
61use crate::yellow::GreenNode; 61use 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)]
64pub struct File { 65pub 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 @@
1fn test<F>()
2where
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 @@
1ROOT@[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)