use crate::*;
use core::ops::Range;
pub type ByteSpan = Range<usize>;
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct Span<'a> {
pub file: &'a str,
pub bytes: ByteSpan,
pub expanded_from: Option<&'a Span<'a>>,
pub included_from: Option<&'a Span<'a>>,
}
#[derive(Debug, PartialEq)]
pub enum SpanRelation {
Earlier,
Later,
Same,
}
impl<'a> Span<'a> {
fn include_indeces(&self) -> Vec<usize> {
match &self.included_from {
None => {
vec![self.bytes.start]
}
Some(inner_span) => {
let mut nested_byte_indeces = inner_span.include_indeces();
nested_byte_indeces.push(self.bytes.start);
nested_byte_indeces
}
}
}
fn indeces_to_compare(&self) -> Vec<Vec<usize>> {
let mut indeces = vec![self.include_indeces()];
match self.expanded_from {
Some(expanded_span) => {
indeces.extend(expanded_span.indeces_to_compare())
}
None => (),
};
indeces
}
pub fn compare(&self, other: &Self) -> SpanRelation {
let mut idx = 0;
let self_include_byte_indeces = self.indeces_to_compare();
let other_include_byte_indeces = other.indeces_to_compare();
loop {
match (
self_include_byte_indeces.get(idx),
other_include_byte_indeces.get(idx),
) {
(Some(self_idxs), Some(other_idxs)) => {
let mut nested_idx = 0;
'match_define: loop {
match (
self_idxs.get(nested_idx),
other_idxs.get(nested_idx),
) {
(Some(self_idx), Some(other_idx)) => {
if self_idx < other_idx {
return SpanRelation::Earlier;
} else if self_idx > other_idx {
return SpanRelation::Later;
} else {
nested_idx += 1;
}
}
(None, None) => {
break 'match_define;
}
_ => {
panic!(
"Internal error comparing spans {:?} and {:?}",
self, other
)
}
}
}
idx += 1;
}
(None, None) => {
break SpanRelation::Same;
}
_ => {
panic!(
"Internal error comparing spans {:?} and {:?}",
self, other
)
}
}
}
}
pub const fn expansion_depth(&self) -> usize {
let mut curr_span: &Span = self;
let mut depth = 0;
loop {
if let Some(expanded_from_span) = curr_span.expanded_from {
curr_span = expanded_from_span;
depth += 1;
} else {
break;
}
}
depth
}
pub const fn inclusion_depth(&self) -> usize {
let mut curr_span: &Span = self;
let mut depth = 0;
loop {
if let Some(included_from_span) = curr_span.included_from {
curr_span = included_from_span;
depth += 1;
} else {
break;
}
}
depth
}
}
#[test]
fn basic_span_comparison() {
let span1 = Span {
file: "",
bytes: (0..2),
expanded_from: None,
included_from: None,
};
let span2 = Span {
file: "",
bytes: (2..4),
expanded_from: None,
included_from: None,
};
assert_eq!(span1.compare(&span2), SpanRelation::Earlier)
}
#[test]
fn include_span_comparison() {
let span1 = Span {
file: "",
bytes: (2..4),
expanded_from: None,
included_from: None,
};
let included_span = Span {
file: "",
bytes: (0..2),
expanded_from: None,
included_from: None,
};
let span2 = Span {
file: "",
bytes: (4..6),
expanded_from: None,
included_from: Some(&included_span),
};
assert_eq!(span1.compare(&span2), SpanRelation::Later)
}
#[test]
fn define_span_comparison() {
let span1 = Span {
file: "",
bytes: (2..4),
expanded_from: None,
included_from: None,
};
let definition_span = Span {
file: "",
bytes: (0..2),
expanded_from: None,
included_from: None,
};
let span2 = Span {
file: "",
bytes: (4..6),
expanded_from: Some(&definition_span),
included_from: None,
};
assert_eq!(span1.compare(&span2), SpanRelation::Earlier)
}
#[test]
fn mixed_define_span_comparison() {
let definition_span1 = Span {
file: "",
bytes: (102..104),
expanded_from: None,
included_from: None,
};
let span1 = Span {
file: "",
bytes: (0..2),
expanded_from: Some(&definition_span1),
included_from: None,
};
let definition_span2 = Span {
file: "",
bytes: (100..102),
expanded_from: None,
included_from: None,
};
let span2 = Span {
file: "",
bytes: (2..4),
expanded_from: Some(&definition_span2),
included_from: None,
};
assert_eq!(span1.compare(&span2), SpanRelation::Earlier)
}
#[test]
fn same_definition_span_comparison() {
let definition_span1 = Span {
file: "",
bytes: (2..4),
expanded_from: None,
included_from: None,
};
let span1 = Span {
file: "",
bytes: (100..104),
expanded_from: Some(&definition_span1),
included_from: None,
};
let definition_span2 = Span {
file: "",
bytes: (0..2),
expanded_from: None,
included_from: None,
};
let span2 = Span {
file: "",
bytes: (100..104),
expanded_from: Some(&definition_span2),
included_from: None,
};
assert_eq!(span1.compare(&span2), SpanRelation::Later)
}
#[test]
fn define_include_span_comparison() {
let definition_span1 = Span {
file: "",
bytes: (2..4),
expanded_from: None,
included_from: None,
};
let inclusion_span1 = Span {
file: "",
bytes: (50..52),
expanded_from: None,
included_from: None,
};
let span1 = Span {
file: "",
bytes: (100..104),
expanded_from: Some(&definition_span1),
included_from: Some(&inclusion_span1),
};
let definition_span2 = Span {
file: "",
bytes: (0..2),
expanded_from: None,
included_from: None,
};
let inclusion_span2 = Span {
file: "",
bytes: (52..54),
expanded_from: None,
included_from: None,
};
let span2 = Span {
file: "",
bytes: (100..104),
expanded_from: Some(&definition_span2),
included_from: Some(&inclusion_span2),
};
assert_eq!(span1.compare(&span2), SpanRelation::Earlier)
}
#[test]
fn same_define_include_span_comparison() {
let definition_span1 = Span {
file: "",
bytes: (2..4),
expanded_from: None,
included_from: None,
};
let inclusion_span1 = Span {
file: "",
bytes: (50..52),
expanded_from: None,
included_from: None,
};
let span1 = Span {
file: "",
bytes: (100..104),
expanded_from: Some(&definition_span1),
included_from: Some(&inclusion_span1),
};
let definition_span2 = Span {
file: "",
bytes: (0..2),
expanded_from: None,
included_from: None,
};
let inclusion_span2 = Span {
file: "",
bytes: (50..52),
expanded_from: None,
included_from: None,
};
let span2 = Span {
file: "",
bytes: (100..104),
expanded_from: Some(&definition_span2),
included_from: Some(&inclusion_span2),
};
assert_eq!(span1.compare(&span2), SpanRelation::Later)
}
#[cfg(feature = "lossless")]
#[derive(Default, Clone, Debug)]
pub struct Metadata<'a> {
pub span: Span<'a>,
pub non_trivia: Vec<NonTriviaToken<'a>>,
}
#[cfg(not(feature = "lossless"))]
#[derive(Default, Clone, Debug)]
pub struct Metadata<'a> {
pub span: Span<'a>,
}
impl<'a> Metadata<'a> {
#[cfg(feature = "lossless")]
pub fn new(span: Span<'a>, non_trivia: Vec<NonTriviaToken<'a>>) -> Self {
Self { span, non_trivia }
}
#[cfg(not(feature = "lossless"))]
#[allow(unused_variables)]
pub fn new(span: Span<'a>, non_trivia: Vec<NonTriviaToken<'a>>) -> Self {
Self { span }
}
}
impl<'a> PartialEq for Metadata<'a> {
fn eq(&self, _: &Self) -> bool {
true
}
}
impl<'a, 'b> IntoIterator for &'b Metadata<'a> {
type Item = Node<'a, 'b>;
type IntoIter = std::iter::Empty<Node<'a, 'b>>;
fn into_iter(self) -> Self::IntoIter {
std::iter::empty()
}
}
impl<'a, 'b> IntoIterator for &'b mut Metadata<'a> {
type Item = Node<'a, 'b>;
type IntoIter = std::iter::Empty<Node<'a, 'b>>;
fn into_iter(self) -> Self::IntoIter {
std::iter::empty()
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum NonTriviaToken<'a> {
OnelineComment(&'a str, Span<'a>),
BlockComment(&'a str, Span<'a>),
Newline,
}