1#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
4pub struct Loc {
5 pub line: u32,
6 pub col: u32,
7 pub byte: usize,
8}
9
10#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
12pub struct Span {
13 pub start: Loc,
14 pub end: Loc,
15}
16
17impl Span {
18 pub(crate) fn new(start: Loc, end: Loc) -> Self {
19 Span { start, end }
20 }
21
22 pub fn unite(self, other: Span) -> Span {
24 let dummy = Span::default();
25 if self == dummy {
26 return other;
27 }
28 if other == dummy {
29 return self;
30 }
31 let start = if self.start.byte <= other.start.byte {
32 self.start
33 } else {
34 other.start
35 };
36 let end = if self.end.byte >= other.end.byte {
37 self.end
38 } else {
39 other.end
40 };
41 Span { start, end }
42 }
43}
44
45impl syan::span::Span for Span {
46 fn migrate(self, other: Self) -> Self {
47 self.unite(other)
48 }
49}
50
51pub fn floor_char_boundary(src: &str, mut byte: usize) -> usize {
60 byte = byte.min(src.len());
61 while byte > 0 && !src.is_char_boundary(byte) {
62 byte -= 1;
63 }
64 byte
65}
66
67impl std::fmt::Display for Span {
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 if self.start.line == self.end.line {
70 write!(
71 f,
72 "line {}, characters {}-{}",
73 self.start.line, self.start.col, self.end.col
74 )
75 } else {
76 write!(
77 f,
78 "line {}, character {} to line {}, character {}",
79 self.start.line, self.start.col, self.end.line, self.end.col
80 )
81 }
82 }
83}