1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use crate::{ast::AST, token::Token};

/// Tree walk interpreter.
pub struct Interpreter;

impl Interpreter {
    /// Public function to starting walking a AST.
    /// # Arguments
    /// * ast : Reference to the AST to walk.
    /// # Returns
    /// Result enum with the value of expression if interpretion was correct,
    /// otherwise string error.
    pub fn walk_ast(ast: &AST) -> Result<f64, String> {
        match ast {
            // if the entire ast is just one token.
            AST::Node(number) => Interpreter::walk_node(number),
            // walk the rest ast.
            AST::Con(operator, sub_tokens) => Interpreter::solve_expr(operator, sub_tokens),
        }
    }

    /// returns the inner valuue of a node, basically a Number Token.
    /// # Arguments
    /// * token - Reference to the token.
    /// # Returns
    /// Result with value of the number inside the token, otherwise error string.
    fn walk_node(token: &Token) -> Result<f64, String> {
        match token {
            Token::Number(f) => Ok(*f),
            _ => Err("Unrecognised node token.".to_string()),
        }
    }

    /// This is nothing but a wrapper which calls functions required
    /// by recognising the type of expression from the length of operands.
    /// # Arguments
    /// * token - Reference to the token.
    /// * sub_tokens - Reference to vector of ast inside the current node.
    /// # Returns
    /// The Result returned by the respective called function.
    fn solve_expr(operator: &Token, sub_tokens: &Vec<AST>) -> Result<f64, String> {
        match sub_tokens.len() {
            // if there are two operands, the expression is binary.
            2 => Interpreter::solve_binary(operator, sub_tokens),
            // if there is only one operand, the expression is unary.
            1 => Interpreter::solve_unary(operator, sub_tokens),
            // everything else is unreal according to this interpreter.
            _ => Err("Unrecognised number of operands.".to_string()),
        }
    }

    /// Solves a binary expression.
    /// # Arguments
    /// * token - Reference to the token.
    /// * sub_tokens - Reference to vector of ast inside the current node.
    /// # Returns
    /// Result with value after solving the binary expresion, otherwise error string.
    fn solve_binary(operator: &Token, sub_tokens: &[AST]) -> Result<f64, String> {
        // the left operand.
        let left = match Interpreter::walk_ast(&sub_tokens[0]) {
            Ok(left) => left,
            Err(e) => return Err(e),
        };

        // the right operand..
        let right = match Interpreter::walk_ast(&sub_tokens[1]) {
            Ok(right) => right,
            Err(e) => return Err(e),
        };

        // checking type of operator, and solving accordingly.
        match operator {
            Token::Plus => Ok(left + right),
            Token::Minus => Ok(left - right),
            Token::Star => Ok(left * right),
            Token::Slash => Ok(left / right),
            _ => Err("Unrecognised binary operator.".to_string()),
            //
        }
    }

    /// Solves a binary expression.
    /// # Arguments
    /// * token - Reference to the token.
    /// * sub_tokens - Reference to vector of ast inside the current node.
    /// # Returns
    /// Result with value after solving the binary expresion, otherwise error string.
    fn solve_unary(token: &Token, sub_tokens: &[AST]) -> Result<f64, String> {
        // the only right operand.
        let right = match Interpreter::walk_ast(&sub_tokens[0]) {
            Ok(right) => right,
            Err(e) => return Err(e),
        };

        // checking type of operator and solving accordingly.
        match token {
            Token::Minus => Ok(-right),
            _ => Err("Unrecognised binary operator.".to_string()),
        }
    }
}