diff options
author | Aleksey Kladov <[email protected]> | 2018-07-29 11:51:55 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-07-29 11:51:55 +0100 |
commit | c12450fb4e30c3418555e47d045bb9fd4318a10a (patch) | |
tree | e2dc508e1e415388392657cda3dfb00175cdabf2 /src/yellow | |
parent | 8d9961b75377a7bd2656b5aa1451710de8c86f60 (diff) |
Introduce red-green syntax tree
Diffstat (limited to 'src/yellow')
-rw-r--r-- | src/yellow/green.rs | 194 | ||||
-rw-r--r-- | src/yellow/mod.rs | 42 | ||||
-rw-r--r-- | src/yellow/red.rs | 87 | ||||
-rw-r--r-- | src/yellow/syntax.rs | 132 |
4 files changed, 455 insertions, 0 deletions
diff --git a/src/yellow/green.rs b/src/yellow/green.rs new file mode 100644 index 000000000..ede23b719 --- /dev/null +++ b/src/yellow/green.rs | |||
@@ -0,0 +1,194 @@ | |||
1 | use std::sync::Arc; | ||
2 | use text_unit::TextUnit; | ||
3 | use SyntaxKind; | ||
4 | |||
5 | type TokenText = String; | ||
6 | |||
7 | #[derive(Debug)] | ||
8 | pub(crate) struct GreenNode { | ||
9 | kind: SyntaxKind, | ||
10 | data: GreenNodeData, | ||
11 | } | ||
12 | |||
13 | impl GreenNode { | ||
14 | pub(crate) fn new_leaf(kind: SyntaxKind, text: TokenText) -> GreenNode { | ||
15 | GreenNode { | ||
16 | kind, | ||
17 | data: GreenNodeData::Leaf(GreenLeaf { text }), | ||
18 | } | ||
19 | } | ||
20 | |||
21 | pub(crate) fn new_branch( | ||
22 | kind: SyntaxKind, | ||
23 | ) -> GreenNode { | ||
24 | let branch = GreenBranch { | ||
25 | text_len: 0.into(), | ||
26 | leading_trivia: Trivias::default(), | ||
27 | children: Vec::new(), | ||
28 | }; | ||
29 | GreenNode { | ||
30 | kind, | ||
31 | data: GreenNodeData::Branch(branch), | ||
32 | } | ||
33 | } | ||
34 | |||
35 | pub(crate) fn push_trivia(&mut self, kind: SyntaxKind, text: TokenText) { | ||
36 | let branch = match &mut self.data { | ||
37 | GreenNodeData::Branch(branch) => branch, | ||
38 | _ => panic!() | ||
39 | }; | ||
40 | branch.text_len += TextUnit::of_str(&text); | ||
41 | let leading = &mut branch.leading_trivia; | ||
42 | branch.children.last_mut().map(|(_, t)| t).unwrap_or(leading) | ||
43 | .push(Arc::new(GreenTrivia { kind, text })); | ||
44 | } | ||
45 | |||
46 | pub(crate) fn push_child(&mut self, node: Arc<GreenNode>) { | ||
47 | let branch = match &mut self.data { | ||
48 | GreenNodeData::Branch(branch) => branch, | ||
49 | _ => panic!() | ||
50 | }; | ||
51 | branch.text_len += node.text_len(); | ||
52 | branch.children.push((node, Trivias::default())); | ||
53 | } | ||
54 | |||
55 | pub(crate) fn kind(&self) -> SyntaxKind { | ||
56 | self.kind | ||
57 | } | ||
58 | |||
59 | pub(crate) fn text_len(&self) -> TextUnit { | ||
60 | match &self.data { | ||
61 | GreenNodeData::Leaf(l) => l.text_len(), | ||
62 | GreenNodeData::Branch(b) => b.text_len(), | ||
63 | } | ||
64 | } | ||
65 | |||
66 | pub(crate) fn text(&self) -> String { | ||
67 | let mut buff = String::new(); | ||
68 | go(self, &mut buff); | ||
69 | return buff; | ||
70 | fn go(node: &GreenNode, buff: &mut String) { | ||
71 | match &node.data { | ||
72 | GreenNodeData::Leaf(l) => buff.push_str(&l.text), | ||
73 | GreenNodeData::Branch(branch) => { | ||
74 | add_trivia(&branch.leading_trivia, buff); | ||
75 | branch.children.iter().for_each(|(child, trivias)| { | ||
76 | go(child, buff); | ||
77 | add_trivia(trivias, buff); | ||
78 | }) | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | |||
83 | fn add_trivia(trivias: &Trivias, buff: &mut String) { | ||
84 | trivias.iter().for_each(|t| buff.push_str(&t.text)) | ||
85 | } | ||
86 | } | ||
87 | |||
88 | pub(crate) fn n_children(&self) -> usize { | ||
89 | match &self.data { | ||
90 | GreenNodeData::Leaf(_) => 0, | ||
91 | GreenNodeData::Branch(branch) => branch.children.len(), | ||
92 | } | ||
93 | } | ||
94 | |||
95 | pub(crate) fn nth_child(&self, idx: usize) -> &Arc<GreenNode> { | ||
96 | match &self.data { | ||
97 | GreenNodeData::Leaf(_) => panic!("leaf nodes have no children"), | ||
98 | GreenNodeData::Branch(branch) => &branch.children[idx].0, | ||
99 | } | ||
100 | } | ||
101 | |||
102 | pub(crate) fn nth_trivias(&self, idx: usize) -> &Trivias { | ||
103 | match &self.data { | ||
104 | GreenNodeData::Leaf(_) => panic!("leaf nodes have no children"), | ||
105 | GreenNodeData::Branch(branch) => if idx == 0 { | ||
106 | &branch.leading_trivia | ||
107 | } else { | ||
108 | &branch.children[idx - 1].1 | ||
109 | }, | ||
110 | } | ||
111 | } | ||
112 | |||
113 | pub(crate) fn is_leaf(&self) -> bool { | ||
114 | match self.data { | ||
115 | GreenNodeData::Leaf(_) => true, | ||
116 | GreenNodeData::Branch(_) => false | ||
117 | } | ||
118 | } | ||
119 | |||
120 | pub(crate) fn leaf_text(&self) -> &str { | ||
121 | match &self.data { | ||
122 | GreenNodeData::Leaf(l) => l.text.as_str(), | ||
123 | GreenNodeData::Branch(_) => panic!("not a leaf") | ||
124 | } | ||
125 | } | ||
126 | } | ||
127 | |||
128 | #[derive(Debug)] | ||
129 | enum GreenNodeData { | ||
130 | Leaf(GreenLeaf), | ||
131 | Branch(GreenBranch), | ||
132 | } | ||
133 | |||
134 | #[derive(Debug)] | ||
135 | struct GreenLeaf { | ||
136 | text: TokenText | ||
137 | } | ||
138 | |||
139 | #[derive(Debug)] | ||
140 | struct GreenBranch { | ||
141 | text_len: TextUnit, | ||
142 | leading_trivia: Trivias, | ||
143 | children: Vec<(Arc<GreenNode>, Trivias)>, | ||
144 | } | ||
145 | |||
146 | #[derive(Debug)] | ||
147 | pub(crate) struct GreenTrivia { | ||
148 | pub(crate) kind: SyntaxKind, | ||
149 | pub(crate) text: TokenText, | ||
150 | } | ||
151 | |||
152 | type Trivias = Vec<Arc<GreenTrivia>>; | ||
153 | |||
154 | |||
155 | pub(crate) trait TextLen { | ||
156 | fn text_len(&self) -> TextUnit; | ||
157 | } | ||
158 | |||
159 | impl TextLen for GreenTrivia { | ||
160 | fn text_len(&self) -> TextUnit { | ||
161 | TextUnit::of_str(&self.text) | ||
162 | } | ||
163 | } | ||
164 | |||
165 | impl<T: TextLen> TextLen for Arc<T> { | ||
166 | fn text_len(&self) -> TextUnit { | ||
167 | let this: &T = self; | ||
168 | this.text_len() | ||
169 | } | ||
170 | } | ||
171 | |||
172 | impl TextLen for GreenNode { | ||
173 | fn text_len(&self) -> TextUnit { | ||
174 | self.text_len() | ||
175 | } | ||
176 | } | ||
177 | |||
178 | impl TextLen for GreenLeaf { | ||
179 | fn text_len(&self) -> TextUnit { | ||
180 | TextUnit::of_str(&self.text) | ||
181 | } | ||
182 | } | ||
183 | |||
184 | impl TextLen for GreenBranch { | ||
185 | fn text_len(&self) -> TextUnit { | ||
186 | self.text_len | ||
187 | } | ||
188 | } | ||
189 | |||
190 | impl<T: TextLen> TextLen for [T] { | ||
191 | fn text_len(&self) -> TextUnit { | ||
192 | self.iter().map(TextLen::text_len).sum() | ||
193 | } | ||
194 | } | ||
diff --git a/src/yellow/mod.rs b/src/yellow/mod.rs new file mode 100644 index 000000000..236328a7f --- /dev/null +++ b/src/yellow/mod.rs | |||
@@ -0,0 +1,42 @@ | |||
1 | mod green; | ||
2 | mod red; | ||
3 | mod syntax; | ||
4 | |||
5 | use std::{ | ||
6 | sync::{Arc, Weak}, | ||
7 | ops::Deref, | ||
8 | mem | ||
9 | }; | ||
10 | pub(crate) use self::{ | ||
11 | green::{GreenNode, TextLen}, | ||
12 | red::RedNode, | ||
13 | syntax::SError, | ||
14 | }; | ||
15 | pub use self::syntax::SyntaxNode; | ||
16 | |||
17 | // This could be just `*const T`, but we use `Weak` for additional checks | ||
18 | #[derive(Debug)] | ||
19 | pub(crate) struct Ptr<T>(Weak<T>); | ||
20 | |||
21 | impl<T> Clone for Ptr<T> { | ||
22 | fn clone(&self) -> Self { | ||
23 | Ptr(self.0.clone()) | ||
24 | } | ||
25 | } | ||
26 | |||
27 | impl<T> Ptr<T> { | ||
28 | fn clone(self_: &Ptr<T>) -> Ptr<T> { | ||
29 | Ptr(Weak::clone(&self_.0)) | ||
30 | } | ||
31 | |||
32 | fn new(arc: &Arc<T>) -> Ptr<T> { | ||
33 | Ptr(Arc::downgrade(arc)) | ||
34 | } | ||
35 | |||
36 | unsafe fn get(&self) -> &T { | ||
37 | let t = self.0.upgrade() | ||
38 | .expect("caller must guarantee that Ptr is not null"); | ||
39 | let t: &T = &*t; | ||
40 | mem::transmute(t) | ||
41 | } | ||
42 | } | ||
diff --git a/src/yellow/red.rs b/src/yellow/red.rs new file mode 100644 index 000000000..feba99faa --- /dev/null +++ b/src/yellow/red.rs | |||
@@ -0,0 +1,87 @@ | |||
1 | use std::sync::{Arc, Weak, RwLock}; | ||
2 | use { | ||
3 | TextUnit, SyntaxKind, TextRange, | ||
4 | yellow::{Ptr, GreenNode, TextLen} | ||
5 | }; | ||
6 | |||
7 | #[derive(Debug)] | ||
8 | pub(crate) struct RedNode { | ||
9 | green: Arc<GreenNode>, | ||
10 | parent: Option<ParentData>, | ||
11 | children: RwLock<Vec<Option<Arc<RedNode>>>>, | ||
12 | } | ||
13 | |||
14 | #[derive(Debug)] | ||
15 | struct ParentData { | ||
16 | parent: Ptr<RedNode>, | ||
17 | start_offset: TextUnit, | ||
18 | index_in_parent: usize, | ||
19 | } | ||
20 | |||
21 | impl RedNode { | ||
22 | pub fn new_root( | ||
23 | green: Arc<GreenNode>, | ||
24 | ) -> RedNode { | ||
25 | RedNode::new(green, None) | ||
26 | } | ||
27 | |||
28 | fn new_child( | ||
29 | green: Arc<GreenNode>, | ||
30 | parent: Ptr<RedNode>, | ||
31 | start_offset: TextUnit, | ||
32 | index_in_parent: usize | ||
33 | ) -> RedNode { | ||
34 | let parent_data = ParentData { | ||
35 | parent, | ||
36 | start_offset, | ||
37 | index_in_parent | ||
38 | }; | ||
39 | RedNode::new(green, Some(parent_data)) | ||
40 | } | ||
41 | |||
42 | fn new( | ||
43 | green: Arc<GreenNode>, | ||
44 | parent: Option<ParentData>, | ||
45 | ) -> RedNode { | ||
46 | let children = vec![None; green.n_children()]; | ||
47 | RedNode { green, parent, children: RwLock::new(children) } | ||
48 | } | ||
49 | |||
50 | pub(crate) fn green(&self) -> &GreenNode { | ||
51 | &self.green | ||
52 | } | ||
53 | |||
54 | pub(crate) fn start_offset(&self) -> TextUnit { | ||
55 | match &self.parent { | ||
56 | None => 0.into(), | ||
57 | Some(p) => p.start_offset, | ||
58 | } | ||
59 | } | ||
60 | |||
61 | pub(crate) fn n_children(&self) -> usize { | ||
62 | self.green.n_children() | ||
63 | } | ||
64 | |||
65 | pub(crate) fn nth_child(&self, me: Ptr<RedNode>, n: usize) -> Arc<RedNode> { | ||
66 | match &self.children.read().unwrap()[n] { | ||
67 | Some(child) => return child.clone(), | ||
68 | None => (), | ||
69 | } | ||
70 | let mut children = self.children.write().unwrap(); | ||
71 | if children[n].is_none() { | ||
72 | let start_offset = { | ||
73 | let mut acc = self.start_offset(); | ||
74 | for i in 0..n { | ||
75 | acc += self.green.nth_trivias(i).text_len(); | ||
76 | acc += self.green.nth_child(i).text_len(); | ||
77 | } | ||
78 | acc += self.green.nth_trivias(n).text_len(); | ||
79 | acc | ||
80 | }; | ||
81 | let green = self.green.nth_child(n).clone(); | ||
82 | let child = RedNode::new_child(green, me, start_offset, n); | ||
83 | children[n] = Some(Arc::new(child)) | ||
84 | } | ||
85 | children[n].as_ref().unwrap().clone() | ||
86 | } | ||
87 | } | ||
diff --git a/src/yellow/syntax.rs b/src/yellow/syntax.rs new file mode 100644 index 000000000..0c9ffeb14 --- /dev/null +++ b/src/yellow/syntax.rs | |||
@@ -0,0 +1,132 @@ | |||
1 | use std::{ | ||
2 | fmt, | ||
3 | sync::Arc, | ||
4 | }; | ||
5 | |||
6 | use { | ||
7 | TextRange, TextUnit, SyntaxKind, | ||
8 | yellow::{Ptr, RedNode, GreenNode, TextLen}, | ||
9 | }; | ||
10 | use yellow::green::GreenTrivia; | ||
11 | |||
12 | #[derive(Clone)] | ||
13 | pub struct SyntaxNode { | ||
14 | pub(crate) root: SyntaxRoot, | ||
15 | red: Ptr<RedNode>, | ||
16 | trivia_pos: Option<(usize, usize)>, | ||
17 | } | ||
18 | |||
19 | #[derive(Clone)] | ||
20 | pub struct SyntaxRoot { | ||
21 | red: Arc<RedNode>, | ||
22 | pub(crate) errors: Arc<Vec<SError>>, | ||
23 | } | ||
24 | |||
25 | #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] | ||
26 | pub(crate) struct SError { | ||
27 | pub(crate) message: String, | ||
28 | pub(crate) offset: TextUnit, | ||
29 | } | ||
30 | |||
31 | impl SyntaxNode { | ||
32 | pub(crate) fn new(root: Arc<GreenNode>, errors: Vec<SError>) -> SyntaxNode { | ||
33 | let root = Arc::new(RedNode::new_root(root)); | ||
34 | let red = Ptr::new(&root); | ||
35 | let root = SyntaxRoot { red: root, errors: Arc::new(errors) }; | ||
36 | SyntaxNode { root, red, trivia_pos: None } | ||
37 | } | ||
38 | |||
39 | pub fn kind(&self) -> SyntaxKind { | ||
40 | let green = self.red().green(); | ||
41 | match self.trivia_pos { | ||
42 | None => green.kind(), | ||
43 | Some((i, j)) => green.nth_trivias(i)[j].kind | ||
44 | } | ||
45 | } | ||
46 | |||
47 | pub fn range(&self) -> TextRange { | ||
48 | let red = self.red(); | ||
49 | let green = red.green(); | ||
50 | match self.trivia_pos { | ||
51 | None => TextRange::offset_len(red.start_offset(), red.green().text_len()), | ||
52 | Some((i, j)) => { | ||
53 | let trivias = green.nth_trivias(i); | ||
54 | let offset = if i == 0 { | ||
55 | red.start_offset() | ||
56 | } else { | ||
57 | let prev_child = red.nth_child(Ptr::clone(&self.red), i - 1); | ||
58 | let mut offset = prev_child.start_offset() + prev_child.green().text_len(); | ||
59 | for k in 0..j { | ||
60 | offset += &trivias[k].text_len(); | ||
61 | } | ||
62 | offset | ||
63 | }; | ||
64 | TextRange::offset_len(offset, trivias[j].text_len()) | ||
65 | } | ||
66 | } | ||
67 | } | ||
68 | |||
69 | pub fn text(&self) -> String { | ||
70 | let green = self.red().green(); | ||
71 | match self.trivia_pos { | ||
72 | None => green.text(), | ||
73 | Some((i, j)) => green.nth_trivias(i)[j].text.clone() | ||
74 | } | ||
75 | } | ||
76 | |||
77 | pub fn children(&self) -> Vec<SyntaxNode> { | ||
78 | let mut res = Vec::new(); | ||
79 | let red = self.red(); | ||
80 | let green = red.green(); | ||
81 | if green.is_leaf() || self.trivia_pos.is_some() { | ||
82 | return Vec::new(); | ||
83 | } | ||
84 | for (j, _) in green.nth_trivias(0).iter().enumerate() { | ||
85 | res.push(SyntaxNode { | ||
86 | root: self.root.clone(), | ||
87 | red: Ptr::clone(&self.red), | ||
88 | trivia_pos: Some((0, j)), | ||
89 | }) | ||
90 | } | ||
91 | |||
92 | let n_children = red.n_children(); | ||
93 | for i in 0..n_children { | ||
94 | res.push(SyntaxNode { | ||
95 | root: self.root.clone(), | ||
96 | red: Ptr::new(&red.nth_child(Ptr::clone(&self.red), i)), | ||
97 | trivia_pos: None, | ||
98 | }); | ||
99 | for (j, _) in green.nth_trivias(i + 1).iter().enumerate() { | ||
100 | res.push(SyntaxNode { | ||
101 | root: self.root.clone(), | ||
102 | red: self.red.clone(), | ||
103 | trivia_pos: Some((i + 1, j)), | ||
104 | }) | ||
105 | } | ||
106 | } | ||
107 | res | ||
108 | } | ||
109 | |||
110 | fn red(&self) -> &RedNode { | ||
111 | // Safe b/c root ptr keeps red alive | ||
112 | unsafe { self.red.get() } | ||
113 | } | ||
114 | } | ||
115 | |||
116 | impl fmt::Debug for SyntaxNode { | ||
117 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||
118 | write!(fmt, "{:?}@{:?}", self.kind(), self.range())?; | ||
119 | if has_short_text(self.kind()) { | ||
120 | write!(fmt, " \"{}\"", self.text())?; | ||
121 | } | ||
122 | Ok(()) | ||
123 | } | ||
124 | } | ||
125 | |||
126 | fn has_short_text(kind: SyntaxKind) -> bool { | ||
127 | use syntax_kinds::*; | ||
128 | match kind { | ||
129 | IDENT | LIFETIME => true, | ||
130 | _ => false, | ||
131 | } | ||
132 | } | ||