Skip to content

Commit

Permalink
New AST node for implicit string concatenation
Browse files Browse the repository at this point in the history
  • Loading branch information
dhruvmanila committed Oct 20, 2023
1 parent 7111576 commit 56e27ac
Show file tree
Hide file tree
Showing 16 changed files with 8,274 additions and 7,738 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -209,5 +209,6 @@ fn is_allowed_value(expr: &Expr) -> bool {
| Expr::Starred(_)
| Expr::Slice(_)
| Expr::IpyEscapeCommand(_) => false,
Expr::StringList(_) => todo!(),
}
}
1 change: 1 addition & 0 deletions crates/ruff_linter/src/rules/ruff/rules/unreachable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,7 @@ impl<'stmt> BasicBlocksBuilder<'stmt> {
| Expr::Yield(_)
| Expr::YieldFrom(_) => self.unconditional_next_block(after),
Expr::IpyEscapeCommand(_) => todo!(),
Expr::StringList(_) => todo!(),
}
}
// The tough branches are done, here is an easy one.
Expand Down
84 changes: 62 additions & 22 deletions crates/ruff_python_ast/src/comparable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -644,17 +644,42 @@ pub struct ExprFString<'a> {
values: Vec<ComparableExpr<'a>>,
}

impl<'a> From<&'a ast::ExprFString> for ExprFString<'a> {
fn from(fstring: &'a ast::ExprFString) -> Self {
Self {
values: fstring.values.iter().map(Into::into).collect(),
}
}
}

#[derive(Debug, PartialEq, Eq, Hash)]
pub struct ExprStringLiteral<'a> {
value: &'a str,
unicode: &'a bool,
}

impl<'a> From<&'a ast::ExprStringLiteral> for ExprStringLiteral<'a> {
fn from(string_literal: &'a ast::ExprStringLiteral) -> Self {
Self {
value: string_literal.value.as_ref(),
unicode: &string_literal.unicode,
}
}
}

#[derive(Debug, PartialEq, Eq, Hash)]
pub struct ExprBytesLiteral<'a> {
value: &'a [u8],
}

impl<'a> From<&'a ast::ExprBytesLiteral> for ExprBytesLiteral<'a> {
fn from(bytes_literal: &'a ast::ExprBytesLiteral) -> Self {
Self {
value: bytes_literal.value.as_ref(),
}
}
}

#[derive(Debug, PartialEq, Eq, Hash)]
pub struct ExprNumberLiteral<'a> {
value: ComparableNumber<'a>,
Expand All @@ -665,6 +690,34 @@ pub struct ExprBoolLiteral<'a> {
value: &'a bool,
}

#[derive(Debug, PartialEq, Eq, Hash)]
pub enum ComparableStringType<'a> {
String(ExprStringLiteral<'a>),
Bytes(ExprBytesLiteral<'a>),
FString(ExprFString<'a>),
}

impl<'a> From<&'a ast::StringType> for ComparableStringType<'a> {
fn from(string_type: &'a ast::StringType) -> Self {
match string_type {
ast::StringType::String(value) => Self::String(value.into()),
ast::StringType::Bytes(value) => Self::Bytes(value.into()),
ast::StringType::FString(value) => Self::FString(value.into()),
}
}
}

impl<'a> From<&'a Box<ast::StringType>> for Box<ComparableStringType<'a>> {
fn from(string_type: &'a Box<ast::StringType>) -> Self {
Box::new((string_type.as_ref()).into())
}
}

#[derive(Debug, PartialEq, Eq, Hash)]
pub struct ExprStringList<'a> {
values: Vec<ComparableStringType<'a>>,
}

