diff --git a/chapter2/ast.rs b/chapter2/ast.rs new file mode 100644 index 0000000..2a91bce --- /dev/null +++ b/chapter2/ast.rs @@ -0,0 +1,81 @@ +// Standard lib +use std::error; +use std::fmt; +//Primary external libraries + +//utility externa libraries + +//internal modules + +//structs + +#[derive(Debug, Clone, PartialEq)] +pub enum Node { + Add(Box, Box), + Subtract(Box, Box), + Multiply(Box, Box), + Divide(Box, Box), + Caret(Box, Box), + LeftParen(Box, Box), + RightParen(Box, Box), + Negative(Box), + Absolute(Box), + Number(f64), +} + +pub fn eval(expr: Node) -> Result { + use self::Node::*; + match expr { + Number(i) => Ok(i), + Add(expr1, expr2) => Ok(eval(*expr1)? + eval(*expr2)?), + Subtract(expr1, expr2) => Ok(eval(*expr1)? - eval(*expr2)?), + Multiply(expr1, expr2) => Ok(eval(*expr1)? * eval(*expr2)?), + Divide(expr1, expr2) => Ok(eval(*expr1)? / eval(*expr2)?), + Negative(expr1) => Ok(-(eval(*expr1)?)), + Caret(expr1, expr2) => Ok(eval(*expr1)?.powf(eval(*expr2)?)), + Absolute(expr1) => Ok(eval(*expr1)?.abs()), + _ => Err(EvaluationError::UnableToEvaluate( + "No clue, sorry".to_string(), + )), + } +} +#[derive(Debug)] +pub enum EvaluationError { + UnableToEvaluate(String), +} + +impl fmt::Display for EvaluationError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match &self { + self::EvaluationError::UnableToEvaluate(e) => write!(f, "Error in evaluating {}", e), + } + } +} +impl error::Error for EvaluationError { + fn description(&self) -> &str { + match &self { + self::EvaluationError::UnableToEvaluate(e) => &e, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_expr1() { + use crate::parsemath::parser::Parser; + + let ast = Parser::new("1+2-3").unwrap().parse().unwrap(); + let value = eval(ast).unwrap(); + assert_eq!(value, 0.0); + } + #[test] + fn test_expr2() { + use crate::parsemath::parser::Parser; + + let ast = Parser::new("3+2-1*5/4").unwrap().parse().unwrap(); + let value = eval(ast).unwrap(); + assert_eq!(value, 3.75); + } +} diff --git a/chapter2/mod.rs b/chapter2/mod.rs new file mode 100644 index 0000000..b9b222d --- /dev/null +++ b/chapter2/mod.rs @@ -0,0 +1,4 @@ +pub mod ast; +pub mod parser; +pub mod token; +pub mod tokenizer; diff --git a/chapter2/parser.rs b/chapter2/parser.rs new file mode 100644 index 0000000..55fe780 --- /dev/null +++ b/chapter2/parser.rs @@ -0,0 +1,167 @@ +// Standard lib +use std::error; +use std::fmt; +// Primary external libs + +// Secondary internal libs + +// Internal modules +use super::ast::Node; +use super::token::{OperPrec, Token}; +use super::tokenizer::Tokenizer; +//Structs and constants + +pub struct Parser<'a> { + tokenizer: Tokenizer<'a>, + current_token: Token, +} + +impl<'a> Parser<'a> { + pub fn new(expr: &'a str) -> Result { + let mut lexer = Tokenizer::new(expr); + let cur_token = lexer.next().unwrap(); + Ok(Parser { + tokenizer: lexer, + current_token: cur_token, + }) + } + fn next_token(&mut self) -> Result<(), ParseError> { + self.current_token = self.tokenizer.next().unwrap(); + Ok(()) + } + pub fn parse(&mut self) -> Result { + let ast = self.generate_ast(OperPrec::DefaultZero); + match ast { + Ok(ast) => Ok(ast), + Err(e) => Err(e), + } + } + + fn generate_ast(&mut self, oper_prec: OperPrec) -> Result { + let mut left_expr = self.parse_number()?; + + while oper_prec < self.current_token.get_oper_prec() { + if self.current_token == Token::EOF { + break; + } + let right_expr = self.convert_token_to_node(left_expr.clone())?; + left_expr = right_expr; + } + Ok(left_expr) + } + + fn parse_number(&mut self) -> Result { + let token = self.current_token.clone(); + match token { + Token::Subtract => { + self.next_token()?; + let expr = self.generate_ast(OperPrec::Negative)?; + Ok(Node::Negative(Box::new(expr))) + } + Token::Num(i) => { + self.next_token()?; + Ok(Node::Number(i)) + } + Token::LeftParen => { + self.next_token()?; + let expr = self.generate_ast(OperPrec::DefaultZero)?; + self.expect(Token::RightParen)?; + if self.current_token == Token::LeftParen { + let right = self.generate_ast(OperPrec::MulDiv)?; + return Ok(Node::Multiply(Box::new(expr), Box::new(right))); + } + + Ok(expr) + } + _ => Err(ParseError::UnableToParse("Unable to parse".to_string())), + } + } + + fn expect(&mut self, expected: Token) -> Result<(), ParseError> { + if expected == self.current_token { + self.next_token()?; + Ok(()) + } else { + Err(ParseError::InvalidOperator(format!( + "Expected {:?}, got {:?}", + expected, self.current_token + ))) + } + } + + fn convert_token_to_node(&mut self, left_expr: Node) -> Result { + match self.current_token { + Token::Add => { + self.next_token()?; + //Get right-side expression + let right_expr = self.generate_ast(OperPrec::AddSub)?; + Ok(Node::Add(Box::new(left_expr), Box::new(right_expr))) + } + Token::Subtract => { + self.next_token()?; + //Get right-side expression + let right_expr = self.generate_ast(OperPrec::AddSub)?; + Ok(Node::Subtract(Box::new(left_expr), Box::new(right_expr))) + } + Token::Multiply => { + self.next_token()?; + //Get right-side expression + let right_expr = self.generate_ast(OperPrec::MulDiv)?; + Ok(Node::Multiply(Box::new(left_expr), Box::new(right_expr))) + } + Token::Divide => { + self.next_token()?; + //Get right-side expression + let right_expr = self.generate_ast(OperPrec::MulDiv)?; + Ok(Node::Divide(Box::new(left_expr), Box::new(right_expr))) + } + Token::Caret => { + self.next_token()?; + //Get right-side expression + let right_expr = self.generate_ast(OperPrec::Power)?; + Ok(Node::Caret(Box::new(left_expr), Box::new(right_expr))) + } + _ => Err(ParseError::InvalidOperator(format!( + "Please enter valid operator {:?}", + self.current_token + ))), + } + } +} + +#[derive(Debug)] +pub enum ParseError { + UnableToParse(String), + InvalidOperator(String), +} + +impl fmt::Display for ParseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match &self { + self::ParseError::UnableToParse(e) => write!(f, "Error in evaluating {}", e), + self::ParseError::InvalidOperator(e) => write!(f, "Error in evaluating {}", e), + } + } +} +impl error::Error for ParseError { + fn description(&self) -> &str { + match &self { + self::ParseError::UnableToParse(e) => &e, + self::ParseError::InvalidOperator(e) => &e, + } + } +} + +// Unit tests + +#[cfg(test)] +mod tests { + use super::*; + use crate::parsemath::ast::Node::{Add, Number}; + #[test] + fn test_addition() { + let mut parser = Parser::new("1+2").unwrap(); + let expected = Add(Box::new(Number(1.0)), Box::new(Number(2.0))); + assert_eq!(parser.parse().unwrap(), expected); + } +} diff --git a/chapter2/token.rs b/chapter2/token.rs new file mode 100644 index 0000000..1d77762 --- /dev/null +++ b/chapter2/token.rs @@ -0,0 +1,36 @@ +#[derive(Debug, PartialEq, Clone)] +pub enum Token { + Add, + Subtract, + Multiply, + Divide, + Caret, + LeftParen, + RightParen, + Num(f64), + EOF, +} + +#[derive(Debug, PartialEq, PartialOrd)] +/// Defines all the OperPrec levels, from lowest to highest. +pub enum OperPrec { + DefaultZero, + AddSub, + MulDiv, + Power, + Negative, +} + +impl Token { + pub fn get_oper_prec(&self) -> OperPrec { + use self::OperPrec::*; + use self::Token::*; + match *self { + Add | Subtract => AddSub, + Multiply | Divide => MulDiv, + Caret => Power, + + _ => DefaultZero, + } + } +} diff --git a/chapter2/tokenizer.rs b/chapter2/tokenizer.rs index 65b105b..63b93ad 100644 --- a/chapter2/tokenizer.rs +++ b/chapter2/tokenizer.rs @@ -4,7 +4,7 @@ use std::fmt; use std::iter::Peekable; use std::str::Chars; -// Priary external libraries +// Primary external libraries // Utility external libraries