use super::ParseTrivium;
use crate::types::{TrailingComment, Trivia, Trivium};
const fn is_trailing(pt: &ParseTrivium) -> bool {
match pt {
ParseTrivium::LineComment { .. } => true,
ParseTrivium::BlockComment(false, lines) => lines.len() <= 1,
_ => false,
}
}
fn convert_trailing(pts: &[ParseTrivium]) -> Option<TrailingComment> {
let texts: Vec<String> = pts
.iter()
.filter_map(|pt| match pt {
ParseTrivium::LineComment { text, .. } => Some(text.trim().to_string()),
ParseTrivium::BlockComment(false, lines) if lines.len() == 1 => {
Some(lines[0].trim().to_string())
}
_ => None,
})
.filter(|s| !s.is_empty())
.collect();
let joined = texts.join(" ");
if joined.is_empty() {
None
} else {
Some(TrailingComment(joined.into()))
}
}
pub(super) fn convert_leading(pts: &[ParseTrivium]) -> Trivia {
let (mut result, pending_newlines) =
pts.iter()
.fold((Vec::new(), 0), |(mut acc, newline_count), pt| match pt {
ParseTrivium::Newlines(count) => (acc, newline_count + count),
other => {
if newline_count > 1 {
acc.push(Trivium::EmptyLine());
}
match other {
ParseTrivium::LineComment { text, .. } => {
acc.push(Trivium::LineComment(text.clone()));
}
ParseTrivium::BlockComment(_, lines) if lines.is_empty() => {}
ParseTrivium::BlockComment(false, lines) if lines.len() == 1 => {
acc.push(Trivium::LineComment(format!(" {}", lines[0].trim())));
}
ParseTrivium::BlockComment(is_doc, lines) => {
acc.push(Trivium::BlockComment(*is_doc, lines.clone()));
}
ParseTrivium::LanguageAnnotation(text) => {
acc.push(Trivium::LanguageAnnotation(text.clone()));
}
ParseTrivium::Newlines(_) => unreachable!(),
}
(acc, 0)
}
});
if pending_newlines > 1 {
result.push(Trivium::EmptyLine());
}
result.into()
}
pub fn convert_trivia(pts: &[ParseTrivium], next_col: usize) -> (Option<TrailingComment>, Trivia) {
match pts {
[] => return (None, Trivia::new()),
[ParseTrivium::Newlines(n)] => {
return (
None,
if *n > 1 {
Trivia::one(Trivium::EmptyLine())
} else {
Trivia::new()
},
);
}
_ => {}
}
let split_pos = pts
.iter()
.position(|pt| !is_trailing(pt))
.unwrap_or(pts.len());
let (trailing_pts, leading_pts) = pts.split_at(split_pos);
match (trailing_pts, leading_pts) {
(
[ParseTrivium::LineComment { col: col1, .. }],
[
ParseTrivium::Newlines(1),
ParseTrivium::LineComment { col: col2, .. },
..,
],
) if col1 == col2 => (None, convert_leading(pts)),
([ParseTrivium::LineComment { col, .. }], [ParseTrivium::Newlines(1)])
if *col == next_col =>
{
(None, convert_leading(pts))
}
_ => (convert_trailing(trailing_pts), convert_leading(leading_pts)),
}
}