This repository has been archived on 2020-09-15. You can view files and clone it, but cannot push or open issues or pull requests.
Files
not-python-old.2020-08-27/src/syn/span.rs

206 lines
4.3 KiB
Rust
Raw Normal View History

use std::fmt::{Display, Formatter, self};
#[derive(Debug, Clone, Copy, Eq)]
#[cfg_attr(not(test), derive(PartialEq))]
pub struct Pos {
pub source: usize,
pub line: usize,
pub col: usize,
pub byte: usize,
pub len: usize,
}
impl Display for Pos {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
write!(fmt, "line {} at {}", self.line + 1, self.col + 1)
}
}
impl Default for Pos {
fn default() -> Self {
Pos {
source: 0,
line: 0,
col: 0,
byte: 0,
len: 1,
}
}
}
#[cfg(test)]
impl PartialEq for Pos {
fn eq(&self, _other: &Pos) -> bool {
true
}
}
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 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);
}
}
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 }
}
}
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)
}
}
}
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
}
}
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()
}
}
#[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);
}
}