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