Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/mbe/src/token_map.rs')
-rw-r--r--crates/mbe/src/token_map.rs140
1 files changed, 24 insertions, 116 deletions
diff --git a/crates/mbe/src/token_map.rs b/crates/mbe/src/token_map.rs
index 32f61af25e..c2ec30ca72 100644
--- a/crates/mbe/src/token_map.rs
+++ b/crates/mbe/src/token_map.rs
@@ -3,7 +3,7 @@
use std::hash::Hash;
use stdx::itertools::Itertools;
-use syntax::TextRange;
+use syntax::{TextRange, TextSize};
use tt::Span;
/// Maps absolute text ranges for the corresponding file to the relevant span data.
@@ -12,138 +12,46 @@ use tt::Span;
pub struct TokenMap<S: Span> {
// FIXME: This needs to be sorted by (FileId, AstId)
// Then we can do a binary search on the file id,
- // then a bin search on the ast id
- pub span_map: Vec<(TextRange, S)>,
- // span_map2: rustc_hash::FxHashMap<TextRange, usize>,
+ // then a bin search on the ast id?
+ spans: Vec<(TextSize, S)>,
}
impl<S: Span> TokenMap<S> {
- pub fn empty() -> Self {
- Self { span_map: Vec::new() }
+ pub(crate) fn empty() -> Self {
+ Self { spans: Vec::new() }
}
- pub fn finish(&mut self) {
- debug_assert_eq!(
- self.span_map
- .iter()
- .sorted_by_key(|it| (it.0.start(), it.0.end()))
- .tuple_windows()
- .find(|(range, next)| range.0.end() != next.0.start()),
- None,
- "span map has holes!"
- );
- self.span_map.shrink_to_fit();
+ pub(crate) fn finish(&mut self) {
+ assert!(self.spans.iter().tuple_windows().all(|(a, b)| a.0 < b.0));
+ self.spans.shrink_to_fit();
}
- pub(crate) fn insert(&mut self, range: TextRange, span: S) {
- self.span_map.push((range, span));
+ pub(crate) fn push(&mut self, offset: TextSize, span: S) {
+ self.spans.push((offset, span));
}
pub fn ranges_with_span(&self, span: S) -> impl Iterator<Item = TextRange> + '_ {
// FIXME: linear search
- // FIXME: Disregards resolving spans to get more matches! See ExpansionInfo::map_token_down
- self.span_map.iter().filter_map(
- move |(range, s)| {
- if s == &span {
- Some(*range)
- } else {
- None
- }
- },
- )
+ self.spans.iter().enumerate().filter_map(move |(idx, &(end, s))| {
+ if s != span {
+ return None;
+ }
+ let start = idx.checked_sub(1).map_or(TextSize::new(0), |prev| self.spans[prev].0);
+ Some(TextRange::new(start, end))
+ })
}
// FIXME: We need APIs for fetching the span of a token as well as for a whole node. The node
// one *is* fallible though.
- // Token span fetching technically only needs an offset really, as the entire file span is
- // populated, where node fetching is more like fetching the spans at all source positions, and
- // then we need to verify that all those positions have the same context, if not we fail! But
- // how do we handle them having different span ranges?
-
- pub fn span_for_range(&self, range: TextRange) -> S {
- // TODO FIXME: make this proper
- self.span_map
- .iter()
- .filter_map(|(r, s)| Some((r, s, r.intersect(range).filter(|it| !it.is_empty())?)))
- .max_by_key(|(_, _, intersection)| intersection.len())
- .map_or_else(
- || panic!("no span for range {:?} in {:#?}", range, self.span_map),
- |(_, &s, _)| s,
- )
+ pub fn span_at(&self, offset: TextSize) -> S {
+ let entry = self.spans.partition_point(|&(it, _)| it <= offset);
+ self.spans[entry].1
}
pub fn spans_for_node_range(&self, range: TextRange) -> impl Iterator<Item = S> + '_ {
- // TODO FIXME: make this proper
- self.span_map
- .iter()
- .filter(move |(r, _)| r.intersect(range).filter(|it| !it.is_empty()).is_some())
- .map(|&(_, s)| s)
+ let (start, end) = (range.start(), range.end());
+ let start_entry = self.spans.partition_point(|&(it, _)| it <= start);
+ let end_entry = self.spans[start_entry..].partition_point(|&(it, _)| it <= end); // FIXME: this might be wrong?
+ (&self.spans[start_entry..][..end_entry]).iter().map(|&(_, s)| s)
}
-
- // pub fn ranges_by_token(
- // &self,
- // token_id: tt::TokenId,
- // kind: SyntaxKind,
- // ) -> impl Iterator<Item = TextRange> + '_ {
- // self.entries
- // .iter()
- // .filter(move |&&(tid, _)| tid == token_id)
- // .filter_map(move |(_, range)| range.by_kind(kind))
- // }
-
- // pub(crate) fn remove_delim(&mut self, idx: usize) {
- // // FIXME: This could be accidentally quadratic
- // self.entries.remove(idx);
- // }
-
- // pub fn entries(&self) -> impl Iterator<Item = (tt::TokenId, TextRange)> + '_ {
- // self.entries.iter().filter_map(|&(tid, tr)| match tr {
- // TokenTextRange::Token(range) => Some((tid, range)),
- // TokenTextRange::Delimiter(_) => None,
- // })
- // }
-
- // pub fn filter(&mut self, id: impl Fn(tt::TokenId) -> bool) {
- // self.entries.retain(|&(tid, _)| id(tid));
- // }
- // pub fn synthetic_token_id(&self, token_id: tt::TokenId) -> Option<SyntheticTokenId> {
- // self.synthetic_entries.iter().find(|(tid, _)| *tid == token_id).map(|(_, id)| *id)
- // }
-
- // pub fn first_range_by_token(
- // &self,
- // token_id: tt::TokenId,
- // kind: SyntaxKind,
- // ) -> Option<TextRange> {
- // self.ranges_by_token(token_id, kind).next()
- // }
-
- // pub(crate) fn insert(&mut self, token_id: tt::TokenId, relative_range: TextRange) {
- // self.entries.push((token_id, TokenTextRange::Token(relative_range)));
- // }
-
- // pub(crate) fn insert_synthetic(&mut self, token_id: tt::TokenId, id: SyntheticTokenId) {
- // self.synthetic_entries.push((token_id, id));
- // }
-
- // pub(crate) fn insert_delim(
- // &mut self,
- // token_id: tt::TokenId,
- // open_relative_range: TextRange,
- // close_relative_range: TextRange,
- // ) -> usize {
- // let res = self.entries.len();
- // let cover = open_relative_range.cover(close_relative_range);
-
- // self.entries.push((token_id, TokenTextRange::Delimiter(cover)));
- // res
- // }
-
- // pub(crate) fn update_close_delim(&mut self, idx: usize, close_relative_range: TextRange) {
- // let (_, token_text_range) = &mut self.entries[idx];
- // if let TokenTextRange::Delimiter(dim) = token_text_range {
- // let cover = dim.cover(close_relative_range);
- // *token_text_range = TokenTextRange::Delimiter(cover);
- // }
- // }
}