diff options
Diffstat (limited to 'crates/ra_syntax/src/ast')
-rw-r--r-- | crates/ra_syntax/src/ast/edit.rs | 81 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/make.rs | 42 |
2 files changed, 77 insertions, 46 deletions
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs index b736098ac..0e78d8b63 100644 --- a/crates/ra_syntax/src/ast/edit.rs +++ b/crates/ra_syntax/src/ast/edit.rs | |||
@@ -22,9 +22,8 @@ impl ast::BinExpr { | |||
22 | #[must_use] | 22 | #[must_use] |
23 | pub fn replace_op(&self, op: SyntaxKind) -> Option<ast::BinExpr> { | 23 | pub fn replace_op(&self, op: SyntaxKind) -> Option<ast::BinExpr> { |
24 | let op_node: SyntaxElement = self.op_details()?.0.into(); | 24 | let op_node: SyntaxElement = self.op_details()?.0.into(); |
25 | let to_insert: Option<SyntaxElement> = Some(tokens::op(op).into()); | 25 | let to_insert: Option<SyntaxElement> = Some(make::token(op).into()); |
26 | let replace_range = RangeInclusive::new(op_node.clone(), op_node); | 26 | Some(replace_children(self, single_node(op_node), to_insert)) |
27 | Some(replace_children(self, replace_range, to_insert.into_iter())) | ||
28 | } | 27 | } |
29 | } | 28 | } |
30 | 29 | ||
@@ -40,11 +39,10 @@ impl ast::FnDef { | |||
40 | } else { | 39 | } else { |
41 | to_insert.push(make::tokens::single_space().into()); | 40 | to_insert.push(make::tokens::single_space().into()); |
42 | to_insert.push(body.syntax().clone().into()); | 41 | to_insert.push(body.syntax().clone().into()); |
43 | return insert_children(self, InsertPosition::Last, to_insert.into_iter()); | 42 | return insert_children(self, InsertPosition::Last, to_insert); |
44 | }; | 43 | }; |
45 | to_insert.push(body.syntax().clone().into()); | 44 | to_insert.push(body.syntax().clone().into()); |
46 | let replace_range = RangeInclusive::new(old_body_or_semi.clone(), old_body_or_semi); | 45 | replace_children(self, single_node(old_body_or_semi), to_insert) |
47 | replace_children(self, replace_range, to_insert.into_iter()) | ||
48 | } | 46 | } |
49 | } | 47 | } |
50 | 48 | ||
@@ -77,7 +75,7 @@ impl ast::ItemList { | |||
77 | let ws = tokens::WsBuilder::new(&format!("\n{}", indent)); | 75 | let ws = tokens::WsBuilder::new(&format!("\n{}", indent)); |
78 | let to_insert: ArrayVec<[SyntaxElement; 2]> = | 76 | let to_insert: ArrayVec<[SyntaxElement; 2]> = |
79 | [ws.ws().into(), item.syntax().clone().into()].into(); | 77 | [ws.ws().into(), item.syntax().clone().into()].into(); |
80 | insert_children(self, position, to_insert.into_iter()) | 78 | insert_children(self, position, to_insert) |
81 | } | 79 | } |
82 | 80 | ||
83 | fn l_curly(&self) -> Option<SyntaxElement> { | 81 | fn l_curly(&self) -> Option<SyntaxElement> { |
@@ -109,9 +107,7 @@ impl ast::ItemList { | |||
109 | let to_insert = iter::once(ws.ws().into()); | 107 | let to_insert = iter::once(ws.ws().into()); |
110 | match existing_ws { | 108 | match existing_ws { |
111 | None => insert_children(self, InsertPosition::After(l_curly), to_insert), | 109 | None => insert_children(self, InsertPosition::After(l_curly), to_insert), |
112 | Some(ws) => { | 110 | Some(ws) => replace_children(self, single_node(ws), to_insert), |
113 | replace_children(self, RangeInclusive::new(ws.clone().into(), ws.into()), to_insert) | ||
114 | } | ||
115 | } | 111 | } |
116 | } | 112 | } |
117 | } | 113 | } |
@@ -188,7 +184,7 @@ impl ast::RecordFieldList { | |||
188 | InsertPosition::After(anchor) => after_field!(anchor), | 184 | InsertPosition::After(anchor) => after_field!(anchor), |
189 | }; | 185 | }; |
190 | 186 | ||
191 | insert_children(self, position, to_insert.iter().cloned()) | 187 | insert_children(self, position, to_insert) |
192 | } | 188 | } |
193 | 189 | ||
194 | fn l_curly(&self) -> Option<SyntaxElement> { | 190 | fn l_curly(&self) -> Option<SyntaxElement> { |
@@ -207,7 +203,49 @@ impl ast::TypeParam { | |||
207 | Some(it) => it.syntax().clone().into(), | 203 | Some(it) => it.syntax().clone().into(), |
208 | None => colon.clone().into(), | 204 | None => colon.clone().into(), |
209 | }; | 205 | }; |
210 | replace_children(self, RangeInclusive::new(colon.into(), end), iter::empty()) | 206 | replace_children(self, colon.into()..=end, iter::empty()) |
207 | } | ||
208 | } | ||
209 | |||
210 | impl ast::Path { | ||
211 | #[must_use] | ||
212 | pub fn with_segment(&self, segment: ast::PathSegment) -> ast::Path { | ||
213 | if let Some(old) = self.segment() { | ||
214 | return replace_children( | ||
215 | self, | ||
216 | single_node(old.syntax().clone()), | ||
217 | iter::once(segment.syntax().clone().into()), | ||
218 | ); | ||
219 | } | ||
220 | self.clone() | ||
221 | } | ||
222 | } | ||
223 | |||
224 | impl ast::PathSegment { | ||
225 | #[must_use] | ||
226 | pub fn with_type_args(&self, type_args: ast::TypeArgList) -> ast::PathSegment { | ||
227 | self._with_type_args(type_args, false) | ||
228 | } | ||
229 | |||
230 | #[must_use] | ||
231 | pub fn with_turbo_fish(&self, type_args: ast::TypeArgList) -> ast::PathSegment { | ||
232 | self._with_type_args(type_args, true) | ||
233 | } | ||
234 | |||
235 | fn _with_type_args(&self, type_args: ast::TypeArgList, turbo: bool) -> ast::PathSegment { | ||
236 | if let Some(old) = self.type_arg_list() { | ||
237 | return replace_children( | ||
238 | self, | ||
239 | single_node(old.syntax().clone()), | ||
240 | iter::once(type_args.syntax().clone().into()), | ||
241 | ); | ||
242 | } | ||
243 | let mut to_insert: ArrayVec<[SyntaxElement; 2]> = ArrayVec::new(); | ||
244 | if turbo { | ||
245 | to_insert.push(make::token(T![::]).into()); | ||
246 | } | ||
247 | to_insert.push(type_args.syntax().clone().into()); | ||
248 | insert_children(self, InsertPosition::Last, to_insert) | ||
211 | } | 249 | } |
212 | } | 250 | } |
213 | 251 | ||
@@ -224,7 +262,7 @@ fn strip_attrs_and_docs_inner(mut node: SyntaxNode) -> SyntaxNode { | |||
224 | Some(el) if el.kind() == WHITESPACE => el.clone(), | 262 | Some(el) if el.kind() == WHITESPACE => el.clone(), |
225 | Some(_) | None => start.clone(), | 263 | Some(_) | None => start.clone(), |
226 | }; | 264 | }; |
227 | node = algo::replace_children(&node, RangeInclusive::new(start, end), &mut iter::empty()); | 265 | node = algo::replace_children(&node, start..=end, &mut iter::empty()); |
228 | } | 266 | } |
229 | node | 267 | node |
230 | } | 268 | } |
@@ -232,9 +270,10 @@ fn strip_attrs_and_docs_inner(mut node: SyntaxNode) -> SyntaxNode { | |||
232 | #[must_use] | 270 | #[must_use] |
233 | pub fn replace_descendants<N: AstNode, D: AstNode>( | 271 | pub fn replace_descendants<N: AstNode, D: AstNode>( |
234 | parent: &N, | 272 | parent: &N, |
235 | replacement_map: impl Iterator<Item = (D, D)>, | 273 | replacement_map: impl IntoIterator<Item = (D, D)>, |
236 | ) -> N { | 274 | ) -> N { |
237 | let map = replacement_map | 275 | let map = replacement_map |
276 | .into_iter() | ||
238 | .map(|(from, to)| (from.syntax().clone().into(), to.syntax().clone().into())) | 277 | .map(|(from, to)| (from.syntax().clone().into(), to.syntax().clone().into())) |
239 | .collect::<FxHashMap<SyntaxElement, _>>(); | 278 | .collect::<FxHashMap<SyntaxElement, _>>(); |
240 | let new_syntax = algo::replace_descendants(parent.syntax(), &|n| map.get(n).cloned()); | 279 | let new_syntax = algo::replace_descendants(parent.syntax(), &|n| map.get(n).cloned()); |
@@ -348,19 +387,25 @@ fn prev_tokens(token: SyntaxToken) -> impl Iterator<Item = SyntaxToken> { | |||
348 | fn insert_children<N: AstNode>( | 387 | fn insert_children<N: AstNode>( |
349 | parent: &N, | 388 | parent: &N, |
350 | position: InsertPosition<SyntaxElement>, | 389 | position: InsertPosition<SyntaxElement>, |
351 | mut to_insert: impl Iterator<Item = SyntaxElement>, | 390 | to_insert: impl IntoIterator<Item = SyntaxElement>, |
352 | ) -> N { | 391 | ) -> N { |
353 | let new_syntax = algo::insert_children(parent.syntax(), position, &mut to_insert); | 392 | let new_syntax = algo::insert_children(parent.syntax(), position, &mut to_insert.into_iter()); |
354 | N::cast(new_syntax).unwrap() | 393 | N::cast(new_syntax).unwrap() |
355 | } | 394 | } |
356 | 395 | ||
396 | fn single_node(element: impl Into<SyntaxElement>) -> RangeInclusive<SyntaxElement> { | ||
397 | let element = element.into(); | ||
398 | element.clone()..=element | ||
399 | } | ||
400 | |||
357 | #[must_use] | 401 | #[must_use] |
358 | fn replace_children<N: AstNode>( | 402 | fn replace_children<N: AstNode>( |
359 | parent: &N, | 403 | parent: &N, |
360 | to_replace: RangeInclusive<SyntaxElement>, | 404 | to_replace: RangeInclusive<SyntaxElement>, |
361 | mut to_insert: impl Iterator<Item = SyntaxElement>, | 405 | to_insert: impl IntoIterator<Item = SyntaxElement>, |
362 | ) -> N { | 406 | ) -> N { |
363 | let new_syntax = algo::replace_children(parent.syntax(), to_replace, &mut to_insert); | 407 | let new_syntax = |
408 | algo::replace_children(parent.syntax(), to_replace, &mut to_insert.into_iter()); | ||
364 | N::cast(new_syntax).unwrap() | 409 | N::cast(new_syntax).unwrap() |
365 | } | 410 | } |
366 | 411 | ||
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs index eef45090d..36e648180 100644 --- a/crates/ra_syntax/src/ast/make.rs +++ b/crates/ra_syntax/src/ast/make.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | //! of smaller pieces. | 2 | //! of smaller pieces. |
3 | use itertools::Itertools; | 3 | use itertools::Itertools; |
4 | 4 | ||
5 | use crate::{algo, ast, AstNode, SourceFile}; | 5 | use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxToken}; |
6 | 6 | ||
7 | pub fn name(text: &str) -> ast::Name { | 7 | pub fn name(text: &str) -> ast::Name { |
8 | ast_from_text(&format!("mod {};", text)) | 8 | ast_from_text(&format!("mod {};", text)) |
@@ -21,20 +21,6 @@ pub fn path_qualified(qual: ast::Path, name_ref: ast::NameRef) -> ast::Path { | |||
21 | fn path_from_text(text: &str) -> ast::Path { | 21 | fn path_from_text(text: &str) -> ast::Path { |
22 | ast_from_text(text) | 22 | ast_from_text(text) |
23 | } | 23 | } |
24 | pub fn path_with_type_arg_list(path: ast::Path, args: Option<ast::TypeArgList>) -> ast::Path { | ||
25 | if let Some(args) = args { | ||
26 | let syntax = path.syntax(); | ||
27 | // FIXME: remove existing type args | ||
28 | let new_syntax = algo::insert_children( | ||
29 | syntax, | ||
30 | crate::algo::InsertPosition::Last, | ||
31 | &mut Some(args).into_iter().map(|n| n.syntax().clone().into()), | ||
32 | ); | ||
33 | ast::Path::cast(new_syntax).unwrap() | ||
34 | } else { | ||
35 | path | ||
36 | } | ||
37 | } | ||
38 | 24 | ||
39 | pub fn record_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordField { | 25 | pub fn record_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordField { |
40 | return match expr { | 26 | return match expr { |
@@ -181,27 +167,27 @@ pub fn let_stmt(pattern: ast::Pat, initializer: Option<ast::Expr>) -> ast::LetSt | |||
181 | ast_from_text(&format!("fn f() {{ {} }}", text)) | 167 | ast_from_text(&format!("fn f() {{ {} }}", text)) |
182 | } | 168 | } |
183 | 169 | ||
170 | pub fn token(kind: SyntaxKind) -> SyntaxToken { | ||
171 | tokens::SOURCE_FILE | ||
172 | .tree() | ||
173 | .syntax() | ||
174 | .descendants_with_tokens() | ||
175 | .filter_map(|it| it.into_token()) | ||
176 | .find(|it| it.kind() == kind) | ||
177 | .unwrap_or_else(|| panic!("unhandled token: {:?}", kind)) | ||
178 | } | ||
179 | |||
184 | fn ast_from_text<N: AstNode>(text: &str) -> N { | 180 | fn ast_from_text<N: AstNode>(text: &str) -> N { |
185 | let parse = SourceFile::parse(text); | 181 | let parse = SourceFile::parse(text); |
186 | parse.tree().syntax().descendants().find_map(N::cast).unwrap() | 182 | parse.tree().syntax().descendants().find_map(N::cast).unwrap() |
187 | } | 183 | } |
188 | 184 | ||
189 | pub mod tokens { | 185 | pub mod tokens { |
190 | use crate::{AstNode, Parse, SourceFile, SyntaxKind, SyntaxKind::*, SyntaxToken, T}; | 186 | use crate::{AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken, T}; |
191 | use once_cell::sync::Lazy; | 187 | use once_cell::sync::Lazy; |
192 | 188 | ||
193 | static SOURCE_FILE: Lazy<Parse<SourceFile>> = | 189 | pub(super) static SOURCE_FILE: Lazy<Parse<SourceFile>> = |
194 | Lazy::new(|| SourceFile::parse("const C: () = (1 != 1, 2 == 2)\n;")); | 190 | Lazy::new(|| SourceFile::parse("const C: <()>::Item = (1 != 1, 2 == 2)\n;")); |
195 | |||
196 | pub fn op(op: SyntaxKind) -> SyntaxToken { | ||
197 | SOURCE_FILE | ||
198 | .tree() | ||
199 | .syntax() | ||
200 | .descendants_with_tokens() | ||
201 | .filter_map(|it| it.into_token()) | ||
202 | .find(|it| it.kind() == op) | ||
203 | .unwrap() | ||
204 | } | ||
205 | 191 | ||
206 | pub fn comma() -> SyntaxToken { | 192 | pub fn comma() -> SyntaxToken { |
207 | SOURCE_FILE | 193 | SOURCE_FILE |