ziyy_core/common/
span.rs

1use std::{
2    fmt::Display,
3    ops::{Add, AddAssign, Sub},
4};
5
6use super::Position;
7
8#[derive(Debug, Default, Clone, Copy, PartialEq)]
9/// A span in source code.
10pub struct Span {
11    start: Position,
12    end: Position,
13}
14
15impl Span {
16    /// Creates a new span.
17    pub fn new(start: Position, end: Position) -> Self {
18        Self { start, end }
19    }
20
21    pub(crate) fn tie_end(&mut self) {
22        self.start = self.end;
23    }
24
25    pub(crate) fn tie_start(&mut self) {
26        self.end = self.start;
27    }
28
29    pub(crate) fn unquote(&self) -> Self {
30        let mut span = *self;
31        span.start += (0, 1);
32        span.end -= (0, 1);
33        span
34    }
35
36    /// Creates a Span that represents inserted text in source.
37    pub(crate) fn inserted() -> Self {
38        let pos = Position::new(0, 0);
39        Span::new(pos, pos)
40    }
41
42    /// Calculate Span from source.
43    pub fn calculate(source: &str) -> Self {
44        let start = Position::default();
45
46        let mut end = start;
47        for c in source.chars() {
48            if c == '\n' {
49                end.line += 1;
50                end.column = 1;
51            } else {
52                end.column += 1;
53            }
54        }
55
56        Self { start, end }
57    }
58}
59
60impl Add<(i32, i32)> for Span {
61    type Output = Span;
62
63    fn add(mut self, rhs: (i32, i32)) -> Self::Output {
64        self.end += rhs;
65        self
66    }
67}
68
69impl AddAssign<(i32, i32)> for Span {
70    fn add_assign(&mut self, rhs: (i32, i32)) {
71        self.end += rhs;
72    }
73}
74
75impl AddAssign for Span {
76    fn add_assign(&mut self, rhs: Self) {
77        self.end = rhs.end
78    }
79}
80
81impl Sub<(i32, i32)> for Span {
82    type Output = Span;
83
84    fn sub(mut self, rhs: (i32, i32)) -> Self::Output {
85        self.start -= rhs;
86        self
87    }
88}
89
90impl Display for Span {
91    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92        if f.alternate() {
93            f.write_fmt(format_args!("{:#}..{:#}", self.start, self.end))
94        } else if *self == Span::inserted() {
95            f.write_str("\x1b[4minserted\x1b[24m")
96        } else {
97            f.write_fmt(format_args!("{}..{}", self.start, self.end))
98        }
99    }
100}