151 lines
3.0 KiB
Rust
151 lines
3.0 KiB
Rust
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||
|
|
pub struct Pos {
|
||
|
|
pub source: usize,
|
||
|
|
pub line: usize,
|
||
|
|
pub col: usize,
|
||
|
|
pub byte: usize,
|
||
|
|
pub len: usize,
|
||
|
|
}
|
||
|
|
|
||
|
|
impl Default for Pos {
|
||
|
|
fn default() -> Self {
|
||
|
|
Pos {
|
||
|
|
source: 0,
|
||
|
|
line: 0,
|
||
|
|
col: 0,
|
||
|
|
byte: 0,
|
||
|
|
len: 1,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl Pos {
|
||
|
|
pub fn from_char(c: char, source: usize, line: usize, col: usize, byte: usize) -> Self {
|
||
|
|
Pos {
|
||
|
|
source, line, col, byte, len: c.len_utf8(),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn next_char(&self, c: char) -> Self {
|
||
|
|
Pos {
|
||
|
|
source: self.source + 1,
|
||
|
|
line: self.line,
|
||
|
|
col: self.col + 1,
|
||
|
|
byte: self.byte + self.len,
|
||
|
|
len: c.len_utf8(),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn min(self, other: Self) -> Self {
|
||
|
|
if self.byte < other.byte {
|
||
|
|
self
|
||
|
|
} else {
|
||
|
|
other
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn max(self, other: Self) -> Self {
|
||
|
|
if self.byte > other.byte {
|
||
|
|
self
|
||
|
|
} else {
|
||
|
|
other
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
|
||
|
|
pub struct Span {
|
||
|
|
pub start: Pos,
|
||
|
|
pub end: Pos,
|
||
|
|
}
|
||
|
|
|
||
|
|
impl Span {
|
||
|
|
pub fn union(self, other: Self) -> Self {
|
||
|
|
let start = self.start.min(other.start);
|
||
|
|
let end = self.end.max(other.end);
|
||
|
|
Span { start, end }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub trait Spanned {
|
||
|
|
fn span(&self) -> Span;
|
||
|
|
|
||
|
|
fn text_at<'t>(&self, text: &'t str) -> &'t str {
|
||
|
|
let Span { start, end } = self.span();
|
||
|
|
&text[start.byte .. end.byte]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl Spanned for Span {
|
||
|
|
fn span(&self) -> Span {
|
||
|
|
*self
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[cfg(test)]
|
||
|
|
mod test {
|
||
|
|
use super::*;
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_pos_min() {
|
||
|
|
let small = Pos::default();
|
||
|
|
let large = Pos {
|
||
|
|
source: 1,
|
||
|
|
byte: 1,
|
||
|
|
..Default::default()
|
||
|
|
};
|
||
|
|
|
||
|
|
assert_eq!(small.min(large), small);
|
||
|
|
assert_eq!(large.min(small), small);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_pos_max() {
|
||
|
|
let small = Pos::default();
|
||
|
|
let large = Pos {
|
||
|
|
source: 1,
|
||
|
|
byte: 1,
|
||
|
|
..Default::default()
|
||
|
|
};
|
||
|
|
|
||
|
|
assert_eq!(small.max(large), large);
|
||
|
|
assert_eq!(large.max(small), large);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_span_union() {
|
||
|
|
let first = Span {
|
||
|
|
start: Pos::default(),
|
||
|
|
end: Pos {
|
||
|
|
source: 15,
|
||
|
|
col: 15,
|
||
|
|
byte: 15,
|
||
|
|
..Default::default()
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
let second = Span {
|
||
|
|
start: Pos {
|
||
|
|
source: 25,
|
||
|
|
col: 25,
|
||
|
|
byte: 25,
|
||
|
|
..Default::default()
|
||
|
|
},
|
||
|
|
end: Pos {
|
||
|
|
source: 27,
|
||
|
|
col: 27,
|
||
|
|
byte: 27,
|
||
|
|
..Default::default()
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
let expected = Span {
|
||
|
|
start: first.start,
|
||
|
|
end: second.end,
|
||
|
|
};
|
||
|
|
|
||
|
|
assert_eq!(first.union(second), expected);
|
||
|
|
assert_eq!(second.union(first), expected);
|
||
|
|
}
|
||
|
|
}
|