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()),
}
}
}