aboutsummaryrefslogtreecommitdiff
path: root/crates/libsyntax2
diff options
context:
space:
mode:
Diffstat (limited to 'crates/libsyntax2')
-rw-r--r--crates/libsyntax2/Cargo.toml2
-rw-r--r--crates/libsyntax2/src/algo/mod.rs48
-rw-r--r--crates/libsyntax2/src/syntax_kinds/mod.rs2
-rw-r--r--crates/libsyntax2/src/yellow/syntax.rs11
-rw-r--r--crates/libsyntax2/tests/test/main.rs48
5 files changed, 62 insertions, 49 deletions
diff --git a/crates/libsyntax2/Cargo.toml b/crates/libsyntax2/Cargo.toml
index 5a76ea82b..4c4040fe5 100644
--- a/crates/libsyntax2/Cargo.toml
+++ b/crates/libsyntax2/Cargo.toml
@@ -12,4 +12,4 @@ drop_bomb = "0.1.4"
12parking_lot = "0.6.0" 12parking_lot = "0.6.0"
13 13
14[dev-dependencies] 14[dev-dependencies]
15difference = "2.0.0" 15assert_eq_text = { path = "../assert_eq_text" }
diff --git a/crates/libsyntax2/src/algo/mod.rs b/crates/libsyntax2/src/algo/mod.rs
index 263b58d97..6efdff12f 100644
--- a/crates/libsyntax2/src/algo/mod.rs
+++ b/crates/libsyntax2/src/algo/mod.rs
@@ -74,7 +74,6 @@ impl<'f> Iterator for LeafAtOffset<'f> {
74 } 74 }
75} 75}
76 76
77
78pub fn find_covering_node(root: SyntaxNodeRef, range: TextRange) -> SyntaxNodeRef { 77pub fn find_covering_node(root: SyntaxNodeRef, range: TextRange) -> SyntaxNodeRef {
79 assert!(is_subrange(root.range(), range)); 78 assert!(is_subrange(root.range(), range));
80 let (left, right) = match ( 79 let (left, right) = match (
@@ -88,31 +87,33 @@ pub fn find_covering_node(root: SyntaxNodeRef, range: TextRange) -> SyntaxNodeRe
88 common_ancestor(left, right) 87 common_ancestor(left, right)
89} 88}
90 89
91fn common_ancestor<'a>(n1: SyntaxNodeRef<'a>, n2: SyntaxNodeRef<'a>) -> SyntaxNodeRef<'a> {
92 for p in ancestors(n1) {
93 if ancestors(n2).any(|a| a == p) {
94 return p;
95 }
96 }
97 panic!("Can't find common ancestor of {:?} and {:?}", n1, n2)
98}
99
100pub fn ancestors<'a>(node: SyntaxNodeRef<'a>) -> impl Iterator<Item=SyntaxNodeRef<'a>> { 90pub fn ancestors<'a>(node: SyntaxNodeRef<'a>) -> impl Iterator<Item=SyntaxNodeRef<'a>> {
101 Ancestors(Some(node)) 91 generate(Some(node), |&node| node.parent())
102} 92}
103 93
104#[derive(Debug)] 94#[derive(Debug)]
105struct Ancestors<'a>(Option<SyntaxNodeRef<'a>>); 95pub enum Direction {
96 Forward,
97 Backward,
98}
106 99
107impl<'a> Iterator for Ancestors<'a> { 100pub fn siblings<'a>(
108 type Item = SyntaxNodeRef<'a>; 101 node: SyntaxNodeRef<'a>,
102 direction: Direction
103) -> impl Iterator<Item=SyntaxNodeRef<'a>> {
104 generate(Some(node), move |&node| match direction {
105 Direction::Forward => node.next_sibling(),
106 Direction::Backward => node.prev_sibling(),
107 })
108}
109 109
110 fn next(&mut self) -> Option<Self::Item> { 110fn common_ancestor<'a>(n1: SyntaxNodeRef<'a>, n2: SyntaxNodeRef<'a>) -> SyntaxNodeRef<'a> {
111 self.0.take().map(|n| { 111 for p in ancestors(n1) {
112 self.0 = n.parent(); 112 if ancestors(n2).any(|a| a == p) {
113 n 113 return p;
114 }) 114 }
115 } 115 }
116 panic!("Can't find common ancestor of {:?} and {:?}", n1, n2)
116} 117}
117 118
118fn contains_offset_nonstrict(range: TextRange, offset: TextUnit) -> bool { 119fn contains_offset_nonstrict(range: TextRange, offset: TextUnit) -> bool {
@@ -122,3 +123,12 @@ fn contains_offset_nonstrict(range: TextRange, offset: TextUnit) -> bool {
122fn is_subrange(range: TextRange, subrange: TextRange) -> bool { 123fn is_subrange(range: TextRange, subrange: TextRange) -> bool {
123 range.start() <= subrange.start() && subrange.end() <= range.end() 124 range.start() <= subrange.start() && subrange.end() <= range.end()
124} 125}
126
127fn generate<T>(seed: Option<T>, step: impl Fn(&T) -> Option<T>) -> impl Iterator<Item=T> {
128 ::itertools::unfold(seed, move |slot| {
129 slot.take().map(|curr| {
130 *slot = step(&curr);
131 curr
132 })
133 })
134}
diff --git a/crates/libsyntax2/src/syntax_kinds/mod.rs b/crates/libsyntax2/src/syntax_kinds/mod.rs
index ed4fa5d4d..332cd13ac 100644
--- a/crates/libsyntax2/src/syntax_kinds/mod.rs
+++ b/crates/libsyntax2/src/syntax_kinds/mod.rs
@@ -17,7 +17,7 @@ pub(crate) struct SyntaxInfo {
17} 17}
18 18
19impl SyntaxKind { 19impl SyntaxKind {
20 pub(crate) fn is_trivia(self) -> bool { 20 pub fn is_trivia(self) -> bool {
21 match self { 21 match self {
22 WHITESPACE | COMMENT | DOC_COMMENT => true, 22 WHITESPACE | COMMENT | DOC_COMMENT => true,
23 _ => false, 23 _ => false,
diff --git a/crates/libsyntax2/src/yellow/syntax.rs b/crates/libsyntax2/src/yellow/syntax.rs
index a22275ed9..00f76e51c 100644
--- a/crates/libsyntax2/src/yellow/syntax.rs
+++ b/crates/libsyntax2/src/yellow/syntax.rs
@@ -101,6 +101,17 @@ impl<R: TreeRoot> SyntaxNode<R> {
101 }) 101 })
102 } 102 }
103 103
104 pub fn prev_sibling(&self) -> Option<SyntaxNode<R>> {
105 let red = self.red();
106 let parent = self.parent()?;
107 let prev_sibling_idx = red.index_in_parent()?.checked_sub(1)?;
108 let sibling_red = parent.red().get_child(prev_sibling_idx)?;
109 Some(SyntaxNode {
110 root: self.root.clone(),
111 red: sibling_red,
112 })
113 }
114
104 pub fn is_leaf(&self) -> bool { 115 pub fn is_leaf(&self) -> bool {
105 self.first_child().is_none() 116 self.first_child().is_none()
106 } 117 }
diff --git a/crates/libsyntax2/tests/test/main.rs b/crates/libsyntax2/tests/test/main.rs
index 18e5bc4d4..64d080dfd 100644
--- a/crates/libsyntax2/tests/test/main.rs
+++ b/crates/libsyntax2/tests/test/main.rs
@@ -1,5 +1,6 @@
1extern crate libsyntax2; 1extern crate libsyntax2;
2extern crate difference; 2#[macro_use]
3extern crate assert_eq_text;
3 4
4use std::{ 5use std::{
5 fs, 6 fs,
@@ -7,8 +8,6 @@ use std::{
7 fmt::Write, 8 fmt::Write,
8}; 9};
9 10
10use difference::Changeset;
11
12#[test] 11#[test]
13fn lexer_tests() { 12fn lexer_tests() {
14 dir_tests(&["lexer"], |text| { 13 dir_tests(&["lexer"], |text| {
@@ -63,10 +62,26 @@ pub fn dir_tests<F>(paths: &[&str], f: F)
63 } 62 }
64} 63}
65 64
65const REWRITE: bool = false;
66
66fn assert_equal_text(expected: &str, actual: &str, path: &Path) { 67fn assert_equal_text(expected: &str, actual: &str, path: &Path) {
67 if expected != actual { 68 if expected == actual {
68 print_difference(expected, actual, path) 69 return;
70 }
71 let dir = project_dir();
72 let path = path.strip_prefix(&dir).unwrap_or_else(|_| path);
73 if expected.trim() == actual.trim() {
74 println!("whitespace difference, rewriting");
75 println!("file: {}\n", path.display());
76 fs::write(path, actual).unwrap();
77 return;
78 }
79 if REWRITE {
80 println!("rewriting {}", path.display());
81 fs::write(path, actual).unwrap();
82 return;
69 } 83 }
84 assert_eq_text!(expected, actual, "file: {}", path.display());
70} 85}
71 86
72fn collect_tests(paths: &[&str]) -> Vec<PathBuf> { 87fn collect_tests(paths: &[&str]) -> Vec<PathBuf> {
@@ -92,29 +107,6 @@ fn test_from_dir(dir: &Path) -> Vec<PathBuf> {
92 acc 107 acc
93} 108}
94 109
95const REWRITE: bool = false;
96
97fn print_difference(expected: &str, actual: &str, path: &Path) {
98 let dir = project_dir();
99 let path = path.strip_prefix(&dir).unwrap_or_else(|_| path);
100 if expected.trim() == actual.trim() {
101 println!("whitespace difference, rewriting");
102 println!("file: {}\n", path.display());
103 fs::write(path, actual).unwrap();
104 return;
105 }
106 if REWRITE {
107 println!("rewriting {}", path.display());
108 fs::write(path, actual).unwrap();
109 return;
110 }
111 let changeset = Changeset::new(actual, expected, "\n");
112 println!("Expected:\n{}\n\nActual:\n{}\n", expected, actual);
113 print!("{}", changeset);
114 println!("file: {}\n", path.display());
115 panic!("Comparison failed")
116}
117
118fn project_dir() -> PathBuf { 110fn project_dir() -> PathBuf {
119 let dir = env!("CARGO_MANIFEST_DIR"); 111 let dir = env!("CARGO_MANIFEST_DIR");
120 PathBuf::from(dir) 112 PathBuf::from(dir)