diff options
Diffstat (limited to 'crates/ra_syntax')
-rw-r--r-- | crates/ra_syntax/Cargo.toml | 3 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/edit.rs | 119 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/make.rs | 14 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar.ron | 2 | ||||
-rw-r--r-- | crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.rs | 3 | ||||
-rw-r--r-- | crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.txt | 43 | ||||
-rw-r--r-- | crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.rs | 7 | ||||
-rw-r--r-- | crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.txt | 97 |
8 files changed, 280 insertions, 8 deletions
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml index 9bc85404a..9c0e856e8 100644 --- a/crates/ra_syntax/Cargo.toml +++ b/crates/ra_syntax/Cargo.toml | |||
@@ -12,9 +12,10 @@ itertools = "0.8.0" | |||
12 | rowan = "0.6.1" | 12 | rowan = "0.6.1" |
13 | rustc_lexer = "0.1.0" | 13 | rustc_lexer = "0.1.0" |
14 | rustc-hash = "1.0.1" | 14 | rustc-hash = "1.0.1" |
15 | arrayvec = "0.4.10" | 15 | arrayvec = "0.5.1" |
16 | once_cell = "1.2.0" | 16 | once_cell = "1.2.0" |
17 | 17 | ||
18 | # This crate transitively depends on `smol_str` via `rowan`. | ||
18 | # ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here | 19 | # ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here |
19 | # to reduce number of compilations | 20 | # to reduce number of compilations |
20 | smol_str = { version = "0.1.12", features = ["serde"] } | 21 | smol_str = { version = "0.1.12", features = ["serde"] } |
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs index 03f3b5fbb..47bdbb81a 100644 --- a/crates/ra_syntax/src/ast/edit.rs +++ b/crates/ra_syntax/src/ast/edit.rs | |||
@@ -15,7 +15,7 @@ use crate::{ | |||
15 | }, | 15 | }, |
16 | AstToken, Direction, InsertPosition, SmolStr, SyntaxElement, | 16 | AstToken, Direction, InsertPosition, SmolStr, SyntaxElement, |
17 | SyntaxKind::{ATTR, COMMENT, WHITESPACE}, | 17 | SyntaxKind::{ATTR, COMMENT, WHITESPACE}, |
18 | SyntaxNode, T, | 18 | SyntaxNode, SyntaxToken, T, |
19 | }; | 19 | }; |
20 | 20 | ||
21 | impl ast::FnDef { | 21 | impl ast::FnDef { |
@@ -231,12 +231,92 @@ pub fn replace_descendants<N: AstNode, D: AstNode>( | |||
231 | N::cast(new_syntax).unwrap() | 231 | N::cast(new_syntax).unwrap() |
232 | } | 232 | } |
233 | 233 | ||
234 | // Note this is copy-pasted from fmt. It seems like fmt should be a separate | 234 | #[derive(Debug, Clone, Copy)] |
235 | // crate, but basic tree building should be this crate. However, tree building | 235 | pub struct IndentLevel(pub u8); |
236 | // might want to call into fmt... | 236 | |
237 | impl From<u8> for IndentLevel { | ||
238 | fn from(level: u8) -> IndentLevel { | ||
239 | IndentLevel(level) | ||
240 | } | ||
241 | } | ||
242 | |||
243 | impl IndentLevel { | ||
244 | pub fn from_node(node: &SyntaxNode) -> IndentLevel { | ||
245 | let first_token = match node.first_token() { | ||
246 | Some(it) => it, | ||
247 | None => return IndentLevel(0), | ||
248 | }; | ||
249 | for ws in prev_tokens(first_token).filter_map(ast::Whitespace::cast) { | ||
250 | let text = ws.syntax().text(); | ||
251 | if let Some(pos) = text.rfind('\n') { | ||
252 | let level = text[pos + 1..].chars().count() / 4; | ||
253 | return IndentLevel(level as u8); | ||
254 | } | ||
255 | } | ||
256 | IndentLevel(0) | ||
257 | } | ||
258 | |||
259 | pub fn increase_indent<N: AstNode>(self, node: N) -> N { | ||
260 | N::cast(self._increase_indent(node.syntax().clone())).unwrap() | ||
261 | } | ||
262 | |||
263 | fn _increase_indent(self, node: SyntaxNode) -> SyntaxNode { | ||
264 | let replacements: FxHashMap<SyntaxElement, SyntaxElement> = node | ||
265 | .descendants_with_tokens() | ||
266 | .filter_map(|el| el.into_token()) | ||
267 | .filter_map(ast::Whitespace::cast) | ||
268 | .filter(|ws| { | ||
269 | let text = ws.syntax().text(); | ||
270 | text.contains('\n') | ||
271 | }) | ||
272 | .map(|ws| { | ||
273 | ( | ||
274 | ws.syntax().clone().into(), | ||
275 | make::tokens::whitespace(&format!( | ||
276 | "{}{:width$}", | ||
277 | ws.syntax().text(), | ||
278 | "", | ||
279 | width = self.0 as usize * 4 | ||
280 | )) | ||
281 | .into(), | ||
282 | ) | ||
283 | }) | ||
284 | .collect(); | ||
285 | algo::replace_descendants(&node, &replacements) | ||
286 | } | ||
287 | |||
288 | pub fn decrease_indent<N: AstNode>(self, node: N) -> N { | ||
289 | N::cast(self._decrease_indent(node.syntax().clone())).unwrap() | ||
290 | } | ||
291 | |||
292 | fn _decrease_indent(self, node: SyntaxNode) -> SyntaxNode { | ||
293 | let replacements: FxHashMap<SyntaxElement, SyntaxElement> = node | ||
294 | .descendants_with_tokens() | ||
295 | .filter_map(|el| el.into_token()) | ||
296 | .filter_map(ast::Whitespace::cast) | ||
297 | .filter(|ws| { | ||
298 | let text = ws.syntax().text(); | ||
299 | text.contains('\n') | ||
300 | }) | ||
301 | .map(|ws| { | ||
302 | ( | ||
303 | ws.syntax().clone().into(), | ||
304 | make::tokens::whitespace( | ||
305 | &ws.syntax() | ||
306 | .text() | ||
307 | .replace(&format!("\n{:1$}", "", self.0 as usize * 4), "\n"), | ||
308 | ) | ||
309 | .into(), | ||
310 | ) | ||
311 | }) | ||
312 | .collect(); | ||
313 | algo::replace_descendants(&node, &replacements) | ||
314 | } | ||
315 | } | ||
316 | |||
317 | // FIXME: replace usages with IndentLevel above | ||
237 | fn leading_indent(node: &SyntaxNode) -> Option<SmolStr> { | 318 | fn leading_indent(node: &SyntaxNode) -> Option<SmolStr> { |
238 | let prev_tokens = std::iter::successors(node.first_token(), |token| token.prev_token()); | 319 | for token in prev_tokens(node.first_token()?) { |
239 | for token in prev_tokens { | ||
240 | if let Some(ws) = ast::Whitespace::cast(token.clone()) { | 320 | if let Some(ws) = ast::Whitespace::cast(token.clone()) { |
241 | let ws_text = ws.text(); | 321 | let ws_text = ws.text(); |
242 | if let Some(pos) = ws_text.rfind('\n') { | 322 | if let Some(pos) = ws_text.rfind('\n') { |
@@ -250,6 +330,10 @@ fn leading_indent(node: &SyntaxNode) -> Option<SmolStr> { | |||
250 | None | 330 | None |
251 | } | 331 | } |
252 | 332 | ||
333 | fn prev_tokens(token: SyntaxToken) -> impl Iterator<Item = SyntaxToken> { | ||
334 | iter::successors(Some(token), |token| token.prev_token()) | ||
335 | } | ||
336 | |||
253 | #[must_use] | 337 | #[must_use] |
254 | fn insert_children<N: AstNode>( | 338 | fn insert_children<N: AstNode>( |
255 | parent: &N, | 339 | parent: &N, |
@@ -269,3 +353,26 @@ fn replace_children<N: AstNode>( | |||
269 | let new_syntax = algo::replace_children(parent.syntax(), to_replace, &mut to_insert); | 353 | let new_syntax = algo::replace_children(parent.syntax(), to_replace, &mut to_insert); |
270 | N::cast(new_syntax).unwrap() | 354 | N::cast(new_syntax).unwrap() |
271 | } | 355 | } |
356 | |||
357 | #[test] | ||
358 | fn test_increase_indent() { | ||
359 | let arm_list = { | ||
360 | let arm = make::match_arm(iter::once(make::placeholder_pat().into()), make::expr_unit()); | ||
361 | make::match_arm_list(vec![arm.clone(), arm].into_iter()) | ||
362 | }; | ||
363 | assert_eq!( | ||
364 | arm_list.syntax().to_string(), | ||
365 | "{ | ||
366 | _ => (), | ||
367 | _ => (), | ||
368 | }" | ||
369 | ); | ||
370 | let indented = IndentLevel(2).increase_indent(arm_list); | ||
371 | assert_eq!( | ||
372 | indented.syntax().to_string(), | ||
373 | "{ | ||
374 | _ => (), | ||
375 | _ => (), | ||
376 | }" | ||
377 | ); | ||
378 | } | ||
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs index 287a40bee..00422ea91 100644 --- a/crates/ra_syntax/src/ast/make.rs +++ b/crates/ra_syntax/src/ast/make.rs | |||
@@ -128,6 +128,14 @@ pub fn where_clause(preds: impl Iterator<Item = ast::WherePred>) -> ast::WhereCl | |||
128 | } | 128 | } |
129 | } | 129 | } |
130 | 130 | ||
131 | pub fn if_expression(condition: &ast::Expr, statement: &str) -> ast::IfExpr { | ||
132 | return ast_from_text(&format!( | ||
133 | "fn f() {{ if !{} {{\n {}\n}}\n}}", | ||
134 | condition.syntax().text(), | ||
135 | statement | ||
136 | )); | ||
137 | } | ||
138 | |||
131 | fn ast_from_text<N: AstNode>(text: &str) -> N { | 139 | fn ast_from_text<N: AstNode>(text: &str) -> N { |
132 | let parse = SourceFile::parse(text); | 140 | let parse = SourceFile::parse(text); |
133 | let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap(); | 141 | let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap(); |
@@ -160,6 +168,12 @@ pub mod tokens { | |||
160 | .unwrap() | 168 | .unwrap() |
161 | } | 169 | } |
162 | 170 | ||
171 | pub fn whitespace(text: &str) -> SyntaxToken { | ||
172 | assert!(text.trim().is_empty()); | ||
173 | let sf = SourceFile::parse(text).ok().unwrap(); | ||
174 | sf.syntax().first_child_or_token().unwrap().into_token().unwrap() | ||
175 | } | ||
176 | |||
163 | pub fn single_newline() -> SyntaxToken { | 177 | pub fn single_newline() -> SyntaxToken { |
164 | SOURCE_FILE | 178 | SOURCE_FILE |
165 | .tree() | 179 | .tree() |
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 25e6f64ce..0a8fd0612 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -1,5 +1,5 @@ | |||
1 | // Stores definitions which must be used in multiple places | 1 | // Stores definitions which must be used in multiple places |
2 | // See `cargo gen-syntax` (defined in crates/ra_tools/src/main.rs) | 2 | // See `cargo xtask codegen` (defined in xtasks/src/main.rs) |
3 | Grammar( | 3 | Grammar( |
4 | punct: [ | 4 | punct: [ |
5 | (";", "SEMI"), | 5 | (";", "SEMI"), |
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.rs b/crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.rs new file mode 100644 index 000000000..a06dec1fa --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.rs | |||
@@ -0,0 +1,3 @@ | |||
1 | fn foo() { | ||
2 | let _ = &1 as *const i32; | ||
3 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.txt b/crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.txt new file mode 100644 index 000000000..9e3767fb7 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.txt | |||
@@ -0,0 +1,43 @@ | |||
1 | SOURCE_FILE@[0; 43) | ||
2 | FN_DEF@[0; 42) | ||
3 | FN_KW@[0; 2) "fn" | ||
4 | WHITESPACE@[2; 3) " " | ||
5 | NAME@[3; 6) | ||
6 | IDENT@[3; 6) "foo" | ||
7 | PARAM_LIST@[6; 8) | ||
8 | L_PAREN@[6; 7) "(" | ||
9 | R_PAREN@[7; 8) ")" | ||
10 | WHITESPACE@[8; 9) " " | ||
11 | BLOCK_EXPR@[9; 42) | ||
12 | BLOCK@[9; 42) | ||
13 | L_CURLY@[9; 10) "{" | ||
14 | WHITESPACE@[10; 15) "\n " | ||
15 | LET_STMT@[15; 40) | ||
16 | LET_KW@[15; 18) "let" | ||
17 | WHITESPACE@[18; 19) " " | ||
18 | PLACEHOLDER_PAT@[19; 20) | ||
19 | UNDERSCORE@[19; 20) "_" | ||
20 | WHITESPACE@[20; 21) " " | ||
21 | EQ@[21; 22) "=" | ||
22 | WHITESPACE@[22; 23) " " | ||
23 | CAST_EXPR@[23; 39) | ||
24 | REF_EXPR@[23; 25) | ||
25 | AMP@[23; 24) "&" | ||
26 | LITERAL@[24; 25) | ||
27 | INT_NUMBER@[24; 25) "1" | ||
28 | WHITESPACE@[25; 26) " " | ||
29 | AS_KW@[26; 28) "as" | ||
30 | WHITESPACE@[28; 29) " " | ||
31 | POINTER_TYPE@[29; 39) | ||
32 | STAR@[29; 30) "*" | ||
33 | CONST_KW@[30; 35) "const" | ||
34 | WHITESPACE@[35; 36) " " | ||
35 | PATH_TYPE@[36; 39) | ||
36 | PATH@[36; 39) | ||
37 | PATH_SEGMENT@[36; 39) | ||
38 | NAME_REF@[36; 39) | ||
39 | IDENT@[36; 39) "i32" | ||
40 | SEMI@[39; 40) ";" | ||
41 | WHITESPACE@[40; 41) "\n" | ||
42 | R_CURLY@[41; 42) "}" | ||
43 | WHITESPACE@[42; 43) "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.rs b/crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.rs new file mode 100644 index 000000000..100fccc64 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.rs | |||
@@ -0,0 +1,7 @@ | |||
1 | fn foo() { | ||
2 | 1 + *&2 + 3; | ||
3 | *&1 as u64; | ||
4 | *x(1); | ||
5 | &x[1]; | ||
6 | -1..2; | ||
7 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.txt b/crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.txt new file mode 100644 index 000000000..d30cb63ff --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.txt | |||
@@ -0,0 +1,97 @@ | |||
1 | SOURCE_FILE@[0; 79) | ||
2 | FN_DEF@[0; 78) | ||
3 | FN_KW@[0; 2) "fn" | ||
4 | WHITESPACE@[2; 3) " " | ||
5 | NAME@[3; 6) | ||
6 | IDENT@[3; 6) "foo" | ||
7 | PARAM_LIST@[6; 8) | ||
8 | L_PAREN@[6; 7) "(" | ||
9 | R_PAREN@[7; 8) ")" | ||
10 | WHITESPACE@[8; 9) " " | ||
11 | BLOCK_EXPR@[9; 78) | ||
12 | BLOCK@[9; 78) | ||
13 | L_CURLY@[9; 10) "{" | ||
14 | WHITESPACE@[10; 15) "\n " | ||
15 | EXPR_STMT@[15; 27) | ||
16 | BIN_EXPR@[15; 26) | ||
17 | BIN_EXPR@[15; 22) | ||
18 | LITERAL@[15; 16) | ||
19 | INT_NUMBER@[15; 16) "1" | ||
20 | WHITESPACE@[16; 17) " " | ||
21 | PLUS@[17; 18) "+" | ||
22 | WHITESPACE@[18; 19) " " | ||
23 | PREFIX_EXPR@[19; 22) | ||
24 | STAR@[19; 20) "*" | ||
25 | REF_EXPR@[20; 22) | ||
26 | AMP@[20; 21) "&" | ||
27 | LITERAL@[21; 22) | ||
28 | INT_NUMBER@[21; 22) "2" | ||
29 | WHITESPACE@[22; 23) " " | ||
30 | PLUS@[23; 24) "+" | ||
31 | WHITESPACE@[24; 25) " " | ||
32 | LITERAL@[25; 26) | ||
33 | INT_NUMBER@[25; 26) "3" | ||
34 | SEMI@[26; 27) ";" | ||
35 | WHITESPACE@[27; 32) "\n " | ||
36 | EXPR_STMT@[32; 43) | ||
37 | CAST_EXPR@[32; 42) | ||
38 | PREFIX_EXPR@[32; 35) | ||
39 | STAR@[32; 33) "*" | ||
40 | REF_EXPR@[33; 35) | ||
41 | AMP@[33; 34) "&" | ||
42 | LITERAL@[34; 35) | ||
43 | INT_NUMBER@[34; 35) "1" | ||
44 | WHITESPACE@[35; 36) " " | ||
45 | AS_KW@[36; 38) "as" | ||
46 | WHITESPACE@[38; 39) " " | ||
47 | PATH_TYPE@[39; 42) | ||
48 | PATH@[39; 42) | ||
49 | PATH_SEGMENT@[39; 42) | ||
50 | NAME_REF@[39; 42) | ||
51 | IDENT@[39; 42) "u64" | ||
52 | SEMI@[42; 43) ";" | ||
53 | WHITESPACE@[43; 48) "\n " | ||
54 | EXPR_STMT@[48; 54) | ||
55 | PREFIX_EXPR@[48; 53) | ||
56 | STAR@[48; 49) "*" | ||
57 | CALL_EXPR@[49; 53) | ||
58 | PATH_EXPR@[49; 50) | ||
59 | PATH@[49; 50) | ||
60 | PATH_SEGMENT@[49; 50) | ||
61 | NAME_REF@[49; 50) | ||
62 | IDENT@[49; 50) "x" | ||
63 | ARG_LIST@[50; 53) | ||
64 | L_PAREN@[50; 51) "(" | ||
65 | LITERAL@[51; 52) | ||
66 | INT_NUMBER@[51; 52) "1" | ||
67 | R_PAREN@[52; 53) ")" | ||
68 | SEMI@[53; 54) ";" | ||
69 | WHITESPACE@[54; 59) "\n " | ||
70 | EXPR_STMT@[59; 65) | ||
71 | REF_EXPR@[59; 64) | ||
72 | AMP@[59; 60) "&" | ||
73 | INDEX_EXPR@[60; 64) | ||
74 | PATH_EXPR@[60; 61) | ||
75 | PATH@[60; 61) | ||
76 | PATH_SEGMENT@[60; 61) | ||
77 | NAME_REF@[60; 61) | ||
78 | IDENT@[60; 61) "x" | ||
79 | L_BRACK@[61; 62) "[" | ||
80 | LITERAL@[62; 63) | ||
81 | INT_NUMBER@[62; 63) "1" | ||
82 | R_BRACK@[63; 64) "]" | ||
83 | SEMI@[64; 65) ";" | ||
84 | WHITESPACE@[65; 70) "\n " | ||
85 | EXPR_STMT@[70; 76) | ||
86 | RANGE_EXPR@[70; 75) | ||
87 | PREFIX_EXPR@[70; 72) | ||
88 | MINUS@[70; 71) "-" | ||
89 | LITERAL@[71; 72) | ||
90 | INT_NUMBER@[71; 72) "1" | ||
91 | DOTDOT@[72; 74) ".." | ||
92 | LITERAL@[74; 75) | ||
93 | INT_NUMBER@[74; 75) "2" | ||
94 | SEMI@[75; 76) ";" | ||
95 | WHITESPACE@[76; 77) "\n" | ||
96 | R_CURLY@[77; 78) "}" | ||
97 | WHITESPACE@[78; 79) "\n" | ||