Skip to content

Commit

Permalink
POC: AST node for implicit string concatenation
Browse files Browse the repository at this point in the history
  • Loading branch information
dhruvmanila committed Oct 12, 2023
1 parent 4454fbf commit 7c763c5
Show file tree
Hide file tree
Showing 16 changed files with 1,182 additions and 1,248 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -205,5 +205,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 @@ -647,6 +647,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
1 change: 1 addition & 0 deletions crates/ruff_python_ast/src/comparable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -960,6 +960,7 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
kind: *kind,
value: value.as_str(),
}),
ast::Expr::StringList(_) => todo!(),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/ruff_python_ast/src/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ impl<'a> From<&'a Expr> for ExpressionRef<'a> {
Expr::Tuple(value) => ExpressionRef::Tuple(value),
Expr::Slice(value) => ExpressionRef::Slice(value),
Expr::IpyEscapeCommand(value) => ExpressionRef::IpyEscapeCommand(value),
Expr::StringList(_) => todo!(),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/ruff_python_ast/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ pub fn any_over_expr(expr: &Expr, func: &dyn Fn(&Expr) -> bool) -> bool {
}
Expr::Name(_) | Expr::Constant(_) => false,
Expr::IpyEscapeCommand(_) => false,
Expr::StringList(_) => todo!(),
}
}

Expand Down
2 changes: 2 additions & 0 deletions crates/ruff_python_ast/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4133,6 +4133,7 @@ impl From<Expr> for AnyNode {
Expr::Tuple(node) => AnyNode::ExprTuple(node),
Expr::Slice(node) => AnyNode::ExprSlice(node),
Expr::IpyEscapeCommand(node) => AnyNode::ExprIpyEscapeCommand(node),
Expr::StringList(_) => todo!(),
}
}
}
Expand Down Expand Up @@ -6040,6 +6041,7 @@ impl<'a> From<&'a Expr> for AnyNodeRef<'a> {
Expr::Tuple(node) => AnyNodeRef::ExprTuple(node),
Expr::Slice(node) => AnyNodeRef::ExprSlice(node),
Expr::IpyEscapeCommand(node) => AnyNodeRef::ExprIpyEscapeCommand(node),
Expr::StringList(_) => todo!(),
}
}
}
Expand Down
44 changes: 44 additions & 0 deletions crates/ruff_python_ast/src/nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,8 @@ pub enum Expr {
FString(ExprFString),
#[is(name = "constant_expr")]
Constant(ExprConstant),
#[is(name = "string_list_expr")]
StringList(ExprStringList),
#[is(name = "attribute_expr")]
Attribute(ExprAttribute),
#[is(name = "subscript_expr")]
Expand Down Expand Up @@ -954,6 +956,42 @@ impl From<ExprConstant> for Expr {
}
}

#[derive(Clone, Debug, PartialEq)]
pub struct ExprStringList {
pub range: TextRange,
pub values: Vec<StringType>,
}

impl From<ExprStringList> for Expr {
fn from(payload: ExprStringList) -> Self {
Expr::StringList(payload)
}
}

impl Ranged for ExprStringList {
fn range(&self) -> TextRange {
self.range
}
}

#[derive(Clone, Debug, PartialEq, is_macro::Is)]
pub enum StringType {
Constant(ExprConstant),
FString(ExprFString),
}

impl From<ExprConstant> for StringType {
fn from(payload: ExprConstant) -> Self {
StringType::Constant(payload)
}
}

impl From<ExprFString> for StringType {
fn from(payload: ExprFString) -> Self {
StringType::FString(payload)
}
}

/// See also [Attribute](https://docs.python.org/3/library/ast.html#ast.Attribute)
#[derive(Clone, Debug, PartialEq)]
pub struct ExprAttribute {
Expand Down Expand Up @@ -3058,6 +3096,7 @@ impl Ranged for crate::Expr {
Self::FormattedValue(node) => node.range(),
Self::FString(node) => node.range(),
Self::Constant(node) => node.range(),
Self::StringList(node) => node.range(),
Self::Attribute(node) => node.range(),
Self::Subscript(node) => node.range(),
Self::Starred(node) => node.range(),
Expand Down Expand Up @@ -3363,6 +3402,11 @@ impl From<ExprConstant> for ParenthesizedExpr {
Expr::Constant(payload).into()
}
}
impl From<ExprStringList> for ParenthesizedExpr {
fn from(payload: ExprStringList) -> Self {
Expr::StringList(payload).into()
}
}
impl From<ExprAttribute> for ParenthesizedExpr {
fn from(payload: ExprAttribute) -> Self {
Expr::Attribute(payload).into()
Expand Down
1 change: 1 addition & 0 deletions crates/ruff_python_ast/src/relocate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,5 +202,6 @@ pub fn relocate_expr(expr: &mut Expr, location: TextRange) {
Expr::IpyEscapeCommand(nodes::ExprIpyEscapeCommand { range, .. }) => {
*range = location;
}
Expr::StringList(_) => todo!(),
}
}
1 change: 1 addition & 0 deletions crates/ruff_python_ast/src/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,7 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
}
}
Expr::IpyEscapeCommand(_) => {}
Expr::StringList(_) => todo!(),
}
}

