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.rs57
1 files changed, 38 insertions, 19 deletions
diff --git a/crates/mbe/src/token_map.rs b/crates/mbe/src/token_map.rs
index dfbf54410b..978ee268c5 100644
--- a/crates/mbe/src/token_map.rs
+++ b/crates/mbe/src/token_map.rs
@@ -2,7 +2,7 @@
use std::hash::Hash;
-use stdx::never;
+use stdx::itertools::Itertools;
use syntax::TextRange;
use tt::Span;
@@ -15,23 +15,29 @@ use tt::Span;
/// Maps absolute text ranges for the corresponding file to the relevant span data.
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
// FIXME: Rename to SpanMap
-pub struct TokenMap<S> {
+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>,
- pub real_file: bool,
}
-impl<S> Default for TokenMap<S> {
- fn default() -> Self {
- Self { span_map: Vec::new(), real_file: true }
+impl<S: Span> TokenMap<S> {
+ pub fn empty() -> Self {
+ Self { span_map: Vec::new() }
}
-}
-impl<S: Span> TokenMap<S> {
- pub(crate) fn shrink_to_fit(&mut self) {
+ 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();
}
@@ -40,6 +46,8 @@ impl<S: Span> TokenMap<S> {
}
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 {
@@ -51,20 +59,31 @@ impl<S: Span> TokenMap<S> {
)
}
- // FIXME: Should be infallible
- pub fn span_for_range(&self, range: TextRange) -> Option<S> {
+ // 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_map(|(r, s)| Some((r, s, r.intersect(range).filter(|it| !it.is_empty())?)))
.max_by_key(|(_, _, intersection)| intersection.len())
- .map(|(_, &s, _)| s)
- .or_else(|| {
- if !self.real_file {
- never!("no span for range {:?} in {:#?}", range, self.span_map);
- }
- None
- })
+ .map_or_else(
+ || panic!("no span for range {:?} in {:#?}", range, self.span_map),
+ |(_, &s, _)| s,
+ )
+ }
+
+ 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)
}
// pub fn ranges_by_token(