piston_meta/meta_rules/
optional.rs

1use range::Range;
2use read_token::ReadToken;
3
4use super::{
5    ret_err,
6    update,
7    IndentSettings,
8};
9use {
10    DebugId,
11    MetaData,
12    ParseError,
13    Rule,
14};
15use tokenizer::TokenizerState;
16
17/// Stores information about optional.
18#[derive(Clone, Debug, PartialEq)]
19pub struct Optional {
20    /// The optional rule.
21    pub rule: Rule,
22    /// A debug id to track down the rule generating an error.
23    pub debug_id: DebugId,
24}
25
26impl Optional {
27    /// Parse optional.
28    /// Returns the old state if any sub rule fails.
29    pub fn parse(
30        &self,
31        tokens: &mut Vec<Range<MetaData>>,
32        state: &TokenizerState,
33        read_token: &ReadToken,
34        refs: &[Rule],
35        indent_settings: &mut IndentSettings,
36    ) -> (Range, TokenizerState, Option<Range<ParseError>>) {
37        let start = read_token;
38        let mut read_token = *start;
39        let mut success_state = state.clone();
40        let mut opt_error = None;
41        success_state = match self.rule.parse(
42            tokens, &success_state, &read_token, refs, indent_settings
43        ) {
44            Ok((range, state, err)) => {
45                update(range, err, &mut read_token, &mut opt_error);
46                state
47            }
48            Err(err) => {
49                return (start.start(), state.clone(),
50                    Some(ret_err(err, opt_error)))
51            }
52        };
53        (read_token.subtract(start), success_state, opt_error)
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use all::*;
60    use all::tokenizer::*;
61    use meta_rules::{ IndentSettings, Number, Optional, Sequence, Text };
62    use range::Range;
63    use read_token::ReadToken;
64    use std::sync::Arc;
65
66    #[test]
67    fn fail_but_continue() {
68        let ref mut indent_settings = IndentSettings::default();
69        let text = "2";
70        let mut tokens = vec![];
71        let s = TokenizerState::new();
72        let num: Arc<String> = Arc::new("num".into());
73        // Will fail because text is expected first.
74        let optional = Optional {
75            debug_id: 0,
76            rule: Rule::Sequence(Sequence {
77                debug_id: 1,
78                args: vec![
79                    Rule::Text(Text {
80                        debug_id: 2,
81                        allow_empty: true,
82                        property: None
83                    }),
84                    Rule::Number(Number {
85                        debug_id: 3,
86                        property: Some(num.clone()),
87                        allow_underscore: false,
88                    })
89                ]
90            }),
91        };
92        let res = optional.parse(&mut tokens, &s,
93            &ReadToken::new(&text, 0), &[], indent_settings);
94        assert_eq!(res, (Range::new(0, 0), TokenizerState(0),
95            Some(Range::new(0, 0).wrap(ParseError::ExpectedText(2)))));
96        assert_eq!(tokens.len(), 0);
97    }
98}