plantuml_parser/dsl/line/
block_comment_close.rs

1use crate::{ParseContainer, ParseResult, wr};
2use nom::Parser;
3use nom::branch::alt;
4use nom::bytes::complete::{tag, take_until};
5use nom::character::complete::{line_ending, not_line_ending, space0};
6use nom::combinator::{eof, map};
7use nom::multi::many1;
8
9/// A token sequence that is an close [`BlockComment`][`crate::BlockComment`] line.
10///
11/// * `"end '/\n"`
12///
13/// # Examples
14///
15/// ```
16/// use plantuml_parser::{BlockCommentCloseLine, ParseContainer};
17///
18/// # fn main() -> anyhow::Result<()> {
19/// let input = "end '/\n";
20/// let (rest, (raws, _token)) = BlockCommentCloseLine::parse(input.into())?;
21/// let combined_raw: ParseContainer = raws.into();
22/// assert_eq!(rest, "");
23/// assert_eq!(combined_raw, "end '/\n");
24/// # Ok(())
25/// # }
26/// ```
27#[derive(Clone, Debug)]
28pub struct BlockCommentCloseLine;
29
30impl BlockCommentCloseLine {
31    /// Tries to parse [`BlockCommentCloseLine`]. (e.g. `"end '/\n"`.)
32    pub fn parse(input: ParseContainer) -> ParseResult<Self> {
33        // Tries to parse into line.
34        let (_, parsed_line) = map(
35            (wr!(not_line_ending), alt((wr!(eof), wr!(line_ending)))),
36            |(line, end)| (&[line, end]).into(),
37        )
38        .parse(input.clone())?;
39
40        let (_, parsed): (_, ParseContainer) = map(
41            (
42                many1((wr!(take_until("'/")), wr!(tag("'/")))),
43                wr!(space0),
44                alt((wr!(eof), wr!(line_ending))),
45            ),
46            |(v, sp, end)| {
47                v.into_iter()
48                    .flat_map(|(a1, a2)| vec![a1, a2])
49                    .chain([sp, end])
50                    .collect::<Vec<_>>()
51                    .into()
52            },
53        )
54        .parse(parsed_line)?;
55
56        let rest = input.split_at(parsed.len()).0;
57
58        Ok((rest, (parsed, Self)))
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn test_parse() -> anyhow::Result<()> {
68        let testdata = [
69            "'/",
70            "'/\n",
71            "'/\t ",
72            "'/ \t  \n",
73            "end '/  ",
74            "end '/ \n",
75            "end '/ '/",
76            "end '/ '/\n",
77            "end '/ '/ '/",
78            "end '/ '/ '/\n",
79        ];
80
81        for testdata in testdata.into_iter() {
82            println!("testdata = {testdata:?}");
83
84            let (rest, (parsed, _)) = BlockCommentCloseLine::parse(testdata.into())?;
85            assert_eq!(rest, "");
86            assert_eq!(parsed, testdata);
87        }
88
89        Ok(())
90    }
91
92    #[test]
93    fn test_failed() -> anyhow::Result<()> {
94        let testdata = [
95            // nothing.
96            "",
97            // A close tag is in next line.
98            "\n'/",
99            "\n'/ \t ",
100            "\n '/ \t ",
101            "\n end '/",
102            "\n end '/ \t ",
103            " \n end '/ \t ",
104        ];
105
106        for testdata in testdata.into_iter() {
107            println!("testdata = {testdata:?}");
108
109            let result = BlockCommentCloseLine::parse(testdata.into());
110            assert!(result.is_err());
111        }
112
113        Ok(())
114    }
115}