#[derive(Debug, PartialEq, Eq, Hash)]
pub struct ExprAttribute<'a> {
value: Box<ComparableExpr<'a>>,
Expand Down Expand Up @@ -737,6 +790,7 @@ pub enum ComparableExpr<'a> {
BoolLiteral(ExprBoolLiteral<'a>),
NoneLiteral,
EllispsisLiteral,
StringList(ExprStringList<'a>),
Attribute(ExprAttribute<'a>),
Subscript(ExprSubscript<'a>),
Starred(ExprStarred<'a>),
Expand Down Expand Up @@ -903,28 +957,9 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
debug_text: debug_text.as_ref(),
format_spec: format_spec.as_ref().map(Into::into),
}),
ast::Expr::FString(ast::ExprFString {
values,
implicit_concatenated: _,
range: _,
}) => Self::FString(ExprFString {
values: values.iter().map(Into::into).collect(),
}),
ast::Expr::StringLiteral(ast::ExprStringLiteral {
value,
// Compare strings based on resolved value, not representation (i.e., ignore whether
// the string was implicitly concatenated).
implicit_concatenated: _,
unicode,
range: _,
}) => Self::StringLiteral(ExprStringLiteral { value, unicode }),
ast::Expr::BytesLiteral(ast::ExprBytesLiteral {
value,
// Compare bytes based on resolved value, not representation (i.e., ignore whether
// the bytes was implicitly concatenated).
implicit_concatenated: _,
range: _,
}) => Self::BytesLiteral(ExprBytesLiteral { value }),
ast::Expr::FString(fstring) => Self::FString(fstring.into()),
ast::Expr::StringLiteral(string_literal) => Self::StringLiteral(string_literal.into()),
ast::Expr::BytesLiteral(bytes_literal) => Self::BytesLiteral(bytes_literal.into()),
ast::Expr::NumberLiteral(ast::ExprNumberLiteral { value, range: _ }) => {
Self::NumberLiteral(ExprNumberLiteral {
value: value.into(),
Expand All @@ -935,6 +970,11 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
}
ast::Expr::NoneLiteral(_) => Self::NoneLiteral,
ast::Expr::EllipsisLiteral(_) => Self::EllispsisLiteral,
ast::Expr::StringList(ast::ExprStringList { values, .. }) => {
Self::StringList(ExprStringList {
values: values.iter().map(Into::into).collect(),
})
}
ast::Expr::Attribute(ast::ExprAttribute {
value,
attr,
Expand Down
9 changes: 9 additions & 0 deletions crates/ruff_python_ast/src/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub enum ExpressionRef<'a> {
BooleanLiteral(&'a ast::ExprBooleanLiteral),
NoneLiteral(&'a ast::ExprNoneLiteral),
EllipsisLiteral(&'a ast::ExprEllipsisLiteral),
StringList(&'a ast::ExprStringList),
Attribute(&'a ast::ExprAttribute),
Subscript(&'a ast::ExprSubscript),
Starred(&'a ast::ExprStarred),
Expand Down Expand Up @@ -75,6 +76,7 @@ impl<'a> From<&'a Expr> for ExpressionRef<'a> {
Expr::BooleanLiteral(value) => ExpressionRef::BooleanLiteral(value),
Expr::NoneLiteral(value) => ExpressionRef::NoneLiteral(value),
Expr::EllipsisLiteral(value) => ExpressionRef::EllipsisLiteral(value),
Expr::StringList(value) => ExpressionRef::StringList(value),
Expr::Attribute(value) => ExpressionRef::Attribute(value),
Expr::Subscript(value) => ExpressionRef::Subscript(value),
Expr::Starred(value) => ExpressionRef::Starred(value),
Expand Down Expand Up @@ -212,6 +214,11 @@ impl<'a> From<&'a ast::ExprEllipsisLiteral> for ExpressionRef<'a> {
Self::EllipsisLiteral(value)
}
}
impl<'a> From<&'a ast::ExprStringList> for ExpressionRef<'a> {
fn from(value: &'a ast::ExprStringList) -> Self {
Self::StringList(value)
}
}
impl<'a> From<&'a ast::ExprAttribute> for ExpressionRef<'a> {
fn from(value: &'a ast::ExprAttribute) -> Self {
Self::Attribute(value)
Expand Down Expand Up @@ -283,6 +290,7 @@ impl<'a> From<ExpressionRef<'a>> for AnyNodeRef<'a> {
ExpressionRef::EllipsisLiteral(expression) => {
AnyNodeRef::ExprEllipsisLiteral(expression)
}
ExpressionRef::StringList(expression) => AnyNodeRef::ExprStringList(expression),
ExpressionRef::Attribute(expression) => AnyNodeRef::ExprAttribute(expression),
ExpressionRef::Subscript(expression) => AnyNodeRef::ExprSubscript(expression),
ExpressionRef::Starred(expression) => AnyNodeRef::ExprStarred(expression),
Expand Down Expand Up @@ -325,6 +333,7 @@ impl Ranged for ExpressionRef<'_> {
ExpressionRef::BooleanLiteral(expression) => expression.range(),
ExpressionRef::NoneLiteral(expression) => expression.range(),
ExpressionRef::EllipsisLiteral(expression) => expression.range(),
ExpressionRef::StringList(expression) => expression.range(),
ExpressionRef::Attribute(expression) => expression.range(),
ExpressionRef::Subscript(expression) => expression.range(),
ExpressionRef::Starred(expression) => expression.range(),
Expand Down
12 changes: 12 additions & 0 deletions crates/ruff_python_ast/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,9 @@ pub fn any_over_expr(expr: &Expr, func: &dyn Fn(&Expr) -> bool) -> bool {
.as_ref()
.is_some_and(|value| any_over_expr(value, func))
}
Expr::StringList(ast::ExprStringList { values, range: _ }) => values
.iter()
.any(|string_type| any_over_string_type(string_type, func)),
Expr::Name(_)
| Expr::StringLiteral(_)
| Expr::BytesLiteral(_)
Expand All @@ -265,6 +268,15 @@ pub fn any_over_expr(expr: &Expr, func: &dyn Fn(&Expr) -> bool) -> bool {
}
}

pub fn any_over_string_type(string_type: &ast::StringType, func: &dyn Fn(&Expr) -> bool) -> bool {
match string_type {
ast::StringType::FString(ast::ExprFString { values, .. }) => {
values.iter().any(|expr| any_over_expr(expr, func))
}
ast::StringType::String(_) | ast::StringType::Bytes(_) => false,
}
}

pub fn any_over_type_param(type_param: &TypeParam, func: &dyn Fn(&Expr) -> bool) -> bool {
match type_param {
TypeParam::TypeVar(ast::TypeParamTypeVar { bound, .. }) => bound
Expand Down
Loading

0 comments on commit 56e27ac

Please sign in to comment.