plantuml_parser/dsl/block/
block_comment.rs

1use crate::PlantUmlLine;
2use crate::{ParseContainer, ParseError, ParseResult};
3use std::sync::Arc;
4
5/// Lines that are representation as block comment. (like `"/' begin \n end '/\n"`.)
6///
7/// * " /' begin \n end '/\n"
8///
9/// # Examples
10///
11/// ```
12/// use plantuml_parser::{BlockComment, ParseContainer};
13///
14/// # fn main() -> anyhow::Result<()> {
15/// let input = r#"  /' begin comment
16/// in comment
17/// end comment '/
18/// outer"#;
19/// let (rest, (parsed, comment)) = BlockComment::parse(input.into())?;
20/// assert_eq!(rest, "outer");
21/// assert_eq!(parsed, r#"  /' begin comment
22/// in comment
23/// end comment '/
24/// "#);
25/// assert!(comment.is_completed());
26///
27/// let input = "  /' not ending comment \n";
28/// let (rest, (parsed, comment)) = BlockComment::parse(input.into())?;
29/// assert_eq!(rest, "");
30/// assert_eq!(parsed, "  /' not ending comment \n");
31/// assert!(!comment.is_completed());
32/// # Ok(())
33/// # }
34/// ```
35#[derive(Clone, Debug)]
36pub struct BlockComment {
37    lines: Vec<Arc<PlantUmlLine>>,
38    completed: bool,
39}
40
41impl BlockComment {
42    /// Tries to parse [`BlockComment`]. (e.g. `"/' begin \n end '/\n"`.)
43    pub fn parse(input: ParseContainer) -> ParseResult<Self> {
44        let (mut rest, (_, line)) = PlantUmlLine::parse(input.clone())?;
45
46        if line.block_comment_open().is_none() {
47            return Err(ParseError::fail(input));
48        }
49
50        let mut lines = vec![Arc::new(line)];
51        let mut completed = false;
52
53        loop {
54            let (rest_inner, (_, mut line_inner)) = PlantUmlLine::parse(rest)?;
55
56            rest = rest_inner;
57
58            let is_closed = line_inner.block_comment_close().is_some();
59            if !is_closed {
60                line_inner = line_inner.into_in_comment();
61            }
62
63            lines.push(Arc::new(line_inner));
64
65            if is_closed {
66                completed = true;
67                break;
68            }
69
70            if rest.is_empty() {
71                break;
72            }
73        }
74
75        let parsed = input.split_at(input.len() - rest.len()).1;
76        Ok((rest, (parsed, Self { lines, completed })))
77    }
78
79    /// Returns whether the [`BlockCommentCloseLine`][`crate::BlockCommentCloseLine`] was found.
80    pub fn is_completed(&self) -> bool {
81        self.completed
82    }
83
84    /// Returns the reference of the list of lines in this block.
85    pub fn lines(&self) -> &[Arc<PlantUmlLine>] {
86        self.lines.as_slice()
87    }
88}
89
90impl std::fmt::Display for BlockComment {
91    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
92        for line in self.lines.iter() {
93            line.raw_str().fmt(formatter)?;
94        }
95
96        Ok(())
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103
104    #[test]
105    fn test_0() -> anyhow::Result<()> {
106        let input = ParseContainer::from(
107            r#"/'
108                comment
109            '/"#,
110        );
111
112        let (rest0, (parsed0, comment)) = BlockComment::parse(input.clone())?;
113        println!("rest0 = {rest0}");
114        println!("parsed0 = {parsed0}");
115        println!("comment = {comment:?}");
116        println!("comment (raw) = {comment}");
117        assert_eq!(rest0, "");
118        assert_eq!(parsed0, input);
119        assert!(comment.is_completed());
120
121        Ok(())
122    }
123
124    #[test]
125    fn test_1() -> anyhow::Result<()> {
126        let input = ParseContainer::from(
127            r#"/' incompleted
128                comment
129            "#,
130        );
131
132        let (rest0, (parsed0, comment)) = BlockComment::parse(input)?;
133        println!("rest0 = {rest0}");
134        println!("parsed0 = {parsed0}");
135        println!("comment = {comment:?}");
136        println!("comment (raw) = {comment}");
137        assert!(!comment.is_completed());
138
139        Ok(())
140    }
141}