simple_interpreter/
interpreter.rs

1use crate::parser::PostfixParser;
2use crate::lexer::Lexer;
3use crate::token::{Token, Token::*};
4use std::collections::HashMap;
5use std::ops::FnMut;
6
7pub struct Interpreter<F> {
8    oper_args_count_map: HashMap<Token, usize>,
9    oper_eval_functor: F,
10    lexer: Lexer,
11    parser: PostfixParser
12}
13
14impl<F> Interpreter<F>
15where F: FnMut(&mut Vec<u8>, &Token) -> Result<u8, String> {
16    pub fn new(
17        literal_token_map: HashMap<&'static str, Token>,
18        oper_prioriry_map: HashMap<Token, i32>,
19        oper_args_count_map: HashMap<Token, usize>,
20        oper_eval_functor: F
21    ) -> Self {
22        Interpreter {
23            oper_args_count_map,
24            oper_eval_functor,
25            lexer: Lexer::new(literal_token_map),
26            parser: PostfixParser::new(oper_prioriry_map)
27        }
28    }
29
30    pub fn evaluate(&mut self, expr: &str) -> Result<u8, String> {
31        use Token::*;
32        let infix = self.lexer.tokenize(expr)?;
33        let postfix = self.parser.parse(infix)?;
34        let mut eval_stack: Vec<u8> = Vec::new();
35    
36        for token in postfix.iter() {
37            match self.get_oper_args_count(token) {
38                Some(_) =>  {
39                    let x = self.eval_op(&mut eval_stack, token)?;
40                    eval_stack.push(x);
41                }
42                None => {
43                    if let ConstVal(x) = token {
44                        eval_stack.push(x.clone());
45                    }
46                    else {
47                        return Err("Logic error: args_count() returned None for non-ConstVal token!".to_string());
48                    }
49                }
50            }
51        }
52        
53        if eval_stack.len() == 1 {
54            Ok(eval_stack.pop().unwrap())
55        } else {
56            Err("Cannot evaluate expression!".to_string())
57        }
58    }
59    
60    fn eval_op(&mut self, stack: &mut Vec<u8>, op: &Token) -> Result<u8, String> {
61        match self.get_oper_args_count(op) {
62            Some(n) => {
63                if stack.len() < n {
64                    Err(format!("Too few operands for {op}!"))
65                } else {
66                    let x = (self.oper_eval_functor)(stack, op)?;
67                    Ok(x)
68                }
69            }
70            None => Err(format!("Logic error: {op} doesn't exist in ARGS_COUNT_MAP!"))
71        }
72    }
73
74    fn get_oper_args_count(&self, op: &Token) -> Option<usize> {
75        self.oper_args_count_map.get(op).copied()
76    }
77}
78
79pub fn default_evaluate_operation(stack: &mut Vec<u8>, op: &Token) -> Result<u8, String> {
80    match op {
81        NotOp => {
82            let x = stack.pop().unwrap() != 0;
83            Ok(!x as u8)
84        }
85        _ => {
86            let rhs = stack.pop().unwrap() != 0;
87            let lhs = stack.pop().unwrap() != 0;
88            match op {
89                OrOp => Ok((lhs || rhs) as u8),
90                XorOp => Ok((lhs ^ rhs) as u8),
91                AndOp => Ok((lhs && rhs) as u8),
92                _ => Err(format!("Logic error: unhandled operation {op}!"))
93            }
94        }
95    }
96}
97
98#[cfg(test)]
99mod tests {
100    use crate::interpreter::*;
101    use lazy_static::*;
102
103    lazy_static! {
104        static ref LITERAL_TOKEN_MAP: HashMap<&'static str, Token> = HashMap::from([
105            ("&", AndOp),
106            ("|", OrOp),
107            ("^", XorOp),
108            ("~", NotOp),
109            ("(", LeftBrace),
110            (")", RightBrace) 
111        ]);
112    }
113
114    lazy_static! {
115        static ref OPER_PRIORITY_MAP: HashMap<Token, i32> = HashMap::from([
116            (OrOp, 1),
117            (XorOp, 1),
118            (AndOp, 2),
119            (NotOp, 3)
120        ]);
121    }
122
123    lazy_static! {
124        static ref ARGS_COUNT_MAP: HashMap<Token, usize> = HashMap::from([
125            (OrOp, 2),
126            (XorOp, 2),
127            (AndOp, 2),
128            (NotOp, 1)
129        ]);
130    }
131
132    #[test]
133    fn evaluate_expr_works() {
134        let mut interpreter = Interpreter::new(
135            LITERAL_TOKEN_MAP.clone(),
136            OPER_PRIORITY_MAP.clone(),
137            ARGS_COUNT_MAP.clone(),
138            default_evaluate_operation
139        );
140
141        let x = interpreter.evaluate("~3f|ab &( c5^10 ) ");
142        assert!(x.is_ok());
143        assert_eq!(x.unwrap(), 0xc1_u8);
144
145        assert!(interpreter.evaluate("~3f|ab &( c5^10 )) ").is_err());
146        assert!(interpreter.evaluate("~3f|ab &) c5^10 ( ").is_err());
147        //assert!(interpreter.evaluate("~3f|ab ~&( c5^10 ) ").is_err());
148        assert!(interpreter.evaluate("~3f|ab &&( c5^10 ) ").is_err());
149        assert!(interpreter.evaluate("~3f|ab bc &( c5^10 ) ").is_err());
150    }
151
152    #[test]
153    fn default_evaluate_operation_fn_works() {
154        let stack = vec![0x11_u8, 0x0f_u8];
155        assert_eq!(
156            default_evaluate_operation(&mut stack.clone(), &AndOp).unwrap(), 
157            0x01_u8
158        );
159        assert_eq!(
160            default_evaluate_operation(&mut stack.clone(), &NotOp).unwrap(), 
161            0xf0_u8
162        );
163    }
164
165    #[test]
166    fn eval_op_method_works() {
167        let mut stack = vec![0x11_u8, 0x0f_u8];
168
169        let mut interpreter = Interpreter::new(
170            LITERAL_TOKEN_MAP.clone(),
171            OPER_PRIORITY_MAP.clone(),
172            ARGS_COUNT_MAP.clone(),
173            default_evaluate_operation
174        );
175
176        assert_eq!(
177            interpreter.eval_op(&mut stack.clone(), &AndOp).unwrap(), 
178            0x01_u8
179        );
180        assert_eq!(
181            interpreter.eval_op(&mut stack.clone(), &NotOp).unwrap(), 
182            0xf0_u8
183        );
184        stack.pop();
185        assert!(interpreter.eval_op(&mut stack.clone(), &AndOp).is_err());
186    }
187}