diff options
Diffstat (limited to 'crates/ra_syntax/src/utils.rs')
-rw-r--r-- | crates/ra_syntax/src/utils.rs | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/crates/ra_syntax/src/utils.rs b/crates/ra_syntax/src/utils.rs new file mode 100644 index 000000000..671dd7afa --- /dev/null +++ b/crates/ra_syntax/src/utils.rs | |||
@@ -0,0 +1,85 @@ | |||
1 | use std::fmt::Write; | ||
2 | use { | ||
3 | algo::walk::{preorder, walk, WalkEvent}, | ||
4 | SyntaxKind, File, SyntaxNodeRef, TreeRoot, | ||
5 | }; | ||
6 | |||
7 | /// Parse a file and create a string representation of the resulting parse tree. | ||
8 | pub fn dump_tree(syntax: SyntaxNodeRef) -> String { | ||
9 | let mut errors: Vec<_> = syntax.root.syntax_root().errors.iter().cloned().collect(); | ||
10 | errors.sort_by_key(|e| e.offset); | ||
11 | let mut err_pos = 0; | ||
12 | let mut level = 0; | ||
13 | let mut buf = String::new(); | ||
14 | macro_rules! indent { | ||
15 | () => { | ||
16 | for _ in 0..level { | ||
17 | buf.push_str(" "); | ||
18 | } | ||
19 | }; | ||
20 | } | ||
21 | |||
22 | for event in walk(syntax) { | ||
23 | match event { | ||
24 | WalkEvent::Enter(node) => { | ||
25 | indent!(); | ||
26 | writeln!(buf, "{:?}", node).unwrap(); | ||
27 | if node.first_child().is_none() { | ||
28 | let off = node.range().end(); | ||
29 | while err_pos < errors.len() && errors[err_pos].offset <= off { | ||
30 | indent!(); | ||
31 | writeln!(buf, "err: `{}`", errors[err_pos].msg).unwrap(); | ||
32 | err_pos += 1; | ||
33 | } | ||
34 | } | ||
35 | level += 1; | ||
36 | } | ||
37 | WalkEvent::Exit(_) => level -= 1, | ||
38 | } | ||
39 | } | ||
40 | |||
41 | assert_eq!(level, 0); | ||
42 | for err in errors[err_pos..].iter() { | ||
43 | writeln!(buf, "err: `{}`", err.msg).unwrap(); | ||
44 | } | ||
45 | |||
46 | return buf; | ||
47 | } | ||
48 | |||
49 | pub fn check_fuzz_invariants(text: &str) { | ||
50 | let file = File::parse(text); | ||
51 | let root = file.syntax(); | ||
52 | validate_block_structure(root); | ||
53 | let _ = file.ast(); | ||
54 | let _ = file.errors(); | ||
55 | } | ||
56 | |||
57 | pub(crate) fn validate_block_structure(root: SyntaxNodeRef) { | ||
58 | let mut stack = Vec::new(); | ||
59 | for node in preorder(root) { | ||
60 | match node.kind() { | ||
61 | SyntaxKind::L_CURLY => { | ||
62 | stack.push(node) | ||
63 | } | ||
64 | SyntaxKind::R_CURLY => { | ||
65 | if let Some(pair) = stack.pop() { | ||
66 | assert_eq!( | ||
67 | node.parent(), | ||
68 | pair.parent(), | ||
69 | "\nunpaired curleys:\n{}\n{}\n", | ||
70 | root.text(), | ||
71 | dump_tree(root), | ||
72 | ); | ||
73 | assert!( | ||
74 | node.next_sibling().is_none() && pair.prev_sibling().is_none(), | ||
75 | "\nfloating curlys at {:?}\nfile:\n{}\nerror:\n{}\n", | ||
76 | node, | ||
77 | root.text(), | ||
78 | node.text(), | ||
79 | ); | ||
80 | } | ||
81 | } | ||
82 | _ => (), | ||
83 | } | ||
84 | } | ||
85 | } | ||