1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//! Coordinate structure used to reference specific locations within parser input
#![allow(clippy::len_without_is_empty)]

use std::cmp::Ordering;
use std::fmt::{Display, Formatter};

/// A [Coord] represents a single location within the parser input
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Coords {
    /// The absolute character position
    pub absolute: usize,
    /// The row position
    pub line: usize,
    /// The column position
    pub column: usize,
}

impl Coords {
    #[inline]
    pub fn inc(&mut self, newline: bool) {
        if newline {
            self.absolute += 1;
            self.line += 1;
            self.column = 1;
        } else {
            self.absolute += 1;
            self.column += 1;
        }
    }
}

impl Display for Coords {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "[abs: {}, line: {}, column: {}]",
            self.absolute, self.line, self.column
        )
    }
}

/// Extract the line number from a [Coords]
#[macro_export]
macro_rules! line {
    ($coords : expr) => {
        $coords.line
    };
}

/// Extract the column number from a [Coords]
#[macro_export]
macro_rules! column {
    ($coords : expr) => {
        $coords.column
    };
}

/// Extract the absolute number from a [Coords]
#[macro_export]
macro_rules! absolute {
    ($coords : expr) => {
        $coords.absolute
    };
}

impl Default for Coords {
    /// The default set of coordinates are positioned at the start of the first row
    fn default() -> Self {
        Coords {
            absolute: 0,
            line: 1,
            column: 0,
        }
    }
}

impl Eq for Coords {}

impl PartialOrd<Self> for Coords {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        match self.absolute.cmp(&other.absolute) {
            Ordering::Less => Some(Ordering::Less),
            Ordering::Equal => Some(Ordering::Equal),
            Ordering::Greater => Some(Ordering::Greater),
        }
    }
}

impl Ord for Coords {
    fn cmp(&self, other: &Self) -> Ordering {
        self.absolute.cmp(&other.absolute)
    }
}

impl std::ops::Sub for Coords {
    type Output = usize;
    /// Subtraction is based on the absolute position, could be +/-ve
    fn sub(self, rhs: Self) -> Self::Output {
        self.absolute - rhs.absolute
    }
}

/// A [Span] represents a linear interval within the parser input
#[derive(Debug, Default, Copy, Clone, PartialEq, PartialOrd)]
pub struct Span {
    /// Start [Coords] for the span
    pub start: Coords,
    /// End [Coords] for the span
    pub end: Coords,
}

impl Span {
    /// Get the length of the span, minimum is 1
    pub fn len(&self) -> usize {
        match self.start.cmp(&self.end) {
            Ordering::Less => self.end - self.start,
            Ordering::Equal => 1,
            Ordering::Greater => self.start - self.end,
        }
    }
}

impl Display for Span {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "start: {}, end: {}, length: {}",
            self.start,
            self.end,
            self.len()
        )
    }
}