mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-03 07:04:37 +00:00
Use the common OperatorPrecedence
for the parser (#16747)
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions
[Knot Playground] Release / publish (push) Waiting to run
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions
[Knot Playground] Release / publish (push) Waiting to run
## 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:
parent
04a8756379
commit
2a4d835132
3 changed files with 19 additions and 95 deletions
|
@ -131,6 +131,12 @@ impl OperatorPrecedence {
|
||||||
pub fn from_expr(expr: &Expr) -> Self {
|
pub fn from_expr(expr: &Expr) -> Self {
|
||||||
Self::from(&ExprRef::from(expr))
|
Self::from(&ExprRef::from(expr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the precedence is right-associative i.e., the operations are evaluated
|
||||||
|
/// from right to left.
|
||||||
|
pub fn is_right_associative(self) -> bool {
|
||||||
|
matches!(self, OperatorPrecedence::Exponent)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&Expr> for OperatorPrecedence {
|
impl From<&Expr> for OperatorPrecedence {
|
||||||
|
@ -177,3 +183,12 @@ impl From<BoolOp> for OperatorPrecedence {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<UnaryOp> for OperatorPrecedence {
|
||||||
|
fn from(unary_op: UnaryOp) -> Self {
|
||||||
|
match unary_op {
|
||||||
|
UnaryOp::UAdd | UnaryOp::USub | UnaryOp::Invert => Self::PosNegBitNot,
|
||||||
|
UnaryOp::Not => Self::Not,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use rustc_hash::{FxBuildHasher, FxHashSet};
|
||||||
use ruff_python_ast::name::Name;
|
use ruff_python_ast::name::Name;
|
||||||
use ruff_python_ast::{
|
use ruff_python_ast::{
|
||||||
self as ast, BoolOp, CmpOp, ConversionFlag, Expr, ExprContext, FStringElement, FStringElements,
|
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};
|
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
|
/// [Python grammar]: https://docs.python.org/3/reference/grammar.html
|
||||||
fn parse_simple_expression(&mut self, context: ExpressionContext) -> ParsedExpr {
|
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].
|
/// Parses a binary expression using the [Pratt parsing algorithm].
|
||||||
|
@ -360,7 +360,7 @@ impl<'src> Parser<'src> {
|
||||||
TokenKind::Star => {
|
TokenKind::Star => {
|
||||||
let starred_expr = self.parse_starred_expression(context);
|
let starred_expr = self.parse_starred_expression(context);
|
||||||
|
|
||||||
if left_precedence > OperatorPrecedence::Initial
|
if left_precedence > OperatorPrecedence::None
|
||||||
|| !context.is_starred_expression_allowed()
|
|| !context.is_starred_expression_allowed()
|
||||||
{
|
{
|
||||||
self.add_error(ParseErrorType::InvalidStarredExpressionUsage, &starred_expr);
|
self.add_error(ParseErrorType::InvalidStarredExpressionUsage, &starred_expr);
|
||||||
|
@ -393,7 +393,7 @@ impl<'src> Parser<'src> {
|
||||||
TokenKind::Yield => {
|
TokenKind::Yield => {
|
||||||
let expr = self.parse_yield_expression();
|
let expr = self.parse_yield_expression();
|
||||||
|
|
||||||
if left_precedence > OperatorPrecedence::Initial
|
if left_precedence > OperatorPrecedence::None
|
||||||
|| !context.is_yield_expression_allowed()
|
|| !context.is_yield_expression_allowed()
|
||||||
{
|
{
|
||||||
self.add_error(ParseErrorType::InvalidYieldExpressionUsage, &expr);
|
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)]
|
#[derive(Debug)]
|
||||||
enum BinaryLikeOperator {
|
enum BinaryLikeOperator {
|
||||||
Boolean(BoolOp),
|
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.
|
/// Represents the precedence used for parsing the value part of a starred expression.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub(super) enum StarredExpressionPrecedence {
|
pub(super) enum StarredExpressionPrecedence {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_parser/tests/fixtures.rs
|
source: crates/ruff_python_parser/tests/fixtures.rs
|
||||||
input_file: crates/ruff_python_parser/resources/valid/expressions/bin_op.py
|
input_file: crates/ruff_python_parser/resources/valid/expressions/bin_op.py
|
||||||
snapshot_kind: text
|
|
||||||
---
|
---
|
||||||
## AST
|
## AST
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue