]> git.lizzy.rs Git - rust.git/blob - src/tree/mod.rs
a330caf54fe538d1de7a1cc086e0cfa1e3044401
[rust.git] / src / tree / mod.rs
1 use text::{TextRange, TextUnit};
2 use syntax_kinds::syntax_info;
3
4 use std::fmt;
5 use std::cmp;
6
7 mod file_builder;
8 pub use self::file_builder::{FileBuilder, Sink};
9
10 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
11 pub struct SyntaxKind(pub(crate) u32);
12
13 pub(crate) const EOF: SyntaxKind = SyntaxKind(!0);
14 pub(crate) const EOF_INFO: SyntaxInfo = SyntaxInfo { name: "EOF" };
15
16 pub(crate) const TOMBSTONE: SyntaxKind = SyntaxKind(!0 - 1);
17 pub(crate) const TOMBSTONE_INFO: SyntaxInfo = SyntaxInfo { name: "TOMBSTONE" };
18
19 impl SyntaxKind {
20     fn info(self) -> &'static SyntaxInfo {
21         match self {
22             EOF => &EOF_INFO,
23             TOMBSTONE => &TOMBSTONE_INFO,
24             _ => syntax_info(self),
25         }
26     }
27 }
28
29 impl fmt::Debug for SyntaxKind {
30     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
31         let name = self.info().name;
32         f.write_str(name)
33     }
34 }
35
36 pub(crate) struct SyntaxInfo {
37     pub name: &'static str,
38 }
39
40 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
41 pub struct Token {
42     pub kind: SyntaxKind,
43     pub len: TextUnit,
44 }
45
46 pub struct File {
47     text: String,
48     nodes: Vec<NodeData>,
49     errors: Vec<SyntaxErrorData>,
50 }
51
52 impl File {
53     pub fn root<'f>(&'f self) -> Node<'f> {
54         assert!(!self.nodes.is_empty());
55         Node {
56             file: self,
57             idx: NodeIdx(0),
58         }
59     }
60 }
61
62 #[derive(Clone, Copy)]
63 pub struct Node<'f> {
64     file: &'f File,
65     idx: NodeIdx,
66 }
67
68 impl<'f> Node<'f> {
69     pub fn kind(&self) -> SyntaxKind {
70         self.data().kind
71     }
72
73     pub fn range(&self) -> TextRange {
74         self.data().range
75     }
76
77     pub fn text(&self) -> &'f str {
78         &self.file.text.as_str()[self.range()]
79     }
80
81     pub fn parent(&self) -> Option<Node<'f>> {
82         self.as_node(self.data().parent)
83     }
84
85     pub fn children(&self) -> Children<'f> {
86         Children {
87             next: self.as_node(self.data().first_child),
88         }
89     }
90
91     pub fn errors(&self) -> SyntaxErrors<'f> {
92         let pos = self.file.errors.iter().position(|e| e.node == self.idx);
93         let next = pos.map(|i| ErrorIdx(i as u32)).map(|idx| SyntaxError {
94             file: self.file,
95             idx,
96         });
97         SyntaxErrors { next }
98     }
99
100     fn data(&self) -> &'f NodeData {
101         &self.file.nodes[self.idx]
102     }
103
104     fn as_node(&self, idx: Option<NodeIdx>) -> Option<Node<'f>> {
105         idx.map(|idx| Node {
106             file: self.file,
107             idx,
108         })
109     }
110 }
111
112 impl<'f> fmt::Debug for Node<'f> {
113     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
114         write!(fmt, "{:?}@{:?}", self.kind(), self.range())
115     }
116 }
117
118 impl<'f> cmp::PartialEq<Node<'f>> for Node<'f> {
119     fn eq(&self, other: &Node<'f>) -> bool {
120         self.idx == other.idx && ::std::ptr::eq(self.file, other.file)
121     }
122 }
123
124 impl<'f> cmp::Eq for Node<'f> {}
125
126 #[derive(Clone, Copy)]
127 pub struct SyntaxError<'f> {
128     file: &'f File,
129     idx: ErrorIdx,
130 }
131
132 impl<'f> SyntaxError<'f> {
133     pub fn message(&self) -> &'f str {
134         self.data().message.as_str()
135     }
136
137     pub fn after_child(&self) -> Option<Node<'f>> {
138         let idx = self.data().after_child?;
139         Some(Node {
140             file: self.file,
141             idx,
142         })
143     }
144
145     fn data(&self) -> &'f SyntaxErrorData {
146         &self.file.errors[self.idx]
147     }
148
149     fn next(&self) -> Option<SyntaxError<'f>> {
150         let next_idx = self.idx.0 + 1;
151         if !((next_idx as usize) < self.file.errors.len()) {
152             return None;
153         }
154         let result = SyntaxError {
155             file: self.file,
156             idx: ErrorIdx(next_idx),
157         };
158         if result.data().node != self.data().node {
159             return None;
160         }
161         Some(result)
162     }
163 }
164
165 pub struct Children<'f> {
166     next: Option<Node<'f>>,
167 }
168
169 impl<'f> Iterator for Children<'f> {
170     type Item = Node<'f>;
171
172     fn next(&mut self) -> Option<Node<'f>> {
173         let next = self.next;
174         self.next = next.and_then(|node| node.as_node(node.data().next_sibling));
175         next
176     }
177 }
178
179 pub struct SyntaxErrors<'f> {
180     next: Option<SyntaxError<'f>>,
181 }
182
183 impl<'f> Iterator for SyntaxErrors<'f> {
184     type Item = SyntaxError<'f>;
185
186     fn next(&mut self) -> Option<SyntaxError<'f>> {
187         let next = self.next;
188         self.next = next.as_ref().and_then(SyntaxError::next);
189         next
190     }
191 }
192
193 #[derive(Clone, Copy, PartialEq, Eq)]
194 struct NodeIdx(u32);
195
196 struct NodeData {
197     kind: SyntaxKind,
198     range: TextRange,
199     parent: Option<NodeIdx>,
200     first_child: Option<NodeIdx>,
201     next_sibling: Option<NodeIdx>,
202 }
203
204 impl ::std::ops::Index<NodeIdx> for Vec<NodeData> {
205     type Output = NodeData;
206
207     fn index(&self, NodeIdx(idx): NodeIdx) -> &NodeData {
208         &self[idx as usize]
209     }
210 }
211
212 impl ::std::ops::IndexMut<NodeIdx> for Vec<NodeData> {
213     fn index_mut(&mut self, NodeIdx(idx): NodeIdx) -> &mut NodeData {
214         &mut self[idx as usize]
215     }
216 }
217
218 #[derive(Clone, Copy)]
219 struct ErrorIdx(u32);
220
221 struct SyntaxErrorData {
222     node: NodeIdx,
223     message: String,
224     after_child: Option<NodeIdx>,
225 }
226
227 impl ::std::ops::Index<ErrorIdx> for Vec<SyntaxErrorData> {
228     type Output = SyntaxErrorData;
229
230     fn index(&self, ErrorIdx(idx): ErrorIdx) -> &SyntaxErrorData {
231         &self[idx as usize]
232     }
233 }