Skip to content

Commit 897cce8

Browse files
authored
Call pattern formatting (#6594)
1 parent 9bf6713 commit 897cce8

22 files changed

+473
-330
lines changed

crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/match.py

+33
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,36 @@ def foo():
108108
bbbbbbbbaaaaaahhhh == 2
109109
): # another comment
110110
pass
111+
112+
113+
match pattern_comments:
114+
case (
115+
only_trailing # trailing 1
116+
# trailing 2
117+
# trailing 3
118+
):
119+
pass
120+
121+
122+
match pattern_comments:
123+
case ( # leading
124+
only_leading
125+
):
126+
pass
127+
128+
129+
match pattern_comments:
130+
case (
131+
# leading
132+
leading_and_trailing # trailing 1
133+
# trailing 2
134+
# trailing 3
135+
):
136+
pass
137+
138+
139+
match pattern_comments:
140+
case (
141+
no_comments
142+
):
143+
pass

crates/ruff_python_formatter/src/comments/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ impl<'a> Comments<'a> {
388388
}
389389

390390
/// Returns an iterator over the [leading](self#leading-comments) and [trailing comments](self#trailing-comments) of `node`.
391+
#[allow(unused)]
391392
pub(crate) fn leading_trailing_comments<T>(
392393
&self,
393394
node: T,

crates/ruff_python_formatter/src/lib.rs

-34
Original file line numberDiff line numberDiff line change
@@ -152,40 +152,6 @@ pub fn format_node<'a>(
152152
Ok(formatted)
153153
}
154154

155-
pub(crate) struct NotYetImplemented<'a>(AnyNodeRef<'a>);
156-
157-
/// Formats a placeholder for nodes that have not yet been implemented
158-
pub(crate) fn not_yet_implemented<'a, T>(node: T) -> NotYetImplemented<'a>
159-
where
160-
T: Into<AnyNodeRef<'a>>,
161-
{
162-
NotYetImplemented(node.into())
163-
}
164-
165-
impl Format<PyFormatContext<'_>> for NotYetImplemented<'_> {
166-
fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> {
167-
let text = std::format!("NOT_YET_IMPLEMENTED_{:?}", self.0.kind());
168-
169-
f.write_element(FormatElement::Tag(Tag::StartVerbatim(
170-
tag::VerbatimKind::Verbatim {
171-
length: text.text_len(),
172-
},
173-
)))?;
174-
175-
f.write_element(FormatElement::DynamicText {
176-
text: Box::from(text),
177-
})?;
178-
179-
f.write_element(FormatElement::Tag(Tag::EndVerbatim))?;
180-
181-
f.context()
182-
.comments()
183-
.mark_verbatim_node_comments_formatted(self.0);
184-
185-
Ok(())
186-
}
187-
}
188-
189155
pub(crate) struct NotYetImplementedCustomText<'a> {
190156
text: &'static str,
191157
node: AnyNodeRef<'a>,

crates/ruff_python_formatter/src/other/match_case.rs

+51-23
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
use ruff_formatter::{write, Buffer, FormatResult};
2-
use ruff_python_ast::MatchCase;
1+
use ruff_formatter::{format_args, write, Buffer, FormatResult};
2+
use ruff_python_ast::{MatchCase, Pattern, Ranged};
3+
use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer};
4+
use ruff_text_size::TextRange;
35

4-
use crate::comments::{trailing_comments, SourceComment};
5-
use crate::not_yet_implemented_custom_text;
6+
use crate::comments::{leading_comments, trailing_comments, SourceComment};
7+
use crate::expression::parentheses::parenthesized;
68
use crate::prelude::*;
7-
use crate::{FormatNodeRule, PyFormatter};
9+
use crate::{FormatError, FormatNodeRule, PyFormatter};
810

