Use the common OperatorPrecedence for the parser (#16747)

## Summary

This change continues to resolve #16071 (and continues the work started
in #16162). Specifically, this PR changes the code in the parser so that
it uses the `OperatorPrecedence` struct from `ruff_python_ast` instead
of its own version. This is part of an effort to get rid of the
redundant definitions of `OperatorPrecedence` throughout the codebase.

Note that this PR only makes this change for `ruff_python_parser` -- we
still want to make a similar change for the formatter (namely the
`OperatorPrecedence` defined in the expression part of the formatter,
the pattern one is different). I separated the work to keep the PRs
small and easily reviewable.

## Test Plan

Because this is an internal change, I didn't add any additional tests.
Existing tests do pass.
This commit is contained in:
Junhson Jean-Baptiste 2025-03-21 00:10:37 -04:00 committed by GitHub
parent 04a8756379
commit 2a4d835132
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 19 additions and 95 deletions

View file

@ -7,7 +7,7 @@ use rustc_hash::{FxBuildHasher, FxHashSet};
use ruff_python_ast::name::Name;
use ruff_python_ast::{
self as ast, BoolOp, CmpOp, ConversionFlag, Expr, ExprContext, FStringElement, FStringElements,
IpyEscapeKind, Number, Operator, StringFlags, UnaryOp,
IpyEscapeKind, Number, Operator, OperatorPrecedence, StringFlags, UnaryOp,
};
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
@ -228,7 +228,7 @@ impl<'src> Parser<'src> {
///
/// [Python grammar]: https://docs.python.org/3/reference/grammar.html
fn parse_simple_expression(&mut self, context: ExpressionContext) -> ParsedExpr {
self.parse_binary_expression_or_higher(OperatorPrecedence::Initial, context)
self.parse_binary_expression_or_higher(OperatorPrecedence::None, context)
}
/// Parses a binary expression using the [Pratt parsing algorithm].
@ -360,7 +360,7 @@ impl<'src> Parser<'src> {
TokenKind::Star => {
let starred_expr = self.parse_starred_expression(context);
if left_precedence > OperatorPrecedence::Initial
if left_precedence > OperatorPrecedence::None
|| !context.is_starred_expression_allowed()
{
self.add_error(ParseErrorType::InvalidStarredExpressionUsage, &starred_expr);
@ -393,7 +393,7 @@ impl<'src> Parser<'src> {
TokenKind::Yield => {
let expr = self.parse_yield_expression();
if left_precedence > OperatorPrecedence::Initial
if left_precedence > OperatorPrecedence::None
|| !context.is_yield_expression_allowed()
{
self.add_error(ParseErrorType::InvalidYieldExpressionUsage, &expr);
@ -2596,57 +2596,6 @@ impl Ranged for ParsedExpr {
}
}
/// Represents the precedence levels for various operators and expressions of Python.
/// Variants at the top have lower precedence and variants at the bottom have
/// higher precedence.
///
/// Note: Some expressions like if-else, named expression (`:=`), lambda, subscription,
/// slicing, call and attribute reference expressions, that are mentioned in the link
/// below are better handled in other parts of the parser.
///
/// See: <https://docs.python.org/3/reference/expressions.html#operator-precedence>
#[derive(Debug, Ord, Eq, PartialEq, PartialOrd, Copy, Clone)]
pub(super) enum OperatorPrecedence {
/// The initial precedence when parsing an expression.
Initial,
/// Precedence of boolean `or` operator.
Or,
/// Precedence of boolean `and` operator.
And,
/// Precedence of boolean `not` unary operator.
Not,
/// Precedence of comparisons operators (`<`, `<=`, `>`, `>=`, `!=`, `==`),
/// memberships tests (`in`, `not in`) and identity tests (`is` `is not`).
ComparisonsMembershipIdentity,
/// Precedence of `Bitwise OR` (`|`) operator.
BitOr,
/// Precedence of `Bitwise XOR` (`^`) operator.
BitXor,
/// Precedence of `Bitwise AND` (`&`) operator.
BitAnd,
/// Precedence of left and right shift operators (`<<`, `>>`).
LeftRightShift,
/// Precedence of addition (`+`) and subtraction (`-`) operators.
AddSub,
/// Precedence of multiplication (`*`), matrix multiplication (`@`), division (`/`), floor
/// division (`//`) and remainder operators (`%`).
MulDivRemain,
/// Precedence of positive (`+`), negative (`-`), `Bitwise NOT` (`~`) unary operators.
PosNegBitNot,
/// Precedence of exponentiation operator (`**`).
Exponent,
/// Precedence of `await` expression.
Await,
}
impl OperatorPrecedence {
/// Returns `true` if the precedence is right-associative i.e., the operations are evaluated
/// from right to left.
fn is_right_associative(self) -> bool {
matches!(self, OperatorPrecedence::Exponent)
}
}
#[derive(Debug)]
enum BinaryLikeOperator {
Boolean(BoolOp),
@ -2678,45 +2627,6 @@ impl BinaryLikeOperator {
}
}
impl From<BoolOp> for OperatorPrecedence {
#[inline]
fn from(op: BoolOp) -> Self {
match op {
BoolOp::And => OperatorPrecedence::And,
BoolOp::Or => OperatorPrecedence::Or,
}
}
}
impl From<UnaryOp> for OperatorPrecedence {
#[inline]
fn from(op: UnaryOp) -> Self {
match op {
UnaryOp::Not => OperatorPrecedence::Not,
_ => OperatorPrecedence::PosNegBitNot,
}
}
}
impl From<Operator> for OperatorPrecedence {
#[inline]
fn from(op: Operator) -> Self {
match op {
Operator::Add | Operator::Sub => OperatorPrecedence::AddSub,
Operator::Mult
| Operator::Div
| Operator::FloorDiv
| Operator::Mod
| Operator::MatMult => OperatorPrecedence::MulDivRemain,
Operator::BitAnd => OperatorPrecedence::BitAnd,
Operator::BitOr => OperatorPrecedence::BitOr,
Operator::BitXor => OperatorPrecedence::BitXor,
Operator::LShift | Operator::RShift => OperatorPrecedence::LeftRightShift,
Operator::Pow => OperatorPrecedence::Exponent,
}
}
}
/// Represents the precedence used for parsing the value part of a starred expression.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) enum StarredExpressionPrecedence {