Pass parent to NeedsParentheses (#5708)

This commit is contained in:
Micha Reiser 2023-07-13 08:57:29 +02:00 committed by GitHub
parent 30702c2977
commit 067b2a6ce6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
55 changed files with 562 additions and 606 deletions

View file

@ -1,11 +1,12 @@
use crate::comments::{leading_comments, trailing_comments, Comments};
use crate::expression::parentheses::{
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
};
use rustpython_parser::ast::{Constant, Expr, ExprAttribute, ExprConstant};
use ruff_formatter::write;
use ruff_python_ast::node::AnyNodeRef;
use crate::comments::{leading_comments, trailing_comments};
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses, Parentheses};
use crate::prelude::*;
use crate::FormatNodeRule;
use ruff_formatter::write;
use rustpython_parser::ast::{Constant, Expr, ExprAttribute, ExprConstant};
#[derive(Default)]
pub struct FormatExprAttribute;
@ -35,7 +36,7 @@ impl FormatNodeRule<ExprAttribute> for FormatExprAttribute {
dangling_comments.split_at(leading_attribute_comments_start);
if needs_parentheses {
value.format().with_options(Parenthesize::Always).fmt(f)?;
value.format().with_options(Parentheses::Always).fmt(f)?;
} else if let Expr::Attribute(expr_attribute) = value.as_ref() {
// We're in a attribute chain (`a.b.c`). The outermost node adds parentheses if
// required, the inner ones don't need them so we skip the `Expr` formatting that
@ -71,41 +72,23 @@ impl FormatNodeRule<ExprAttribute> for FormatExprAttribute {
}
}
/// Checks if there are any own line comments in an attribute chain (a.b.c). This method is
/// recursive up to the innermost expression that the attribute chain starts behind.
fn has_breaking_comments_attribute_chain(
expr_attribute: &ExprAttribute,
comments: &Comments,
) -> bool {
if comments
.dangling_comments(expr_attribute)
.iter()
.any(|comment| comment.line_position().is_own_line())
|| comments.has_trailing_own_line_comments(expr_attribute)
{
return true;
}
if let Expr::Attribute(inner) = expr_attribute.value.as_ref() {
return has_breaking_comments_attribute_chain(inner, comments);
}
return comments.has_trailing_own_line_comments(expr_attribute.value.as_ref());
}
impl NeedsParentheses for ExprAttribute {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
parent: AnyNodeRef,
context: &PyFormatContext,
) -> Parentheses {
if has_breaking_comments_attribute_chain(self, context.comments()) {
return Parentheses::Always;
}
match default_expression_needs_parentheses(self.into(), parenthesize, context) {
Parentheses::Optional => Parentheses::Never,
parentheses => parentheses,
) -> OptionalParentheses {
// Checks if there are any own line comments in an attribute chain (a.b.c).
if context
.comments()
.dangling_comments(self)
.iter()
.any(|comment| comment.line_position().is_own_line())
|| context.comments().has_trailing_own_line_comments(self)
{
OptionalParentheses::Always
} else {
self.value.needs_parentheses(parent, context)
}
}
}

View file

@ -1,10 +1,9 @@
use crate::context::PyFormatContext;
use crate::expression::parentheses::{
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
};
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::{AsFormat, FormatNodeRule, PyFormatter};
use ruff_formatter::prelude::{space, text};
use ruff_formatter::{write, Buffer, FormatResult};
use ruff_python_ast::node::AnyNodeRef;
use rustpython_parser::ast::ExprAwait;
#[derive(Default)]
@ -20,9 +19,9 @@ impl FormatNodeRule<ExprAwait> for FormatExprAwait {
impl NeedsParentheses for ExprAwait {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
default_expression_needs_parentheses(self.into(), parenthesize, context)
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::Multiline
}
}

View file

@ -1,13 +1,12 @@
use crate::comments::{trailing_comments, trailing_node_comments};
use crate::expression::parentheses::{
default_expression_needs_parentheses, in_parentheses_only_group, is_expression_parenthesized,
NeedsParentheses, Parenthesize,
in_parentheses_only_group, is_expression_parenthesized, NeedsParentheses, OptionalParentheses,
};
use crate::expression::Parentheses;
use crate::prelude::*;
use crate::FormatNodeRule;
use ruff_formatter::{write, FormatOwnedWithRule, FormatRefWithRule, FormatRuleWithOptions};
use ruff_python_ast::node::AstNode;
use ruff_python_ast::node::{AnyNodeRef, AstNode};
use rustpython_parser::ast::{
Constant, Expr, ExprAttribute, ExprBinOp, ExprConstant, ExprUnaryOp, Operator, UnaryOp,
};
@ -175,9 +174,9 @@ impl FormatRule<Operator, PyFormatContext<'_>> for FormatOperator {
impl NeedsParentheses for ExprBinOp {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
default_expression_needs_parentheses(self.into(), parenthesize, context)
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::Multiline
}
}

View file

@ -1,10 +1,10 @@
use crate::comments::leading_comments;
use crate::expression::parentheses::{
default_expression_needs_parentheses, in_parentheses_only_group, NeedsParentheses, Parentheses,
Parenthesize,
in_parentheses_only_group, NeedsParentheses, OptionalParentheses, Parentheses,
};
use crate::prelude::*;
use ruff_formatter::{write, FormatOwnedWithRule, FormatRefWithRule, FormatRuleWithOptions};
use ruff_python_ast::node::AnyNodeRef;
use rustpython_parser::ast::{BoolOp, ExprBoolOp};
#[derive(Default)]
@ -70,10 +70,10 @@ impl FormatNodeRule<ExprBoolOp> for FormatExprBoolOp {
impl NeedsParentheses for ExprBoolOp {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
default_expression_needs_parentheses(self.into(), parenthesize, context)
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::Multiline
}
}

View file

@ -1,17 +1,18 @@
use crate::builders::PyFormatterExtensions;
use crate::comments::dangling_comments;
use crate::context::PyFormatContext;
use crate::expression::parentheses::{
default_expression_needs_parentheses, parenthesized, NeedsParentheses, Parentheses,
Parenthesize,
};
use crate::trivia::{SimpleTokenizer, TokenKind};
use crate::{AsFormat, FormatNodeRule, PyFormatter};
use ruff_formatter::prelude::{format_with, group, text};
use ruff_formatter::{write, Buffer, FormatResult};
use ruff_text_size::{TextRange, TextSize};
use rustpython_parser::ast::{Expr, ExprCall, Ranged};
use ruff_formatter::write;
use ruff_python_ast::node::AnyNodeRef;
use crate::comments::dangling_comments;
use crate::expression::parentheses::{
parenthesized, NeedsParentheses, OptionalParentheses, Parentheses,
};
use crate::prelude::*;
use crate::trivia::{SimpleTokenizer, TokenKind};
use crate::FormatNodeRule;
#[derive(Default)]
pub struct FormatExprCall;
@ -52,14 +53,21 @@ impl FormatNodeRule<ExprCall> for FormatExprCall {
[argument] if keywords.is_empty() => {
let parentheses =
if is_single_argument_parenthesized(argument, item.end(), source) {
Parenthesize::Always
Parentheses::Always
} else {
Parenthesize::Never
Parentheses::Never
};
joiner.entry(argument, &argument.format().with_options(parentheses));
}
arguments => {
joiner.nodes(arguments).nodes(keywords.iter());
joiner
.entries(
// We have the parentheses from the call so the arguments never need any
arguments
.iter()
.map(|arg| (arg, arg.format().with_options(Parentheses::Preserve))),
)
.nodes(keywords.iter());
}
}
@ -100,13 +108,10 @@ impl FormatNodeRule<ExprCall> for FormatExprCall {
impl NeedsParentheses for ExprCall {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
parent: AnyNodeRef,
context: &PyFormatContext,
) -> Parentheses {
match default_expression_needs_parentheses(self.into(), parenthesize, context) {
Parentheses::Optional => Parentheses::Never,
parentheses => parentheses,
}
) -> OptionalParentheses {
self.func.needs_parentheses(parent, context)
}
}

