Tweak precedence handling in the parser
continuous-integration/drone/push Build is passing Details

main
Clément FRÉVILLE 2 years ago
parent 55848c5b36
commit 1311897416

@ -284,4 +284,18 @@ mod tests {
]; ];
assert!(!is_valid_guess_of_tokens(&tokens)); 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));
}
} }

@ -30,53 +30,60 @@ pub fn parse(tokens: &[Token]) -> Result<Expressions, ()> {
let mut tokens = tokens.iter().peekable(); let mut tokens = tokens.iter().peekable();
let mut expressions = Vec::new(); let mut expressions = Vec::new();
while tokens.peek().is_some() { while tokens.peek().is_some() {
expressions.push(parse_expression(&mut tokens)?); expressions.push(parse_term(&mut tokens)?);
tokens.next(); tokens.next();
} }
Ok(expressions) Ok(expressions)
} }
fn parse_expression<'a>( fn parse_primary<'a>(
tokens: &mut Peekable<impl Iterator<Item = &'a Token>>, tokens: &mut Peekable<impl Iterator<Item = &'a Token>>,
) -> Result<Expression, ()> { ) -> Result<Expression, ()> {
let mut left = parse_term(tokens)?; if let Some(Token::NumberLiteral(value)) = tokens.peek() {
while let Some(Token::Operator(operator)) = tokens.peek() { tokens.next();
let operator = *operator; Ok(Expression::Digit(*value))
} else if let Some(Token::LeftParen) = tokens.peek() {
tokens.next(); tokens.next();
let right = parse_term(tokens)?; let expr = parse_term(tokens)?;
left = Expression::Binary(operator, Box::new(left), Box::new(right)); 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>( fn parse_term<'a>(
tokens: &mut Peekable<impl Iterator<Item = &'a Token>>, tokens: &mut Peekable<impl Iterator<Item = &'a Token>>,
) -> Result<Expression, ()> { ) -> Result<Expression, ()> {
let mut left = parse_unary(tokens)?; let mut expr = parse_factor(tokens)?;
while let Some(Token::Operator(operator)) = tokens.peek() { while let Some(Token::Operator(operator)) = tokens.peek() {
let operator = *operator; if !matches!(operator, Operator::Add | Operator::Subtract) {
break;
}
tokens.next(); tokens.next();
let right = parse_unary(tokens)?; let right = parse_factor(tokens)?;
left = Expression::Binary(operator, Box::new(left), Box::new(right)); expr = Expression::Binary(*operator, Box::new(expr), Box::new(right));
} }
Ok(left) Ok(expr)
} }
fn parse_factor<'a>( fn parse_factor<'a>(
tokens: &mut Peekable<impl Iterator<Item = &'a Token>>, tokens: &mut Peekable<impl Iterator<Item = &'a Token>>,
) -> Result<Expression, ()> { ) -> Result<Expression, ()> {
match tokens.next() { let mut expr = parse_unary(tokens)?;
Some(Token::NumberLiteral(value)) => Ok(Expression::Digit(*value)), while let Some(Token::Operator(operator)) = tokens.peek() {
Some(Token::LeftParen) => { if !matches!(operator, Operator::Multiply | Operator::Divide) {
let expression = parse_expression(tokens)?; break;
if let Some(Token::RightParen) = tokens.next() {
Ok(Expression::Parentheses(Box::new(expression)))
} else {
Err(())
}
} }
_ => Err(()), tokens.next();
let right = parse_unary(tokens)?;
expr = Expression::Binary(*operator, Box::new(expr), Box::new(right));
} }
Ok(expr)
} }
fn parse_unary<'a>( fn parse_unary<'a>(
@ -87,7 +94,7 @@ fn parse_unary<'a>(
let expression = parse_unary(tokens)?; let expression = parse_unary(tokens)?;
Ok(Expression::Unary(Operator::Subtract, Box::new(expression))) Ok(Expression::Unary(Operator::Subtract, Box::new(expression)))
} else { } else {
parse_factor(tokens) parse_primary(tokens)
} }
} }
@ -108,13 +115,37 @@ mod tests {
assert_eq!( assert_eq!(
expression, expression,
vec![Expression::Binary( vec![Expression::Binary(
Operator::Multiply, Operator::Add,
Box::new(Expression::Digit(1)),
Box::new(Expression::Binary( Box::new(Expression::Binary(
Operator::Add, Operator::Multiply,
Box::new(Expression::Digit(1)),
Box::new(Expression::Digit(2)), 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)),
)], )],
); );
} }

Loading…
Cancel
Save