expr_solver/interpreter.rs
1use crate::{ast::AST, token::Token, utils::factorial};
2
3/// Tree walk interpreter.
4pub struct Interpreter;
5
6impl Interpreter {
7 /// Public function to starting walking a AST.
8 /// # Arguments
9 /// * ast : Reference to the AST to walk.
10 /// # Returns
11 /// Result enum with the value of expression if interpretion was correct,
12 /// otherwise string error.
13 pub fn walk_ast(ast: &AST) -> Result<f64, String> {
14 match ast {
15 // if the entire ast is just one token.
16 AST::Node(number) => Interpreter::walk_node(number),
17 // walk the rest ast.
18 AST::Con(operator, sub_tokens) => Interpreter::solve_expr(operator, sub_tokens),
19 }
20 }
21
22 /// returns the inner valuue of a node, basically a Number Token.
23 /// # Arguments
24 /// * token - Reference to the token.
25 /// # Returns
26 /// Result with value of the number inside the token, otherwise error string.
27 fn walk_node(token: &Token) -> Result<f64, String> {
28 match token {
29 Token::Number(f) => Ok(*f),
30 _ => Err("Unrecognised node token.".to_string()),
31 }
32 }
33
34 /// This is nothing but a wrapper which calls functions required
35 /// by recognising the type of expression from the length of operands.
36 /// # Arguments
37 /// * token - Reference to the token.
38 /// * sub_tokens - Reference to vector of ast inside the current node.
39 /// # Returns
40 /// The Result returned by the respective called function.
41 fn solve_expr(operator: &Token, sub_tokens: &[AST]) -> Result<f64, String> {
42 match sub_tokens.len() {
43 // if there are two operands, the expression is binary.
44 2 => Interpreter::solve_binary(operator, sub_tokens),
45 // if there is only one operand, the expression is unary.
46 1 => Interpreter::solve_unary(operator, sub_tokens),
47 // everything else is unreal according to this interpreter.
48 _ => Err("Unrecognised number of operands.".to_string()),
49 }
50 }
51
52 /// Solves a binary expression.
53 /// # Arguments
54 /// * token - Reference to the token.
55 /// * sub_tokens - Reference to vector of ast inside the current node.
56 /// # Returns
57 /// Result with value after solving the binary expresion, otherwise error string.
58 fn solve_binary(operator: &Token, sub_tokens: &[AST]) -> Result<f64, String> {
59 // the left operand.
60 let left = match Interpreter::walk_ast(&sub_tokens[0]) {
61 Ok(left) => left,
62 Err(e) => return Err(e),
63 };
64
65 // the right operand..
66 let right = match Interpreter::walk_ast(&sub_tokens[1]) {
67 Ok(right) => right,
68 Err(e) => return Err(e),
69 };
70
71 log::trace!("Solving binary left={left} operator={operator} right={right}");
72 // checking type of operator, and solving accordingly.
73 match operator {
74 Token::Plus => Ok(left + right),
75 Token::Minus => Ok(left - right),
76 Token::Star => Ok(left * right),
77 Token::Slash => Ok(left / right),
78 _ => Err("Unrecognised binary operator.".to_string()),
79 //
80 }
81 }
82
83 /// Solves a binary expression.
84 /// # Arguments
85 /// * token - Reference to the token.
86 /// * sub_tokens - Reference to vector of ast inside the current node.
87 /// # Returns
88 /// Result with value after solving the binary expresion, otherwise error string.
89 fn solve_unary(operator: &Token, sub_tokens: &[AST]) -> Result<f64, String> {
90 // the only right operand.
91 let right = match Interpreter::walk_ast(&sub_tokens[0]) {
92 Ok(right) => right,
93 Err(e) => return Err(e),
94 };
95
96 log::trace!("Solving binary operator={operator} right={right}");
97 // checking type of operator and solving accordingly.
98 match operator {
99 Token::Minus => Ok(-right),
100 Token::Bang => Ok(factorial(right)),
101 _ => Err("Unrecognised binary operator.".to_string()),
102 }
103 }
104}