Skip to content

Commit

Permalink
Format PatternMatchSingleton
Browse files Browse the repository at this point in the history
  • Loading branch information
LaBatata101 committed Aug 21, 2023
1 parent 82e0a97 commit 71b142c
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 90 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,20 @@ def foo():
no_comments
):
pass


match pattern_singleton:
case (
# leading 1
# leading 2
None # trailing
# trailing own 1
# trailing own 2
):
pass
case (
True # trailing
):
...
case False:
...
115 changes: 33 additions & 82 deletions crates/ruff_python_formatter/src/expression/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use std::cmp::Ordering;

use ruff_formatter::{
write, FormatOwnedWithRule, FormatRefWithRule, FormatRule, FormatRuleWithOptions,
};
use ruff_formatter::{write, FormatOwnedWithRule, FormatRefWithRule, FormatRule, FormatRuleWithOptions};
use ruff_python_ast as ast;
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::visitor::preorder::{walk_expr, PreorderVisitor};
Expand All @@ -11,8 +9,8 @@ use ruff_python_ast::{Expr, ExpressionRef, Operator};
use crate::builders::parenthesize_if_expands;
use crate::context::{NodeLevel, WithNodeLevel};
use crate::expression::parentheses::{
is_expression_parenthesized, optional_parentheses, parenthesized, NeedsParentheses,
OptionalParentheses, Parentheses, Parenthesize,
is_expression_parenthesized, optional_parentheses, parenthesized, NeedsParentheses, OptionalParentheses,
Parentheses, Parenthesize,
};
use crate::prelude::*;

Expand Down Expand Up @@ -98,9 +96,7 @@ impl FormatRule<Expr, PyFormatContext<'_>> for FormatExpr {
});

let parenthesize = match parentheses {
Parentheses::Preserve => {
is_expression_parenthesized(expression.into(), f.context().source())
}
Parentheses::Preserve => is_expression_parenthesized(expression.into(), f.context().source()),
Parentheses::Always => true,
// Fluent style means we already have parentheses
Parentheses::Never => false,
Expand All @@ -110,18 +106,12 @@ impl FormatRule<Expr, PyFormatContext<'_>> for FormatExpr {
let comments = f.context().comments().clone();
let open_parenthesis_comment = comments.open_parenthesis_comment(expression);
parenthesized("(", &format_expr, ")")
.with_dangling_comments(
open_parenthesis_comment
.map(std::slice::from_ref)
.unwrap_or_default(),
)
.with_dangling_comments(open_parenthesis_comment.map(std::slice::from_ref).unwrap_or_default())
.fmt(f)
} else {
let level = match f.context().node_level() {
NodeLevel::TopLevel | NodeLevel::CompoundStatement => NodeLevel::Expression(None),
saved_level @ (NodeLevel::Expression(_) | NodeLevel::ParenthesizedExpression) => {
saved_level
}
saved_level @ (NodeLevel::Expression(_) | NodeLevel::ParenthesizedExpression) => saved_level,
};

let mut f = WithNodeLevel::new(level, f);
Expand Down Expand Up @@ -164,11 +154,11 @@ impl Format<PyFormatContext<'_>> for MaybeParenthesizeExpression<'_> {
} = self;

let comments = f.context().comments();
let preserve_parentheses = parenthesize.is_optional()
&& is_expression_parenthesized((*expression).into(), f.context().source());
let preserve_parentheses =
parenthesize.is_optional() && is_expression_parenthesized((*expression).into(), f.context().source());

let has_comments = comments.has_leading_comments(*expression)
|| comments.has_trailing_own_line_comments(*expression);
let has_comments =
comments.has_leading_comments(*expression) || comments.has_trailing_own_line_comments(*expression);

// If the expression has comments, we always want to preserve the parentheses. This also
// ensures that we correctly handle parenthesized comments, and don't need to worry about
Expand All @@ -186,55 +176,39 @@ impl Format<PyFormatContext<'_>> for MaybeParenthesizeExpression<'_> {
needs_parentheses
}
}
Parenthesize::Optional
| Parenthesize::IfBreaks
| Parenthesize::IfBreaksOrIfRequired => needs_parentheses,
Parenthesize::Optional | Parenthesize::IfBreaks | Parenthesize::IfBreaksOrIfRequired => needs_parentheses,
};

