1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// misc.rs
use crate::{
    parse::Parse, processing_instruction::ProcessingInstruction, Document, Error, IResult,
};
use nom::{branch::alt, combinator::map};

#[derive(Clone, PartialEq, Eq)]
pub enum MiscState {
    BeforeDoctype,
    AfterDoctype,
}

#[derive(Clone, PartialEq, Eq)]
pub struct Misc {
    pub content: Box<Document>, // Document::Comment | Document::ProcessingInstruction>
    pub state: MiscState,
}

impl<'a> Parse<'a> for Misc {
    type Args = MiscState;
    type Output = IResult<&'a str, Self>;

    //[27] Misc ::= Comment | PI | S
    fn parse(input: &'a str, args: Self::Args) -> Self::Output {
        let mut input_remaining = input;
        let mut content_vec: Vec<Document> = vec![];
        loop {
            let parse_result = alt((
                Document::parse_comment,
                map(
                    |i| ProcessingInstruction::parse(i, ()),
                    Document::ProcessingInstruction,
                ),
                map(Self::parse_multispace1, |_| Document::Empty),
            ))(input_remaining);

            match parse_result {
                Ok((remaining, document)) => {
                    match document {
                        Document::Empty => {} // Don't add Document::Empty types to content_vec
                        _ => content_vec.push(document),
                    }
                    input_remaining = remaining;
                }

                Err(_) => {
                    if !content_vec.is_empty() {
                        break;
                    } else {
                        return Err(nom::Err::Error(Error::NomError(nom::error::Error::new(
                            input.to_string(),
                            nom::error::ErrorKind::Many0,
                        ))));
                    }
                }
            }
        }

        let content = Box::new(Document::Nested(content_vec));
        Ok((
            input_remaining,
            Misc {
                content,
                state: args,
            },
        ))
    }
}