aboutsummaryrefslogtreecommitdiff
path: root/crates/mbe/src/token_map.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/mbe/src/token_map.rs')
-rw-r--r--crates/mbe/src/token_map.rs83
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 @@
1use parser::{SyntaxKind, T};
2use syntax::{TextRange, TextSize};
3
4#[derive(Debug, PartialEq, Eq, Clone, Copy)]
5pub enum TokenTextRange {
6 Token(TextRange),
7 Delimiter(TextRange),
8}
9
10impl 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)]
27pub struct TokenMap {
28 /// Maps `tt::TokenId` to the *relative* source range.
29 entries: Vec<(tt::TokenId, TokenTextRange)>,
30}
31
32impl 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}