match needs_parentheses {
OptionalParentheses::Multiline => match parenthesize {
Parenthesize::IfBreaksOrIfRequired => {
parenthesize_if_expands(&expression.format().with_options(Parentheses::Never))
.fmt(f)
}
Parenthesize::IfRequired => {
expression.format().with_options(Parentheses::Never).fmt(f)
parenthesize_if_expands(&expression.format().with_options(Parentheses::Never)).fmt(f)
}
Parenthesize::IfRequired => expression.format().with_options(Parentheses::Never).fmt(f),
Parenthesize::Optional | Parenthesize::IfBreaks => {
if can_omit_optional_parentheses(expression, f.context()) {
optional_parentheses(&expression.format().with_options(Parentheses::Never))
.fmt(f)
optional_parentheses(&expression.format().with_options(Parentheses::Never)).fmt(f)
} else {
parenthesize_if_expands(
&expression.format().with_options(Parentheses::Never),
)
.fmt(f)
parenthesize_if_expands(&expression.format().with_options(Parentheses::Never)).fmt(f)
}
}
},
OptionalParentheses::Never => match parenthesize {
Parenthesize::IfBreaksOrIfRequired => {
parenthesize_if_expands(&expression.format().with_options(Parentheses::Never))
.fmt(f)
parenthesize_if_expands(&expression.format().with_options(Parentheses::Never)).fmt(f)
}

Parenthesize::Optional | Parenthesize::IfBreaks | Parenthesize::IfRequired => {
expression.format().with_options(Parentheses::Never).fmt(f)
}
},
OptionalParentheses::Always => {
expression.format().with_options(Parentheses::Always).fmt(f)
}
OptionalParentheses::Always => expression.format().with_options(Parentheses::Always).fmt(f),
}
}
}

