]> git.lizzy.rs Git - rust.git/blob - crates/ra_syntax/src/reparsing.rs
Don't order import alphabetical
[rust.git] / crates / ra_syntax / src / reparsing.rs
1 use crate::algo;
2 use crate::grammar;
3 use crate::lexer::{tokenize, Token};
4 use crate::parser_api::Parser;
5 use crate::parser_impl;
6 use crate::text_utils::replace_range;
7 use crate::yellow::{self, GreenNode, SyntaxError, SyntaxNodeRef};
8 use crate::{SyntaxKind::*, TextRange, TextUnit};
9
10 #[derive(Debug, Clone)]
11 pub struct AtomEdit {
12     pub delete: TextRange,
13     pub insert: String,
14 }
15
16 impl AtomEdit {
17     pub fn replace(range: TextRange, replace_with: String) -> AtomEdit {
18         AtomEdit {
19             delete: range,
20             insert: replace_with,
21         }
22     }
23
24     pub fn delete(range: TextRange) -> AtomEdit {
25         AtomEdit::replace(range, String::new())
26     }
27
28     pub fn insert(offset: TextUnit, text: String) -> AtomEdit {
29         AtomEdit::replace(TextRange::offset_len(offset, 0.into()), text)
30     }
31 }
32
33 pub(crate) fn incremental_reparse(
34     node: SyntaxNodeRef,
35     edit: &AtomEdit,
36     errors: Vec<SyntaxError>,
37 ) -> Option<(GreenNode, Vec<SyntaxError>)> {
38     let (node, green, new_errors) =
39         reparse_leaf(node, &edit).or_else(|| reparse_block(node, &edit))?;
40     let green_root = node.replace_with(green);
41     let errors = merge_errors(errors, new_errors, node, edit);
42     Some((green_root, errors))
43 }
44
45 fn reparse_leaf<'node>(
46     node: SyntaxNodeRef<'node>,
47     edit: &AtomEdit,
48 ) -> Option<(SyntaxNodeRef<'node>, GreenNode, Vec<SyntaxError>)> {
49     let node = algo::find_covering_node(node, edit.delete);
50     match node.kind() {
51         WHITESPACE | COMMENT | IDENT | STRING | RAW_STRING => {
52             let text = get_text_after_edit(node, &edit);
53             let tokens = tokenize(&text);
54             let token = match tokens[..] {
55                 [token] if token.kind == node.kind() => token,
56                 _ => return None,
57             };
58
59             if token.kind == IDENT && is_contextual_kw(&text) {
60                 return None;
61             }
62
63             let green = GreenNode::new_leaf(node.kind(), text.into());
64             let new_errors = vec![];
65             Some((node, green, new_errors))
66         }
67         _ => None,
68     }
69 }
70
71 fn reparse_block<'node>(
72     node: SyntaxNodeRef<'node>,
73     edit: &AtomEdit,
74 ) -> Option<(SyntaxNodeRef<'node>, GreenNode, Vec<SyntaxError>)> {
75     let (node, reparser) = find_reparsable_node(node, edit.delete)?;
76     let text = get_text_after_edit(node, &edit);
77     let tokens = tokenize(&text);
78     if !is_balanced(&tokens) {
79         return None;
80     }
81     let (green, new_errors) =
82         parser_impl::parse_with(yellow::GreenBuilder::new(), &text, &tokens, reparser);
83     Some((node, green, new_errors))
84 }
85
86 fn get_text_after_edit(node: SyntaxNodeRef, edit: &AtomEdit) -> String {
87     replace_range(
88         node.text().to_string(),
89         edit.delete - node.range().start(),
90         &edit.insert,
91     )
92 }
93
94 fn is_contextual_kw(text: &str) -> bool {
95     match text {
96         "auto" | "default" | "union" => true,
97         _ => false,
98     }
99 }
100
101 type ParseFn = fn(&mut Parser);
102 fn find_reparsable_node(
103     node: SyntaxNodeRef<'_>,
104     range: TextRange,
105 ) -> Option<(SyntaxNodeRef<'_>, ParseFn)> {
106     let node = algo::find_covering_node(node, range);
107     return node
108         .ancestors()
109         .filter_map(|node| reparser(node).map(|r| (node, r)))
110         .next();
111
112     fn reparser(node: SyntaxNodeRef) -> Option<ParseFn> {
113         let res = match node.kind() {
114             BLOCK => grammar::block,
115             NAMED_FIELD_DEF_LIST => grammar::named_field_def_list,
116             NAMED_FIELD_LIST => grammar::named_field_list,
117             ENUM_VARIANT_LIST => grammar::enum_variant_list,
118             MATCH_ARM_LIST => grammar::match_arm_list,
119             USE_TREE_LIST => grammar::use_tree_list,
120             EXTERN_ITEM_LIST => grammar::extern_item_list,
121             TOKEN_TREE if node.first_child().unwrap().kind() == L_CURLY => grammar::token_tree,
122             ITEM_LIST => {
123                 let parent = node.parent().unwrap();
124                 match parent.kind() {
125                     IMPL_ITEM => grammar::impl_item_list,
126                     TRAIT_DEF => grammar::trait_item_list,
127                     MODULE => grammar::mod_item_list,
128                     _ => return None,
129                 }
130             }
131             _ => return None,
132         };
133         Some(res)
134     }
135 }
136
137 fn is_balanced(tokens: &[Token]) -> bool {
138     if tokens.is_empty()
139         || tokens.first().unwrap().kind != L_CURLY
140         || tokens.last().unwrap().kind != R_CURLY
141     {
142         return false;
143     }
144     let mut balance = 0usize;
145     for t in tokens.iter() {
146         match t.kind {
147             L_CURLY => balance += 1,
148             R_CURLY => {
149                 balance = match balance.checked_sub(1) {
150                     Some(b) => b,
151                     None => return false,
152                 }
153             }
154             _ => (),
155         }
156     }
157     balance == 0
158 }
159
160 fn merge_errors(
161     old_errors: Vec<SyntaxError>,
162     new_errors: Vec<SyntaxError>,
163     old_node: SyntaxNodeRef,
164     edit: &AtomEdit,
165 ) -> Vec<SyntaxError> {
166     let mut res = Vec::new();
167     for e in old_errors {
168         if e.offset <= old_node.range().start() {
169             res.push(e)
170         } else if e.offset >= old_node.range().end() {
171             res.push(SyntaxError {
172                 msg: e.msg,
173                 offset: e.offset + TextUnit::of_str(&edit.insert) - edit.delete.len(),
174             })
175         }
176     }
177     for e in new_errors {
178         res.push(SyntaxError {
179             msg: e.msg,
180             offset: e.offset + old_node.range().start(),
181         })
182     }
183     res
184 }
185
186 #[cfg(test)]
187 mod tests {
188     use super::{
189         super::{test_utils::extract_range, text_utils::replace_range, utils::dump_tree, File},
190         reparse_block, reparse_leaf, AtomEdit, GreenNode, SyntaxError, SyntaxNodeRef,
191 };
192
193     fn do_check<F>(before: &str, replace_with: &str, reparser: F)
194     where
195         for<'a> F: Fn(SyntaxNodeRef<'a>, &AtomEdit)
196             -> Option<(SyntaxNodeRef<'a>, GreenNode, Vec<SyntaxError>)>,
197     {
198         let (range, before) = extract_range(before);
199         let after = replace_range(before.clone(), range, replace_with);
200
201         let fully_reparsed = File::parse(&after);
202         let incrementally_reparsed = {
203             let f = File::parse(&before);
204             let edit = AtomEdit {
205                 delete: range,
206                 insert: replace_with.to_string(),
207             };
208             let (node, green, new_errors) =
209                 reparser(f.syntax(), &edit).expect("cannot incrementally reparse");
210             let green_root = node.replace_with(green);
211             let errors = super::merge_errors(f.errors(), new_errors, node, &edit);
212             File::new(green_root, errors)
213         };
214
215         assert_eq_text!(
216             &dump_tree(fully_reparsed.syntax()),
217             &dump_tree(incrementally_reparsed.syntax()),
218         )
219     }
220
221     #[test]
222     fn reparse_block_tests() {
223         let do_check = |before, replace_to| do_check(before, replace_to, reparse_block);
224
225         do_check(
226             r"
227 fn foo() {
228     let x = foo + <|>bar<|>
229 }
230 ",
231             "baz",
232         );
233         do_check(
234             r"
235 fn foo() {
236     let x = foo<|> + bar<|>
237 }
238 ",
239             "baz",
240         );
241         do_check(
242             r"
243 struct Foo {
244     f: foo<|><|>
245 }
246 ",
247             ",\n    g: (),",
248         );
249         do_check(
250             r"
251 fn foo {
252     let;
253     1 + 1;
254     <|>92<|>;
255 }
256 ",
257             "62",
258         );
259         do_check(
260             r"
261 mod foo {
262     fn <|><|>
263 }
264 ",
265             "bar",
266         );
267         do_check(
268             r"
269 trait Foo {
270     type <|>Foo<|>;
271 }
272 ",
273             "Output",
274         );
275         do_check(
276             r"
277 impl IntoIterator<Item=i32> for Foo {
278     f<|><|>
279 }
280 ",
281             "n next(",
282         );
283         do_check(
284             r"
285 use a::b::{foo,<|>,bar<|>};
286     ",
287             "baz",
288         );
289         do_check(
290             r"
291 pub enum A {
292     Foo<|><|>
293 }
294 ",
295             "\nBar;\n",
296         );
297         do_check(
298             r"
299 foo!{a, b<|><|> d}
300 ",
301             ", c[3]",
302         );
303         do_check(
304             r"
305 fn foo() {
306     vec![<|><|>]
307 }
308 ",
309             "123",
310         );
311         do_check(
312             r"
313 extern {
314     fn<|>;<|>
315 }
316 ",
317             " exit(code: c_int)",
318         );
319     }
320
321     #[test]
322     fn reparse_leaf_tests() {
323         let do_check = |before, replace_to| do_check(before, replace_to, reparse_leaf);
324
325         do_check(
326             r"<|><|>
327 fn foo() -> i32 { 1 }
328 ",
329             "\n\n\n   \n",
330         );
331         do_check(
332             r"
333 fn foo() -> <|><|> {}
334 ",
335             "  \n",
336         );
337         do_check(
338             r"
339 fn <|>foo<|>() -> i32 { 1 }
340 ",
341             "bar",
342         );
343         do_check(
344             r"
345 fn foo<|><|>foo() {  }
346 ",
347             "bar",
348         );
349         do_check(
350             r"
351 fn foo /* <|><|> */ () {}
352 ",
353             "some comment",
354         );
355         do_check(
356             r"
357 fn baz <|><|> () {}
358 ",
359             "    \t\t\n\n",
360         );
361         do_check(
362             r"
363 fn baz <|><|> () {}
364 ",
365             "    \t\t\n\n",
366         );
367         do_check(
368             r"
369 /// foo <|><|>omment
370 mod { }
371 ",
372             "c",
373         );
374         do_check(
375             r#"
376 fn -> &str { "Hello<|><|>" }
377 "#,
378             ", world",
379         );
380         do_check(
381             r#"
382 fn -> &str { // "Hello<|><|>"
383 "#,
384             ", world",
385         );
386         do_check(
387             r##"
388 fn -> &str { r#"Hello<|><|>"#
389 "##,
390             ", world",
391         );
392         do_check(
393             r"
394 #[derive(<|>Copy<|>)]
395 enum Foo {
396
397 }
398 ",
399             "Clone",
400         );
401     }
402 }