moxy_token/source/
file.rs1use std::cell::RefCell;
2use std::collections::BTreeMap;
3
4use super::Location;
5use crate::span::fallback::Span;
6
7#[derive(Debug)]
10pub struct Source {
11 text: String,
13
14 span: Span,
16
17 lines: Vec<usize>,
19
20 char_to_byte: RefCell<BTreeMap<usize, usize>>,
22}
23
24impl Source {
25 pub(crate) fn new(start: usize, src: impl Into<String>) -> Self {
26 let text = src.into();
27 let mut lines = vec![0];
28 let mut total = 0usize;
29
30 for ch in text.chars() {
31 total += 1;
32
33 if ch == '\n' {
34 lines.push(total);
35 }
36 }
37
38 let mut char_to_byte = BTreeMap::new();
39 char_to_byte.insert(0, 0);
40
41 Self {
42 text,
43 span: Span::new(start as u32, (start + total) as u32),
44 lines,
45 char_to_byte: RefCell::new(char_to_byte),
46 }
47 }
48
49 pub fn text(&self) -> &str {
50 &self.text
51 }
52
53 pub fn span(&self) -> Span {
54 self.span
55 }
56
57 pub fn range(&self, span: Span) -> std::ops::Range<usize> {
59 let r = span.byte_range();
60 self.byte(r.start)..self.byte(r.end)
61 }
62
63 pub fn slice(&self, span: Span) -> String {
65 self.text[self.range(span)].to_owned()
66 }
67
68 pub fn location(&self, i: usize) -> Location {
70 let index = i - self.span.byte_range().start;
71
72 match self.lines.binary_search(&index) {
73 Err(next) => Location::new(index, next - 1, index - self.lines[next - 1]),
74 Ok(line) => Location::new(index, line, 0),
75 }
76 }
77
78 pub fn byte(&self, i: usize) -> usize {
80 let index = i - self.span.byte_range().start;
81 let mut cache = self.char_to_byte.borrow_mut();
82
83 if let Some(byte_index) = cache.get(&index) {
84 return *byte_index;
85 }
86
87 let (&ci, &bi) = cache.range(..=index).next_back().unwrap();
88
89 let mut char_index = ci;
90 let mut byte_index = bi;
91
92 for ch in self.text[bi..].chars() {
93 if char_index == index {
94 cache.insert(index, byte_index);
95 return byte_index;
96 }
97
98 char_index += 1;
99 byte_index += ch.len_utf8();
100 }
101
102 cache.insert(index, byte_index);
103 byte_index
104 }
105}
106
107impl Default for Source {
108 fn default() -> Self {
109 Self {
110 text: String::default(),
111 span: Span::default(),
112 lines: vec![0],
113 char_to_byte: RefCell::new(BTreeMap::default()),
114 }
115 }
116}