simple_interpreter/
interpreter.rs1use 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());
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}