1use std::fmt;
4
5#[derive(Clone, Copy, PartialEq, Eq, Hash, Default)]
7pub struct Span {
8 pub lo: u32,
9 pub hi: u32,
10}
11
12impl Span {
13 pub fn new(lo: usize, hi: usize) -> Span {
14 Span {
15 lo: lo as u32,
16 hi: hi as u32,
17 }
18 }
19
20 pub fn to(self, other: Span) -> Span {
22 Span {
23 lo: self.lo.min(other.lo),
24 hi: self.hi.max(other.hi),
25 }
26 }
27
28 pub fn range(self) -> std::ops::Range<usize> {
29 self.lo as usize..self.hi as usize
30 }
31
32 pub fn shifted(self, by: u32) -> Span {
33 Span {
34 lo: self.lo + by,
35 hi: self.hi + by,
36 }
37 }
38}
39
40impl fmt::Debug for Span {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 write!(f, "{}..{}", self.lo, self.hi)
43 }
44}
45
46#[derive(Clone, Debug)]
48pub struct SourceFile {
49 pub name: String,
50 pub text: String,
51}
52
53impl SourceFile {
54 pub fn new(name: impl Into<String>, text: impl Into<String>) -> SourceFile {
55 SourceFile {
56 name: name.into(),
57 text: text.into(),
58 }
59 }
60
61 pub fn slice(&self, span: Span) -> &str {
63 self.text.get(span.range()).unwrap_or("")
64 }
65
66 pub fn line_col(&self, offset: u32) -> (usize, usize) {
68 let offset = (offset as usize).min(self.text.len());
69 let before = &self.text[..offset];
70 let line = before.matches('\n').count() + 1;
71 let col = before.rfind('\n').map_or(offset, |nl| offset - nl - 1) + 1;
72 (line, col)
73 }
74}