911
#[derive(Default)]
1012
pub struct FormatMatchCase;
@@ -21,24 +23,20 @@ impl FormatNodeRule<MatchCase> for FormatMatchCase {
2123
let comments = f.context().comments().clone();
2224
let dangling_item_comments = comments.dangling_comments(item);
2325

24-
write!(
25-
f,
26-
[
27-
text("case"),
28-
space(),
29-
format_with(|f: &mut PyFormatter| {
30-
let comments = f.context().comments();
31-
32-
for comment in comments.leading_trailing_comments(pattern) {
33-
// This is a lie, but let's go with it.
34-
comment.mark_formatted();
35-
}
36-
37-
// Replace the whole `format_with` with `pattern.format()` once pattern formatting is implemented.
38-
not_yet_implemented_custom_text("NOT_YET_IMPLEMENTED_Pattern", pattern).fmt(f)
39-
}),
40-
]
41-
)?;
26+
write!(f, [text("case"), space()])?;
27+
let leading_pattern_comments = comments.leading_comments(pattern);
28+
if !leading_pattern_comments.is_empty() {
29+
parenthesized(
30+
"(",
31+
&format_args![leading_comments(leading_pattern_comments), pattern.format()],
32+
")",
33+
)
34+
.fmt(f)?;
35+
} else if is_match_case_pattern_parenthesized(item, pattern, f.context())? {
36+
parenthesized("(", &pattern.format(), ")").fmt(f)?;
37+
} else {
38+
pattern.format().fmt(f)?;
39+
}
4240

4341
if let Some(guard) = guard {
4442
write!(f, [space(), text("if"), space(), guard.format()])?;
@@ -63,3 +61,33 @@ impl FormatNodeRule<MatchCase> for FormatMatchCase {
6361
Ok(())
6462
}
6563
}
64+
65+
fn is_match_case_pattern_parenthesized(
66+
case: &MatchCase,
67+
pattern: &Pattern,
68+
context: &PyFormatContext,
69+
) -> FormatResult<bool> {
70+
let mut tokenizer = SimpleTokenizer::new(
71+
context.source(),
72+
TextRange::new(case.range().start(), pattern.range().start()),
73+
)
74+
.skip_trivia();
75+
76+
let case_keyword = tokenizer.next().ok_or(FormatError::syntax_error(
77+
"Expected a `case` keyword, didn't find any token",
78+
))?;
79+
80+
debug_assert_eq!(
81+
case_keyword.kind(),
82+
SimpleTokenKind::Case,
83+
"Expected `case` keyword but at {case_keyword:?}"
84+
);
85+
86+
match tokenizer.next() {
87+
Some(left_paren) => {
88+
debug_assert_eq!(left_paren.kind(), SimpleTokenKind::LParen);
89+
Ok(true)
90+
}
91+
None => Ok(false),
92+
}
93+
}
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1-
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter};
21
use ruff_formatter::{write, Buffer, FormatResult};
32
use ruff_python_ast::PatternMatchAs;
43

4+
use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter};
5+
56
#[derive(Default)]
67
pub struct FormatPatternMatchAs;
78

89
impl FormatNodeRule<PatternMatchAs> for FormatPatternMatchAs {
910
fn fmt_fields(&self, item: &PatternMatchAs, f: &mut PyFormatter) -> FormatResult<()> {
10-
write!(f, [not_yet_implemented(item)])
11+
write!(
12+
f,
13+
[not_yet_implemented_custom_text(
14+
"x as NOT_YET_IMPLEMENTED_PatternMatchAs",
15+
item
16+
)]
17+
)
1118
}
1219
}
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1-
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter};
21
use ruff_formatter::{write, Buffer, FormatResult};
32
use ruff_python_ast::PatternMatchClass;
43

4+
use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter};
5+
56
#[derive(Default)]
67
pub struct FormatPatternMatchClass;
78

89
impl FormatNodeRule<PatternMatchClass> for FormatPatternMatchClass {
910
fn fmt_fields(&self, item: &PatternMatchClass, f: &mut PyFormatter) -> FormatResult<()> {
10-
write!(f, [not_yet_implemented(item)])
11+
write!(
12+
f,
13+
[not_yet_implemented_custom_text(
14+
"NOT_YET_IMPLEMENTED_PatternMatchClass(0, 0)",
15+
item
16+
)]
17+
)
1118
}
1219
}
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1-
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter};
21
use ruff_formatter::{write, Buffer, FormatResult};
32
use ruff_python_ast::PatternMatchMapping;
43

4+
use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter};
5+
56
#[derive(Default)]
67
pub struct FormatPatternMatchMapping;
78

89
impl FormatNodeRule<PatternMatchMapping> for FormatPatternMatchMapping {
910
fn fmt_fields(&self, item: &PatternMatchMapping, f: &mut PyFormatter) -> FormatResult<()> {
10-
write!(f, [not_yet_implemented(item)])
11+
write!(
12+
f,
13+
[not_yet_implemented_custom_text(
14+
"{\"NOT_YET_IMPLEMENTED_PatternMatchMapping\": _, 2: _}",
15+
item
16+
)]
17+
)
1118
}
1219
}
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1-
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter};
21
use ruff_formatter::{write, Buffer, FormatResult};
32
use ruff_python_ast::PatternMatchOr;
43

