custom_expression/
custom_expression.rs

1extern crate ripin;
2
3use std::env;
4use std::marker::PhantomData;
5use ripin::{Stack, pop_two_operands};
6use ripin::convert_ref::TryFromRef;
7use ripin::expression::Expression;
8use ripin::evaluate::Evaluate;
9use ripin::variable::DummyVariable;
10
11// Implementing Expression for a new specific type
12// is not a difficult thing to do:
13
14// First you will need something that
15// can be understand as an Operand type, like float or integer.
16// The type you choose need to implement TryFromRef.
17#[derive(Debug, Copy, Clone)]
18enum MyOperand {
19    Number1,
20    Number2,
21}
22
23impl<'a> TryFromRef<&'a str> for MyOperand {
24    type Err = MyOperandErr<&'a str>;
25    fn try_from_ref(s: &&'a str) -> Result<Self, Self::Err> {
26        match *s {
27            "1" => Ok(MyOperand::Number1),
28            "2" => Ok(MyOperand::Number2),
29            _ => Err(MyOperandErr::InvalidToken(s))
30        }
31    }
32}
33
34// Secondly an Evaluator type to make evaluation
35// of Operands and generate other ones on the stack.
36// It needs to implement TryFromRef too.
37#[derive(Debug, Copy, Clone)]
38enum MyEvaluator<T> {
39    Add,
40    Sub,
41    _Phantom(PhantomData<T>) // make it generic but
42                             // don't own the generic T type
43}
44
45impl<'a, T> TryFromRef<&'a str> for MyEvaluator<T> {
46    type Err = MyOperandErr<&'a str>;
47    fn try_from_ref(s: &&'a str) -> Result<Self, Self::Err> {
48        match *s {
49            "+" => Ok(MyEvaluator::Add),
50            "-" => Ok(MyEvaluator::Sub),
51            _ => Err(MyOperandErr::InvalidToken(s))
52        }
53    }
54}
55
56// A clear error struct/enum is really important for the parsing part
57#[derive(Debug)]
58enum MyOperandErr<T> {
59    InvalidToken(T),
60}
61
62// Be careful both needs to implement the same TryFromRef Trait signature !
63// If the Operand type works with TryFromRef<&str>
64// then the Evaluator needs the same TryFromRef signature.
65
66// A clear error struct/enum is really important for the evaluation part
67#[derive(Debug)]
68enum MyEvalErr<T> {
69    CannotAddOperands(T, T),
70    CannotSubOperands(T, T),
71    NotEnoughOperands
72}
73
74// The last step is to implement the Evaluate trait on your custom Evaluator.
75// Evaluations are done with this trait.
76impl Evaluate<MyOperand> for MyEvaluator<MyOperand> {
77    type Err = MyEvalErr<MyOperand>;
78
79    fn operands_needed(&self) -> usize {
80        match *self {
81            MyEvaluator::Add | MyEvaluator::Sub => 2,
82            _ => unreachable!(), // _Phantom
83        }
84    }
85    fn operands_generated(&self) -> usize {
86        match *self {
87            MyEvaluator::Add | MyEvaluator::Sub => 1,
88            _ => unreachable!(), // _Phantom
89        }
90    }
91
92    fn evaluate(self, stack: &mut Stack<MyOperand>) -> Result<(), Self::Err> {
93        let (a, b) = pop_two_operands(stack).ok_or(MyEvalErr::NotEnoughOperands)?;
94        match self {
95            MyEvaluator::Add => {
96                match (a, b) {
97                    (MyOperand::Number1, MyOperand::Number1) => {
98                        Ok(stack.push(MyOperand::Number2))
99                    },
100                    _ => Err(MyEvalErr::CannotAddOperands(a, b)),
101                }
102            },
103            MyEvaluator::Sub => {
104                match (a, b) {
105                    (MyOperand::Number2, MyOperand::Number1) => {
106                        Ok(stack.push(MyOperand::Number1))
107                    },
108                    _ => Err(MyEvalErr::CannotSubOperands(a, b)),
109                }
110            }
111            _ => unreachable!() // _Phantom
112        }
113    }
114}
115
116type MyExpression = Expression<MyOperand, DummyVariable, MyEvaluator<MyOperand>>;
117
118// Once you implement the TryFromRef trait on your “custom” types,
119// make an iterator of it and give it to the Expression struct.
120fn main() {
121    let expr_str = env::args().nth(1).unwrap_or_else(|| {
122        println!("Give me an expression as first argument!");
123        "1 1 +".into()
124    });
125
126    let tokens = expr_str.split_whitespace();
127    match MyExpression::from_iter(tokens) {
128        Ok(expr) => println!("Evaluation of {:?} gives {:?}", expr_str, expr.evaluate()),
129        Err(err) => println!("Parsing results in {:?}", err),
130    }
131}