From 1311897416d7e9cd9f5530e3467963a862923dac Mon Sep 17 00:00:00 2001 From: clfreville2 Date: Sat, 25 Mar 2023 18:15:54 +0100 Subject: [PATCH] Tweak precedence handling in the parser --- board-shared/src/expr.rs | 14 ++++++ board-shared/src/parser.rs | 87 ++++++++++++++++++++++++++------------ 2 files changed, 73 insertions(+), 28 deletions(-) diff --git a/board-shared/src/expr.rs b/board-shared/src/expr.rs index 31e8cd4..4374d98 100644 --- a/board-shared/src/expr.rs +++ b/board-shared/src/expr.rs @@ -284,4 +284,18 @@ mod tests { ]; assert!(!is_valid_guess_of_tokens(&tokens)); } + + #[test] + fn is_valid_guess_of_tiles_precedence() { + let tokens = vec![ + Token::NumberLiteral(5), + Token::Operator(Operator::Add), + Token::NumberLiteral(-2), + Token::Operator(Operator::Multiply), + Token::NumberLiteral(3), + Token::Equals, + Token::NumberLiteral(-1), + ]; + assert!(is_valid_guess_of_tokens(&tokens)); + } } diff --git a/board-shared/src/parser.rs b/board-shared/src/parser.rs index 1348ee7..9c75f77 100644 --- a/board-shared/src/parser.rs +++ b/board-shared/src/parser.rs @@ -30,53 +30,60 @@ pub fn parse(tokens: &[Token]) -> Result { let mut tokens = tokens.iter().peekable(); let mut expressions = Vec::new(); while tokens.peek().is_some() { - expressions.push(parse_expression(&mut tokens)?); + expressions.push(parse_term(&mut tokens)?); tokens.next(); } Ok(expressions) } -fn parse_expression<'a>( +fn parse_primary<'a>( tokens: &mut Peekable>, ) -> Result { - let mut left = parse_term(tokens)?; - while let Some(Token::Operator(operator)) = tokens.peek() { - let operator = *operator; + if let Some(Token::NumberLiteral(value)) = tokens.peek() { + tokens.next(); + Ok(Expression::Digit(*value)) + } else if let Some(Token::LeftParen) = tokens.peek() { tokens.next(); - let right = parse_term(tokens)?; - left = Expression::Binary(operator, Box::new(left), Box::new(right)); + let expr = parse_term(tokens)?; + if let Some(Token::RightParen) = tokens.peek() { + tokens.next(); + Ok(Expression::Parentheses(Box::new(expr))) + } else { + Err(()) + } + } else { + Err(()) } - Ok(left) } fn parse_term<'a>( tokens: &mut Peekable>, ) -> Result { - let mut left = parse_unary(tokens)?; + let mut expr = parse_factor(tokens)?; while let Some(Token::Operator(operator)) = tokens.peek() { - let operator = *operator; + if !matches!(operator, Operator::Add | Operator::Subtract) { + break; + } tokens.next(); - let right = parse_unary(tokens)?; - left = Expression::Binary(operator, Box::new(left), Box::new(right)); + let right = parse_factor(tokens)?; + expr = Expression::Binary(*operator, Box::new(expr), Box::new(right)); } - Ok(left) + Ok(expr) } fn parse_factor<'a>( tokens: &mut Peekable>, ) -> Result { - match tokens.next() { - Some(Token::NumberLiteral(value)) => Ok(Expression::Digit(*value)), - Some(Token::LeftParen) => { - let expression = parse_expression(tokens)?; - if let Some(Token::RightParen) = tokens.next() { - Ok(Expression::Parentheses(Box::new(expression))) - } else { - Err(()) - } + let mut expr = parse_unary(tokens)?; + while let Some(Token::Operator(operator)) = tokens.peek() { + if !matches!(operator, Operator::Multiply | Operator::Divide) { + break; } - _ => Err(()), + tokens.next(); + let right = parse_unary(tokens)?; + expr = Expression::Binary(*operator, Box::new(expr), Box::new(right)); } + Ok(expr) } fn parse_unary<'a>( @@ -87,7 +94,7 @@ fn parse_unary<'a>( let expression = parse_unary(tokens)?; Ok(Expression::Unary(Operator::Subtract, Box::new(expression))) } else { - parse_factor(tokens) + parse_primary(tokens) } } @@ -108,13 +115,37 @@ mod tests { assert_eq!( expression, vec![Expression::Binary( - Operator::Multiply, + Operator::Add, + Box::new(Expression::Digit(1)), Box::new(Expression::Binary( - Operator::Add, - Box::new(Expression::Digit(1)), + Operator::Multiply, Box::new(Expression::Digit(2)), + Box::new(Expression::Digit(3)), )), - Box::new(Expression::Digit(3)), + )], + ); + } + + #[test] + fn test_parse_reverse() { + let tokens = vec![ + Token::NumberLiteral(2), + Token::Operator(Operator::Multiply), + Token::NumberLiteral(3), + Token::Operator(Operator::Add), + Token::NumberLiteral(1), + ]; + let expression = parse(&tokens).unwrap(); + assert_eq!( + expression, + vec![Expression::Binary( + Operator::Add, + Box::new(Expression::Binary( + Operator::Multiply, + Box::new(Expression::Digit(2)), + Box::new(Expression::Digit(3)), + )), + Box::new(Expression::Digit(1)), )], ); }