|
|
|
@ -1,34 +1,39 @@
|
|
|
|
|
/// This program reads tokens returned by Tokenizer and converts them into AST.
|
|
|
|
|
// 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
|
|
|
|
|
|
|
|
|
|
// Parser struct
|
|
|
|
|
pub struct Parser<'a> {
|
|
|
|
|
tokenizer: Tokenizer<'a>,
|
|
|
|
|
current_token: Token,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Public methods of Parser
|
|
|
|
|
|
|
|
|
|
impl<'a> Parser<'a> {
|
|
|
|
|
// Create a new instance of Parser
|
|
|
|
|
pub fn new(expr: &'a str) -> Result<Self, ParseError> {
|
|
|
|
|
let mut lexer = Tokenizer::new(expr);
|
|
|
|
|
let cur_token = lexer.next().unwrap();
|
|
|
|
|
let cur_token = match lexer.next() {
|
|
|
|
|
Some(token) => token,
|
|
|
|
|
None => return Err(ParseError::InvalidOperator("Invalid character".into())),
|
|
|
|
|
};
|
|
|
|
|
Ok(Parser {
|
|
|
|
|
tokenizer: lexer,
|
|
|
|
|
current_token: cur_token,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
fn next_token(&mut self) -> Result<(), ParseError> {
|
|
|
|
|
self.current_token = self.tokenizer.next().unwrap();
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Take an arithmetic expression as input and return an AST
|
|
|
|
|
|
|
|
|
|
pub fn parse(&mut self) -> Result<Node, ParseError> {
|
|
|
|
|
let ast = self.generate_ast(OperPrec::DefaultZero);
|
|
|
|
|
match ast {
|
|
|
|
@ -36,6 +41,22 @@ impl<'a> Parser<'a> {
|
|
|
|
|
Err(e) => Err(e),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Private methods of Parser
|
|
|
|
|
|
|
|
|
|
impl<'a> Parser<'a> {
|
|
|
|
|
// Retrieve the next token from arithmetic expression and set it to current_token field in Parser struct
|
|
|
|
|
fn get_next_token(&mut self) -> Result<(), ParseError> {
|
|
|
|
|
let next_token = match self.tokenizer.next() {
|
|
|
|
|
Some(token) => token,
|
|
|
|
|
None => return Err(ParseError::InvalidOperator("Invalid character".into())),
|
|
|
|
|
};
|
|
|
|
|
self.current_token = next_token;
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Main workhorse method that is called recursively
|
|
|
|
|
|
|
|
|
|
fn generate_ast(&mut self, oper_prec: OperPrec) -> Result<Node, ParseError> {
|
|
|
|
|
let mut left_expr = self.parse_number()?;
|
|
|
|
@ -50,22 +71,24 @@ impl<'a> Parser<'a> {
|
|
|
|
|
Ok(left_expr)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Construct AST node for numbers, taking into account negative prefixes while handling parenthesis
|
|
|
|
|
|
|
|
|
|
fn parse_number(&mut self) -> Result<Node, ParseError> {
|
|
|
|
|
let token = self.current_token.clone();
|
|
|
|
|
match token {
|
|
|
|
|
Token::Subtract => {
|
|
|
|
|
self.next_token()?;
|
|
|
|
|
self.get_next_token()?;
|
|
|
|
|
let expr = self.generate_ast(OperPrec::Negative)?;
|
|
|
|
|
Ok(Node::Negative(Box::new(expr)))
|
|
|
|
|
}
|
|
|
|
|
Token::Num(i) => {
|
|
|
|
|
self.next_token()?;
|
|
|
|
|
self.get_next_token()?;
|
|
|
|
|
Ok(Node::Number(i))
|
|
|
|
|
}
|
|
|
|
|
Token::LeftParen => {
|
|
|
|
|
self.next_token()?;
|
|
|
|
|
self.get_next_token()?;
|
|
|
|
|
let expr = self.generate_ast(OperPrec::DefaultZero)?;
|
|
|
|
|
self.expect(Token::RightParen)?;
|
|
|
|
|
self.check_paren(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)));
|
|
|
|
@ -77,9 +100,11 @@ impl<'a> Parser<'a> {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn expect(&mut self, expected: Token) -> Result<(), ParseError> {
|
|
|
|
|
// Check for balancing parenthesis
|
|
|
|
|
|
|
|
|
|
fn check_paren(&mut self, expected: Token) -> Result<(), ParseError> {
|
|
|
|
|
if expected == self.current_token {
|
|
|
|
|
self.next_token()?;
|
|
|
|
|
self.get_next_token()?;
|
|
|
|
|
Ok(())
|
|
|
|
|
} else {
|
|
|
|
|
Err(ParseError::InvalidOperator(format!(
|
|
|
|
@ -89,34 +114,36 @@ impl<'a> Parser<'a> {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Construct Operator AST nodes
|
|
|
|
|
|
|
|
|
|
fn convert_token_to_node(&mut self, left_expr: Node) -> Result<Node, ParseError> {
|
|
|
|
|
match self.current_token {
|
|
|
|
|
Token::Add => {
|
|
|
|
|
self.next_token()?;
|
|
|
|
|
self.get_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()?;
|
|
|
|
|
self.get_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()?;
|
|
|
|
|
self.get_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()?;
|
|
|
|
|
self.get_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()?;
|
|
|
|
|
self.get_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)))
|
|
|
|
@ -129,6 +156,7 @@ impl<'a> Parser<'a> {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Custom error handler for Parser
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub enum ParseError {
|
|
|
|
|
UnableToParse(String),
|
|
|
|
@ -143,6 +171,7 @@ impl fmt::Display for ParseError {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl error::Error for ParseError {
|
|
|
|
|
fn description(&self) -> &str {
|
|
|
|
|
match &self {
|
|
|
|
@ -152,6 +181,14 @@ impl error::Error for ParseError {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Handle error thrown from Tokenizer
|
|
|
|
|
|
|
|
|
|
impl std::convert::From<std::boxed::Box<dyn std::error::Error>> for ParseError {
|
|
|
|
|
fn from(_evalerr: std::boxed::Box<dyn std::error::Error>) -> Self {
|
|
|
|
|
return ParseError::UnableToParse("Unable to parse".into());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Unit tests
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|