aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_mbe/src/tt_cursor.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_mbe/src/tt_cursor.rs')
-rw-r--r--crates/ra_mbe/src/tt_cursor.rs106
1 files changed, 105 insertions, 1 deletions
diff --git a/crates/ra_mbe/src/tt_cursor.rs b/crates/ra_mbe/src/tt_cursor.rs
index 741b5ea1c..eef642a9c 100644
--- a/crates/ra_mbe/src/tt_cursor.rs
+++ b/crates/ra_mbe/src/tt_cursor.rs
@@ -1,12 +1,18 @@
1use crate::ParseError; 1use crate::ParseError;
2use crate::subtree_parser::Parser; 2use crate::subtree_parser::Parser;
3use crate::subtree_source::TokenPeek;
4use smallvec::{SmallVec, smallvec};
3 5
4#[derive(Clone)] 6#[derive(Debug, Clone)]
5pub(crate) struct TtCursor<'a> { 7pub(crate) struct TtCursor<'a> {
6 subtree: &'a tt::Subtree, 8 subtree: &'a tt::Subtree,
7 pos: usize, 9 pos: usize,
8} 10}
9 11
12pub(crate) struct TtCursorMemento {
13 pos: usize,
14}
15
10impl<'a> TtCursor<'a> { 16impl<'a> TtCursor<'a> {
11 pub(crate) fn new(subtree: &'a tt::Subtree) -> TtCursor<'a> { 17 pub(crate) fn new(subtree: &'a tt::Subtree) -> TtCursor<'a> {
12 TtCursor { subtree, pos: 0 } 18 TtCursor { subtree, pos: 0 }
@@ -157,4 +163,102 @@ impl<'a> TtCursor<'a> {
157 Err(ParseError::Expected(format!("`{}`", char))) 163 Err(ParseError::Expected(format!("`{}`", char)))
158 } 164 }
159 } 165 }
166
167 fn eat_punct3(&mut self, p: &tt::Punct) -> Option<SmallVec<[tt::Punct; 3]>> {
168 let sec = self.eat_punct()?.clone();
169 let third = self.eat_punct()?.clone();
170 Some(smallvec![p.clone(), sec, third])
171 }
172
173 fn eat_punct2(&mut self, p: &tt::Punct) -> Option<SmallVec<[tt::Punct; 3]>> {
174 let sec = self.eat_punct()?.clone();
175 Some(smallvec![p.clone(), sec])
176 }
177
178 fn eat_multi_char_punct<'b, I>(
179 &mut self,
180 p: &tt::Punct,
181 iter: &mut TokenPeek<'b, I>,
182 ) -> Option<SmallVec<[tt::Punct; 3]>>
183 where
184 I: Iterator<Item = &'b tt::TokenTree>,
185 {
186 if let Some((m, _)) = iter.current_punct3(p) {
187 if let r @ Some(_) = match m {
188 ('<', '<', '=') | ('>', '>', '=') | ('.', '.', '.') | ('.', '.', '=') => {
189 self.eat_punct3(p)
190 }
191 _ => None,
192 } {
193 return r;
194 }
195 }
196
197 if let Some((m, _)) = iter.current_punct2(p) {
198 if let r @ Some(_) = match m {
199 ('<', '=')
200 | ('>', '=')
201 | ('+', '=')
202 | ('-', '=')
203 | ('|', '=')
204 | ('&', '=')
205 | ('^', '=')
206 | ('/', '=')
207 | ('*', '=')
208 | ('%', '=')
209 | ('&', '&')
210 | ('|', '|')
211 | ('<', '<')
212 | ('>', '>')
213 | ('-', '>')
214 | ('!', '=')
215 | ('=', '>')
216 | ('=', '=')
217 | ('.', '.')
218 | (':', ':') => self.eat_punct2(p),
219
220 _ => None,
221 } {
222 return r;
223 }
224 }
225
226 None
227 }
228
229 pub(crate) fn eat_seperator(&mut self) -> Option<crate::Separator> {
230 match self.eat()? {
231 tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => {
232 Some(crate::Separator::Literal(lit.clone()))
233 }
234 tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => {
235 Some(crate::Separator::Ident(ident.clone()))
236 }
237 tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => {
238 match punct.char {
239 '*' | '+' | '?' => return None,
240 _ => {}
241 };
242
243 // FIXME: The parser is only handle some compositeable punct,
244 // But at this phase, some punct still is jointed.
245 // So we by pass that check here.
246 let mut peekable = TokenPeek::new(self.subtree.token_trees[self.pos..].iter());
247 let puncts = self.eat_multi_char_punct(punct, &mut peekable);
248 let puncts = puncts.unwrap_or_else(|| smallvec![punct.clone()]);
249
250 Some(crate::Separator::Puncts(puncts))
251 }
252 _ => None,
253 }
254 }
255
256 #[must_use]
257 pub(crate) fn save(&self) -> TtCursorMemento {
258 TtCursorMemento { pos: self.pos }
259 }
260
261 pub(crate) fn rollback(&mut self, memento: TtCursorMemento) {
262 self.pos = memento.pos;
263 }
160} 264}