use crate::text::parse_result::{IonParseResult, UpgradeIResult};
use crate::text::parsers::whitespace;
use nom::branch::alt;
use nom::bytes::streaming::{is_not, tag, take_until};
use nom::character::streaming::one_of;
use nom::combinator::{peek, recognize, value};
use nom::multi::many0_count;
use nom::sequence::{delimited, preceded};
pub(crate) fn whitespace_or_comments(input: &str) -> IonParseResult<&str> {
recognize(many0_count(alt((
whitespace, comment,
))))(input)
}
pub(crate) fn comment(input: &str) -> IonParseResult<&str> {
alt((rest_of_line_comment, multiline_comment))(input)
}
fn rest_of_line_comment(input: &str) -> IonParseResult<&str> {
preceded(
tag("//"),
alt((
is_not("\r\n"),
value("", peek(recognize(one_of("\r\n")))),
)),
)(input)
.upgrade()
}
fn multiline_comment(input: &str) -> IonParseResult<&str> {
delimited(
tag("/*"),
take_until("*/"),
tag("*/"),
)(input)
}
#[cfg(test)]
pub(crate) mod comment_parser_tests {
use super::*;
use rstest::*;
#[rstest]
#[case("//hello!\n", "hello!")]
#[case("//😎 😎 😎\n", "😎 😎 😎")]
#[case("//\n ", "")] #[case("//\t \n ", "\t ")] #[should_panic]
#[case("// no newline ", "<should panic>")]
fn test_parse_rest_of_line_comment(#[case] text: &str, #[case] expected: &str) {
assert_eq!(rest_of_line_comment(text).unwrap().1, expected);
}
#[rstest]
#[case("/*hello!*/", "hello!")]
#[case("/*foo\nbar\nbaz*/", "foo\nbar\nbaz")]
#[should_panic]
#[case("/* no closing tag", "<should panic>")]
fn test_parse_multiline_comment(#[case] text: &str, #[case] expected: &str) {
assert_eq!(multiline_comment(text).unwrap().1, expected);
}
#[rstest]
#[case("//hello!\n", "hello!")]
#[case("//😎 😎 😎\n", "😎 😎 😎")]
#[case("/*hello!*/", "hello!")]
#[case("/*foo\nbar\nbaz*/", "foo\nbar\nbaz")]
fn test_parse_comment(#[case] text: &str, #[case] expected: &str) {
assert_eq!(comment(text).unwrap().1, expected);
}
#[rstest]
#[case(" //hello!\n0", "0")]
#[case(" //foo\n//bar\nbaz\n", "baz\n")]
#[case(" /*hello!*/5", "5")]
#[case(" /*foo\nbar\nbaz*/\n//foo\ntrue", "true")]
fn test_parse_whitespace_or_comments(#[case] text: &str, #[case] remaining: &str) {
assert_eq!(whitespace_or_comments(text).unwrap().0, remaining);
}
}