View file

@ -1,11 +1,11 @@
use crate::comments::leading_comments;
use crate::expression::parentheses::{
default_expression_needs_parentheses, in_parentheses_only_group, NeedsParentheses, Parentheses,
Parenthesize,
in_parentheses_only_group, NeedsParentheses, OptionalParentheses, Parentheses,
};
use crate::prelude::*;
use crate::FormatNodeRule;
use ruff_formatter::{write, FormatOwnedWithRule, FormatRefWithRule, FormatRuleWithOptions};
use ruff_python_ast::node::AnyNodeRef;
use rustpython_parser::ast::{CmpOp, ExprCompare};
#[derive(Default)]
@ -73,10 +73,10 @@ impl FormatNodeRule<ExprCompare> for FormatExprCompare {
impl NeedsParentheses for ExprCompare {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
default_expression_needs_parentheses(self.into(), parenthesize, context)
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::Multiline
}
}

View file

@ -1,25 +1,17 @@
use crate::expression::parentheses::{
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
};
use crate::expression::string::{FormatString, StringLayout};
use ruff_text_size::{TextLen, TextRange};
use rustpython_parser::ast::{Constant, ExprConstant, Ranged};
use ruff_formatter::write;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::str::is_implicit_concatenation;
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::expression::string::{FormatString, StringPrefix, StringQuotes};
use crate::prelude::*;
use crate::{not_yet_implemented_custom_text, verbatim_text, FormatNodeRule};
use ruff_formatter::{write, FormatRuleWithOptions};
use rustpython_parser::ast::{Constant, ExprConstant};
#[derive(Default)]
pub struct FormatExprConstant {
string_layout: StringLayout,
}
impl FormatRuleWithOptions<ExprConstant, PyFormatContext<'_>> for FormatExprConstant {
type Options = StringLayout;
fn with_options(mut self, options: Self::Options) -> Self {
self.string_layout = options;
self
}
}
pub struct FormatExprConstant;
impl FormatNodeRule<ExprConstant> for FormatExprConstant {
fn fmt_fields(&self, item: &ExprConstant, f: &mut PyFormatter) -> FormatResult<()> {
@ -39,7 +31,7 @@ impl FormatNodeRule<ExprConstant> for FormatExprConstant {
Constant::Int(_) | Constant::Float(_) | Constant::Complex { .. } => {
write!(f, [verbatim_text(item)])
}
Constant::Str(_) => FormatString::new(item, self.string_layout).fmt(f),
Constant::Str(_) => FormatString::new(item).fmt(f),
Constant::Bytes(_) => {
not_yet_implemented_custom_text(r#"b"NOT_YET_IMPLEMENTED_BYTE_STRING""#).fmt(f)
}
@ -61,20 +53,32 @@ impl FormatNodeRule<ExprConstant> for FormatExprConstant {
impl NeedsParentheses for ExprConstant {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
_parent: AnyNodeRef,
context: &PyFormatContext,
) -> Parentheses {
match default_expression_needs_parentheses(self.into(), parenthesize, context) {
Parentheses::Optional if self.value.is_str() && parenthesize.is_if_breaks() => {
// Custom handling that only adds parentheses for implicit concatenated strings.
if parenthesize.is_if_breaks() {
Parentheses::Custom
} else {
Parentheses::Optional
}
) -> OptionalParentheses {
if self.value.is_str() {
let contents = context.locator().slice(self.range());
// Don't wrap triple quoted strings
if is_multiline_string(self, context.source()) || !is_implicit_concatenation(contents) {
OptionalParentheses::Never
} else {
OptionalParentheses::Multiline
}
Parentheses::Optional => Parentheses::Never,
parentheses => parentheses,
} else {
OptionalParentheses::Never
}
}
}
pub(super) fn is_multiline_string(constant: &ExprConstant, source: &str) -> bool {
if constant.value.is_str() {
let contents = &source[constant.range()];
let prefix = StringPrefix::parse(contents);
let quotes =
StringQuotes::parse(&contents[TextRange::new(prefix.text_len(), contents.text_len())]);
quotes.map_or(false, StringQuotes::is_triple) && contents.contains(['\n', '\r'])
} else {
false
}
}

View file

@ -1,11 +1,9 @@
use crate::comments::{dangling_node_comments, leading_comments};
use crate::expression::parentheses::{
default_expression_needs_parentheses, parenthesized, NeedsParentheses, Parentheses,
Parenthesize,
};
use crate::expression::parentheses::{parenthesized, NeedsParentheses, OptionalParentheses};
use crate::prelude::*;
use crate::FormatNodeRule;
use ruff_formatter::{format_args, write};
use ruff_python_ast::node::AnyNodeRef;
use ruff_text_size::TextRange;
use rustpython_parser::ast::Ranged;
use rustpython_parser::ast::{Expr, ExprDict};
@ -99,12 +97,9 @@ impl FormatNodeRule<ExprDict> for FormatExprDict {
impl NeedsParentheses for ExprDict {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
match default_expression_needs_parentheses(self.into(), parenthesize, context) {
Parentheses::Optional => Parentheses::Never,
parentheses => parentheses,
}
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::Never
}
}

View file

@ -1,9 +1,8 @@
use crate::context::PyFormatContext;
use crate::expression::parentheses::{
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
};
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter};
use ruff_formatter::{write, Buffer, FormatResult};
use ruff_python_ast::node::AnyNodeRef;
use rustpython_parser::ast::ExprDictComp;
#[derive(Default)]
@ -23,12 +22,9 @@ impl FormatNodeRule<ExprDictComp> for FormatExprDictComp {
impl NeedsParentheses for ExprDictComp {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
match default_expression_needs_parentheses(self.into(), parenthesize, context) {
Parentheses::Optional => Parentheses::Never,
parentheses => parentheses,
}
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::Never
}
}

View file

@ -1,9 +1,8 @@
use crate::context::PyFormatContext;
use crate::expression::parentheses::{
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
};
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter};
use ruff_formatter::{write, Buffer, FormatResult};
use ruff_python_ast::node::AnyNodeRef;
use rustpython_parser::ast::ExprFormattedValue;
#[derive(Default)]
@ -18,9 +17,9 @@ impl FormatNodeRule<ExprFormattedValue> for FormatExprFormattedValue {
impl NeedsParentheses for ExprFormattedValue {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
default_expression_needs_parentheses(self.into(), parenthesize, context)
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::Multiline
}
}

View file

@ -1,9 +1,8 @@
use crate::context::PyFormatContext;
use crate::expression::parentheses::{
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
};
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter};
use ruff_formatter::{write, Buffer, FormatResult};
use ruff_python_ast::node::AnyNodeRef;
use rustpython_parser::ast::ExprGeneratorExp;
#[derive(Default)]
@ -23,12 +22,9 @@ impl FormatNodeRule<ExprGeneratorExp> for FormatExprGeneratorExp {
impl NeedsParentheses for ExprGeneratorExp {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
match default_expression_needs_parentheses(self.into(), parenthesize, context) {
Parentheses::Optional => Parentheses::Never,
parentheses => parentheses,
}
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::Never
}
}

View file

@ -1,11 +1,11 @@
use crate::comments::leading_comments;
use crate::expression::parentheses::{
default_expression_needs_parentheses, in_parentheses_only_group, NeedsParentheses, Parentheses,
Parenthesize,
in_parentheses_only_group, NeedsParentheses, OptionalParentheses,
};
use crate::prelude::*;
use crate::FormatNodeRule;
use ruff_formatter::{format_args, write};
use ruff_python_ast::node::AnyNodeRef;
use rustpython_parser::ast::ExprIfExp;
#[derive(Default)]
@ -46,9 +46,9 @@ impl FormatNodeRule<ExprIfExp> for FormatExprIfExp {
impl NeedsParentheses for ExprIfExp {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
default_expression_needs_parentheses(self.into(), parenthesize, context)
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::Multiline
}
}

View file

@ -1,9 +1,8 @@
use crate::context::PyFormatContext;
use crate::expression::parentheses::{
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
};
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter};
use ruff_formatter::{write, Buffer, FormatResult};
use ruff_python_ast::node::AnyNodeRef;
use rustpython_parser::ast::ExprJoinedStr;
#[derive(Default)]
@ -18,9 +17,9 @@ impl FormatNodeRule<ExprJoinedStr> for FormatExprJoinedStr {
impl NeedsParentheses for ExprJoinedStr {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
default_expression_needs_parentheses(self.into(), parenthesize, context)
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::Multiline
}
}

View file

@ -1,9 +1,8 @@
use crate::context::PyFormatContext;
use crate::expression::parentheses::{
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
};
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter};
use ruff_formatter::{write, Buffer, FormatResult};
use ruff_python_ast::node::AnyNodeRef;
use rustpython_parser::ast::ExprLambda;
#[derive(Default)]
@ -23,9 +22,9 @@ impl FormatNodeRule<ExprLambda> for FormatExprLambda {
impl NeedsParentheses for ExprLambda {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
default_expression_needs_parentheses(self.into(), parenthesize, context)
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::Multiline
}
}

View file

@ -1,11 +1,9 @@
use crate::comments::{dangling_comments, CommentLinePosition};
use crate::expression::parentheses::{
default_expression_needs_parentheses, parenthesized, NeedsParentheses, Parentheses,
Parenthesize,
};
use crate::expression::parentheses::{parenthesized, NeedsParentheses, OptionalParentheses};
use crate::prelude::*;
use crate::FormatNodeRule;
use ruff_formatter::{format_args, write};
use ruff_python_ast::node::AnyNodeRef;
use rustpython_parser::ast::{ExprList, Ranged};
#[derive(Default)]
@ -71,12 +69,9 @@ impl FormatNodeRule<ExprList> for FormatExprList {
impl NeedsParentheses for ExprList {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
match default_expression_needs_parentheses(self.into(), parenthesize, context) {
Parentheses::Optional => Parentheses::Never,
parentheses => parentheses,
}
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::Never
}
}

View file

@ -1,12 +1,10 @@
use crate::context::PyFormatContext;
use crate::expression::parentheses::{
default_expression_needs_parentheses, parenthesized, NeedsParentheses, Parentheses,
Parenthesize,
};
use crate::expression::parentheses::{parenthesized, NeedsParentheses, OptionalParentheses};
use crate::prelude::*;
use crate::AsFormat;
use crate::{FormatNodeRule, PyFormatter};
use ruff_formatter::{format_args, write, Buffer, FormatResult};
use ruff_python_ast::node::AnyNodeRef;
use rustpython_parser::ast::ExprListComp;
#[derive(Default)]
@ -44,12 +42,9 @@ impl FormatNodeRule<ExprListComp> for FormatExprListComp {
impl NeedsParentheses for ExprListComp {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
match default_expression_needs_parentheses(self.into(), parenthesize, context) {
Parentheses::Optional => Parentheses::Never,
parentheses => parentheses,
}
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::Never
}
}

View file

@ -1,9 +1,8 @@
use crate::expression::parentheses::{
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
};
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::prelude::*;
use crate::FormatNodeRule;
use ruff_formatter::{write, FormatContext};
use ruff_python_ast::node::AnyNodeRef;
use rustpython_parser::ast::ExprName;
#[derive(Default)]
@ -28,10 +27,10 @@ impl FormatNodeRule<ExprName> for FormatExprName {
impl NeedsParentheses for ExprName {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
default_expression_needs_parentheses(self.into(), parenthesize, context)
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::Never
}
}

View file

@ -1,10 +1,9 @@
use crate::context::PyFormatContext;
use crate::expression::parentheses::{
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
};
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::{AsFormat, FormatNodeRule, PyFormatter};
use ruff_formatter::prelude::{space, text};
use ruff_formatter::{write, Buffer, FormatResult};
use ruff_python_ast::node::AnyNodeRef;
use rustpython_parser::ast::ExprNamedExpr;
#[derive(Default)]
@ -33,14 +32,11 @@ impl FormatNodeRule<ExprNamedExpr> for FormatExprNamedExpr {
impl NeedsParentheses for ExprNamedExpr {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
match default_expression_needs_parentheses(self.into(), parenthesize, context) {
// Unlike tuples, named expression parentheses are not part of the range even when
// mandatory. See [PEP 572](https://peps.python.org/pep-0572/) for details.
Parentheses::Optional => Parentheses::Always,
parentheses => parentheses,
}
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
// Unlike tuples, named expression parentheses are not part of the range even when
// mandatory. See [PEP 572](https://peps.python.org/pep-0572/) for details.
OptionalParentheses::Always
}
}

View file

@ -1,10 +1,8 @@
use crate::expression::parentheses::{
default_expression_needs_parentheses, parenthesized, NeedsParentheses, Parentheses,
Parenthesize,
};
use crate::expression::parentheses::{parenthesized, NeedsParentheses, OptionalParentheses};
use crate::prelude::*;
use crate::FormatNodeRule;
use ruff_formatter::format_args;
use ruff_python_ast::node::AnyNodeRef;
use rustpython_parser::ast::ExprSet;
#[derive(Default)]
@ -29,12 +27,9 @@ impl FormatNodeRule<ExprSet> for FormatExprSet {
impl NeedsParentheses for ExprSet {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
match default_expression_needs_parentheses(self.into(), parenthesize, context) {
Parentheses::Optional => Parentheses::Never,
parentheses => parentheses,
}
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::Never
}
}

View file

@ -1,9 +1,8 @@
use crate::context::PyFormatContext;
use crate::expression::parentheses::{
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
};
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter};
use ruff_formatter::{write, Buffer, FormatResult};
use ruff_python_ast::node::AnyNodeRef;
use rustpython_parser::ast::ExprSetComp;
#[derive(Default)]
@ -23,12 +22,9 @@ impl FormatNodeRule<ExprSetComp> for FormatExprSetComp {
impl NeedsParentheses for ExprSetComp {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
match default_expression_needs_parentheses(self.into(), parenthesize, context) {
Parentheses::Optional => Parentheses::Never,
parentheses => parentheses,
}
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::Never
}
}

