nom_xml/prolog/
content_particle.rs

1use crate::{namespaces::ParseNamespace, parse::Parse, ConditionalState, IResult, Name};
2use nom::{
3    branch::alt,
4    character::complete::char,
5    combinator::{map, opt},
6    multi::{many0, many1},
7    sequence::{delimited, tuple},
8};
9
10#[derive(Clone, Debug, PartialEq, Eq)]
11pub enum ContentParticle {
12    Name(Name, ConditionalState),
13    Choice(Vec<ContentParticle>, ConditionalState),
14    Sequence(Vec<ContentParticle>, ConditionalState),
15}
16impl<'a> ParseNamespace<'a> for ContentParticle {}
17impl<'a> Parse<'a> for ContentParticle {
18    type Args = ();
19    type Output = IResult<&'a str, Self>;
20
21    // [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')?
22    // Namespaces (Third Edition) [18] cp ::= (QName | choice | seq) ('?' | '*' | '+')?
23    fn parse(input: &'a str, _args: Self::Args) -> Self::Output {
24        let (input, res) = alt((
25            map(
26                tuple((
27                    alt((Self::parse_name, Self::parse_qualified_name)),
28                    opt(|i| ConditionalState::parse(i, ())),
29                )),
30                |(name, conditional_state)| {
31                    ContentParticle::Name(name, conditional_state.unwrap_or(ConditionalState::None))
32                },
33            ),
34            map(
35                tuple((Self::parse_choice, opt(|i| ConditionalState::parse(i, ())))),
36                |(choice, conditional_state)| {
37                    ContentParticle::Choice(
38                        choice,
39                        conditional_state.unwrap_or(ConditionalState::None),
40                    )
41                },
42            ),
43            map(
44                tuple((
45                    Self::parse_sequence,
46                    opt(|i| ConditionalState::parse(i, ())),
47                )),
48                |(sequence, conditional_state)| {
49                    ContentParticle::Sequence(
50                        sequence,
51                        conditional_state.unwrap_or(ConditionalState::None),
52                    )
53                },
54            ),
55        ))(input)?;
56        Ok((input, res))
57    }
58}
59
60impl ContentParticle {
61    // [49] choice ::= '(' S? cp ( S? '|' S? cp )+ S? ')'
62    pub fn parse_choice(input: &str) -> IResult<&str, Vec<ContentParticle>> {
63        map(
64            delimited(
65                tuple((char('('), Self::parse_multispace0)),
66                tuple((
67                    |i| Self::parse(i, ()),
68                    many1(tuple((
69                        tuple((Self::parse_multispace0, char('|'), Self::parse_multispace0)),
70                        |i| Self::parse(i, ()),
71                    ))),
72                )),
73                tuple((Self::parse_multispace0, char(')'))),
74            ),
75            |(first_cp, others)| {
76                let mut all_cps = Vec::new();
77                all_cps.push(first_cp);
78                all_cps.extend(others.into_iter().map(|(_, cp)| cp));
79                all_cps
80            },
81        )(input)
82    }
83
84    // [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')'
85    pub fn parse_sequence(input: &str) -> IResult<&str, Vec<ContentParticle>> {
86        map(
87            delimited(
88                tuple((char('('), Self::parse_multispace0)),
89                tuple((
90                    |i| Self::parse(i, ()),
91                    many0(tuple((
92                        tuple((Self::parse_multispace0, char(','), Self::parse_multispace0)),
93                        |i| Self::parse(i, ()),
94                    ))),
95                )),
96                tuple((Self::parse_multispace0, char(')'))),
97            ),
98            |(first_cp, others)| {
99                let mut all_cps = Vec::new();
100                all_cps.push(first_cp);
101                all_cps.extend(others.into_iter().map(|(_, cp)| cp));
102                all_cps
103            },
104        )(input)
105    }
106}