Refactor unary expression parsing (#11088)

## Summary

This PR refactors unary expression parsing with the following changes:
* Ability to get `OperatorPrecedence` from a unary operator (`UnaryOp`)
* Implement methods on `TokenKind`
	* Add `as_unary_operator` which returns an `Option<UnaryOp>`
* Add `as_unary_arithmetic_operator` which returns an `Option<UnaryOp>`
(used for pattern parsing)
* Rename `is_unary` to `is_unary_arithmetic_operator` (used in the
linter)

resolves: #10752 

## Test Plan

Verify that the existing test cases pass, no ecosystem changes, run the
Python based fuzzer on 3000 random inputs and run it on dozens of
open-source repositories.
This commit is contained in:
Dhruv Manilawala 2024-04-23 10:25:02 +05:30 committed by GitHub
parent 7eba967e16
commit 38d2562f41
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 125 additions and 85 deletions

View file

@ -478,30 +478,34 @@ impl<'src> Parser<'src> {
},
})
}
// The `+` is only for better error recovery.
TokenKind::Minus | TokenKind::Plus
if matches!(
self.peek(),
TokenKind::Int | TokenKind::Float | TokenKind::Complex
) =>
{
let unary_expr = self.parse_unary_expression(ExpressionContext::default());
kind => {
// The `+` is only for better error recovery.
if let Some(unary_arithmetic_op) = kind.as_unary_arithmetic_operator() {
if matches!(
self.peek(),
TokenKind::Int | TokenKind::Float | TokenKind::Complex
) {
let unary_expr = self.parse_unary_expression(
unary_arithmetic_op,
ExpressionContext::default(),
);
if unary_expr.op.is_u_add() {
self.add_error(
ParseErrorType::OtherError(
"Unary '+' is not allowed as a literal pattern".to_string(),
),
&unary_expr,
);
if unary_expr.op.is_u_add() {
self.add_error(
ParseErrorType::OtherError(
"Unary '+' is not allowed as a literal pattern".to_string(),
),
&unary_expr,
);
}
return Pattern::MatchValue(ast::PatternMatchValue {
value: Box::new(Expr::UnaryOp(unary_expr)),
range: self.node_range(start),
});
}
}
Pattern::MatchValue(ast::PatternMatchValue {
value: Box::new(Expr::UnaryOp(unary_expr)),
range: self.node_range(start),
})
}
kind => {
// Upon encountering an unexpected token, return a `Pattern::MatchValue` containing
// an empty `Expr::Name`.
let invalid_node = if kind.is_keyword() {