View file

@ -1,14 +1,12 @@
use crate::comments::{dangling_comments, SourceComment};
use crate::context::PyFormatContext;
use crate::expression::parentheses::{
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
};
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::trivia::Token;
use crate::trivia::{first_non_trivia_token, TokenKind};
use crate::{AsFormat, FormatNodeRule, PyFormatter};
use ruff_formatter::prelude::{hard_line_break, line_suffix_boundary, space, text};
use ruff_formatter::{write, Buffer, Format, FormatError, FormatResult};
use ruff_python_ast::node::AstNode;
use ruff_python_ast::node::{AnyNodeRef, AstNode};
use ruff_text_size::TextRange;
use rustpython_parser::ast::ExprSlice;
use rustpython_parser::ast::{Expr, Ranged};
@ -262,9 +260,9 @@ fn leading_comments_spacing(
impl NeedsParentheses for ExprSlice {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
default_expression_needs_parentheses(self.into(), parenthesize, context)
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::Multiline
}
}

View file

@ -1,11 +1,10 @@
use rustpython_parser::ast::ExprStarred;
use ruff_formatter::write;
use ruff_python_ast::node::AnyNodeRef;
use crate::context::PyFormatContext;
use crate::expression::parentheses::{
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
};
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::prelude::*;
use crate::FormatNodeRule;
@ -33,9 +32,9 @@ impl FormatNodeRule<ExprStarred> for FormatExprStarred {
impl NeedsParentheses for ExprStarred {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
default_expression_needs_parentheses(self.into(), parenthesize, context)
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::Multiline
}
}

