Introduce a new CST element for slice segments (#3195)

This commit is contained in:
Charlie Marsh 2023-02-23 19:49:41 -05:00 committed by GitHub
parent eb15371453
commit 6eaacf96be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 425 additions and 143 deletions

View file

@ -10,7 +10,8 @@ use crate::builders::literal;
use crate::context::ASTFormatContext;
use crate::core::types::Range;
use crate::cst::{
Arguments, Boolop, Cmpop, Comprehension, Expr, ExprKind, Keyword, Operator, Unaryop,
Arguments, Boolop, Cmpop, Comprehension, Expr, ExprKind, Keyword, Operator, SliceIndex,
SliceIndexKind, Unaryop,
};
use crate::format::helpers::{is_self_closing, is_simple_power, is_simple_slice};
use crate::format::numbers::{complex_literal, float_literal, int_literal};
@ -86,15 +87,30 @@ fn format_subscript(
value: &Expr,
slice: &Expr,
) -> FormatResult<()> {
write!(f, [value.format()])?;
write!(f, [text("[")])?;
write!(
f,
[
value.format(),
text("["),
group(&format_args![soft_block_indent(&slice.format())]),
text("]")
]
[group(&format_args![soft_block_indent(&format_with(|f| {
write!(f, [slice.format()])?;
// Apply any dangling comments.
for trivia in &expr.trivia {
if matches!(trivia.relationship, Relationship::Dangling) {
if let TriviaKind::OwnLineComment(range) = trivia.kind {
write!(f, [expand_parent()])?;
write!(f, [hard_line_break()])?;
write!(f, [literal(range)])?;
}
}
}
Ok(())
}))])]
)?;
write!(f, [text("]")])?;
Ok(())
}
@ -187,51 +203,182 @@ fn format_tuple(
fn format_slice(
f: &mut Formatter<ASTFormatContext<'_>>,
expr: &Expr,
lower: Option<&Expr>,
upper: Option<&Expr>,
step: Option<&Expr>,
lower: &SliceIndex,
upper: &SliceIndex,
step: Option<&SliceIndex>,
) -> FormatResult<()> {
// https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#slices
let is_simple = lower.map_or(true, is_simple_slice)
&& upper.map_or(true, is_simple_slice)
&& step.map_or(true, is_simple_slice);
if let Some(lower) = lower {
write!(f, [lower.format()])?;
if !is_simple {
write!(f, [space()])?;
}
}
write!(f, [text(":")])?;
if let Some(upper) = upper {
if !is_simple {
write!(f, [space()])?;
}
write!(f, [upper.format()])?;
if !is_simple && step.is_some() {
write!(f, [space()])?;
}
}
if let Some(step) = step {
if !is_simple && upper.is_some() {
write!(f, [space()])?;
}
write!(f, [text(":")])?;
if !is_simple {
write!(f, [space()])?;
}
write!(f, [step.format()])?;
// // https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#slices
let lower_is_simple = if let SliceIndexKind::Index { value } = &lower.node {
is_simple_slice(value)
} else {
let magic_trailing_colon = expr
.trivia
.iter()
.any(|c| matches!(c.kind, TriviaKind::MagicTrailingColon));
if magic_trailing_colon {
if !is_simple && upper.is_some() {
write!(f, [space()])?;
true
};
let upper_is_simple = if let SliceIndexKind::Index { value } = &upper.node {
is_simple_slice(value)
} else {
true
};
let step_is_simple = step.map_or(true, |step| {
if let SliceIndexKind::Index { value } = &step.node {
is_simple_slice(value)
} else {
true
}
});
let is_simple = lower_is_simple && upper_is_simple && step_is_simple;
write!(
f,
[group(&format_with(|f| {
if let SliceIndexKind::Index { value } = &lower.node {
write!(f, [value.format()])?;
}
// Apply any dangling comments.
for trivia in &lower.trivia {
if matches!(trivia.relationship, Relationship::Dangling) {
if let TriviaKind::OwnLineComment(range) = trivia.kind {
write!(f, [expand_parent()])?;
write!(f, [hard_line_break()])?;
write!(f, [literal(range)])?;
write!(f, [hard_line_break()])?;
}
}
}
if matches!(lower.node, SliceIndexKind::Index { .. }) {
if !is_simple {
write!(f, [space()])?;
}
}
write!(f, [text(":")])?;
// Format any end-of-line comments.
let mut first = true;
for range in lower.trivia.iter().filter_map(|trivia| {
if matches!(trivia.relationship, Relationship::Trailing) {
if let TriviaKind::EndOfLineComment(range) = trivia.kind {
Some(range)
} else {
None
}
} else {
None
}
}) {
if std::mem::take(&mut first) {
write!(f, [line_suffix(&text(" "))])?;
}
write!(f, [line_suffix(&literal(range))])?;
}
if let SliceIndexKind::Index { value } = &upper.node {
if !is_simple {
write!(f, [space()])?;
}
write!(f, [if_group_breaks(&soft_line_break())])?;
write!(f, [value.format()])?;
}
// Apply any dangling comments.
for trivia in &upper.trivia {
if matches!(trivia.relationship, Relationship::Dangling) {
if let TriviaKind::OwnLineComment(range) = trivia.kind {
write!(f, [expand_parent()])?;
write!(f, [hard_line_break()])?;
write!(f, [literal(range)])?;
write!(f, [hard_line_break()])?;
}
}
}
// Format any end-of-line comments.
let mut first = true;
for range in upper.trivia.iter().filter_map(|trivia| {
if matches!(trivia.relationship, Relationship::Trailing) {
if let TriviaKind::EndOfLineComment(range) = trivia.kind {
Some(range)
} else {
None
}
} else {
None
}
}) {
if std::mem::take(&mut first) {
write!(f, [line_suffix(&text(" "))])?;
}
write!(f, [line_suffix(&literal(range))])?;
}
if let Some(step) = step {
if matches!(upper.node, SliceIndexKind::Index { .. }) {
if !is_simple {
write!(f, [space()])?;
}
}
write!(f, [text(":")])?;
if let SliceIndexKind::Index { value } = &step.node {
if !is_simple {
write!(f, [space()])?;
}
write!(f, [if_group_breaks(&soft_line_break())])?;
write!(f, [value.format()])?;
}
// Apply any dangling comments.
for trivia in &step.trivia {
if matches!(trivia.relationship, Relationship::Dangling) {
if let TriviaKind::OwnLineComment(range) = trivia.kind {
write!(f, [expand_parent()])?;
write!(f, [hard_line_break()])?;
write!(f, [literal(range)])?;
write!(f, [hard_line_break()])?;
}
}
}
// Format any end-of-line comments.
let mut first = true;
for range in step.trivia.iter().filter_map(|trivia| {
if matches!(trivia.relationship, Relationship::Trailing) {
if let TriviaKind::EndOfLineComment(range) = trivia.kind {
Some(range)
} else {
None
}
} else {
None
}
}) {
if std::mem::take(&mut first) {
write!(f, [line_suffix(&text(" "))])?;
}
write!(f, [line_suffix(&literal(range))])?;
}
}
Ok(())
}))]
)?;
// Format any end-of-line comments.
let mut first = true;
for range in expr.trivia.iter().filter_map(|trivia| {
if matches!(trivia.relationship, Relationship::Trailing) {
if let TriviaKind::EndOfLineComment(range) = trivia.kind {
Some(range)
} else {
None
}
} else {
None
}
}) {
if std::mem::take(&mut first) {
write!(f, [line_suffix(&text(" "))])?;
}
write!(f, [line_suffix(&literal(range))])?;
}
Ok(())
@ -973,13 +1120,9 @@ impl Format<ASTFormatContext<'_>> for FormatExpr<'_> {
ExprKind::Name { id, .. } => format_name(f, self.item, id),
ExprKind::List { elts, .. } => format_list(f, self.item, elts),
ExprKind::Tuple { elts, .. } => format_tuple(f, self.item, elts),
ExprKind::Slice { lower, upper, step } => format_slice(
f,
self.item,
lower.as_deref(),
upper.as_deref(),
step.as_deref(),
),
ExprKind::Slice { lower, upper, step } => {
format_slice(f, self.item, lower, upper, step.as_ref())
}
_ => {
unimplemented!("Implement ExprKind: {:?}", self.item.node)
}