Skip to main content

xrust/parser/combinators/
list.rs

1use crate::item::Node;
2use crate::parser::{ParseError, ParseInput, StaticState};
3use qualname::{NamespacePrefix, NamespaceUri};
4
5pub fn separated_list0<'a, P1, P2, R1, N: Node, L>(
6    sep: P1,
7    f: P2,
8) -> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, Vec<R1>), ParseError>
9where
10    P1: Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, ()), ParseError>,
11    P2: Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, R1), ParseError>,
12    L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
13{
14    move |mut input, ss| {
15        let mut res = Vec::new();
16
17        match f(input.clone(), ss) {
18            Err(_e) => {
19                return Ok((input, res));
20            }
21            Ok((i1, o)) => {
22                res.push(o);
23                input = i1;
24            }
25        }
26
27        loop {
28            match sep(input.clone(), ss) {
29                Err(ParseError::Combinator(_)) => {
30                    return Ok((input, res));
31                }
32                Err(e) => return Err(e),
33                Ok((i1, _)) => {
34                    // infinite loop check: the parser must always consume
35                    // SRB: not sure if this check is necessary with this parser, since input is an iterator
36                    //		    if i1.input_len() == len {
37                    //			return Err(ParseError::Combinator);
38                    //		    }
39
40                    match f(i1, ss) {
41                        Err(ParseError::Combinator(_)) => return Ok((input, res)),
42                        Err(e) => return Err(e),
43                        Ok((i2, o)) => {
44                            res.push(o);
45                            input = i2;
46                        }
47                    }
48                }
49            }
50        }
51    }
52}
53
54pub(crate) fn separated_list1<'a, P1, P2, R1, N: Node, L>(
55    sep: P1,
56    f: P2,
57) -> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, Vec<R1>), ParseError>
58where
59    P1: Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, ()), ParseError>,
60    P2: Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, R1), ParseError>,
61    L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
62{
63    move |mut input, ss| {
64        let mut res = Vec::new();
65
66        match f(input.clone(), ss) {
67            Err(e) => return Err(e),
68            Ok((i1, o)) => {
69                res.push(o);
70                input = i1;
71            }
72        }
73
74        loop {
75            match sep(input.clone(), ss) {
76                Err(ParseError::Combinator(_)) => {
77                    return Ok((input, res));
78                }
79                Err(e) => return Err(e),
80                Ok((i1, _)) => {
81                    // infinite loop check: the parser must always consume
82                    // SRB: not sure if this check is necessary with this parser, since input is an iterator
83                    //		    if i1.input_len() == len {
84                    //			return Err(ParseError::Combinator);
85                    //		    }
86
87                    match f(i1, ss) {
88                        Err(ParseError::Combinator(_)) => {
89                            return Ok((input, res));
90                        }
91                        Err(e) => return Err(e),
92                        Ok((i2, o)) => {
93                            res.push(o);
94                            input = i2;
95                        }
96                    }
97                }
98            }
99        }
100    }
101}
102
103#[cfg(test)]
104mod tests {
105    use crate::parser::combinators::alt::alt4;
106    use crate::parser::combinators::list::{separated_list0, separated_list1};
107    use crate::parser::combinators::map::map;
108    use crate::parser::combinators::tag::tag;
109    use crate::parser::{ParseError, ParserState, StaticStateBuilder};
110    use crate::trees::nullo::Nullo;
111    use qualname::NamespaceUri;
112
113    #[test]
114    fn parser_separated_list0_test1() {
115        let testdoc = "b";
116        let teststate: ParserState<Nullo> = ParserState::new();
117        let mut static_state = StaticStateBuilder::new()
118            .namespace(|_| {
119                NamespaceUri::try_from("urn:xrust").map_err(|_| ParseError::MissingNameSpace)
120            })
121            .build();
122        let parse_doc = separated_list0(tag(","), map(tag("a"), |_| "a"));
123
124        assert_eq!(
125            Ok((("b", ParserState::new()), vec![])),
126            parse_doc((testdoc, teststate), &mut static_state)
127        );
128    }
129
130    #[test]
131    fn parser_separated_list0_test2() {
132        let testdoc = "a";
133        let teststate: ParserState<Nullo> = ParserState::new();
134        let mut static_state = StaticStateBuilder::new()
135            .namespace(|_| {
136                NamespaceUri::try_from("urn:xrust").map_err(|_| ParseError::MissingNameSpace)
137            })
138            .build();
139        let parse_doc = separated_list0(tag(","), map(tag("a"), |_| "a"));
140
141        assert_eq!(
142            Ok((("", ParserState::new()), vec!["a"])),
143            parse_doc((testdoc, teststate), &mut static_state)
144        );
145    }
146
147    #[test]
148    fn parser_separated_list0_test3() {
149        let testdoc = "a,b,c,d";
150        let teststate: ParserState<Nullo> = ParserState::new();
151        let mut static_state = StaticStateBuilder::new()
152            .namespace(|_| {
153                NamespaceUri::try_from("urn:xrust").map_err(|_| ParseError::MissingNameSpace)
154            })
155            .build();
156        let parse_doc = separated_list1(
157            tag(","),
158            alt4(
159                map(tag("a"), |_| "1"),
160                map(tag("b"), |_| "2"),
161                map(tag("c"), |_| "3"),
162                map(tag("d"), |_| "4"),
163            ),
164        );
165
166        assert_eq!(
167            Ok((("", ParserState::new()), vec!["1", "2", "3", "4"])),
168            parse_doc((testdoc, teststate), &mut static_state)
169        );
170    }
171
172    #[test]
173    fn parser_separated_list1_test1() {
174        let testdoc = "a";
175        let teststate: ParserState<Nullo> = ParserState::new();
176        let mut static_state = StaticStateBuilder::new()
177            .namespace(|_| {
178                NamespaceUri::try_from("urn:xrust").map_err(|_| ParseError::MissingNameSpace)
179            })
180            .build();
181        let parse_doc = separated_list1(tag(","), map(tag("a"), |_| "a"));
182
183        assert_eq!(
184            Ok((("", ParserState::new()), vec!["a"])),
185            parse_doc((testdoc, teststate), &mut static_state)
186        );
187    }
188
189    #[test]
190    fn parser_separated_list1_test2() {
191        let testdoc = "a,b,c,d";
192        let teststate: ParserState<Nullo> = ParserState::new();
193        let mut static_state = StaticStateBuilder::new()
194            .namespace(|_| {
195                NamespaceUri::try_from("urn:xrust").map_err(|_| ParseError::MissingNameSpace)
196            })
197            .build();
198        let parse_doc = separated_list1(
199            tag(","),
200            alt4(
201                map(tag("a"), |_| "1"),
202                map(tag("b"), |_| "2"),
203                map(tag("c"), |_| "3"),
204                map(tag("d"), |_| "4"),
205            ),
206        );
207
208        assert_eq!(
209            Ok((("", ParserState::new()), vec!["1", "2", "3", "4"])),
210            parse_doc((testdoc, teststate), &mut static_state)
211        );
212    }
213}