1#[cfg(feature = "serde_borsh")]
13use borsh::{
14 maybestd::io::Result as BorshResult, maybestd::io::Write as BorshWrite, BorshDeserialize,
15 BorshSerialize,
16};
17use std::borrow::Borrow;
18use std::fmt;
19use std::fmt::Write;
20use std::rc::Rc;
21
22pub type Pos = usize;
23
24#[derive(Clone, Debug)]
25pub struct FilePos {
26 pub filename: Rc<String>,
27 pub offset: usize, pub line: usize,
29 pub column: usize,
30}
31
32impl FilePos {
33 pub fn is_valid(&self) -> bool {
34 self.line > 0
35 }
36
37 pub fn null() -> FilePos {
38 FilePos {
39 filename: Rc::new("[null_file]".to_owned()),
40 line: 0,
41 offset: 0,
42 column: 0,
43 }
44 }
45}
46
47impl fmt::Display for FilePos {
48 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
49 let mut s = String::clone(&*self.filename);
50 if self.is_valid() {
51 if s != "" {
52 s.push(':');
53 }
54 s.push_str(&self.line.to_string());
55 }
56 if self.column != 0 {
57 write!(&mut s, ":{}", self.column).unwrap();
58 }
59 if s.is_empty() {
60 s.push('-');
61 }
62 f.write_str(&s)
63 }
64}
65
66#[derive(Debug)]
67pub struct File {
68 name: Rc<String>,
69 base: usize,
70 size: usize,
71 lines: Vec<usize>,
72}
73
74impl File {
75 pub fn new(name: String) -> File {
76 File {
77 name: Rc::new(name),
78 base: 0,
79 size: 0,
80 lines: vec![0],
81 }
82 }
83
84 pub fn name(&self) -> &str {
85 &self.name
86 }
87
88 pub fn base(&self) -> usize {
89 self.base
90 }
91
92 pub fn size(&self) -> usize {
93 self.size
94 }
95
96 pub fn line_count(&self) -> usize {
97 self.lines.len()
98 }
99
100 pub fn add_line(&mut self, offset: usize) {
101 let i = self.line_count();
102 if (i == 0 || self.lines[i - 1] < offset) && offset < self.size {
103 self.lines.push(offset);
104 }
105 }
106
107 pub fn merge_line(&mut self, line: usize) {
108 if line < 1 {
109 panic!("illegal line number (line numbering starts at 1)");
110 }
111 if line >= self.line_count() {
112 panic!("illegal line number");
113 }
114 let lines = &self.lines;
120 self.lines = lines
121 .into_iter()
122 .enumerate()
123 .filter(|&(i, _)| i != line)
124 .map(|(_, l)| *l)
125 .collect();
126 }
127
128 pub fn set_lines(&mut self, lines: Vec<usize>) -> bool {
129 let size = self.size;
130 for (i, &offset) in self.lines.iter().enumerate() {
131 if (i == 0 && size <= offset) || offset < lines[i - 1] {
132 return false;
133 }
134 }
135 self.lines = lines;
136 true
137 }
138
139 pub fn set_lines_for_content(&mut self, content: &mut std::str::Chars) {
140 let (mut new_line, mut line) = (true, 0);
141 for (offset, b) in content.enumerate() {
142 if new_line {
143 self.lines.push(line);
144 }
145 new_line = false;
146 if b == '\n' {
147 new_line = true;
148 line = offset + 1;
149 }
150 }
151 }
152
153 pub fn line_start(&self, line: usize) -> usize {
154 if line < 1 {
155 panic!("illegal line number (line numbering starts at 1)");
156 }
157 if line >= self.line_count() {
158 panic!("illegal line number");
159 }
160 self.base + self.lines[line - 1]
161 }
162
163 pub fn pos(&self, offset: usize) -> Pos {
164 if offset > self.size() {
165 panic!("illegal file offset")
166 }
167 self.base() + offset
168 }
169
170 pub fn position(&self, p: Pos) -> FilePos {
171 if p < self.base || p > self.base + self.size {
172 panic!("illegal Pos value");
173 }
174
175 let line_count = self.line_count();
176 let offset = p - self.base;
177 let line = match self
178 .lines
179 .iter()
180 .enumerate()
181 .find(|&(_, &line)| line > offset)
182 {
183 Some((i, _)) => i,
184 None => line_count,
185 };
186 let column = offset - self.lines[line - 1] + 1;
187
188 FilePos {
189 filename: self.name.clone(),
190 line: line,
191 offset: offset,
192 column: column,
193 }
194 }
195}
196
197#[cfg(feature = "serde_borsh")]
198impl BorshSerialize for File {
199 #[inline]
200 fn serialize<W: BorshWrite>(&self, writer: &mut W) -> BorshResult<()> {
201 let name_str: &str = &*self.name;
202 name_str.serialize(writer)?;
203 self.base.serialize(writer)?;
204 self.size.serialize(writer)?;
205 self.lines.serialize(writer)
206 }
207}
208
209#[cfg(feature = "serde_borsh")]
210impl BorshDeserialize for File {
211 #[inline]
212 fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> BorshResult<Self> {
213 let name = String::deserialize_reader(reader)?;
214 let base = usize::deserialize_reader(reader)?;
215 let size = usize::deserialize_reader(reader)?;
216 let lines = Vec::<usize>::deserialize_reader(reader)?;
217 Ok(File {
218 name: Rc::new(name),
219 base,
220 size,
221 lines,
222 })
223 }
224}
225
226#[cfg_attr(feature = "serde_borsh", derive(BorshDeserialize, BorshSerialize))]
227#[derive(Debug)]
228pub struct FileSet {
229 base: usize,
230 files: Vec<File>,
231}
232
233impl FileSet {
234 pub fn new() -> FileSet {
235 FileSet {
236 base: 0,
237 files: vec![],
238 }
239 }
240
241 pub fn base(&self) -> usize {
242 self.base
243 }
244
245 pub fn iter(&self) -> FileSetIter {
246 FileSetIter { fs: self, cur: 0 }
247 }
248
249 pub fn file(&self, p: Pos) -> Option<&File> {
250 for f in self.files.iter() {
251 if f.base <= p && f.base + f.size >= p {
252 return Some(f.borrow());
253 }
254 }
255 None
256 }
257
258 pub fn position(&self, p: Pos) -> Option<FilePos> {
259 self.file(p).map(|f| f.position(p))
260 }
261
262 pub fn index_file(&mut self, i: usize) -> Option<&mut File> {
263 if i >= self.files.len() {
264 None
265 } else {
266 Some(&mut self.files[i])
267 }
268 }
269
270 pub fn recent_file(&mut self) -> Option<&mut File> {
271 let c = self.files.len();
272 if c == 0 {
273 None
274 } else {
275 self.index_file(c - 1)
276 }
277 }
278
279 pub fn add_file(&mut self, name: String, base: Option<usize>, size: usize) -> &mut File {
280 let real_base = if let Some(b) = base { b } else { self.base };
281 if real_base < self.base {
282 panic!("illegal base");
283 }
284
285 let mut f = File::new(name);
286 f.base = real_base;
287 f.size = size;
288 let set_base = self.base + size + 1; if set_base < self.base {
290 panic!("token.Pos offset overflow (> 2G of source code in file set)");
291 }
292 self.base = set_base;
293 self.files.push(f);
294 self.recent_file().unwrap()
295 }
296}
297
298pub struct FileSetIter<'a> {
299 fs: &'a FileSet,
300 cur: usize,
301}
302
303impl<'a> Iterator for FileSetIter<'a> {
304 type Item = &'a File;
305
306 fn next(&mut self) -> Option<&'a File> {
307 if self.cur < self.fs.files.len() {
308 self.cur += 1;
309 Some(self.fs.files[self.cur - 1].borrow())
310 } else {
311 None
312 }
313 }
314}
315
316#[cfg(test)]
317mod test {
318 use super::*;
319
320 #[test]
321 fn test_position() {
322 let p = FilePos {
323 filename: Rc::new("test.gs".to_owned()),
324 offset: 0,
325 line: 54321,
326 column: 8,
327 };
328 print!("this is the position: {} ", p);
329 let mut fs = FileSet::new();
330 let mut f = File::new("test.gs".to_owned());
331 f.size = 12345;
332 f.add_line(123);
333 f.add_line(133);
334 f.add_line(143);
335 print!("\nfile: {:?}", f);
336 f.merge_line(1);
337 print!("\nfile after merge: {:?}", f);
338
339 {
340 fs.add_file("testfile1.gs".to_owned(), None, 222);
341 fs.add_file("testfile2.gs".to_owned(), None, 222);
342 fs.add_file("testfile3.gs".to_owned(), None, 222);
343 print!("\nset {:?}", fs);
344 }
345
346 for f in fs.iter() {
347 print!("\nfiles in set: {:?}", f);
348 }
349 print!("\nfile at 100: {:?}", fs.file(100))
350 }
351}