From 6807779a923234c829ec119da21d58e0c9ec9e64 Mon Sep 17 00:00:00 2001 From: Felipe Coury Date: Tue, 17 Sep 2024 23:15:53 -0300 Subject: [PATCH] feat: parser binary operations --- core/src/ir.rs | 1 + core/src/parser.rs | 125 +++++++++++++++++++++++++++++++++++++++++- samples/operators.prg | 4 ++ 3 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 samples/operators.prg diff --git a/core/src/ir.rs b/core/src/ir.rs index f137cd5..a4a424f 100644 --- a/core/src/ir.rs +++ b/core/src/ir.rs @@ -91,6 +91,7 @@ pub fn emit_ir( result } Exp::Unary(_, _) => todo!(), + Exp::Binary(_, _, _) => todo!(), }; Ok(val) diff --git a/core/src/parser.rs b/core/src/parser.rs index e771245..3795d41 100644 --- a/core/src/parser.rs +++ b/core/src/parser.rs @@ -24,6 +24,44 @@ impl<'a> Parser<'a> { } fn parse_exp(&mut self) -> anyhow::Result { + let left = self.parse_lhs()?; + + if let Some(op) = self.parse_binary_operator()? { + let right = self.parse_exp()?; + return Ok(Exp::Binary(Box::new(left), op, Box::new(right))); + } + + Ok(left) + } + + fn parse_binary_operator(&mut self) -> anyhow::Result> { + let res = match self.peek_token() { + Some(Token::Plus) => Some(BinaryOperator::Add), + Some(Token::Minus) => Some(BinaryOperator::Subtract), + Some(Token::Star) => Some(BinaryOperator::Multiply), + Some(Token::Slash) => Some(BinaryOperator::Divide), + Some(Token::StarStar) => Some(BinaryOperator::Exponent), + Some(Token::Percent) => Some(BinaryOperator::Modulo), + Some(Token::And) => Some(BinaryOperator::And), + Some(Token::Or) => Some(BinaryOperator::Or), + Some(Token::Less) => Some(BinaryOperator::LessThan), + Some(Token::LessEqual) => Some(BinaryOperator::LessThanEqual), + Some(Token::Greater) => Some(BinaryOperator::GreaterThan), + Some(Token::GreaterEqual) => Some(BinaryOperator::GreaterThanEqual), + Some(Token::LessGreater) | Some(Token::BangEqual) | Some(Token::Hash) => { + Some(BinaryOperator::NotEqual) + } + _ => None, + }; + + if res.is_some() { + self.take_token()?; + } + + Ok(res) + } + + fn parse_lhs(&mut self) -> anyhow::Result { let exp = match self.peek_token() { Some(Token::Identifier(name)) => { self.take_token()?; // consumes identifier @@ -40,7 +78,7 @@ impl<'a> Parser<'a> { Exp::Constant(n) } Some(_) => { - self.parse_unary()? + self.parse_unary_prefix()? // anyhow::bail!("Expected expression, found {token:?}"); } None => { @@ -75,9 +113,15 @@ impl<'a> Parser<'a> { Ok(Exp::FunCall(name, args)) } - fn parse_unary(&mut self) -> anyhow::Result { + fn parse_unary_prefix(&mut self) -> anyhow::Result { let operator = match self.next_token()? { Some(Token::Not) => UnaryOperator::Not, + Some(Token::And) => UnaryOperator::And, + Some(Token::Plus) => UnaryOperator::Positive, + Some(Token::Minus) => UnaryOperator::Negative, + Some(Token::PlusPlus) => UnaryOperator::Increment, + Some(Token::MinusMinus) => UnaryOperator::Decrement, + Some(Token::At) => UnaryOperator::Ref, Some(token) => { return Err(anyhow::anyhow!( "Expected unary operator, found {:?}", @@ -150,11 +194,45 @@ pub enum Exp { Assignment(Box, Box), FunCall(String, Vec), Unary(UnaryOperator, Box), + Binary(Box, BinaryOperator, Box), } #[derive(Debug, Clone, PartialEq)] pub enum UnaryOperator { Not, + And, + Positive, + Negative, + Increment, + Decrement, + Ref, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum BinaryOperator { + Add, + Subtract, + Multiply, + Divide, + Exponent, + Modulo, + + And, + Or, + + LessThan, + LessThanEqual, + GreaterThan, + GreaterThanEqual, + Equal, + NotEqual, + + // TODO: implement those + SimpleAssign, + CompoundAssign, + SubstringComparison, + AliasAssignment, + Send, } #[cfg(test)] @@ -163,6 +241,49 @@ mod tests { use super::*; + #[test] + fn binary_subtraction() { + let program = r#"nVar2 := 10 - nVar1"#; + let mut lexer = Lexer::new(program); + let tokens = lexer.tokenize().unwrap(); + let mut parser = Parser::new(&tokens); + let program = parser.parse().unwrap(); + + assert_eq!( + program, + Program { + statements: vec![Statement::Expression(Exp::Assignment( + Box::new(Exp::Var("nVar2".into())), + Box::new(Exp::Binary( + Box::new(Exp::Constant(10)), + BinaryOperator::Subtract, + Box::new(Exp::Var("nVar1".into()),) + )) + ))] + } + ); + } + + #[test] + fn binary_add() { + let program = r#"2 + 3"#; + let mut lexer = Lexer::new(program); + let tokens = lexer.tokenize().unwrap(); + let mut parser = Parser::new(&tokens); + let program = parser.parse().unwrap(); + + assert_eq!( + program, + Program { + statements: vec![Statement::Expression(Exp::Binary( + Box::new(Exp::Constant(2)), + BinaryOperator::Add, + Box::new(Exp::Constant(3)), + ))] + } + ); + } + #[test] fn unary_not() { let program = r#".NOT. a"#; diff --git a/samples/operators.prg b/samples/operators.prg new file mode 100644 index 0000000..0b90856 --- /dev/null +++ b/samples/operators.prg @@ -0,0 +1,4 @@ +nVar1 := 2 + 2 +nVar2 := 10 - nVar1 +nVar3 := -nVar1 +nVar4 := ++nVar2