diff options
Diffstat (limited to 'crates/mbe/src/token_map.rs')
-rw-r--r-- | crates/mbe/src/token_map.rs | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/crates/mbe/src/token_map.rs b/crates/mbe/src/token_map.rs new file mode 100644 index 000000000..58c9f5aa5 --- /dev/null +++ b/crates/mbe/src/token_map.rs | |||
@@ -0,0 +1,83 @@ | |||
1 | use parser::{SyntaxKind, T}; | ||
2 | use syntax::{TextRange, TextSize}; | ||
3 | |||
4 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
5 | pub enum TokenTextRange { | ||
6 | Token(TextRange), | ||
7 | Delimiter(TextRange), | ||
8 | } | ||
9 | |||
10 | impl TokenTextRange { | ||
11 | pub fn by_kind(self, kind: SyntaxKind) -> Option<TextRange> { | ||
12 | match self { | ||
13 | TokenTextRange::Token(it) => Some(it), | ||
14 | TokenTextRange::Delimiter(it) => match kind { | ||
15 | T!['{'] | T!['('] | T!['['] => Some(TextRange::at(it.start(), 1.into())), | ||
16 | T!['}'] | T![')'] | T![']'] => { | ||
17 | Some(TextRange::at(it.end() - TextSize::of('}'), 1.into())) | ||
18 | } | ||
19 | _ => None, | ||
20 | }, | ||
21 | } | ||
22 | } | ||
23 | } | ||
24 | |||
25 | /// Maps `tt::TokenId` to the relative range of the original token. | ||
26 | #[derive(Debug, PartialEq, Eq, Clone, Default)] | ||
27 | pub struct TokenMap { | ||
28 | /// Maps `tt::TokenId` to the *relative* source range. | ||
29 | entries: Vec<(tt::TokenId, TokenTextRange)>, | ||
30 | } | ||
31 | |||
32 | impl TokenMap { | ||
33 | pub fn token_by_range(&self, relative_range: TextRange) -> Option<tt::TokenId> { | ||
34 | let &(token_id, _) = self.entries.iter().find(|(_, range)| match range { | ||
35 | TokenTextRange::Token(it) => *it == relative_range, | ||
36 | TokenTextRange::Delimiter(it) => { | ||
37 | let open = TextRange::at(it.start(), 1.into()); | ||
38 | let close = TextRange::at(it.end() - TextSize::of('}'), 1.into()); | ||
39 | open == relative_range || close == relative_range | ||
40 | } | ||
41 | })?; | ||
42 | Some(token_id) | ||
43 | } | ||
44 | |||
45 | pub fn range_by_token(&self, token_id: tt::TokenId) -> Option<TokenTextRange> { | ||
46 | let &(_, range) = self.entries.iter().find(|(tid, _)| *tid == token_id)?; | ||
47 | Some(range) | ||
48 | } | ||
49 | |||
50 | pub(crate) fn shrink_to_fit(&mut self) { | ||
51 | self.entries.shrink_to_fit(); | ||
52 | } | ||
53 | |||
54 | pub(crate) fn insert(&mut self, token_id: tt::TokenId, relative_range: TextRange) { | ||
55 | self.entries.push((token_id, TokenTextRange::Token(relative_range))); | ||
56 | } | ||
57 | |||
58 | pub(crate) fn insert_delim( | ||
59 | &mut self, | ||
60 | token_id: tt::TokenId, | ||
61 | open_relative_range: TextRange, | ||
62 | close_relative_range: TextRange, | ||
63 | ) -> usize { | ||
64 | let res = self.entries.len(); | ||
65 | let cover = open_relative_range.cover(close_relative_range); | ||
66 | |||
67 | self.entries.push((token_id, TokenTextRange::Delimiter(cover))); | ||
68 | res | ||
69 | } | ||
70 | |||
71 | pub(crate) fn update_close_delim(&mut self, idx: usize, close_relative_range: TextRange) { | ||
72 | let (_, token_text_range) = &mut self.entries[idx]; | ||
73 | if let TokenTextRange::Delimiter(dim) = token_text_range { | ||
74 | let cover = dim.cover(close_relative_range); | ||
75 | *token_text_range = TokenTextRange::Delimiter(cover); | ||
76 | } | ||
77 | } | ||
78 | |||
79 | pub(crate) fn remove_delim(&mut self, idx: usize) { | ||
80 | // FIXME: This could be accidentally quadratic | ||
81 | self.entries.remove(idx); | ||
82 | } | ||
83 | } | ||