• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Mapping between `TokenId`s and the token's position in macro definitions or inputs.
2 
3 use std::hash::Hash;
4 
5 use parser::{SyntaxKind, T};
6 use syntax::{TextRange, TextSize};
7 
8 use crate::syntax_bridge::SyntheticTokenId;
9 
10 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
11 enum TokenTextRange {
12     Token(TextRange),
13     Delimiter(TextRange),
14 }
15 
16 impl TokenTextRange {
by_kind(self, kind: SyntaxKind) -> Option<TextRange>17     fn by_kind(self, kind: SyntaxKind) -> Option<TextRange> {
18         match self {
19             TokenTextRange::Token(it) => Some(it),
20             TokenTextRange::Delimiter(it) => match kind {
21                 T!['{'] | T!['('] | T!['['] => Some(TextRange::at(it.start(), 1.into())),
22                 T!['}'] | T![')'] | T![']'] => {
23                     Some(TextRange::at(it.end() - TextSize::of('}'), 1.into()))
24                 }
25                 _ => None,
26             },
27         }
28     }
29 }
30 
31 /// Maps `tt::TokenId` to the relative range of the original token.
32 #[derive(Debug, PartialEq, Eq, Clone, Default, Hash)]
33 pub struct TokenMap {
34     /// Maps `tt::TokenId` to the *relative* source range.
35     entries: Vec<(tt::TokenId, TokenTextRange)>,
36     pub synthetic_entries: Vec<(tt::TokenId, SyntheticTokenId)>,
37 }
38 
39 impl TokenMap {
token_by_range(&self, relative_range: TextRange) -> Option<tt::TokenId>40     pub fn token_by_range(&self, relative_range: TextRange) -> Option<tt::TokenId> {
41         let &(token_id, _) = self.entries.iter().find(|(_, range)| match range {
42             TokenTextRange::Token(it) => *it == relative_range,
43             TokenTextRange::Delimiter(it) => {
44                 let open = TextRange::at(it.start(), 1.into());
45                 let close = TextRange::at(it.end() - TextSize::of('}'), 1.into());
46                 open == relative_range || close == relative_range
47             }
48         })?;
49         Some(token_id)
50     }
51 
ranges_by_token( &self, token_id: tt::TokenId, kind: SyntaxKind, ) -> impl Iterator<Item = TextRange> + '_52     pub fn ranges_by_token(
53         &self,
54         token_id: tt::TokenId,
55         kind: SyntaxKind,
56     ) -> impl Iterator<Item = TextRange> + '_ {
57         self.entries
58             .iter()
59             .filter(move |&&(tid, _)| tid == token_id)
60             .filter_map(move |(_, range)| range.by_kind(kind))
61     }
62 
synthetic_token_id(&self, token_id: tt::TokenId) -> Option<SyntheticTokenId>63     pub fn synthetic_token_id(&self, token_id: tt::TokenId) -> Option<SyntheticTokenId> {
64         self.synthetic_entries.iter().find(|(tid, _)| *tid == token_id).map(|(_, id)| *id)
65     }
66 
first_range_by_token( &self, token_id: tt::TokenId, kind: SyntaxKind, ) -> Option<TextRange>67     pub fn first_range_by_token(
68         &self,
69         token_id: tt::TokenId,
70         kind: SyntaxKind,
71     ) -> Option<TextRange> {
72         self.ranges_by_token(token_id, kind).next()
73     }
74 
shrink_to_fit(&mut self)75     pub(crate) fn shrink_to_fit(&mut self) {
76         self.entries.shrink_to_fit();
77         self.synthetic_entries.shrink_to_fit();
78     }
79 
insert(&mut self, token_id: tt::TokenId, relative_range: TextRange)80     pub(crate) fn insert(&mut self, token_id: tt::TokenId, relative_range: TextRange) {
81         self.entries.push((token_id, TokenTextRange::Token(relative_range)));
82     }
83 
insert_synthetic(&mut self, token_id: tt::TokenId, id: SyntheticTokenId)84     pub(crate) fn insert_synthetic(&mut self, token_id: tt::TokenId, id: SyntheticTokenId) {
85         self.synthetic_entries.push((token_id, id));
86     }
87 
insert_delim( &mut self, token_id: tt::TokenId, open_relative_range: TextRange, close_relative_range: TextRange, ) -> usize88     pub(crate) fn insert_delim(
89         &mut self,
90         token_id: tt::TokenId,
91         open_relative_range: TextRange,
92         close_relative_range: TextRange,
93     ) -> usize {
94         let res = self.entries.len();
95         let cover = open_relative_range.cover(close_relative_range);
96 
97         self.entries.push((token_id, TokenTextRange::Delimiter(cover)));
98         res
99     }
100 
update_close_delim(&mut self, idx: usize, close_relative_range: TextRange)101     pub(crate) fn update_close_delim(&mut self, idx: usize, close_relative_range: TextRange) {
102         let (_, token_text_range) = &mut self.entries[idx];
103         if let TokenTextRange::Delimiter(dim) = token_text_range {
104             let cover = dim.cover(close_relative_range);
105             *token_text_range = TokenTextRange::Delimiter(cover);
106         }
107     }
108 
remove_delim(&mut self, idx: usize)109     pub(crate) fn remove_delim(&mut self, idx: usize) {
110         // FIXME: This could be accidentally quadratic
111         self.entries.remove(idx);
112     }
113 }
114