yaccas/parser/
parser.rs

1use std::collections::HashMap;
2use std::convert::Into;
3
4use ::arguments::*;
5use ::scanner::{Scanner, Token};
6
7use super::{FreeArgumentSupport, Result};
8
9/// The parser which parses the `Argument`s upon `Token`s provided by a `Scanner`.
10pub struct Parser<'a> {
11    /// Behavior on free arguments.
12    pub free_arguments: FreeArgumentSupport,
13    names: HashMap<&'a str, usize>,
14    arguments: Vec<Argument<'a>>,
15}
16
17impl<'a> Parser<'a> {
18    /// Registers an `Argument` with specific name(s) and a callback which is called after successful parsing.
19    /// # Example
20    /// ```
21    /// use yaccas::arguments::{Argument, Flag};
22    /// use yaccas::parser::{Parser, Result};
23    /// use yaccas::scanner::Unix;
24    ///
25    /// let mut parser = Parser::default();
26    /// let flag = Flag::default();
27    ///
28    /// parser.register(&["option", "o1", "o2"], Argument::with_callback(flag, | _flag | {
29    ///     // Do something with the argument here
30    /// }));
31    ///
32    /// assert_eq!(parser.parse(Unix::new(&["-option"])), Result::Success(Vec::new()));
33    /// ```
34    pub fn register<T: Into<Argument<'a>>>(&mut self, names: &[&'a str], argument: T) {
35        self.arguments.push(argument.into());
36
37        let index = self.arguments.len() - 1;
38
39        for name in names {
40            self.names.insert(name, index);
41        }
42    }
43
44    /// Parses the `Tokens` provided by a `Scanner` and matches them with registered `Argument`s.
45    pub fn parse<S: Scanner>(&mut self, scanner: S) -> Result {
46        let mut expecting_value = None;
47        let mut add_to_free_variables = false;
48        let mut free_variables = Vec::new();
49
50        for token in scanner {
51            // Check if further arguments need to be parsed
52            if add_to_free_variables {
53                free_variables.push(token.into());
54                continue;
55            }
56
57            // If a `Value` is expecting a value...
58            if let Some(index) = expecting_value {
59                match token {
60                    // Fail if the value is skipped
61                    Token::Bound(_) => {
62                        return Result::InvalidValue;
63                    }
64                    // Try to set the value
65                    Token::Free(value) => {
66                        if let Argument::Value(ref mut argument, _) = self.arguments[index] {
67                            if !argument.set_value(value) || !argument.has_value() {
68                                return Result::InvalidValue;
69                            }
70                            expecting_value = None;
71                        } else {
72                            panic!("Argument index was invalid!");
73                        }
74                    }
75                }
76            } else {
77                // Try to parse the argument or return it as a free argument
78                let free_argument = if let Token::Bound(name) = token {
79                    // Try to find the argument by name
80                    let arg_index = self.names.get::<str>(&name).cloned();
81                    // Process the argument if possible
82                    match arg_index.map(|index| {
83                        (index, self.arguments.get_mut(index).expect("Invalid index"))
84                    }) {
85                        Some((_, &mut Argument::Flag(ref mut flag, _))) => {
86                            flag.activate();
87                            None
88                        }
89                        Some((_, &mut Argument::Command(ref mut command, _))) => {
90                            if let Some(abort_reason) = command.execute() {
91                                return Result::Aborted(abort_reason);
92                            }
93                            None
94                        }
95                        Some((index, &mut Argument::Value(_, _))) => {
96                            expecting_value = Some(index);
97                            None
98                        }
99                        _ => Some(name),
100                    }
101                } else {
102                    Some(token.into())
103                };
104
105                // Process the free argument if set
106                if let Some(free_argument) = free_argument {
107                    match self.free_arguments {
108                        FreeArgumentSupport::None => {
109                            return Result::InvalidArgument;
110                        }
111                        FreeArgumentSupport::AtTheEnd => {
112                            if !add_to_free_variables {
113                                add_to_free_variables = true;
114                            }
115                            free_variables.push(free_argument);
116                        }
117                        FreeArgumentSupport::Everywhere => {
118                            free_variables.push(free_argument);
119                        }
120                    }
121                }
122            }
123        }
124
125        // Check if all arguments are sufficient
126        if self.arguments.iter().any(|argument| {
127            match argument {
128                &Argument::Value(ref value, _) if !value.has_value() => true,
129                _ => false,
130            }
131        }) {
132            return Result::NotSufficient;
133        }
134
135        // Parsing was successful: Execute the callbacks.
136        for argument in self.arguments.iter_mut() {
137            argument.execute_callback();
138        }
139
140        Result::Success(free_variables)
141    }
142}
143
144impl<'a> Default for Parser<'a> {
145    fn default() -> Parser<'a> {
146        Parser {
147            free_arguments: FreeArgumentSupport::AtTheEnd,
148            names: HashMap::new(),
149            arguments: Vec::new(),
150        }
151    }
152}