rpn_cli/read/
action.rs

1use crate::calc::value::{Value, ValueRef};
2use crate::error::{EngineError, MyError, MyResult};
3use crate::read::count::Count;
4use crate::read::interface::{Directive, Interface, Operation};
5use num::CheckedSub;
6use std::cell::RefCell;
7use std::io::Write;
8use std::rc::Rc;
9
10pub enum Action<W: Write> {
11    Operation(Rc<Operation<W>>),
12    Directive(Rc<Directive<W>>, Vec<String>),
13    Definition(Vec<Action<W>>),
14    Value(ValueRef, bool),
15}
16
17impl<W: Write> Clone for Action<W> {
18    fn clone(&self) -> Self {
19        match self {
20            Self::Operation(operation) => Self::Operation(Rc::clone(operation)),
21            Self::Directive(directive, tokens) => Self::Directive(Rc::clone(directive), tokens.clone()),
22            Self::Definition(actions) => Self::Definition(actions.clone()),
23            Self::Value(value, dirty) => Self::Value(Rc::clone(value), *dirty),
24        }
25    }
26}
27
28pub struct Actions<'a, W: Write, I: Iterator<Item = &'a str>> {
29    interface: Rc<RefCell<Interface<W>>>,
30    tokens: I,
31}
32
33impl<'a, W: Write, I: Iterator<Item = &'a str>> Actions<'a, W, I> {
34    pub fn new(
35        interface: &Rc<RefCell<Interface<W>>>,
36        tokens: I,
37    ) -> Self {
38        let interface = Rc::clone(interface);
39        Self { interface, tokens }
40    }
41}
42
43// noinspection RsLift
44impl<'a, W: Write, I: Iterator<Item = &'a str>> Iterator for Actions<'a, W, I> {
45    type Item = MyResult<(Action<W>, &'a str)>;
46
47    fn next(&mut self) -> Option<Self::Item> {
48        if let Some(token) = self.tokens.next() {
49            let interface = self.interface.borrow();
50            if let Some(operation) = interface.get_operation(token) {
51                let action = Action::Operation(operation);
52                return Some(Ok((action, token)));
53            } else if let Some(directive) = interface.get_directive(token) {
54                let mut tokens = Vec::new();
55                while let Some(token) = self.tokens.next() {
56                    tokens.push(String::from(token));
57                }
58                let action = Action::Directive(directive, tokens);
59                return Some(Ok((action, token)));
60            } else if let Some(actions) = interface.get_definition(token) {
61                let action = Action::Definition(actions);
62                return Some(Ok((action, token)));
63            } else if let Some(value) = interface.get_variable(token) {
64                let action = Action::Value(value, true);
65                return Some(Ok((action, token)));
66            } else {
67                match Value::from_string(token) {
68                    Ok(value) => {
69                        let value = Rc::new(RefCell::new(value));
70                        let action = Action::Value(value, false);
71                        return Some(Ok((action, token)));
72                    }
73                    Err(_) => {
74                        let error = EngineError::ParseError(String::from(token));
75                        return Some(Err(MyError::from(error)));
76                    }
77                }
78            }
79        }
80        None
81    }
82}
83
84pub fn fold_actions<W: Write>(actions: &Vec<Action<W>>) -> (Count, Count) {
85    actions.iter().fold((Count::Some(0), Count::Some(0)), fold_action)
86}
87
88fn fold_action<W: Write>((input, output): (Count, Count), action: &Action<W>) -> (Count, Count) {
89    match action {
90        Action::Operation(operation) => fold_operation(input, output, operation),
91        Action::Directive(_, _) => (input, output),
92        Action::Definition(actions) => fold_definition(input, output, actions),
93        Action::Value(_, _) => fold_value(input, output),
94    }
95}
96
97//                               E L E M E N T
98//         |   NULLARY   |    UNARY    |   BINARY    |   SERIES
99//     I/O | 0/0 0/1 0/2 | 1/0 1/1 1/2 | 2/0 2/1 2/2 | */0 */1 */2
100//    -----+-------------+-------------+-------------+-------------
101//  .  0/0 | 0/0 0/1 0/2 | 1/0 1/1 1/2 | 2/0 2/1 2/2 | */0 */1 */2
102//  .  0/1 | 0/1 0/2 0/3 | 0/0 0/1 0/2 | 1/0 1/1 1/2 | */0 */1 */2
103//  A  0/2 | 0/2 0/3 0/4 | 0/1 0/2 0/3 | 0/0 0/1 0/2 | */0 */1 */2
104//  C -----+-------------+-------------+-------------+-------------
105//  C  1/0 | 1/0 1/1 1/2 | 2/0 2/1 2/2 | 3/0 3/1 3/2 | */0 */1 */2
106//  U  1/1 | 1/1 1/2 1/3 | 1/0 1/1 1/2 | 2/0 2/1 2/2 | */0 */1 */2
107//  M  1/2 | 1/2 1/3 1/4 | 1/1 1/2 1/3 | 1/0 1/1 1/2 | */0 */1 */2
108//  U -----+-------------+-------------+-------------+-------------
109//  L  2/0 | 2/0 2/1 2/2 | 3/0 3/1 3/2 | 4/0 4/1 4/2 | */0 */1 */2
110//  A  2/1 | 2/1 2/2 2/3 | 2/0 2/1 2/2 | 3/0 3/1 3/2 | */0 */1 */2
111//  T  2/2 | 2/2 2/3 2/4 | 2/1 2/2 2/3 | 2/0 2/1 2/2 | */0 */1 */2
112//  O -----+-------------+-------------+-------------+-------------
113//  R  */0 | */0 */1 */2 | */0 */1 */2 | */0 */1 */2 | */0 */1 */2
114//  .  */1 | */1 */2 */3 | */0 */1 */2 | */0 */1 */2 | */0 */1 */2
115//  .  */2 | */2 */3 */4 | */1 */2 */3 | */0 */1 */2 | */0 */1 */2
116
117fn fold_operation<W: Write>(
118    input: Count,
119    output: Count,
120    operation: &Rc<Operation<W>>,
121) -> (Count, Count) {
122    // Check there are enough input parameters.
123    let (input2, output2) = operation.count_parameters();
124    if let Some(output) = output.checked_sub(&input2) {
125        // Append the output parameters.
126        (input, output + output2)
127    } else {
128        // Prepend the input parameters.
129        let input2 = input2.checked_sub(&output).unwrap_or(Count::Some(0));
130        (input + input2, output2)
131    }
132}
133
134fn fold_definition<W: Write>(
135    input: Count,
136    output: Count,
137    actions: &Vec<Action<W>>,
138) -> (Count, Count) {
139    actions.iter().fold((input, output), fold_action)
140}
141
142fn fold_value(input: Count, output: Count) -> (Count, Count) {
143    (input, output + Count::Some(1))
144}
145
146// noinspection DuplicatedCode
147#[cfg(test)]
148pub mod tests {
149    use crate::calc::value::tests::create_nan;
150    use crate::read::action::{fold_actions, Action};
151    use crate::read::count::Count;
152    use crate::read::interface::tests::{dummy_binary, dummy_directive, dummy_nullary, dummy_series, dummy_unary};
153    use crate::read::interface::{Completion, Directive, Operation};
154    use crate::util::text::tests::BufferWriter;
155    use std::rc::Rc;
156
157    #[test]
158    fn test_folds_values_only() {
159        let actions: Vec<Action<BufferWriter>> = vec![
160        ];
161        std::assert_eq!(fold_actions(&actions), (Count::Some(0), Count::Some(0)));
162
163        let actions: Vec<Action<BufferWriter>> = vec![
164            Action::Value(create_nan(), false),
165            Action::Value(create_nan(), false),
166            Action::Value(create_nan(), false),
167        ];
168        std::assert_eq!(fold_actions(&actions), (Count::Some(0), Count::Some(3)));
169    }
170
171    #[test]
172    fn test_folds_nullary_operation() {
173        let actions: Vec<Action<BufferWriter>> = vec![
174            Action::Value(create_nan(), false),
175            Action::Value(create_nan(), false),
176            Action::Operation(Rc::new(Operation::ValueNone(dummy_nullary))),
177        ];
178        std::assert_eq!(fold_actions(&actions), (Count::Some(0), Count::Some(3)));
179
180        let actions: Vec<Action<BufferWriter>> = vec![
181            Action::Value(create_nan(), false),
182            Action::Value(create_nan(), false),
183            Action::Operation(Rc::new(Operation::ValueNone(dummy_nullary))),
184            Action::Operation(Rc::new(Operation::ValueNone(dummy_nullary))),
185        ];
186        std::assert_eq!(fold_actions(&actions), (Count::Some(0), Count::Some(4)));
187    }
188
189    #[test]
190    fn test_folds_unary_operation() {
191        let actions: Vec<Action<BufferWriter>> = vec![
192            Action::Value(create_nan(), false),
193            Action::Value(create_nan(), false),
194            Action::Operation(Rc::new(Operation::ValueOne(dummy_unary))),
195        ];
196        std::assert_eq!(fold_actions(&actions), (Count::Some(0), Count::Some(2)));
197
198        let actions: Vec<Action<BufferWriter>> = vec![
199            Action::Value(create_nan(), false),
200            Action::Value(create_nan(), false),
201            Action::Operation(Rc::new(Operation::ValueOne(dummy_unary))),
202            Action::Operation(Rc::new(Operation::ValueOne(dummy_unary))),
203        ];
204        std::assert_eq!(fold_actions(&actions), (Count::Some(0), Count::Some(2)));
205    }
206
207    #[test]
208    fn test_folds_binary_operation() {
209        let actions: Vec<Action<BufferWriter>> = vec![
210            Action::Value(create_nan(), false),
211            Action::Value(create_nan(), false),
212            Action::Operation(Rc::new(Operation::ValueTwo(dummy_binary))),
213        ];
214        std::assert_eq!(fold_actions(&actions), (Count::Some(0), Count::Some(1)));
215
216        let actions: Vec<Action<BufferWriter>> = vec![
217            Action::Value(create_nan(), false),
218            Action::Value(create_nan(), false),
219            Action::Operation(Rc::new(Operation::ValueTwo(dummy_binary))),
220            Action::Operation(Rc::new(Operation::ValueTwo(dummy_binary))),
221        ];
222        std::assert_eq!(fold_actions(&actions), (Count::Some(1), Count::Some(1)));
223
224        let actions: Vec<Action<BufferWriter>> = vec![
225            Action::Value(create_nan(), false),
226            Action::Value(create_nan(), false),
227            Action::Operation(Rc::new(Operation::ValueTwo(dummy_binary))),
228            Action::Operation(Rc::new(Operation::ValueTwo(dummy_binary))),
229            Action::Operation(Rc::new(Operation::ValueTwo(dummy_binary))),
230        ];
231        std::assert_eq!(fold_actions(&actions), (Count::Some(2), Count::Some(1)));
232    }
233
234    #[test]
235    fn test_folds_series_operation() {
236        let actions: Vec<Action<BufferWriter>> = vec![
237            Action::Value(create_nan(), false),
238            Action::Value(create_nan(), false),
239            Action::Operation(Rc::new(Operation::ValueAll(dummy_series))),
240        ];
241        std::assert_eq!(fold_actions(&actions), (Count::All, Count::Some(1)));
242
243        let actions: Vec<Action<BufferWriter>> = vec![
244            Action::Value(create_nan(), false),
245            Action::Value(create_nan(), false),
246            Action::Value(create_nan(), false),
247            Action::Operation(Rc::new(Operation::ValueAll(dummy_series))),
248        ];
249        std::assert_eq!(fold_actions(&actions), (Count::All, Count::Some(1)));
250
251        let actions: Vec<Action<BufferWriter>> = vec![
252            Action::Value(create_nan(), false),
253            Action::Value(create_nan(), false),
254            Action::Value(create_nan(), false),
255            Action::Value(create_nan(), false),
256            Action::Operation(Rc::new(Operation::ValueAll(dummy_series))),
257        ];
258        std::assert_eq!(fold_actions(&actions), (Count::All, Count::Some(1)));
259    }
260
261    #[test]
262    fn test_folds_directive_as_noop() {
263        let actions: Vec<Action<BufferWriter>> = vec![
264            Action::Value(create_nan(), false),
265            Action::Value(create_nan(), false),
266            Action::Directive(Rc::new(Directive::EngineAll(dummy_directive, Completion::Keyword)), vec![]),
267        ];
268        std::assert_eq!(fold_actions(&actions), (Count::Some(0), Count::Some(2)));
269
270        let actions: Vec<Action<BufferWriter>> = vec![
271            Action::Value(create_nan(), false),
272            Action::Value(create_nan(), false),
273            Action::Directive(Rc::new(Directive::EngineAll(dummy_directive, Completion::Keyword)), vec![]),
274            Action::Directive(Rc::new(Directive::EngineAll(dummy_directive, Completion::Keyword)), vec![]),
275        ];
276        std::assert_eq!(fold_actions(&actions), (Count::Some(0), Count::Some(2)));
277    }
278
279    #[test]
280    fn test_folds_defined_function() {
281        let actions: Vec<Action<BufferWriter>> = vec![
282            Action::Value(create_nan(), false),
283            Action::Value(create_nan(), false),
284            Action::Operation(Rc::new(Operation::ValueNone(dummy_nullary))),
285            Action::Operation(Rc::new(Operation::ValueNone(dummy_nullary))),
286        ];
287        let actions: Vec<Action<BufferWriter>> = vec![
288            Action::Definition(actions),
289        ];
290        std::assert_eq!(fold_actions(&actions), (Count::Some(0), Count::Some(4)));
291
292        let actions: Vec<Action<BufferWriter>> = vec![
293            Action::Value(create_nan(), false),
294            Action::Value(create_nan(), false),
295            Action::Operation(Rc::new(Operation::ValueOne(dummy_unary))),
296            Action::Operation(Rc::new(Operation::ValueOne(dummy_unary))),
297        ];
298        let actions: Vec<Action<BufferWriter>> = vec![
299            Action::Definition(actions),
300        ];
301        std::assert_eq!(fold_actions(&actions), (Count::Some(0), Count::Some(2)));
302
303        let actions: Vec<Action<BufferWriter>> = vec![
304            Action::Value(create_nan(), false),
305            Action::Value(create_nan(), false),
306            Action::Operation(Rc::new(Operation::ValueTwo(dummy_binary))),
307            Action::Operation(Rc::new(Operation::ValueTwo(dummy_binary))),
308            Action::Operation(Rc::new(Operation::ValueTwo(dummy_binary))),
309        ];
310        let actions: Vec<Action<BufferWriter>> = vec![
311            Action::Definition(actions),
312        ];
313        std::assert_eq!(fold_actions(&actions), (Count::Some(2), Count::Some(1)));
314
315        let actions: Vec<Action<BufferWriter>> = vec![
316            Action::Value(create_nan(), false),
317            Action::Value(create_nan(), false),
318            Action::Operation(Rc::new(Operation::ValueAll(dummy_series))),
319        ];
320        let actions: Vec<Action<BufferWriter>> = vec![
321            Action::Definition(actions),
322        ];
323        std::assert_eq!(fold_actions(&actions), (Count::All, Count::Some(1)));
324    }
325}