added chapter2 parser ast token
parent
03efb5f021
commit
222338ca3b
@ -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<Node>, Box<Node>),
|
||||
Subtract(Box<Node>, Box<Node>),
|
||||
Multiply(Box<Node>, Box<Node>),
|
||||
Divide(Box<Node>, Box<Node>),
|
||||
Caret(Box<Node>, Box<Node>),
|
||||
LeftParen(Box<Node>, Box<Node>),
|
||||
RightParen(Box<Node>, Box<Node>),
|
||||
Negative(Box<Node>),
|
||||
Absolute(Box<Node>),
|
||||
Number(f64),
|
||||
}
|
||||
|
||||
pub fn eval(expr: Node) -> Result<f64, EvaluationError> {
|
||||
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);
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
pub mod ast;
|
||||
pub mod parser;
|
||||
pub mod token;
|
||||
pub mod tokenizer;
|
@ -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<Self, ParseError> {
|
||||
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<Node, ParseError> {
|
||||
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<Node, ParseError> {
|
||||
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<Node, ParseError> {
|
||||
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<Node, ParseError> {
|
||||
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);
|
||||
}
|
||||
}
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue