aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax')
-rw-r--r--crates/ra_syntax/Cargo.toml3
-rw-r--r--crates/ra_syntax/src/ast/edit.rs119
-rw-r--r--crates/ra_syntax/src/ast/make.rs14
-rw-r--r--crates/ra_syntax/src/grammar.ron2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.rs3
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.txt43
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.rs7
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.txt97
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"
12rowan = "0.6.1" 12rowan = "0.6.1"
13rustc_lexer = "0.1.0" 13rustc_lexer = "0.1.0"
14rustc-hash = "1.0.1" 14rustc-hash = "1.0.1"
15arrayvec = "0.4.10" 15arrayvec = "0.5.1"
16once_cell = "1.2.0" 16once_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
20smol_str = { version = "0.1.12", features = ["serde"] } 21smol_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
21impl ast::FnDef { 21impl 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 235pub struct IndentLevel(pub u8);
236// might want to call into fmt... 236
237impl From<u8> for IndentLevel {
238 fn from(level: u8) -> IndentLevel {
239 IndentLevel(level)
240 }
241}
242
243impl 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
237fn leading_indent(node: &SyntaxNode) -> Option<SmolStr> { 318fn 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
333fn 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]
254fn insert_children<N: AstNode>( 338fn 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]
358fn 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
131pub 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
131fn ast_from_text<N: AstNode>(text: &str) -> N { 139fn 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)
3Grammar( 3Grammar(
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 @@
1fn 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 @@
1SOURCE_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 @@
1fn 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 @@
1SOURCE_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"