piston_meta/meta_rules/
separate_by.rs

1use range::Range;
2use read_token::ReadToken;
3
4use super::{
5    ret_err,
6    err_update,
7    update,
8    IndentSettings,
9    ParseResult,
10};
11use {
12    DebugId,
13    MetaData,
14    Rule,
15};
16use tokenizer::TokenizerState;
17
18/// Stores inforamtion about separated by.
19#[derive(Clone, Debug, PartialEq)]
20pub struct SeparateBy {
21    /// The rule to separate.
22    pub rule: Rule,
23    /// The rule to separate by.
24    pub by: Rule,
25    /// Whether the rule must occur at least once.
26    pub optional: bool,
27    /// Whether the rule can end with separator.
28    pub allow_trail: bool,
29    /// A debug id to track down the rule generating an error.
30    pub debug_id: DebugId,
31}
32
33impl SeparateBy {
34    /// Parses rule repeatedly separated by another rule.
35    pub fn parse(
36        &self,
37        tokens: &mut Vec<Range<MetaData>>,
38        state: &TokenizerState,
39        read_token: &ReadToken,
40        refs: &[Rule],
41        indent_settings: &mut IndentSettings,
42    ) -> ParseResult<TokenizerState> {
43        let start = read_token;
44        let mut read_token = *start;
45        let mut state = state.clone();
46        let mut first = true;
47        let mut opt_error = None;
48        loop {
49            state = match self.rule.parse(tokens, &state, &read_token, refs, indent_settings) {
50                Err(err) => {
51                    match (first, self.optional, self.allow_trail) {
52                          (true, false, _)
53                        | (false, _, false) => {
54                            return Err(ret_err(err, opt_error));
55                        }
56                          (true, true, _)
57                        | (false, _, true) => {
58                            err_update(Some(err), &mut opt_error);
59                            break;
60                        }
61                    }
62                }
63                Ok((range, state, err)) => {
64                    update(range, err, &mut read_token, &mut opt_error);
65                    state
66                }
67            };
68            state = match self.by.parse(
69                tokens, &state, &read_token, refs, indent_settings
70            ) {
71                Err(err) => {
72                    err_update(Some(err), &mut opt_error);
73                    break;
74                }
75                Ok((range, state, err)) => {
76                    update(range, err, &mut read_token, &mut opt_error);
77                    state
78                }
79            };
80            first = false;
81        }
82        Ok((read_token.subtract(start), state, opt_error))
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use all::*;
89    use all::tokenizer::*;
90    use meta_rules::{ IndentSettings, SeparateBy, Tag, UntilAnyOrWhitespace };
91    use std::sync::Arc;
92    use range::Range;
93    use read_token::ReadToken;
94
95    #[test]
96    fn required() {
97        let ref mut indent_settings = IndentSettings::default();
98        let text = "foo()";
99        let mut tokens = vec![];
100        let s = TokenizerState::new();
101        let sep = SeparateBy {
102            debug_id: 0,
103            rule: Rule::UntilAnyOrWhitespace(UntilAnyOrWhitespace {
104                debug_id: 1,
105                any_characters: Arc::new(",)".into()),
106                optional: false,
107                property: None,
108            }),
109            by: Rule::Tag(Tag {
110                debug_id: 2,
111                text: Arc::new(",".into()),
112                not: false,
113                inverted: false,
114                property: None,
115            }),
116            optional: false,
117            allow_trail: false,
118        };
119        let res = sep.parse(&mut tokens, &s,
120            &ReadToken::new(&text[4..], 4), &[], indent_settings);
121        assert_eq!(res, Err(Range::new(4, 0).wrap(
122            ParseError::ExpectedSomething(1))));
123    }
124
125    #[test]
126    fn optional() {
127        let ref mut indent_settings = IndentSettings::default();
128        let text = "foo()";
129        let mut tokens = vec![];
130        let s = TokenizerState::new();
131        let sep = SeparateBy {
132            debug_id: 0,
133            rule: Rule::UntilAnyOrWhitespace(UntilAnyOrWhitespace {
134                debug_id: 1,
135                any_characters: Arc::new(",)".into()),
136                optional: false,
137                property: None,
138            }),
139            by: Rule::Tag(Tag {
140                debug_id: 2,
141                text: Arc::new(",".into()),
142                not: false,
143                inverted: false,
144                property: None,
145            }),
146            optional: true,
147            allow_trail: false,
148        };
149        let res = sep.parse(&mut tokens, &s,
150            &ReadToken::new(&text[4..], 4), &[], indent_settings);
151        assert_eq!(res, Ok((Range::new(4, 0), s,
152            Some(Range::new(4, 0).wrap(ParseError::ExpectedSomething(1))))));
153    }
154
155    #[test]
156    fn disallow_trail() {
157        let ref mut indent_settings = IndentSettings::default();
158        let text = "foo(a,b,c,)";
159        let mut tokens = vec![];
160        let s = TokenizerState::new();
161        let arg: Arc<String> = Arc::new("arg".into());
162        let sep = SeparateBy {
163            debug_id: 0,
164            rule: Rule::UntilAnyOrWhitespace(UntilAnyOrWhitespace {
165                debug_id: 1,
166                any_characters: Arc::new(",)".into()),
167                optional: false,
168                property: Some(arg.clone()),
169            }),
170            by: Rule::Tag(Tag {
171                debug_id: 2,
172                text: Arc::new(",".into()),
173                not: false,
174                inverted: false,
175                property: None,
176            }),
177            optional: true,
178            allow_trail: false,
179        };
180        let res = sep.parse(&mut tokens, &s,
181            &ReadToken::new(&text[4..], 4), &[], indent_settings);
182        assert_eq!(res, Err(Range::new(10, 0).wrap(
183            ParseError::ExpectedSomething(1))));
184    }
185
186    #[test]
187    fn allow_trail() {
188        let ref mut indent_settings = IndentSettings::default();
189        let text = "foo(a,b,c,)";
190        let mut tokens = vec![];
191        let s = TokenizerState::new();
192        let arg: Arc<String> = Arc::new("arg".into());
193        let sep = SeparateBy {
194            debug_id: 0,
195            rule: Rule::UntilAnyOrWhitespace(UntilAnyOrWhitespace {
196                debug_id: 1,
197                any_characters: Arc::new(",)".into()),
198                optional: false,
199                property: Some(arg.clone()),
200            }),
201            by: Rule::Tag(Tag {
202                debug_id: 2,
203                text: Arc::new(",".into()),
204                not: false,
205                inverted: false,
206                property: None,
207            }),
208            optional: true,
209            allow_trail: true,
210        };
211        let res = sep.parse(&mut tokens, &s,
212            &ReadToken::new(&text[4..], 4), &[], indent_settings);
213        assert_eq!(res, Ok((Range::new(4, 6), TokenizerState(3),
214            Some(Range::new(10, 0).wrap(ParseError::ExpectedSomething(1))))));
215        assert_eq!(tokens.len(), 3);
216        assert_eq!(&tokens[0].data,
217            &MetaData::String(arg.clone(), Arc::new("a".into())));
218        assert_eq!(&tokens[1].data,
219            &MetaData::String(arg.clone(), Arc::new("b".into())));
220        assert_eq!(&tokens[2].data,
221            &MetaData::String(arg.clone(), Arc::new("c".into())));
222    }
223
224    #[test]
225    fn successful() {
226        let ref mut indent_settings = IndentSettings::default();
227        let text = "foo(a,b,c)";
228        let mut tokens = vec![];
229        let s = TokenizerState::new();
230        let arg: Arc<String> = Arc::new("arg".into());
231        let sep = SeparateBy {
232            debug_id: 0,
233            rule: Rule::UntilAnyOrWhitespace(UntilAnyOrWhitespace {
234                debug_id: 1,
235                any_characters: Arc::new(",)".into()),
236                optional: false,
237                property: Some(arg.clone()),
238            }),
239            by: Rule::Tag(Tag {
240                debug_id: 2,
241                text: Arc::new(",".into()),
242                not: false,
243                inverted: false,
244                property: None,
245            }),
246            optional: true,
247            allow_trail: false,
248        };
249        let res = sep.parse(&mut tokens, &s,
250            &ReadToken::new(&text[4..], 4), &[], indent_settings);
251        assert_eq!(res, Ok((Range::new(4, 5), TokenizerState(3),
252            Some(Range::new(9, 0).wrap(
253                ParseError::ExpectedTag(Arc::new(",".into()), 2))))));
254        assert_eq!(tokens.len(), 3);
255        assert_eq!(&tokens[0].data,
256            &MetaData::String(arg.clone(), Arc::new("a".into())));
257        assert_eq!(&tokens[1].data,
258            &MetaData::String(arg.clone(), Arc::new("b".into())));
259        assert_eq!(&tokens[2].data,
260            &MetaData::String(arg.clone(), Arc::new("c".into())));
261    }
262
263    #[test]
264    fn nested() {
265        let ref mut indent_settings = IndentSettings::default();
266        let text = "a,b,c;d,e,f;";
267        let mut tokens = vec![];
268        let s = TokenizerState::new();
269        let arg: Arc<String> = Arc::new("arg".into());
270        let sep = SeparateBy {
271            debug_id: 0,
272            rule: Rule::SeparateBy(Box::new(SeparateBy {
273                debug_id: 1,
274                rule: Rule::UntilAnyOrWhitespace(UntilAnyOrWhitespace {
275                    debug_id: 2,
276                    any_characters: Arc::new(",;".into()),
277                    optional: false,
278                    property: Some(arg.clone()),
279                }),
280                by: Rule::Tag(Tag {
281                    debug_id: 3,
282                    text: Arc::new(",".into()),
283                    not: false,
284                    inverted: false,
285                    property: None,
286                }),
287                optional: false,
288                allow_trail: true,
289            })),
290            by: Rule::Tag(Tag {
291                debug_id: 4,
292                text: Arc::new(";".into()),
293                not: false,
294                inverted: false,
295                property: None,
296            }),
297            optional: false,
298            allow_trail: true,
299        };
300        let res = sep.parse(&mut tokens, &s, &ReadToken::new(&text, 0), &[], indent_settings);
301        assert_eq!(res, Ok((Range::new(0, 12), TokenizerState(6),
302            Some(Range::new(12, 0).wrap(
303                ParseError::ExpectedSomething(2))))));
304        assert_eq!(tokens.len(), 6);
305        assert_eq!(&tokens[0].data,
306            &MetaData::String(arg.clone(), Arc::new("a".into())));
307        assert_eq!(&tokens[1].data,
308            &MetaData::String(arg.clone(), Arc::new("b".into())));
309        assert_eq!(&tokens[2].data,
310            &MetaData::String(arg.clone(), Arc::new("c".into())));
311        assert_eq!(&tokens[3].data,
312            &MetaData::String(arg.clone(), Arc::new("d".into())));
313        assert_eq!(&tokens[4].data,
314            &MetaData::String(arg.clone(), Arc::new("e".into())));
315    }
316}