From a04e4762c5126572633b240065ad830666068773 Mon Sep 17 00:00:00 2001 From: Carlos Macasaet Date: Sat, 28 Dec 2024 17:21:06 -0600 Subject: [PATCH] Implement initial parser --- src/grammar.rs | 237 +++++++++++++++++++--------------- src/main.rs | 1 + src/parser.rs | 338 +++++++++++++++++++++++++++++++++++++++++++++++++ src/token.rs | 2 +- 4 files changed, 473 insertions(+), 105 deletions(-) create mode 100644 src/parser.rs diff --git a/src/grammar.rs b/src/grammar.rs index 3ca10f7..7510fa1 100644 --- a/src/grammar.rs +++ b/src/grammar.rs @@ -1,14 +1,14 @@ use bigdecimal::{BigDecimal, Zero}; use std::fmt::{Debug, Display, Formatter}; use std::ops::Neg; -use DataType::{BooleanType, NumberType, StringType}; +use std::str::FromStr; use EvaluationError::{DivideByZero, NilValue, TypeMismatch}; -use EvaluationResult::{BooleanResult, NilResult, NumberResult, StringResult}; +#[derive(Clone, Eq, PartialEq)] pub(crate) enum Expression { - LiteralExpression(Literal), - UnaryExpression(UnaryOperator, Box), - BinaryExpression { + Literal(Literal), + Unary(UnaryOperator, Box), + Binary { operator: BinaryOperator, left_value: Box, right_value: Box, @@ -19,24 +19,22 @@ pub(crate) enum Expression { impl Expression { pub fn evaluate(&self) -> Result { match self.result_type() { - None => Ok(NilResult), + None => Ok(EvaluationResult::Nil), Some(data_type) => data_type.evaluate(self), } } pub fn result_type(&self) -> Option { match self { - Self::LiteralExpression(literal) => match literal { - Literal::NumberLiteral(_) => Some(NumberType), - Literal::StringLiteral(_) => Some(StringType), - Literal::True => Some(BooleanType), - Literal::False => Some(BooleanType), + Self::Literal(literal) => match literal { + Literal::Number(_) => Some(DataType::Number), + Literal::String(_) => Some(DataType::String), + Literal::True => Some(DataType::Boolean), + Literal::False => Some(DataType::Boolean), Literal::Nil => None, }, - Self::UnaryExpression(operator, expression) => { - operator.result_type(expression.result_type()) - } - Self::BinaryExpression { + Self::Unary(operator, expression) => operator.result_type(expression.result_type()), + Self::Binary { operator, left_value: _left_value, right_value: _right_value, @@ -47,21 +45,21 @@ impl Expression { pub fn evaluate_boolean(&self) -> Result { match self { - Self::LiteralExpression(literal) => match literal { - Literal::NumberLiteral(_) => Err(TypeMismatch), - Literal::StringLiteral(_) => Err(TypeMismatch), + Self::Literal(literal) => match literal { + Literal::Number(_) => Err(TypeMismatch), + Literal::String(_) => Err(TypeMismatch), Literal::True => Ok(true), Literal::False => Ok(false), Literal::Nil => Err(NilValue), }, - Self::UnaryExpression(operator, argument) => { + Self::Unary(operator, argument) => { if *operator == UnaryOperator::Not { argument.evaluate_boolean().map(|result| !result) } else { Err(TypeMismatch) } } - Self::BinaryExpression { + Self::Binary { operator, left_value, right_value, @@ -72,19 +70,19 @@ impl Expression { pub fn evaluate_number(&self) -> Result { match self { - Self::LiteralExpression(literal) => match literal { - Literal::NumberLiteral(number) => Ok(number.clone()), + Self::Literal(literal) => match literal { + Literal::Number(number) => Ok(number.clone()), Literal::Nil => Err(NilValue), _ => Err(TypeMismatch), }, - Self::UnaryExpression(operator, argument) => { + Self::Unary(operator, argument) => { if *operator == UnaryOperator::Negative { argument.evaluate_number().map(BigDecimal::neg) } else { Err(TypeMismatch) } } - Self::BinaryExpression { + Self::Binary { operator, left_value, right_value, @@ -95,13 +93,13 @@ impl Expression { pub fn evaluate_string(&self) -> Result { match self { - Self::LiteralExpression(literal) => match literal { - Literal::StringLiteral(value) => Ok(value.clone()), + Self::Literal(literal) => match literal { + Literal::String(value) => Ok(value.clone()), Literal::Nil => Err(NilValue), _ => Err(TypeMismatch), }, - Self::UnaryExpression(_, _) => Err(TypeMismatch), - Self::BinaryExpression { + Self::Unary(_, _) => Err(TypeMismatch), + Self::Binary { operator, left_value, right_value, @@ -114,18 +112,18 @@ impl Expression { impl Debug for Expression { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { - Self::LiteralExpression(literal) => match literal { - Literal::NumberLiteral(number) => f.write_str(&number.to_string()), - Literal::StringLiteral(string) => f.write_str(string), + Self::Literal(literal) => match literal { + Literal::Number(number) => f.write_str(&number.to_string()), + Literal::String(string) => f.write_str(string), Literal::True => f.write_str("true"), Literal::False => f.write_str("false"), Literal::Nil => f.write_str("nil"), }, - Self::UnaryExpression(operator, expression) => match operator { + Self::Unary(operator, expression) => match operator { UnaryOperator::Negative => f.write_fmt(format_args!("(- {:?})", expression)), UnaryOperator::Not => f.write_fmt(format_args!("(! {:?})", expression)), }, - Self::BinaryExpression { + Self::Binary { operator, left_value, right_value, @@ -137,8 +135,8 @@ impl Debug for Expression { BinaryOperator::GreaterThan => ">", BinaryOperator::LessThanOrEqual => "<=", BinaryOperator::GreaterThanOrEqual => ">=", - BinaryOperator::Plus => "+", - BinaryOperator::Minus => "-", + BinaryOperator::Add => "+", + BinaryOperator::Subtract => "-", BinaryOperator::Multiply => "*", BinaryOperator::Divide => "/", }; @@ -152,13 +150,14 @@ impl Debug for Expression { } } -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq, Copy, Clone)] pub enum EvaluationError { TypeMismatch, NilValue, DivideByZero, } +#[derive(Copy, Clone, Eq, PartialEq, Debug)] pub(crate) enum BinaryOperator { Equal, NotEqual, @@ -166,8 +165,8 @@ pub(crate) enum BinaryOperator { GreaterThan, LessThanOrEqual, GreaterThanOrEqual, - Plus, - Minus, + Add, + Subtract, Multiply, Divide, } @@ -183,13 +182,13 @@ impl BinaryOperator { match (left_value.result_type(), right_value.result_type()) { (None, None) => Ok(true), (None, Some(_)) | (Some(_), None) => Ok(false), - (Some(StringType), Some(StringType)) => { + (Some(DataType::String), Some(DataType::String)) => { Ok(left_value.evaluate_string()? == right_value.evaluate_string()?) } - (Some(NumberType), Some(NumberType)) => { + (Some(DataType::Number), Some(DataType::Number)) => { Ok(left_value.evaluate_number()? == right_value.evaluate_number()?) } - (Some(BooleanType), Some(BooleanType)) => { + (Some(DataType::Boolean), Some(DataType::Boolean)) => { Ok(left_value.evaluate_boolean()? == right_value.evaluate_boolean()?) } _ => Ok(false), // two different types, cannot be equal to each other @@ -199,13 +198,13 @@ impl BinaryOperator { match (left_value.result_type(), right_value.result_type()) { (None, None) => Ok(false), (None, Some(_)) | (Some(_), None) => Ok(true), - (Some(StringType), Some(StringType)) => { + (Some(DataType::String), Some(DataType::String)) => { Ok(left_value.evaluate_string()? != right_value.evaluate_string()?) } - (Some(NumberType), Some(NumberType)) => { + (Some(DataType::Number), Some(DataType::Number)) => { Ok(left_value.evaluate_number()? != right_value.evaluate_number()?) } - (Some(BooleanType), Some(BooleanType)) => { + (Some(DataType::Boolean), Some(DataType::Boolean)) => { Ok(left_value.evaluate_boolean()? != right_value.evaluate_boolean()?) } _ => Ok(true), // two different types, cannot be equal to each other @@ -214,7 +213,7 @@ impl BinaryOperator { Self::LessThan => { match (left_value.result_type(), right_value.result_type()) { (None, _) | (_, None) => Err(NilValue), - (Some(NumberType), Some(NumberType)) => { + (Some(DataType::Number), Some(DataType::Number)) => { Ok(left_value.evaluate_number()? < right_value.evaluate_number()?) } (Some(_), Some(_)) => Err(TypeMismatch), // both values must be numbers @@ -223,7 +222,7 @@ impl BinaryOperator { Self::GreaterThan => { match (left_value.result_type(), right_value.result_type()) { (None, _) | (_, None) => Err(NilValue), - (Some(NumberType), Some(NumberType)) => { + (Some(DataType::Number), Some(DataType::Number)) => { Ok(left_value.evaluate_number()? > right_value.evaluate_number()?) } (Some(_), Some(_)) => Err(TypeMismatch), // both values must be numbers @@ -232,7 +231,7 @@ impl BinaryOperator { Self::LessThanOrEqual => { match (left_value.result_type(), right_value.result_type()) { (None, _) | (_, None) => Err(NilValue), - (Some(NumberType), Some(NumberType)) => { + (Some(DataType::Number), Some(DataType::Number)) => { Ok(left_value.evaluate_number()? <= right_value.evaluate_number()?) } (Some(_), Some(_)) => Err(TypeMismatch), // both values must be numbers @@ -241,7 +240,7 @@ impl BinaryOperator { Self::GreaterThanOrEqual => { match (left_value.result_type(), right_value.result_type()) { (None, _) | (_, None) => Err(NilValue), - (Some(NumberType), Some(NumberType)) => { + (Some(DataType::Number), Some(DataType::Number)) => { Ok(left_value.evaluate_number()? >= right_value.evaluate_number()?) } (Some(_), Some(_)) => Err(TypeMismatch), // both values must be numbers @@ -257,8 +256,8 @@ impl BinaryOperator { right_value: &Expression, ) -> Result { match self { - Self::Plus => Ok(left_value.evaluate_number()? + right_value.evaluate_number()?), - Self::Minus => Ok(left_value.evaluate_number()? - right_value.evaluate_number()?), + Self::Add => Ok(left_value.evaluate_number()? + right_value.evaluate_number()?), + Self::Subtract => Ok(left_value.evaluate_number()? - right_value.evaluate_number()?), Self::Multiply => Ok(left_value.evaluate_number()? * right_value.evaluate_number()?), Self::Divide => { let right_value = right_value.evaluate_number()?; @@ -283,16 +282,16 @@ impl BinaryOperator { pub fn result_type(&self) -> DataType { match self { - Self::Equal => BooleanType, - Self::NotEqual => BooleanType, - Self::LessThan => BooleanType, - Self::GreaterThan => BooleanType, - Self::LessThanOrEqual => BooleanType, - Self::GreaterThanOrEqual => BooleanType, - Self::Plus => NumberType, - Self::Minus => NumberType, - Self::Multiply => NumberType, - Self::Divide => NumberType, + Self::Equal => DataType::Boolean, + Self::NotEqual => DataType::Boolean, + Self::LessThan => DataType::Boolean, + Self::GreaterThan => DataType::Boolean, + Self::LessThanOrEqual => DataType::Boolean, + Self::GreaterThanOrEqual => DataType::Boolean, + Self::Add => DataType::Number, + Self::Subtract => DataType::Number, + Self::Multiply => DataType::Number, + Self::Divide => DataType::Number, } } } @@ -306,15 +305,15 @@ impl Display for BinaryOperator { Self::GreaterThan => f.write_str("GreaterThan"), Self::LessThanOrEqual => f.write_str("LessThanOrEqual"), Self::GreaterThanOrEqual => f.write_str("GreaterThanOrEqual"), - Self::Plus => f.write_str("Plus"), - Self::Minus => f.write_str("Minus"), + Self::Add => f.write_str("Add"), + Self::Subtract => f.write_str("Subtract"), Self::Multiply => f.write_str("Multiply"), Self::Divide => f.write_str("Divide"), } } } -#[derive(Eq, PartialEq)] +#[derive(Eq, PartialEq, Copy, Clone, Debug)] pub(crate) enum UnaryOperator { Negative, Not, @@ -326,63 +325,93 @@ impl UnaryOperator { } } +#[derive(Clone, Eq, PartialEq, Debug)] pub(crate) enum Literal { - NumberLiteral(BigDecimal), - StringLiteral(String), + Number(BigDecimal), + String(String), True, False, Nil, } -#[derive(Eq, PartialEq)] +impl FromStr for Literal { + type Err = (); + + fn from_str(s: &str) -> Result { + Ok(Self::String(s.to_string())) + } +} + +impl From for Literal { + fn from(value: String) -> Self { + Self::String(value) + } +} + +impl From for Literal { + fn from(value: BigDecimal) -> Self { + Self::Number(value) + } +} + +impl From for Literal { + fn from(value: bool) -> Self { + if value { + Self::True + } else { + Self::False + } + } +} + +#[derive(Eq, PartialEq, Copy, Clone, Debug)] pub(crate) enum DataType { - NumberType, - StringType, - BooleanType, + Number, + String, + Boolean, } impl DataType { pub fn evaluate(&self, expression: &Expression) -> Result { match self { - NumberType => Ok(NumberResult(expression.evaluate_number()?)), - StringType => Ok(StringResult(expression.evaluate_string()?)), - BooleanType => Ok(BooleanResult(expression.evaluate_boolean()?)), + Self::Number => Ok(EvaluationResult::Number(expression.evaluate_number()?)), + Self::String => Ok(EvaluationResult::String(expression.evaluate_string()?)), + Self::Boolean => Ok(EvaluationResult::Boolean(expression.evaluate_boolean()?)), } } } -#[derive(Eq, PartialEq, Debug)] +#[derive(Eq, PartialEq, Debug, Clone)] pub(crate) enum EvaluationResult { - NumberResult(BigDecimal), - StringResult(String), - BooleanResult(bool), - NilResult, + Number(BigDecimal), + String(String), + Boolean(bool), + Nil, } #[cfg(test)] mod tests { use super::BinaryOperator::{Divide, Equal, LessThan, Multiply}; - use super::EvaluationResult::{BooleanResult, NumberResult, StringResult}; - use super::Expression::{BinaryExpression, Grouping, LiteralExpression, UnaryExpression}; - use super::Literal::{False, Nil, NumberLiteral, StringLiteral, True}; + use super::Expression::{Binary, Grouping, Unary}; + use super::Literal::Nil; use super::UnaryOperator::Negative; use crate::grammar::EvaluationError::{DivideByZero, NilValue, TypeMismatch}; - use crate::grammar::{EvaluationError, EvaluationResult, Expression}; + use crate::grammar::{EvaluationError, EvaluationResult, Expression, Literal}; use bigdecimal::{BigDecimal, One, Zero}; use std::str::FromStr; #[test] fn ast_prefix_printer() { // given - let ast = BinaryExpression { + let ast = Binary { operator: Multiply, - left_value: Box::new(UnaryExpression( + left_value: Box::new(Unary( Negative, - Box::new(LiteralExpression(NumberLiteral( + Box::new(Expression::Literal(Literal::Number( BigDecimal::from_str("123").unwrap(), ))), )), - right_value: Box::new(Grouping(Box::new(LiteralExpression(NumberLiteral( + right_value: Box::new(Grouping(Box::new(Expression::Literal(Literal::Number( BigDecimal::from_str("45.67").unwrap(), ))))), }; @@ -433,23 +462,23 @@ mod tests { } successful_evaluation_tests! { - number_literal: (LiteralExpression(NumberLiteral(BigDecimal::from_str("2.718281828").unwrap())), NumberResult(BigDecimal::from_str("2.718281828").unwrap())), - string_literal: (LiteralExpression(StringLiteral("🎄".to_string())), StringResult("🎄".to_string())), + number_literal: (Expression::Literal(Literal::Number(BigDecimal::from_str("2.718281828").unwrap())), EvaluationResult::Number(BigDecimal::from_str("2.718281828").unwrap())), + string_literal: (Expression::Literal(Literal::String("🎄".to_string())), EvaluationResult::String("🎄".to_string())), pi_less_than_tau: ( - BinaryExpression { + Binary { operator: LessThan, - left_value: Box::new(LiteralExpression(NumberLiteral(BigDecimal::from_str("3.14159").unwrap()))), - right_value: Box::new(LiteralExpression(NumberLiteral(BigDecimal::from_str("6.283185307179586").unwrap()))), + left_value: Box::new(Expression::Literal(Literal::Number(BigDecimal::from_str("3.14159").unwrap()))), + right_value: Box::new(Expression::Literal(Literal::Number(BigDecimal::from_str("6.283185307179586").unwrap()))), }, - BooleanResult(true), + EvaluationResult::Boolean(true), ), string_not_equal_to_number: ( - BinaryExpression { + Binary { operator: Equal, - left_value: Box::new(LiteralExpression(StringLiteral("🥧".to_string()))), - right_value: Box::new(LiteralExpression(NumberLiteral(BigDecimal::from_str("3.14159").unwrap()))), + left_value: Box::new(Expression::Literal(Literal::String("🥧".to_string()))), + right_value: Box::new(Expression::Literal(Literal::Number(BigDecimal::from_str("3.14159").unwrap()))), }, - BooleanResult(false), + EvaluationResult::Boolean(false), ), } @@ -467,26 +496,26 @@ mod tests { unsuccessful_evaluation_tests! { divide_by_zero: ( - BinaryExpression { + Binary { operator: Divide, - left_value: Box::new(LiteralExpression(NumberLiteral(BigDecimal::one()))), - right_value: Box::new(LiteralExpression(NumberLiteral(BigDecimal::zero()))), + left_value: Box::new(Expression::Literal(Literal::Number(BigDecimal::one()))), + right_value: Box::new(Expression::Literal(Literal::Number(BigDecimal::zero()))), }, DivideByZero, ), unexpected_nil: ( - BinaryExpression { + Binary { operator: Multiply, - left_value: Box::new(LiteralExpression(NumberLiteral(BigDecimal::one()))), - right_value: Box::new(LiteralExpression(Nil)), + left_value: Box::new(Expression::Literal(Literal::Number(BigDecimal::one()))), + right_value: Box::new(Expression::Literal(Nil)), }, NilValue, ), type_mismatch: ( - BinaryExpression { + Binary { operator: LessThan, - left_value: Box::new(LiteralExpression(NumberLiteral(BigDecimal::from_str("3.14159").unwrap()))), - right_value: Box::new(LiteralExpression(StringLiteral("🥧".to_string()))), + left_value: Box::new(Expression::Literal(Literal::Number(BigDecimal::from_str("3.14159").unwrap()))), + right_value: Box::new(Expression::Literal(Literal::String("🥧".to_string()))), }, TypeMismatch, ), diff --git a/src/main.rs b/src/main.rs index 52938df..5d1bb79 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ mod grammar; mod interpreter; mod lexical_error; +mod parser; mod scanner; mod token; diff --git a/src/parser.rs b/src/parser.rs new file mode 100644 index 0000000..14f4df3 --- /dev/null +++ b/src/parser.rs @@ -0,0 +1,338 @@ +use crate::grammar::Expression::{Binary, Unary}; +use crate::grammar::{BinaryOperator, Expression, Literal, UnaryOperator}; +use crate::parser::ParseError::{ + InvalidBinaryOperator, InvalidLiteral, InvalidPrimaryToken, InvalidUnaryOperator, + UnclosedGrouping, +}; +use crate::token::{Token, TokenType}; + +#[derive(Debug)] +pub(crate) struct Parser { + tokens: Vec, + current: usize, +} + +impl From> for Parser { + fn from(value: Vec) -> Self { + Self { + tokens: value, + current: 0, + } + } +} + +#[derive(Clone, Debug)] +pub(crate) enum ParseError { + InvalidBinaryOperator(Token), + InvalidUnaryOperator(Token), + InvalidPrimaryToken(Option), + InvalidLiteral(Token), + UnclosedGrouping, +} + +impl TryFrom for BinaryOperator { + type Error = ParseError; + + fn try_from(value: Token) -> Result { + match value.token_type { + TokenType::Minus => Ok(BinaryOperator::Subtract), + TokenType::Plus => Ok(BinaryOperator::Add), + TokenType::ForwardSlash => Ok(BinaryOperator::Divide), + TokenType::Asterisk => Ok(BinaryOperator::Multiply), + TokenType::NotEqual => Ok(BinaryOperator::NotEqual), + TokenType::Equal => Ok(BinaryOperator::Equal), + TokenType::GreaterThan => Ok(BinaryOperator::GreaterThan), + TokenType::GreaterThanOrEqual => Ok(BinaryOperator::GreaterThanOrEqual), + TokenType::LessThan => Ok(BinaryOperator::LessThan), + TokenType::LessThanOrEqual => Ok(BinaryOperator::LessThanOrEqual), + _ => Err(InvalidBinaryOperator(value)), + } + } +} + +impl TryFrom for UnaryOperator { + type Error = ParseError; + + fn try_from(value: Token) -> Result { + match value.token_type { + TokenType::Not => Ok(UnaryOperator::Not), + TokenType::Minus => Ok(UnaryOperator::Negative), + _ => Err(InvalidUnaryOperator(value)), + } + } +} + +impl TryFrom for Literal { + type Error = ParseError; + + fn try_from(value: Token) -> Result { + match value.token_type { + TokenType::NumberLiteral => Ok(Literal::Number( + value.literal_number.expect("Missing number literal"), + )), + TokenType::StringLiteral => Ok(Literal::String( + value.literal_string.expect("Missing string literal"), + )), + TokenType::False => Ok(Literal::False), + TokenType::True => Ok(Literal::True), + TokenType::Nil => Ok(Literal::Nil), + _ => Err(InvalidLiteral(value)), + } + } +} + +impl Parser { + fn expression(&mut self) -> Result { + self.equality() + } + + fn equality(&mut self) -> Result { + let mut result = self.comparison()?; + while self.token_match(&[TokenType::NotEqual, TokenType::Equal]) { + let operator_token = self.previous().clone(); + let right_value = self.comparison()?; + result = Binary { + operator: operator_token.try_into()?, + left_value: Box::new(result.clone()), + right_value: Box::new(right_value), + }; + } + Ok(result) + } + + fn comparison(&mut self) -> Result { + let mut result = self.term()?; + while self.token_match(&[ + TokenType::GreaterThan, + TokenType::GreaterThanOrEqual, + TokenType::LessThan, + TokenType::LessThanOrEqual, + ]) { + let operator_token = self.previous().clone(); + let right_value = self.term()?; + result = Binary { + operator: operator_token.try_into()?, + left_value: Box::new(result.clone()), + right_value: Box::new(right_value), + }; + } + Ok(result) + } + + fn term(&mut self) -> Result { + let mut result = self.factor()?; + while self.token_match(&[TokenType::Minus, TokenType::Plus]) { + let operator_token = self.previous().clone(); + let right_value = self.factor()?; + result = Binary { + operator: operator_token.try_into()?, + left_value: Box::new(result.clone()), + right_value: Box::new(right_value), + }; + } + Ok(result) + } + + fn factor(&mut self) -> Result { + let mut result = self.unary()?; + while self.token_match(&[TokenType::ForwardSlash, TokenType::Asterisk]) { + let operator_token = self.previous().clone(); + let right_value = self.unary()?; + result = Binary { + operator: operator_token.try_into()?, + left_value: Box::new(result.clone()), + right_value: Box::new(right_value), + }; + } + Ok(result) + } + + fn unary(&mut self) -> Result { + if self.token_match(&[TokenType::Not, TokenType::Minus]) { + let operator_token = self.previous().clone(); + let operand = self.unary()?; + Ok(Unary(operator_token.try_into()?, Box::new(operand))) + } else { + self.primary() + } + } + + fn primary(&mut self) -> Result { + if self.token_match(&[ + TokenType::False, + TokenType::True, + TokenType::Nil, + TokenType::NumberLiteral, + TokenType::StringLiteral, + ]) { + Ok(Expression::Literal(self.previous().clone().try_into()?)) + } else if self.token_match(&[TokenType::OpenParenthesis]) { + let expression = self.expression()?; + self.consume(&TokenType::CloseParenthesis, UnclosedGrouping)?; + Ok(Expression::Grouping(Box::new(expression))) + } else { + Err(InvalidPrimaryToken( + self.peek().map(|token| token.token_type), + )) + } + } + + fn consume( + &mut self, + token_type: &TokenType, + conditional_error: ParseError, + ) -> Result<&Token, ParseError> { + if self.check(token_type) { + return Ok(self.advance()); + } + Err(conditional_error) + } + + fn token_match(&mut self, types: &[TokenType]) -> bool { + for token_type in types { + if self.check(token_type) { + self.advance(); + return true; + } + } + false + } + + fn check(&self, token_type: &TokenType) -> bool { + if let Some(current) = self.peek() { + current.token_type == *token_type + } else { + false + } + } + + fn advance(&mut self) -> &Token { + if !self.at_end() { + self.current += 1; + } + self.previous() + } + + fn at_end(&self) -> bool { + if let Some(current) = self.peek() { + current.token_type == TokenType::Eof + } else { + false + } + } + + fn peek(&self) -> Option<&Token> { + self.tokens.get(self.current) + } + + fn previous(&self) -> &Token { + &self.tokens[self.current - 1] + } +} + +#[cfg(test)] +mod tests { + use crate::grammar::Expression::Literal; + use crate::grammar::Literal::Number; + use crate::grammar::{BinaryOperator, Expression}; + use crate::parser::Parser; + use crate::token::{Token, TokenType}; + use bigdecimal::{BigDecimal, One}; + use std::ops::Deref; + + #[test] + fn minus_is_left_associative() { + // given + let tokens = [ + Token::new_int(5), + Token::new(TokenType::Minus, "-".to_string(), 0), + Token::new_int(3), + Token::new(TokenType::Minus, "-".to_string(), 0), + Token::new_int(1), + ] + .to_vec(); + let mut parser: Parser = tokens.into(); + + // when + let result = parser.expression().expect("Unable to parse expression"); + + // then + if let Expression::Binary { + operator, + left_value, + right_value, + } = result + { + assert_eq!(operator, BinaryOperator::Subtract); + assert_eq!(right_value, Box::new(Literal(Number(BigDecimal::one())))); + if let Expression::Binary { + operator, + left_value, + right_value, + } = left_value.deref() + { + assert_eq!(*operator, BinaryOperator::Subtract); + assert_eq!(*left_value, Box::new(Literal(Number(BigDecimal::from(5))))); + assert_eq!(*right_value, Box::new(Literal(Number(BigDecimal::from(3))))); + } else { + panic!("Expected binary expression, got: {:?}", left_value) + } + } else { + panic!("Expected binary expression, got: {:?}", result); + } + } + + #[test] + fn parse_grouping() { + // given + let tokens = [ + Token::new(TokenType::OpenParenthesis, "(".to_string(), 0), + Token::new_int(6), + Token::new(TokenType::ForwardSlash, "/".to_string(), 0), + Token::new_int(3), + Token::new(TokenType::CloseParenthesis, "(".to_string(), 0), + Token::new(TokenType::Minus, "-".to_string(), 0), + Token::new_int(1), + ] + .to_vec(); + let mut parser: Parser = tokens.into(); + + // when + let result = parser.expression().expect("Unable to parse expression"); + + // then + if let Expression::Binary { + operator, + left_value, + right_value, + } = result + { + assert_eq!(operator, BinaryOperator::Subtract); + assert_eq!(right_value, Box::new(Literal(Number(BigDecimal::one())))); + if let Expression::Grouping(left_value) = *left_value { + if let Expression::Binary { + operator, + left_value, + right_value, + } = left_value.deref() + { + assert_eq!(*operator, BinaryOperator::Divide); + assert_eq!(*left_value, Box::new(Literal(Number(BigDecimal::from(6))))); + assert_eq!(*right_value, Box::new(Literal(Number(BigDecimal::from(3))))); + } else { + panic!("Expected binary expression, got: {:?}", left_value); + } + } else { + panic!("Expected grouping, got: {:?}", left_value); + } + } else { + panic!("Expected binary expression, got: {:?}", result); + } + } + + impl Token { + fn new_int(int: u8) -> Self { + Self::new_number(format!("{}", int), BigDecimal::from(int), 0) + } + } +} diff --git a/src/token.rs b/src/token.rs index d6c13d8..618197d 100644 --- a/src/token.rs +++ b/src/token.rs @@ -60,7 +60,7 @@ pub(crate) enum TokenType { Eof, } -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq, Clone)] pub(crate) struct Token { pub token_type: TokenType, pub lexeme: String,