View file

@ -1,15 +1,14 @@
use rustpython_parser::ast::{Expr, ExprSubscript};
use ruff_formatter::{format_args, write};
use ruff_python_ast::node::AstNode;
use ruff_python_ast::node::{AnyNodeRef, AstNode};
use crate::comments::trailing_comments;
use crate::context::NodeLevel;
use crate::context::PyFormatContext;
use crate::expression::expr_tuple::TupleParentheses;
use crate::expression::parentheses::{
default_expression_needs_parentheses, in_parentheses_only_group, NeedsParentheses, Parentheses,
Parenthesize,
in_parentheses_only_group, NeedsParentheses, OptionalParentheses,
};
use crate::prelude::*;
use crate::FormatNodeRule;
@ -87,12 +86,11 @@ impl FormatNodeRule<ExprSubscript> for FormatExprSubscript {
impl NeedsParentheses for ExprSubscript {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
match default_expression_needs_parentheses(self.into(), parenthesize, context) {
Parentheses::Optional => Parentheses::Never,
parentheses => parentheses,
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
{
OptionalParentheses::Never
}
}
}

View file

@ -1,15 +1,17 @@
use crate::builders::parenthesize_if_expands;
use crate::comments::{dangling_comments, CommentLinePosition};
use crate::expression::parentheses::{
default_expression_needs_parentheses, parenthesized, NeedsParentheses, Parentheses,
Parenthesize,
};
use crate::prelude::*;
use ruff_formatter::{format_args, write, FormatRuleWithOptions};
use ruff_text_size::TextRange;
use rustpython_parser::ast::ExprTuple;
use rustpython_parser::ast::{Expr, Ranged};
use ruff_formatter::{format_args, write, FormatRuleWithOptions};
use ruff_python_ast::node::AnyNodeRef;
use crate::builders::parenthesize_if_expands;
use crate::comments::{dangling_comments, CommentLinePosition};
use crate::expression::parentheses::{
parenthesized, NeedsParentheses, OptionalParentheses, Parentheses,
};
use crate::prelude::*;
#[derive(Eq, PartialEq, Debug, Default)]
pub enum TupleParentheses {
/// Effectively `None` in `Option<Parentheses>`
@ -148,13 +150,10 @@ impl Format<PyFormatContext<'_>> for ExprSequence<'_> {
impl NeedsParentheses for ExprTuple {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
match default_expression_needs_parentheses(self.into(), parenthesize, context) {
Parentheses::Optional => Parentheses::Never,
parentheses => parentheses,
}
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::Never
}
}

View file

@ -1,12 +1,11 @@
use crate::comments::trailing_comments;
use crate::context::PyFormatContext;
use crate::expression::parentheses::{
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
};
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::trivia::{SimpleTokenizer, TokenKind};
use crate::{AsFormat, FormatNodeRule, PyFormatter};
use ruff_formatter::prelude::{hard_line_break, space, text};
use ruff_formatter::{Format, FormatContext, FormatResult};
use ruff_python_ast::node::AnyNodeRef;
use ruff_text_size::{TextLen, TextRange};
use rustpython_parser::ast::UnaryOp;
use rustpython_parser::ast::{ExprUnaryOp, Ranged};
@ -70,19 +69,14 @@ impl FormatNodeRule<ExprUnaryOp> for FormatExprUnaryOp {
impl NeedsParentheses for ExprUnaryOp {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
_parent: AnyNodeRef,
context: &PyFormatContext,
) -> Parentheses {
match default_expression_needs_parentheses(self.into(), parenthesize, context) {
Parentheses::Optional => {
// We preserve the parentheses of the operand. It should not be necessary to break this expression.
if is_operand_parenthesized(self, context.source()) {
Parentheses::Never
} else {
Parentheses::Optional
}
}
parentheses => parentheses,
) -> OptionalParentheses {
// We preserve the parentheses of the operand. It should not be necessary to break this expression.
if is_operand_parenthesized(self, context.source()) {
OptionalParentheses::Never
} else {
OptionalParentheses::Multiline
}
}
}

View file

@ -1,9 +1,8 @@
use crate::context::PyFormatContext;
use crate::expression::parentheses::{
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
};
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter};
use ruff_formatter::{write, Buffer, FormatResult};
use ruff_python_ast::node::AnyNodeRef;
use rustpython_parser::ast::ExprYield;
#[derive(Default)]
@ -18,9 +17,9 @@ impl FormatNodeRule<ExprYield> for FormatExprYield {
impl NeedsParentheses for ExprYield {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
default_expression_needs_parentheses(self.into(), parenthesize, context)
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::Multiline
}
}

View file

@ -1,9 +1,8 @@
use crate::context::PyFormatContext;
use crate::expression::parentheses::{
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
};
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter};
use ruff_formatter::{write, Buffer, FormatResult};
use ruff_python_ast::node::AnyNodeRef;
use rustpython_parser::ast::ExprYieldFrom;
#[derive(Default)]
@ -18,9 +17,9 @@ impl FormatNodeRule<ExprYieldFrom> for FormatExprYieldFrom {
impl NeedsParentheses for ExprYieldFrom {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
default_expression_needs_parentheses(self.into(), parenthesize, context)
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::Multiline
}
}

View file

@ -1,19 +1,19 @@
use rustpython_parser::ast;
use rustpython_parser::ast::{Expr, Operator};
use std::cmp::Ordering;
use crate::builders::parenthesize_if_expands;
use rustpython_parser::ast;
use rustpython_parser::ast::{Expr, Operator};
use ruff_formatter::{FormatOwnedWithRule, FormatRefWithRule, FormatRule, FormatRuleWithOptions};
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::visitor::preorder::{walk_expr, PreorderVisitor};
use crate::builders::parenthesize_if_expands;
use crate::context::NodeLevel;
use crate::expression::expr_tuple::TupleParentheses;
use crate::expression::parentheses::{
is_expression_parenthesized, optional_parentheses, parenthesized, NeedsParentheses,
Parentheses, Parenthesize,
OptionalParentheses, Parentheses, Parenthesize,
};
use crate::expression::string::StringLayout;
use crate::prelude::*;
pub(crate) mod expr_attribute;
@ -46,25 +46,25 @@ pub(crate) mod expr_yield_from;
pub(crate) mod parentheses;
pub(crate) mod string;
#[derive(Default)]
#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct FormatExpr {
parenthesize: Parenthesize,
parentheses: Parentheses,
}
impl FormatRuleWithOptions<Expr, PyFormatContext<'_>> for FormatExpr {
type Options = Parenthesize;
type Options = Parentheses;
fn with_options(mut self, options: Self::Options) -> Self {
self.parenthesize = options;
self.parentheses = options;
self
}
}
impl FormatRule<Expr, PyFormatContext<'_>> for FormatExpr {
fn fmt(&self, item: &Expr, f: &mut PyFormatter) -> FormatResult<()> {
let parentheses = item.needs_parentheses(self.parenthesize, f.context());
fn fmt(&self, expression: &Expr, f: &mut PyFormatter) -> FormatResult<()> {
let parentheses = self.parentheses;
let format_expr = format_with(|f| match item {
let format_expr = format_with(|f| match expression {
Expr::BoolOp(expr) => expr.format().with_options(Some(parentheses)).fmt(f),
Expr::NamedExpr(expr) => expr.format().fmt(f),
Expr::BinOp(expr) => expr.format().with_options(Some(parentheses)).fmt(f),
@ -84,10 +84,7 @@ impl FormatRule<Expr, PyFormatContext<'_>> for FormatExpr {
Expr::Call(expr) => expr.format().fmt(f),
Expr::FormattedValue(expr) => expr.format().fmt(f),
Expr::JoinedStr(expr) => expr.format().fmt(f),
Expr::Constant(expr) => expr
.format()
.with_options(StringLayout::Default(Some(parentheses)))
.fmt(f),
Expr::Constant(expr) => expr.format().fmt(f),
Expr::Attribute(expr) => expr.format().fmt(f),
Expr::Subscript(expr) => expr.format().fmt(f),
Expr::Starred(expr) => expr.format().fmt(f),
@ -100,74 +97,136 @@ impl FormatRule<Expr, PyFormatContext<'_>> for FormatExpr {
Expr::Slice(expr) => expr.format().fmt(f),
});
let result = match parentheses {
Parentheses::Always => parenthesized("(", &format_expr, ")").fmt(f),
// Add optional parentheses. Ignore if the item renders parentheses itself.
Parentheses::Optional => {
if can_omit_optional_parentheses(item, f.context()) {
optional_parentheses(&format_expr).fmt(f)
} else {
parenthesize_if_expands(&format_expr).fmt(f)
}
}
Parentheses::Custom | Parentheses::Never => {
let saved_level = f.context().node_level();
let new_level = match saved_level {
NodeLevel::TopLevel | NodeLevel::CompoundStatement => {
NodeLevel::Expression(None)
}
level @ (NodeLevel::Expression(_) | NodeLevel::ParenthesizedExpression) => {
level
}
};
f.context_mut().set_node_level(new_level);
let result = Format::fmt(&format_expr, f);
f.context_mut().set_node_level(saved_level);
result
let parenthesize = match parentheses {
Parentheses::Preserve => {
is_expression_parenthesized(AnyNodeRef::from(expression), f.context().source())
}
Parentheses::Always => true,
Parentheses::Never => false,
};
result
if parenthesize {
parenthesized("(", &format_expr, ")").fmt(f)
} else {
let saved_level = match f.context().node_level() {
saved_level @ (NodeLevel::TopLevel | NodeLevel::CompoundStatement) => {
f.context_mut().set_node_level(NodeLevel::Expression(None));
Some(saved_level)
}
NodeLevel::Expression(_) | NodeLevel::ParenthesizedExpression => None,
};
let result = Format::fmt(&format_expr, f);
if let Some(saved_level) = saved_level {
f.context_mut().set_node_level(saved_level);
}
result
}
}
}
/// Wraps an expression in an optional parentheses except if its [`NeedsParentheses::needs_parentheses`] implementation
/// indicates that it is okay to omit the parentheses. For example, parentheses can always be omitted for lists,
/// because they already bring their own parentheses.
pub(crate) fn maybe_parenthesize_expression<'a, T>(
expression: &'a Expr,
parent: T,
parenthesize: Parenthesize,
) -> MaybeParenthesizeExpression<'a>
where
T: Into<AnyNodeRef<'a>>,
{
MaybeParenthesizeExpression {
expression,
parent: parent.into(),
parenthesize,
}
}
pub(crate) struct MaybeParenthesizeExpression<'a> {
expression: &'a Expr,
parent: AnyNodeRef<'a>,
parenthesize: Parenthesize,
}
impl Format<PyFormatContext<'_>> for MaybeParenthesizeExpression<'_> {
fn fmt(&self, f: &mut Formatter<PyFormatContext<'_>>) -> FormatResult<()> {
let MaybeParenthesizeExpression {
expression,
parent,
parenthesize,
} = self;
let parenthesize = match parenthesize {
Parenthesize::Optional => {
is_expression_parenthesized(AnyNodeRef::from(*expression), f.context().source())
}
Parenthesize::IfBreaks => false,
};
let parentheses =
if parenthesize || f.context().comments().has_leading_comments(*expression) {
OptionalParentheses::Always
} else {
expression.needs_parentheses(*parent, f.context())
};
match parentheses {
OptionalParentheses::Multiline => {
if can_omit_optional_parentheses(expression, f.context()) {
optional_parentheses(&expression.format().with_options(Parentheses::Never))
.fmt(f)
} else {
parenthesize_if_expands(&expression.format().with_options(Parentheses::Never))
.fmt(f)
}
}
OptionalParentheses::Always => {
expression.format().with_options(Parentheses::Always).fmt(f)
}
OptionalParentheses::Never => {
expression.format().with_options(Parentheses::Never).fmt(f)
}
}
}
}
impl NeedsParentheses for Expr {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
parent: AnyNodeRef,
context: &PyFormatContext,
) -> Parentheses {
) -> OptionalParentheses {
match self {
Expr::BoolOp(expr) => expr.needs_parentheses(parenthesize, context),
Expr::NamedExpr(expr) => expr.needs_parentheses(parenthesize, context),
Expr::BinOp(expr) => expr.needs_parentheses(parenthesize, context),
Expr::UnaryOp(expr) => expr.needs_parentheses(parenthesize, context),
Expr::Lambda(expr) => expr.needs_parentheses(parenthesize, context),
Expr::IfExp(expr) => expr.needs_parentheses(parenthesize, context),
Expr::Dict(expr) => expr.needs_parentheses(parenthesize, context),
Expr::Set(expr) => expr.needs_parentheses(parenthesize, context),
Expr::ListComp(expr) => expr.needs_parentheses(parenthesize, context),
Expr::SetComp(expr) => expr.needs_parentheses(parenthesize, context),
Expr::DictComp(expr) => expr.needs_parentheses(parenthesize, context),
Expr::GeneratorExp(expr) => expr.needs_parentheses(parenthesize, context),
Expr::Await(expr) => expr.needs_parentheses(parenthesize, context),
Expr::Yield(expr) => expr.needs_parentheses(parenthesize, context),
Expr::YieldFrom(expr) => expr.needs_parentheses(parenthesize, context),
Expr::Compare(expr) => expr.needs_parentheses(parenthesize, context),
Expr::Call(expr) => expr.needs_parentheses(parenthesize, context),
Expr::FormattedValue(expr) => expr.needs_parentheses(parenthesize, context),
Expr::JoinedStr(expr) => expr.needs_parentheses(parenthesize, context),
Expr::Constant(expr) => expr.needs_parentheses(parenthesize, context),
Expr::Attribute(expr) => expr.needs_parentheses(parenthesize, context),
Expr::Subscript(expr) => expr.needs_parentheses(parenthesize, context),
Expr::Starred(expr) => expr.needs_parentheses(parenthesize, context),
Expr::Name(expr) => expr.needs_parentheses(parenthesize, context),
Expr::List(expr) => expr.needs_parentheses(parenthesize, context),
Expr::Tuple(expr) => expr.needs_parentheses(parenthesize, context),
Expr::Slice(expr) => expr.needs_parentheses(parenthesize, context),
Expr::BoolOp(expr) => expr.needs_parentheses(parent, context),
Expr::NamedExpr(expr) => expr.needs_parentheses(parent, context),
Expr::BinOp(expr) => expr.needs_parentheses(parent, context),
Expr::UnaryOp(expr) => expr.needs_parentheses(parent, context),
Expr::Lambda(expr) => expr.needs_parentheses(parent, context),
Expr::IfExp(expr) => expr.needs_parentheses(parent, context),
Expr::Dict(expr) => expr.needs_parentheses(parent, context),
Expr::Set(expr) => expr.needs_parentheses(parent, context),
Expr::ListComp(expr) => expr.needs_parentheses(parent, context),
Expr::SetComp(expr) => expr.needs_parentheses(parent, context),
Expr::DictComp(expr) => expr.needs_parentheses(parent, context),
Expr::GeneratorExp(expr) => expr.needs_parentheses(parent, context),
Expr::Await(expr) => expr.needs_parentheses(parent, context),
Expr::Yield(expr) => expr.needs_parentheses(parent, context),
Expr::YieldFrom(expr) => expr.needs_parentheses(parent, context),
Expr::Compare(expr) => expr.needs_parentheses(parent, context),
Expr::Call(expr) => expr.needs_parentheses(parent, context),
Expr::FormattedValue(expr) => expr.needs_parentheses(parent, context),
Expr::JoinedStr(expr) => expr.needs_parentheses(parent, context),
Expr::Constant(expr) => expr.needs_parentheses(parent, context),
Expr::Attribute(expr) => expr.needs_parentheses(parent, context),
Expr::Subscript(expr) => expr.needs_parentheses(parent, context),
Expr::Starred(expr) => expr.needs_parentheses(parent, context),
Expr::Name(expr) => expr.needs_parentheses(parent, context),
Expr::List(expr) => expr.needs_parentheses(parent, context),
Expr::Tuple(expr) => expr.needs_parentheses(parent, context),
Expr::Slice(expr) => expr.needs_parentheses(parent, context),
}
}
}

View file

@ -6,101 +6,50 @@ use ruff_formatter::{format_args, Argument, Arguments};
use ruff_python_ast::node::AnyNodeRef;
use rustpython_parser::ast::Ranged;
pub(crate) trait NeedsParentheses {
fn needs_parentheses(
&self,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub(crate) enum OptionalParentheses {
/// Add parentheses if the expression expands over multiple lines
Multiline,
/// Always set parentheses regardless if the expression breaks or if they were
/// present in the source.
Always,
/// Never add parentheses
Never,
}
pub(super) fn default_expression_needs_parentheses(
node: AnyNodeRef,
parenthesize: Parenthesize,
context: &PyFormatContext,
) -> Parentheses {
debug_assert!(
node.is_expression(),
"Should only be called for expressions"
);
#[allow(clippy::if_same_then_else)]
if parenthesize.is_always() {
Parentheses::Always
} else if parenthesize.is_never() {
Parentheses::Never
}
// `Optional` or `Preserve` and expression has parentheses in source code.
else if !parenthesize.is_if_breaks() && is_expression_parenthesized(node, context.source()) {
Parentheses::Always
}
// `Optional` or `IfBreaks`: Add parentheses if the expression doesn't fit on a line but enforce
// parentheses if the expression has leading comments
else if !parenthesize.is_preserve() {
if context.comments().has_leading_comments(node) {
Parentheses::Always
} else {
Parentheses::Optional
}
} else {
//`Preserve` and expression has no parentheses in the source code
Parentheses::Never
}
pub(crate) trait NeedsParentheses {
/// Determines if this object needs optional parentheses or if it is safe to omit the parentheses.
fn needs_parentheses(
&self,
parent: AnyNodeRef,
context: &PyFormatContext,
) -> OptionalParentheses;
}
/// Configures if the expression should be parenthesized.
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub enum Parenthesize {
/// Parenthesize the expression if it has parenthesis in the source.
#[default]
Preserve,
#[derive(Copy, Clone, Debug, PartialEq)]
pub(crate) enum Parenthesize {
/// Parenthesizes the expression if it doesn't fit on a line OR if the expression is parenthesized in the source code.
Optional,
/// Parenthesizes the expression only if it doesn't fit on a line.
IfBreaks,
/// Always adds parentheses
Always,
/// Never adds parentheses. Parentheses are handled by the caller.
Never,
}
impl Parenthesize {
pub(crate) const fn is_always(self) -> bool {
matches!(self, Parenthesize::Always)
}
pub(crate) const fn is_never(self) -> bool {
matches!(self, Parenthesize::Never)
}
pub(crate) const fn is_if_breaks(self) -> bool {
matches!(self, Parenthesize::IfBreaks)
}
pub(crate) const fn is_preserve(self) -> bool {
matches!(self, Parenthesize::Preserve)
}
}
/// Whether it is necessary to add parentheses around an expression.
/// This is different from [`Parenthesize`] in that it is the resolved representation: It takes into account
/// whether there are parentheses in the source code or not.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
pub enum Parentheses {
#[default]
Preserve,
/// Always set parentheses regardless if the expression breaks or if they were
/// present in the source.
Always,
/// Only add parentheses when necessary because the expression breaks over multiple lines.
Optional,
/// Custom handling by the node's formatter implementation
Custom,
/// Never add parentheses
Never,
}
@ -182,20 +131,20 @@ impl<'ast> Format<PyFormatContext<'ast>> for FormatParenthesized<'_, 'ast> {
/// a parentheses (`()`, `[]`, `{}`).
pub(crate) fn optional_parentheses<'content, 'ast, Content>(
content: &'content Content,
) -> OptionalParentheses<'content, 'ast>
) -> FormatOptionalParentheses<'content, 'ast>
where
Content: Format<PyFormatContext<'ast>>,
{
OptionalParentheses {
FormatOptionalParentheses {
content: Argument::new(content),
}
}
pub(crate) struct OptionalParentheses<'content, 'ast> {
pub(crate) struct FormatOptionalParentheses<'content, 'ast> {
content: Argument<'content, PyFormatContext<'ast>>,
}
impl<'ast> Format<PyFormatContext<'ast>> for OptionalParentheses<'_, 'ast> {
impl<'ast> Format<PyFormatContext<'ast>> for FormatOptionalParentheses<'_, 'ast> {
fn fmt(&self, f: &mut Formatter<PyFormatContext<'ast>>) -> FormatResult<()> {
let saved_level = f.context().node_level();

View file

@ -1,41 +1,27 @@
use crate::builders::parenthesize_if_expands;
use crate::comments::{leading_comments, trailing_comments};
use crate::expression::parentheses::Parentheses;
use crate::prelude::*;
use crate::QuoteStyle;
use std::borrow::Cow;
use bitflags::bitflags;
use ruff_formatter::{format_args, write, FormatError};
use ruff_python_ast::str::is_implicit_concatenation;
use ruff_text_size::{TextLen, TextRange, TextSize};
use rustpython_parser::ast::{ExprConstant, Ranged};
use rustpython_parser::lexer::{lex_starts_at, LexicalError, LexicalErrorType};
use rustpython_parser::{Mode, Tok};
use std::borrow::Cow;
#[derive(Copy, Clone, Debug)]
pub enum StringLayout {
Default(Option<Parentheses>),
use ruff_formatter::{format_args, write, FormatError};
use ruff_python_ast::str::is_implicit_concatenation;
/// Enforces that implicit continuation strings are printed on a single line even if they exceed
/// the configured line width.
Flat,
}
impl Default for StringLayout {
fn default() -> Self {
Self::Default(None)
}
}
use crate::comments::{leading_comments, trailing_comments};
use crate::expression::parentheses::in_parentheses_only_group;
use crate::prelude::*;
use crate::QuoteStyle;
pub(super) struct FormatString<'a> {
constant: &'a ExprConstant,
layout: StringLayout,
}
impl<'a> FormatString<'a> {
pub(super) fn new(constant: &'a ExprConstant, layout: StringLayout) -> Self {
pub(super) fn new(constant: &'a ExprConstant) -> Self {
debug_assert!(constant.value.is_str());
Self { constant, layout }
Self { constant }
}
}
@ -45,13 +31,7 @@ impl<'a> Format<PyFormatContext<'_>> for FormatString<'a> {
let string_content = f.context().locator().slice(string_range);
if is_implicit_concatenation(string_content) {
let format_continuation = FormatStringContinuation::new(self.constant, self.layout);
if let StringLayout::Default(Some(Parentheses::Custom)) = self.layout {
parenthesize_if_expands(&format_continuation).fmt(f)
} else {
format_continuation.fmt(f)
}
in_parentheses_only_group(&FormatStringContinuation::new(self.constant)).fmt(f)
} else {
FormatStringPart::new(string_range).fmt(f)
}
@ -60,13 +40,12 @@ impl<'a> Format<PyFormatContext<'_>> for FormatString<'a> {
struct FormatStringContinuation<'a> {
constant: &'a ExprConstant,
layout: StringLayout,
}
impl<'a> FormatStringContinuation<'a> {
fn new(constant: &'a ExprConstant, layout: StringLayout) -> Self {
fn new(constant: &'a ExprConstant) -> Self {
debug_assert!(constant.value.is_str());
Self { constant, layout }
Self { constant }
}
}
@ -85,12 +64,7 @@ impl Format<PyFormatContext<'_>> for FormatStringContinuation<'_> {
// because this is a black preview style.
let lexer = lex_starts_at(string_content, Mode::Expression, string_range.start());
let separator = format_with(|f| match self.layout {
StringLayout::Default(_) => soft_line_break_or_space().fmt(f),
StringLayout::Flat => space().fmt(f),
});
let mut joiner = f.join_with(separator);
let mut joiner = f.join_with(soft_line_break_or_space());
for token in lexer {
let (token, token_range) = match token {
@ -220,7 +194,7 @@ impl Format<PyFormatContext<'_>> for FormatStringPart {
bitflags! {
#[derive(Copy, Clone, Debug)]
struct StringPrefix: u8 {
pub(super) struct StringPrefix: u8 {
const UNICODE = 0b0000_0001;
/// `r"test"`
const RAW = 0b0000_0010;
@ -232,7 +206,7 @@ bitflags! {
}
impl StringPrefix {
fn parse(input: &str) -> StringPrefix {
pub(super) fn parse(input: &str) -> StringPrefix {
let chars = input.chars();
let mut prefix = StringPrefix::empty();
@ -257,7 +231,7 @@ impl StringPrefix {
prefix
}
const fn text_len(self) -> TextSize {
pub(super) const fn text_len(self) -> TextSize {
TextSize::new(self.bits().count_ones())
}
}
@ -383,13 +357,13 @@ fn preferred_quotes(
}
#[derive(Copy, Clone, Debug)]
struct StringQuotes {
pub(super) struct StringQuotes {
triple: bool,
style: QuoteStyle,
}
impl StringQuotes {
fn parse(input: &str) -> Option<StringQuotes> {
pub(super) fn parse(input: &str) -> Option<StringQuotes> {
let mut chars = input.chars();
let quote_char = chars.next()?;
@ -400,6 +374,10 @@ impl StringQuotes {
Some(Self { triple, style })
}
pub(super) const fn is_triple(self) -> bool {
self.triple
}
const fn text_len(self) -> TextSize {
if self.triple {
TextSize::new(3)

View file

@ -1,3 +1,4 @@
use crate::expression::maybe_parenthesize_expression;
use crate::expression::parentheses::Parenthesize;
use crate::prelude::*;
use crate::FormatNodeRule;
@ -18,7 +19,7 @@ impl FormatNodeRule<Decorator> for FormatDecorator {
f,
[
text("@"),
expression.format().with_options(Parenthesize::Optional)
maybe_parenthesize_expression(expression, item, Parenthesize::Optional)
]
)
}

View file

@ -1,4 +1,5 @@
use crate::comments::trailing_comments;
use crate::expression::maybe_parenthesize_expression;
use crate::expression::parentheses::Parenthesize;
use crate::prelude::*;
use crate::{FormatNodeRule, PyFormatter};
@ -60,7 +61,10 @@ impl FormatNodeRule<ExceptHandlerExceptHandler> for FormatExceptHandlerExceptHan
if let Some(type_) = type_ {
write!(
f,
[space(), type_.format().with_options(Parenthesize::IfBreaks)]
[
space(),
maybe_parenthesize_expression(type_, item, Parenthesize::IfBreaks)
]
)?;
if let Some(name) = name {
write!(f, [space(), text("as"), space(), name.format()])?;

View file

@ -1,3 +1,4 @@
use crate::expression::maybe_parenthesize_expression;
use crate::expression::parentheses::Parenthesize;
use crate::prelude::*;
use crate::{FormatNodeRule, PyFormatter};
@ -18,7 +19,11 @@ impl FormatNodeRule<WithItem> for FormatWithItem {
let inner = format_with(|f| {
write!(
f,
[context_expr.format().with_options(Parenthesize::IfBreaks)]
[maybe_parenthesize_expression(
context_expr,
item,
Parenthesize::IfBreaks
)]
)?;
if let Some(optional_vars) = optional_vars {
write!(f, [space(), text("as"), space(), optional_vars.format()])?;

View file

@ -2,6 +2,7 @@ use rustpython_parser::ast::StmtAssign;
use ruff_formatter::write;
use crate::expression::maybe_parenthesize_expression;
use crate::expression::parentheses::Parenthesize;
use crate::prelude::*;
use crate::FormatNodeRule;
@ -26,6 +27,13 @@ impl FormatNodeRule<StmtAssign> for FormatStmtAssign {
write!(f, [target.format(), space(), text("="), space()])?;
}
write!(f, [value.format().with_options(Parenthesize::IfBreaks)])
write!(
f,
[maybe_parenthesize_expression(
value,
item,
Parenthesize::IfBreaks
)]
)
}
}

View file

@ -1,7 +1,9 @@
use rustpython_parser::ast::StmtAsyncFunctionDef;
use ruff_python_ast::function::AnyFunctionDefinition;
use crate::prelude::*;
use crate::FormatNodeRule;
use ruff_python_ast::function::AnyFunctionDefinition;
use rustpython_parser::ast::StmtAsyncFunctionDef;
#[derive(Default)]
pub struct FormatStmtAsyncFunctionDef;

View file

@ -1,3 +1,4 @@
use crate::expression::maybe_parenthesize_expression;
use crate::expression::parentheses::Parenthesize;
use crate::{AsFormat, FormatNodeRule, PyFormatter};
use ruff_formatter::prelude::{space, text};
@ -23,7 +24,7 @@ impl FormatNodeRule<StmtAugAssign> for FormatStmtAugAssign {
op.format(),
text("="),
space(),
value.format().with_options(Parenthesize::IfBreaks)
maybe_parenthesize_expression(value, item, Parenthesize::IfBreaks)
]
)
}

View file

@ -1,5 +1,6 @@
use crate::comments::trailing_comments;
use crate::expression::parentheses::Parenthesize;
use crate::expression::parentheses::Parentheses;
use crate::prelude::*;
use crate::trivia::{SimpleTokenizer, TokenKind};
use ruff_formatter::{format_args, write};
@ -100,13 +101,13 @@ impl Format<PyFormatContext<'_>> for FormatInheritanceClause<'_> {
.count();
// Ignore the first parentheses count
let parenthesize = if left_paren_count > 1 {
Parenthesize::Always
let parentheses = if left_paren_count > 1 {
Parentheses::Always
} else {
Parenthesize::Never
Parentheses::Never
};
joiner.entry(first, &first.format().with_options(parenthesize));
joiner.entry(first, &first.format().with_options(parentheses));
joiner.nodes(rest.iter());
}

View file

@ -1,7 +1,8 @@
use crate::builders::{parenthesize_if_expands, PyFormatterExtensions};
use crate::comments::dangling_node_comments;
use crate::expression::maybe_parenthesize_expression;
use crate::expression::parentheses::Parenthesize;
use crate::{AsFormat, FormatNodeRule, PyFormatter};
use crate::{FormatNodeRule, PyFormatter};
use ruff_formatter::prelude::{block_indent, format_with, space, text};
use ruff_formatter::{write, Buffer, Format, FormatResult};
use rustpython_parser::ast::{Ranged, StmtDelete};
@ -32,7 +33,14 @@ impl FormatNodeRule<StmtDelete> for FormatStmtDelete {
)
}
[single] => {
write!(f, [single.format().with_options(Parenthesize::IfBreaks)])
write!(
f,
[maybe_parenthesize_expression(
single,
item,
Parenthesize::IfBreaks
)]
)
}
targets => {
let item = format_with(|f| {

View file

@ -1,8 +1,9 @@
use crate::expression::parentheses::{is_expression_parenthesized, Parenthesize};
use crate::expression::string::StringLayout;
use rustpython_parser::ast::StmtExpr;
use crate::expression::maybe_parenthesize_expression;
use crate::expression::parentheses::Parenthesize;
use crate::prelude::*;
use crate::FormatNodeRule;
use rustpython_parser::ast::StmtExpr;
#[derive(Default)]
pub struct FormatStmtExpr;
@ -11,14 +12,6 @@ impl FormatNodeRule<StmtExpr> for FormatStmtExpr {
fn fmt_fields(&self, item: &StmtExpr, f: &mut PyFormatter) -> FormatResult<()> {
let StmtExpr { value, .. } = item;
if let Some(constant) = value.as_constant_expr() {
if constant.value.is_str()
&& !is_expression_parenthesized(value.as_ref().into(), f.context().source())
{
return constant.format().with_options(StringLayout::Flat).fmt(f);
}
}
value.format().with_options(Parenthesize::Optional).fmt(f)
maybe_parenthesize_expression(value, item, Parenthesize::Optional).fmt(f)
}
}

View file

@ -1,5 +1,6 @@
use crate::comments::{leading_alternate_branch_comments, trailing_comments};
use crate::expression::expr_tuple::TupleParentheses;
use crate::expression::maybe_parenthesize_expression;
use crate::expression::parentheses::Parenthesize;
use crate::prelude::*;
use crate::{FormatNodeRule, PyFormatter};
@ -17,7 +18,7 @@ impl Format<PyFormatContext<'_>> for ExprTupleWithoutParentheses<'_> {
.format()
.with_options(TupleParentheses::StripInsideForLoop)
.fmt(f),
other => other.format().with_options(Parenthesize::IfBreaks).fmt(f),
other => maybe_parenthesize_expression(other, self.0, Parenthesize::IfBreaks).fmt(f),
}
}
}
@ -54,7 +55,7 @@ impl FormatNodeRule<StmtFor> for FormatStmtFor {
space(),
text("in"),
space(),
iter.format().with_options(Parenthesize::IfBreaks),
maybe_parenthesize_expression(iter, item, Parenthesize::IfBreaks),
text(":"),
trailing_comments(trailing_condition_comments),
block_indent(&body.format())

View file

@ -1,12 +1,14 @@
use rustpython_parser::ast::{Ranged, StmtFunctionDef};
use ruff_formatter::{write, FormatOwnedWithRule, FormatRefWithRule};
use ruff_python_ast::function::AnyFunctionDefinition;
use crate::comments::{leading_comments, trailing_comments};
use crate::context::NodeLevel;
use crate::expression::parentheses::{optional_parentheses, Parenthesize};
use crate::expression::parentheses::{optional_parentheses, Parentheses};
use crate::prelude::*;
use crate::trivia::{lines_after, skip_trailing_trivia};
use crate::FormatNodeRule;
use ruff_formatter::{write, FormatOwnedWithRule, FormatRefWithRule};
use ruff_python_ast::function::AnyFunctionDefinition;
use rustpython_parser::ast::{Ranged, StmtFunctionDef};
#[derive(Default)]
pub struct FormatStmtFunctionDef;
@ -98,7 +100,7 @@ impl FormatRule<AnyFunctionDefinition<'_>, PyFormatContext<'_>> for FormatAnyFun
text("->"),
space(),
optional_parentheses(
&return_annotation.format().with_options(Parenthesize::Never)
&return_annotation.format().with_options(Parentheses::Never)
)
]
)?;

View file

@ -1,4 +1,5 @@
use crate::comments::{leading_alternate_branch_comments, trailing_comments, SourceComment};
use crate::expression::maybe_parenthesize_expression;
use crate::expression::parentheses::Parenthesize;
use crate::prelude::*;
use crate::FormatNodeRule;
@ -48,7 +49,7 @@ impl FormatNodeRule<StmtIf> for FormatStmtIf {
[
text(current.keyword()),
space(),
test.format().with_options(Parenthesize::IfBreaks),
maybe_parenthesize_expression(test, current_statement, Parenthesize::IfBreaks),
text(":"),
trailing_comments(if_trailing_comments),
block_indent(&body.format())

View file

@ -1,8 +1,9 @@
use crate::expression::parentheses::Parenthesize;
use crate::{AsFormat, FormatNodeRule, PyFormatter};
use crate::{FormatNodeRule, PyFormatter};
use ruff_formatter::prelude::{space, text};
use ruff_formatter::{write, Buffer, Format, FormatResult};
use crate::expression::maybe_parenthesize_expression;
use rustpython_parser::ast::StmtRaise;
#[derive(Default)]
@ -21,7 +22,10 @@ impl FormatNodeRule<StmtRaise> for FormatStmtRaise {
if let Some(value) = exc {
write!(
f,
[space(), value.format().with_options(Parenthesize::Optional)]
[
space(),
maybe_parenthesize_expression(value, item, Parenthesize::Optional)
]
)?;
}
@ -32,7 +36,7 @@ impl FormatNodeRule<StmtRaise> for FormatStmtRaise {
space(),
text("from"),
space(),
value.format().with_options(Parenthesize::Optional)
maybe_parenthesize_expression(value, item, Parenthesize::Optional)
]
)?;
}

View file

@ -1,5 +1,6 @@
use crate::expression::maybe_parenthesize_expression;
use crate::expression::parentheses::Parenthesize;
use crate::{AsFormat, FormatNodeRule, PyFormatter};
use crate::{FormatNodeRule, PyFormatter};
use ruff_formatter::prelude::{space, text};
use ruff_formatter::{write, Buffer, Format, FormatResult};
use rustpython_parser::ast::StmtReturn;
@ -16,7 +17,7 @@ impl FormatNodeRule<StmtReturn> for FormatStmtReturn {
[
text("return"),
space(),
value.format().with_options(Parenthesize::IfBreaks)
maybe_parenthesize_expression(value, item, Parenthesize::IfBreaks)
]
)
} else {

View file

@ -1,4 +1,5 @@
use crate::comments::{leading_alternate_branch_comments, trailing_comments};
use crate::expression::maybe_parenthesize_expression;
use crate::expression::parentheses::Parenthesize;
use crate::prelude::*;
use crate::FormatNodeRule;
@ -33,7 +34,7 @@ impl FormatNodeRule<StmtWhile> for FormatStmtWhile {
[
text("while"),
space(),
test.format().with_options(Parenthesize::IfBreaks),
maybe_parenthesize_expression(test, item, Parenthesize::IfBreaks),
text(":"),
trailing_comments(trailing_condition_comments),
block_indent(&body.format())