2020-05-02 18:42:01 -04:00
|
|
|
use std::fmt::{Display, Formatter, self};
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, Eq)]
|
|
|
|
|
#[cfg_attr(not(test), derive(PartialEq))]
|
2020-04-27 12:42:17 -04:00
|
|
|
pub struct Pos {
|
|
|
|
|
pub source: usize,
|
|
|
|
|
pub line: usize,
|
|
|
|
|
pub col: usize,
|
|
|
|
|
pub byte: usize,
|
|
|
|
|
pub len: usize,
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-02 18:42:01 -04:00
|
|
|
impl Display for Pos {
|
|
|
|
|
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
|
|
|
|
write!(fmt, "line {} at {}", self.line + 1, self.col + 1)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-27 12:42:17 -04:00
|
|
|
impl Default for Pos {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Pos {
|
|
|
|
|
source: 0,
|
|
|
|
|
line: 0,
|
|
|
|
|
col: 0,
|
|
|
|
|
byte: 0,
|
|
|
|
|
len: 1,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-02 18:42:01 -04:00
|
|
|
#[cfg(test)]
|
|
|
|
|
impl PartialEq for Pos {
|
|
|
|
|
fn eq(&self, _other: &Pos) -> bool {
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-27 12:42:17 -04:00
|
|
|
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(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-27 19:50:46 -04:00
|
|
|
pub fn adv_char(&mut self, c: char) {
|
|
|
|
|
*self = self.next_char(c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn adv_str(&mut self, s: &str) {
|
|
|
|
|
for c in s.chars() {
|
|
|
|
|
self.adv_char(c);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-27 12:42:17 -04:00
|
|
|
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 }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-02 18:42:01 -04:00
|
|
|
impl Display for Span {
|
|
|
|
|
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
|
|
|
|
if self.start == self.end {
|
|
|
|
|
Display::fmt(&self.start, fmt)
|
|
|
|
|
} else if self.start.line == self.end.line {
|
|
|
|
|
write!(fmt, "line {} at {}-{}", self.start.line + 1, self.start.col + 1, self.end.col + 1)
|
|
|
|
|
} else {
|
|
|
|
|
write!(fmt, "lines {} to {}", self.start.line + 1, self.end.line + 1)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-27 12:42:17 -04:00
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-05 16:38:07 -04:00
|
|
|
/*
|
2020-05-02 18:42:01 -04:00
|
|
|
pub struct Sourced<'t, T: Spanned> {
|
|
|
|
|
text: &'t str,
|
|
|
|
|
inner: T,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'t, T: Spanned> Sourced<'t, T> {
|
|
|
|
|
fn text(&self) -> &'t str {
|
|
|
|
|
self.text_at(self.text)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T: Spanned> Spanned for Sourced<'_, T> {
|
|
|
|
|
fn span(&self) -> Span {
|
|
|
|
|
self.inner.span()
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-05 16:38:07 -04:00
|
|
|
*/
|
2020-05-02 18:42:01 -04:00
|
|
|
|
2020-04-27 12:42:17 -04:00
|
|
|
#[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);
|
|
|
|
|
}
|
|
|
|
|
}
|