Expand Down
1 change: 1 addition & 0 deletions crates/ruff_python_ast/src/visitor/preorder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ where
Expr::Tuple(expr) => expr.visit_preorder(visitor),
Expr::Slice(expr) => expr.visit_preorder(visitor),
Expr::IpyEscapeCommand(expr) => expr.visit_preorder(visitor),
Expr::StringList(_) => todo!(),
}
}

Expand Down
1 change: 1 addition & 0 deletions crates/ruff_python_codegen/src/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,7 @@ impl<'a> Generator<'a> {
Expr::IpyEscapeCommand(ast::ExprIpyEscapeCommand { kind, value, .. }) => {
self.p(&format!("{kind}{value}"));
}
Expr::StringList(_) => todo!(),
}
}

Expand Down
3 changes: 3 additions & 0 deletions crates/ruff_python_formatter/src/expression/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ impl FormatRule<Expr, PyFormatContext<'_>> for FormatExpr {
Expr::Tuple(expr) => expr.format().fmt(f),
Expr::Slice(expr) => expr.format().fmt(f),
Expr::IpyEscapeCommand(expr) => expr.format().fmt(f),
Expr::StringList(_) => todo!(),
});

let parenthesize = match parentheses {
Expand Down Expand Up @@ -316,6 +317,7 @@ impl NeedsParentheses for Expr {
Expr::Tuple(expr) => expr.needs_parentheses(parent, context),
Expr::Slice(expr) => expr.needs_parentheses(parent, context),
Expr::IpyEscapeCommand(_) => todo!(),
Expr::StringList(_) => todo!(),
}
}
}
Expand Down Expand Up @@ -544,6 +546,7 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> {
| Expr::Name(_)
| Expr::Slice(_) => {}
Expr::IpyEscapeCommand(_) => todo!(),
Expr::StringList(_) => todo!(),
};

walk_expr(self, expr);
Expand Down
33 changes: 21 additions & 12 deletions crates/ruff_python_parser/src/python.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
lexer::{LexicalError, LexicalErrorType},
function::{ArgumentList, parse_arguments, validate_pos_params, validate_arguments},
context::set_context,
string::{StringType, concatenate_strings, parse_fstring_middle, parse_string_literal},
string::{parse_fstring_middle, parse_string_literal},
token::{self, StringKind},
};
use lalrpop_util::ParseError;
Expand Down Expand Up @@ -668,10 +668,10 @@ LiteralPattern: ast::Pattern = {
value: Box::new(value.into()),
range: (location..end_location).into()
}.into(),
<location:@L> <strings:StringLiteral+> <end_location:@R> =>? Ok(ast::PatternMatchValue {
value: Box::new(concatenate_strings(strings, (location..end_location).into())?),
<location:@L> <strings:StringLiteral+> <end_location:@R> => ast::PatternMatchValue {
value: Box::new(ast::ExprStringList { values: strings, range: (location..end_location).into() }.into()),
range: (location..end_location).into()
}.into()),
}.into(),
}

CapturePattern: ast::Pattern = {
Expand Down Expand Up @@ -726,7 +726,10 @@ MappingKey: ast::Expr = {
value: false.into(),
range: (location..end_location).into()
}.into(),
<location:@L> <strings:StringLiteralOrFString+> <end_location:@R> =>? Ok(concatenate_strings(strings, (location..end_location).into())?),
<location:@L> <strings:StringLiteralOrFString+> <end_location:@R> => ast::ExprStringList {
values: strings,
range: (location..end_location).into()
}.into(),
}

MatchMappingEntry: (ast::Expr, ast::Pattern) = {
Expand Down Expand Up @@ -1579,21 +1582,24 @@ SliceOp: Option<ast::ParenthesizedExpr> = {
<location:@L> ":" <e:Test<"all">?> => e,
}

StringLiteralOrFString: StringType = {
StringLiteralOrFString: ast::StringType = {
StringLiteral,
FStringExpr,
};

StringLiteral: StringType = {
<start_location:@L> <string:string> =>? {
StringLiteral: ast::StringType = {
<location:@L> <string:string> <end_location:@R> =>? {
let (source, kind, triple_quoted) = string;
Ok(parse_string_literal(&source, kind, triple_quoted, start_location)?)
Ok(ast::ExprConstant {
value: parse_string_literal(&source, kind, triple_quoted, location)?,
range: (location..end_location).into(),
}.into())
}
};

FStringExpr: StringType = {
FStringExpr: ast::StringType = {
<location:@L> FStringStart <values:FStringMiddlePattern*> FStringEnd <end_location:@R> => {
StringType::FString(ast::ExprFString {
ast::StringType::FString(ast::ExprFString {
values,
implicit_concatenated: false,
range: (location..end_location).into()
Expand Down Expand Up @@ -1677,7 +1683,10 @@ FStringConversion: (TextSize, ast::ConversionFlag) = {
};

Atom<Goal>: ast::ParenthesizedExpr = {
<location:@L> <strings:StringLiteralOrFString+> <end_location:@R> =>? Ok(concatenate_strings(strings, (location..end_location).into())?.into()),
<location:@L> <strings:StringLiteralOrFString+> <end_location:@R> => ast::ExprStringList {
values: strings,
range: (location..end_location).into(),
}.into(),
<location:@L> <value:Constant> <end_location:@R> => ast::ExprConstant {
value,
range: (location..end_location).into(),
Expand Down
Loading

0 comments on commit 7c763c5

Please sign in to comment.