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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
use crate::{namespaces::ParseNamespace, parse::Parse, ConditionalState, IResult, Name};
use nom::{
    branch::alt,
    bytes::complete::tag,
    combinator::{map, opt},
    multi::many1,
    sequence::{preceded, tuple},
};

use super::content_particle::ContentParticle;

#[derive(Clone, PartialEq, Eq)]
pub enum DeclarationContent {
    Mixed(Mixed),
    Children(ContentParticle),
    Empty,
    Any,
}

impl<'a> Parse<'a> for DeclarationContent {
    type Args = ();
    type Output = IResult<&'a str, Self>;
    // [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children
    fn parse(input: &'a str, args: Self::Args) -> Self::Output {
        alt((
            map(tag("EMPTY"), |_| Self::Empty),
            map(tag("ANY"), |_| Self::Any),
            map(|i| Mixed::parse(i, args), Self::Mixed),
            map(Self::parse_children, Self::Children),
        ))(input)
    }
}
impl<'a> ParseNamespace<'a> for DeclarationContent {}
impl DeclarationContent {
    // [47] children ::= (choice | seq) ('?' | '*' | '+')?
    fn parse_children(input: &str) -> IResult<&str, ContentParticle> {
        let (input, particle) = alt((
            map(
                tuple((
                    ContentParticle::parse_choice,
                    opt(|i| ConditionalState::parse(i, ())),
                )),
                |(choice, state)| {
                    ContentParticle::Choice(choice, state.unwrap_or(ConditionalState::None))
                },
            ),
            map(
                tuple((
                    ContentParticle::parse_sequence,
                    opt(|i| ConditionalState::parse(i, ())),
                )),
                |(seq, state)| {
                    ContentParticle::Sequence(seq, state.unwrap_or(ConditionalState::None))
                },
            ),
        ))(input)?;
        Ok((input, particle))
    }
}

#[derive(Clone, PartialEq, Eq)]
pub enum Mixed {
    PCDATA,
    Names(Vec<Name>),
}

impl<'a> ParseNamespace<'a> for Mixed {}
impl<'a> Parse<'a> for Mixed {
    type Args = ();
    type Output = IResult<&'a str, Self>;
    // [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' | '(' S? '#PCDATA' S? ')'
    // Namespaces (Third Edition) [19] Mixed ::= '(' S? '#PCDATA' (S? '|' S? QName)* S? ')*' | '(' S? '#PCDATA' S? ')'

    fn parse(input: &'a str, _args: Self::Args) -> Self::Output {
        alt((
            map(
                tuple((
                    tag("("),
                    Self::parse_multispace0,
                    tag("#PCDATA"),
                    many1(preceded(
                        tuple((Self::parse_multispace0, tag("|"), Self::parse_multispace0)),
                        alt((Self::parse_name, Self::parse_qualified_name)),
                    )),
                    Self::parse_multispace0,
                    tag(")*"),
                )),
                |(_, _, _, names, _, _)| Mixed::Names(names),
            ),
            map(
                tuple((
                    tag("("),
                    Self::parse_multispace0,
                    tag("#PCDATA"),
                    Self::parse_multispace0,
                    tag(")"),
                )),
                |_| Mixed::PCDATA,
            ),
        ))(input)
    }
}