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
103
104
105
106
107
108
109
110
111
112
113
114
use range::Range;
use read_token::ReadToken;

use super::{
    err_update,
    ParseResult,
};
use {
    DebugId,
    MetaData,
    ParseError,
    Rule,
};
use tokenizer::TokenizerState;

/// Stores information about select.
#[derive(Clone, Debug, PartialEq)]
pub struct Select {
    /// The rules to select from.
    pub args: Vec<Rule>,
    /// A debug id to track down the rule generating an error.
    pub debug_id: DebugId,
}

impl Select {
    /// Parses select.
    pub fn parse(
        &self,
        tokens: &mut Vec<Range<MetaData>>,
        state: &TokenizerState,
        read_token: &ReadToken,
        refs: &[Rule]
    ) -> ParseResult<TokenizerState> {
        let mut opt_error: Option<Range<ParseError>> = None;
        for sub_rule in &self.args {
            match sub_rule.parse(tokens, state, read_token, refs) {
                Ok((range, state, err)) => {
                    err_update(err, &mut opt_error);
                    return Ok((read_token.peek(range.length),
                        state, opt_error));
                }
                Err(err) => {
                    err_update(Some(err), &mut opt_error);
                }
            }
        }
        match opt_error {
            None => Err(read_token.start().wrap(
                ParseError::InvalidRule(
                "`Select` requires at least one sub rule", self.debug_id))),
            Some(err) => Err(err),
        }
    }
}

#[cfg(test)]
mod tests {
    use all::*;
    use meta_rules::{ Number, Select, Text };
    use range::Range;
    use std::sync::Arc;

    #[test]
    fn invalid_rule() {
        let text = "";
        let select = Rule::Select(Select {
            debug_id: 0,
            args: vec![]
        });
        let mut syntax = Syntax::new();
        syntax.push(Arc::new("".into()), select);
        let mut tokens = vec![];
        let res = parse(&syntax, &text, &mut tokens);
        let invalid_rule = match &res {
            &Err(ref range_err) => {
                match range_err.data {
                    ParseError::InvalidRule(_, _) => true,
                    _ => false
                }
            }
            _ => false
        };
        assert!(invalid_rule);
    }

    #[test]
    fn fail_first() {
        let text = "2";
        let num: Arc<String> = Arc::new("num".into());
        let select = Rule::Select(Select {
            debug_id: 0,
            args: vec![
                Rule::Text(Text {
                    debug_id: 1,
                    allow_empty: true,
                    property: None
                }),
                Rule::Number(Number {
                    debug_id: 2,
                    property: Some(num.clone()),
                    allow_underscore: false,
                })
            ]
        });
        let mut syntax = Syntax::new();
        syntax.push(Arc::new("".into()), select);
        let mut tokens = vec![];
        let res = parse(&syntax, &text, &mut tokens);
        assert_eq!(res, Ok(()));
        assert_eq!(tokens, vec![
            Range::new(0, 1).wrap(MetaData::F64(num.clone(), 2.0))
        ]);
    }
}