Skip to main content

moxy_token/source/
map.rs

1use std::cell::RefCell;
2
3use super::Source;
4use crate::span::fallback::Span;
5
6thread_local! {
7    static GLOBAL: RefCell<SourceMap> = RefCell::new(SourceMap::new());
8}
9
10/// A collection of source files used to resolve token locations.
11#[derive(Debug, Default)]
12pub struct SourceMap(Vec<Source>);
13
14impl SourceMap {
15    pub fn new() -> Self {
16        Self(vec![])
17    }
18
19    pub fn with<R>(f: impl FnOnce(&Self) -> R) -> R {
20        GLOBAL.with(|sm| f(&sm.borrow()))
21    }
22
23    pub fn with_mut<R>(f: impl FnOnce(&mut Self) -> R) -> R {
24        GLOBAL.with(|sm| f(&mut sm.borrow_mut()))
25    }
26
27    pub fn as_slice(&self) -> &[Source] {
28        &self.0
29    }
30
31    pub fn len(&self) -> usize {
32        self.0.len()
33    }
34
35    pub fn is_empty(&self) -> bool {
36        self.0.is_empty()
37    }
38
39    pub fn find(&self, span: Span) -> Option<&Source> {
40        match self.find_index(span) {
41            None => None,
42            Some(i) => Some(&self.0[i]),
43        }
44    }
45
46    pub fn find_mut(&mut self, span: Span) -> Option<&mut Source> {
47        match self.find_index(span) {
48            None => None,
49            Some(i) => Some(&mut self.0[i]),
50        }
51    }
52
53    pub fn find_path(&self, span: Span) -> Option<String> {
54        if let Some(i) = self.find_index(span) {
55            return if i == 0 {
56                Some("<unspecified>".to_owned())
57            } else {
58                Some(format!("<parsed string {}>", i))
59            };
60        }
61
62        None
63    }
64
65    pub fn find_index(&self, span: Span) -> Option<usize> {
66        let sr = span.byte_range();
67        self.0
68            .binary_search_by(|src| {
69                let fr = src.span().byte_range();
70
71                if fr.end < sr.start {
72                    std::cmp::Ordering::Less
73                } else if fr.start > sr.end {
74                    std::cmp::Ordering::Greater
75                } else {
76                    std::cmp::Ordering::Equal
77                }
78            })
79            .ok()
80    }
81
82    pub fn push(&mut self, src: impl Into<String>) -> Span {
83        let start = self.0.last().map(|src| src.span().byte_range().end).unwrap_or(0);
84        let src = Source::new(start, src);
85        let span = src.span();
86        self.0.push(src);
87        span
88    }
89}