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}