4+
use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter};
5+
56
#[derive(Default)]
67
pub struct FormatPatternMatchOr;
78

89
impl FormatNodeRule<PatternMatchOr> for FormatPatternMatchOr {
910
fn fmt_fields(&self, item: &PatternMatchOr, f: &mut PyFormatter) -> FormatResult<()> {
10-
write!(f, [not_yet_implemented(item)])
11+
write!(
12+
f,
13+
[not_yet_implemented_custom_text(
14+
"NOT_YET_IMPLEMENTED_PatternMatchOf | (y)",
15+
item
16+
)]
17+
)
1118
}
1219
}
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1-
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter};
21
use ruff_formatter::{write, Buffer, FormatResult};
32
use ruff_python_ast::PatternMatchSequence;
43

4+
use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter};
5+
56
#[derive(Default)]
67
pub struct FormatPatternMatchSequence;
78

89
impl FormatNodeRule<PatternMatchSequence> for FormatPatternMatchSequence {
910
fn fmt_fields(&self, item: &PatternMatchSequence, f: &mut PyFormatter) -> FormatResult<()> {
10-
write!(f, [not_yet_implemented(item)])
11+
write!(
12+
f,
13+
[not_yet_implemented_custom_text(
14+
"[NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]",
15+
item
16+
)]
17+
)
1118
}
1219
}
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter};
21
use ruff_formatter::{write, Buffer, FormatResult};
32
use ruff_python_ast::PatternMatchSingleton;
43

4+
use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter};
5+
56
#[derive(Default)]
67
pub struct FormatPatternMatchSingleton;
78

89
impl FormatNodeRule<PatternMatchSingleton> for FormatPatternMatchSingleton {
910
fn fmt_fields(&self, item: &PatternMatchSingleton, f: &mut PyFormatter) -> FormatResult<()> {
10-
write!(f, [not_yet_implemented(item)])
11+
write!(f, [not_yet_implemented_custom_text("None", item)])
1112
}
1213
}
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1-
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter};
21
use ruff_formatter::{write, Buffer, FormatResult};
32
use ruff_python_ast::PatternMatchStar;
43

4+
use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter};
5+
56
#[derive(Default)]
67
pub struct FormatPatternMatchStar;
78

89
impl FormatNodeRule<PatternMatchStar> for FormatPatternMatchStar {
910
fn fmt_fields(&self, item: &PatternMatchStar, f: &mut PyFormatter) -> FormatResult<()> {
10-
write!(f, [not_yet_implemented(item)])
11+
write!(
12+
f,
13+
[not_yet_implemented_custom_text(
14+
"*NOT_YET_IMPLEMENTED_PatternMatchStar",
15+
item
16+
)]
17+
)
1118
}
1219
}
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
1-
use ruff_python_ast::PatternMatchValue;
2-
31
use ruff_formatter::{write, Buffer, FormatResult};
2+
use ruff_python_ast::PatternMatchValue;
43

5-
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter};
4+
use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter};
65

76
#[derive(Default)]
87
pub struct FormatPatternMatchValue;
98

109
impl FormatNodeRule<PatternMatchValue> for FormatPatternMatchValue {
1110
fn fmt_fields(&self, item: &PatternMatchValue, f: &mut PyFormatter) -> FormatResult<()> {
12-
write!(f, [not_yet_implemented(item)])
11+
write!(
12+
f,
13+
[not_yet_implemented_custom_text(
14+
"\"NOT_YET_IMPLEMENTED_PatternMatchValue\"",
15+
item
16+
)]
17+
)
1318
}
1419
}

crates/ruff_python_formatter/src/statement/stmt_match.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,11 @@ impl FormatNodeRule<StmtMatch> for FormatStmtMatch {
5151
write!(
5252
f,
5353
[block_indent(&format_args!(
54-
&leading_alternate_branch_comments(
54+
leading_alternate_branch_comments(
5555
comments.leading_comments(case),
5656
last_case.body.last(),
5757
),
58-
&case.format()
58+
case.format()
5959
))]
6060
)?;
6161
last_case = case;

0 commit comments

Comments
 (0)