diff options
Diffstat (limited to 'crates/ra_mbe/src/subtree_parser.rs')
-rw-r--r-- | crates/ra_mbe/src/subtree_parser.rs | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/crates/ra_mbe/src/subtree_parser.rs b/crates/ra_mbe/src/subtree_parser.rs new file mode 100644 index 000000000..ce39a40bb --- /dev/null +++ b/crates/ra_mbe/src/subtree_parser.rs | |||
@@ -0,0 +1,61 @@ | |||
1 | use crate::subtree_source::SubtreeTokenSource; | ||
2 | |||
3 | use ra_parser::{TokenSource, TreeSink}; | ||
4 | use ra_syntax::{SyntaxKind}; | ||
5 | |||
6 | struct OffsetTokenSink { | ||
7 | token_pos: usize, | ||
8 | } | ||
9 | |||
10 | impl TreeSink for OffsetTokenSink { | ||
11 | fn token(&mut self, _kind: SyntaxKind, n_tokens: u8) { | ||
12 | self.token_pos += n_tokens as usize; | ||
13 | } | ||
14 | fn start_node(&mut self, _kind: SyntaxKind) {} | ||
15 | fn finish_node(&mut self) {} | ||
16 | fn error(&mut self, _error: ra_parser::ParseError) {} | ||
17 | } | ||
18 | |||
19 | pub(crate) struct Parser<'a> { | ||
20 | subtree: &'a tt::Subtree, | ||
21 | cur_pos: &'a mut usize, | ||
22 | } | ||
23 | |||
24 | impl<'a> Parser<'a> { | ||
25 | pub fn new(cur_pos: &'a mut usize, subtree: &'a tt::Subtree) -> Parser<'a> { | ||
26 | Parser { cur_pos, subtree } | ||
27 | } | ||
28 | |||
29 | pub fn parse_path(self) -> Option<tt::TokenTree> { | ||
30 | self.parse(ra_parser::parse_path) | ||
31 | } | ||
32 | |||
33 | fn parse<F>(self, f: F) -> Option<tt::TokenTree> | ||
34 | where | ||
35 | F: FnOnce(&dyn TokenSource, &mut dyn TreeSink), | ||
36 | { | ||
37 | let mut src = SubtreeTokenSource::new(self.subtree); | ||
38 | src.start_from_nth(*self.cur_pos); | ||
39 | let mut sink = OffsetTokenSink { token_pos: 0 }; | ||
40 | |||
41 | f(&src, &mut sink); | ||
42 | |||
43 | self.finish(sink.token_pos, &mut src) | ||
44 | } | ||
45 | |||
46 | fn finish(self, parsed_token: usize, src: &mut SubtreeTokenSource) -> Option<tt::TokenTree> { | ||
47 | let res = src.bump_n(parsed_token); | ||
48 | *self.cur_pos += res.len(); | ||
49 | |||
50 | let res: Vec<_> = res.into_iter().cloned().collect(); | ||
51 | |||
52 | match res.len() { | ||
53 | 0 => None, | ||
54 | 1 => Some(res[0].clone()), | ||
55 | _ => Some(tt::TokenTree::Subtree(tt::Subtree { | ||
56 | delimiter: tt::Delimiter::None, | ||
57 | token_trees: res, | ||
58 | })), | ||
59 | } | ||
60 | } | ||
61 | } | ||