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