impl NeedsParentheses for Expr {
fn needs_parentheses(
&self,
parent: AnyNodeRef,
context: &PyFormatContext,
) -> OptionalParentheses {
fn needs_parentheses(&self, parent: AnyNodeRef, context: &PyFormatContext) -> OptionalParentheses {
match self {
Expr::BoolOp(expr) => expr.needs_parentheses(parent, context),
Expr::NamedExpr(expr) => expr.needs_parentheses(parent, context),
Expand Down Expand Up @@ -309,12 +283,12 @@ fn can_omit_optional_parentheses(expr: &Expr, context: &PyFormatContext) -> bool
} else {
// Only use the layout if the first or last expression has parentheses of some sort, and
// those parentheses are non-empty.
let first_parenthesized = visitor.first.is_some_and(|first| {
has_parentheses(first, context).is_some_and(|parentheses| parentheses.is_non_empty())
});
let last_parenthesized = visitor.last.is_some_and(|last| {
has_parentheses(last, context).is_some_and(|parentheses| parentheses.is_non_empty())
});
let first_parenthesized = visitor
.first
.is_some_and(|first| has_parentheses(first, context).is_some_and(|parentheses| parentheses.is_non_empty()));
let last_parenthesized = visitor
.last
.is_some_and(|last| has_parentheses(last, context).is_some_and(|parentheses| parentheses.is_non_empty()));
first_parenthesized || last_parenthesized
}
}
Expand Down Expand Up @@ -584,11 +558,7 @@ impl CallChainLayout {

/// Determine whether to actually apply fluent layout in attribute, call and subscript
/// formatting
pub(crate) fn apply_in_node<'a>(
self,
item: impl Into<ExpressionRef<'a>>,
f: &mut PyFormatter,
) -> CallChainLayout {
pub(crate) fn apply_in_node<'a>(self, item: impl Into<ExpressionRef<'a>>, f: &mut PyFormatter) -> CallChainLayout {
match self {
CallChainLayout::Default => {
if f.context().node_level().is_parenthesized() {
Expand Down Expand Up @@ -641,48 +611,31 @@ fn has_parentheses(expr: &Expr, context: &PyFormatContext) -> Option<OwnParenthe
/// that is inherent to the node (e.g., as in `f()`, `[]`, or `{1: 2}`, but not `(a.b.c)`).
///
/// Parentheses are considered to be non-empty if they contain any elements or comments.
pub(crate) fn has_own_parentheses(
expr: &Expr,
context: &PyFormatContext,
) -> Option<OwnParentheses> {
pub(crate) fn has_own_parentheses(expr: &Expr, context: &PyFormatContext) -> Option<OwnParentheses> {
match expr {
// These expressions are always non-empty.
Expr::ListComp(_) | Expr::SetComp(_) | Expr::DictComp(_) | Expr::Subscript(_) => {
Some(OwnParentheses::NonEmpty)
}
Expr::ListComp(_) | Expr::SetComp(_) | Expr::DictComp(_) | Expr::Subscript(_) => Some(OwnParentheses::NonEmpty),

// These expressions must contain _some_ child or trivia token in order to be non-empty.
Expr::List(ast::ExprList { elts, .. })
| Expr::Set(ast::ExprSet { elts, .. })
| Expr::Tuple(ast::ExprTuple { elts, .. }) => {
if !elts.is_empty()
|| context
.comments()
.has_dangling_comments(AnyNodeRef::from(expr))
{
if !elts.is_empty() || context.comments().has_dangling_comments(AnyNodeRef::from(expr)) {
Some(OwnParentheses::NonEmpty)
} else {
Some(OwnParentheses::Empty)
}
}

Expr::Dict(ast::ExprDict { keys, .. }) => {
if !keys.is_empty()
|| context
.comments()
.has_dangling_comments(AnyNodeRef::from(expr))
{
if !keys.is_empty() || context.comments().has_dangling_comments(AnyNodeRef::from(expr)) {
Some(OwnParentheses::NonEmpty)
} else {
Some(OwnParentheses::Empty)
}
}
Expr::Call(ast::ExprCall { arguments, .. }) => {
if !arguments.is_empty()
|| context
.comments()
.has_dangling_comments(AnyNodeRef::from(expr))
{
if !arguments.is_empty() || context.comments().has_dangling_comments(AnyNodeRef::from(expr)) {
Some(OwnParentheses::NonEmpty)
} else {
Some(OwnParentheses::Empty)
Expand Down Expand Up @@ -718,11 +671,9 @@ impl From<ast::Operator> for OperatorPriority {
fn from(value: Operator) -> Self {
match value {
Operator::Add | Operator::Sub => OperatorPriority::Additive,
Operator::Mult
| Operator::MatMult
| Operator::Div
| Operator::Mod
| Operator::FloorDiv => OperatorPriority::Multiplicative,
Operator::Mult | Operator::MatMult | Operator::Div | Operator::Mod | Operator::FloorDiv => {
OperatorPriority::Multiplicative
}
Operator::Pow => OperatorPriority::Exponential,
Operator::LShift | Operator::RShift => OperatorPriority::Shift,
Operator::BitOr => OperatorPriority::BitwiseOr,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
use ruff_formatter::{write, Buffer, FormatResult};
use ruff_python_ast::PatternMatchSingleton;
use crate::prelude::*;
use ruff_python_ast::{Constant, PatternMatchSingleton};

use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter};
use crate::{FormatNodeRule, PyFormatter};

#[derive(Default)]
pub struct FormatPatternMatchSingleton;

impl FormatNodeRule<PatternMatchSingleton> for FormatPatternMatchSingleton {
fn fmt_fields(&self, item: &PatternMatchSingleton, f: &mut PyFormatter) -> FormatResult<()> {
write!(f, [not_yet_implemented_custom_text("None", item)])
match item.value {
Constant::None => text("None").fmt(f),
Constant::Bool(true) => text("True").fmt(f),
Constant::Bool(false) => text("False").fmt(f),
_ => unreachable!(),
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ match x:
y = 0
# case black_test_patma_232
match x:
@@ -108,37 +108,37 @@
@@ -108,7 +108,7 @@
y = 0
# case black_test_patma_058
match x:
Expand All @@ -301,8 +301,7 @@ match x:
y = 0
# case black_test_patma_233
match x:
- case False:
+ case None:
@@ -116,29 +116,29 @@
y = 0
# case black_test_patma_078
match x:
Expand Down Expand Up @@ -460,7 +459,7 @@ match x:
y = 0
# case black_test_patma_233
match x:
case None:
case False:
y = 0
# case black_test_patma_078
match x:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,23 @@ match pattern_comments:
no_comments
):
pass
match pattern_singleton:
case (
# leading 1
# leading 2
None # trailing
# trailing own 1
# trailing own 2
):
pass
case (
True # trailing
):
...
case False:
...
```

## Output
Expand Down Expand Up @@ -285,6 +302,23 @@ match pattern_comments:
match pattern_comments:
case (x as NOT_YET_IMPLEMENTED_PatternMatchAs):
pass
match pattern_singleton:
case (
# leading 1
# leading 2
None # trailing
# trailing own 1
# trailing own 2
):
pass
case (
True # trailing
):
...
case False:
...
```


Expand Down

0 comments on commit 71b142c

Please sign in to comment.