Skip to content

Commit 6b31ed3

Browse files
authored
Merge pull request RustPython#4116 from charliermarsh/charlie/f-string
Avoid creating unused JoinedStr in FStringParser
2 parents bd4b1a1 + 5e480b8 commit 6b31ed3

15 files changed

+587
-753
lines changed

compiler/parser/src/fstring.rs

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::{
44
error::{FStringError, FStringErrorType, ParseError},
55
parser::parse_expression,
66
};
7+
use itertools::Itertools;
78
use std::{iter, mem, str};
89

910
struct FStringParser<'a> {
@@ -105,19 +106,16 @@ impl<'a> FStringParser<'a> {
105106
nested -= 1;
106107
if nested == 0 {
107108
formatted_value_piece.push(next);
108-
spec_constructor.push(
109-
self.expr(ExprKind::FormattedValue {
110-
value: Box::new(
111-
FStringParser::new(
112-
&formatted_value_piece,
113-
Location::default(),
114-
&self.recurse_lvl + 1,
115-
)
116-
.parse()?,
117-
),
118-
conversion: ConversionFlag::None as _,
119-
format_spec: None,
120-
}),
109+
let values = FStringParser::new(
110+
&formatted_value_piece,
111+
Location::default(),
112+
&self.recurse_lvl + 1,
113+
)
114+
.parse()?;
115+
spec_constructor.push(values
116+
.into_iter()
117+
.exactly_one()
118+
.expect("Expected formatted value to produce exactly one expression.")
121119
);
122120
formatted_value_piece.clear();
123121
} else {
@@ -129,11 +127,13 @@ impl<'a> FStringParser<'a> {
129127
}
130128
'{' => {
131129
nested += 1;
132-
spec_constructor.push(self.expr(ExprKind::Constant {
133-
value: constant_piece.to_owned().into(),
134-
kind: None,
135-
}));
136-
constant_piece.clear();
130+
if !constant_piece.is_empty() {
131+
spec_constructor.push(self.expr(ExprKind::Constant {
132+
value: constant_piece.to_owned().into(),
133+
kind: None,
134+
}));
135+
constant_piece.clear();
136+
}
137137
formatted_value_piece.push(next);
138138
formatted_value_piece.push(' ');
139139
}
@@ -144,11 +144,13 @@ impl<'a> FStringParser<'a> {
144144
}
145145
self.chars.next();
146146
}
147-
spec_constructor.push(self.expr(ExprKind::Constant {
148-
value: constant_piece.to_owned().into(),
149-
kind: None,
150-
}));
151-
constant_piece.clear();
147+
if !constant_piece.is_empty() {
148+
spec_constructor.push(self.expr(ExprKind::Constant {
149+
value: constant_piece.to_owned().into(),
150+
kind: None,
151+
}));
152+
constant_piece.clear();
153+
}
152154
if nested > 0 {
153155
return Err(UnclosedLbrace);
154156
}
@@ -241,7 +243,7 @@ impl<'a> FStringParser<'a> {
241243
Err(UnclosedLbrace)
242244
}
243245

244-
fn parse(mut self) -> Result<Expr, FStringErrorType> {
246+
fn parse(mut self) -> Result<Vec<Expr>, FStringErrorType> {
245247
if self.recurse_lvl >= 2 {
246248
return Err(ExpressionNestedTooDeeply);
247249
}
@@ -287,7 +289,7 @@ impl<'a> FStringParser<'a> {
287289
}))
288290
}
289291

290-
Ok(self.expr(ExprKind::JoinedStr { values }))
292+
Ok(values)
291293
}
292294
}
293295

@@ -298,7 +300,7 @@ fn parse_fstring_expr(source: &str) -> Result<Expr, ParseError> {
298300

299301
/// Parse an fstring from a string, located at a certain position in the sourcecode.
300302
/// In case of errors, we will get the location and the error returned.
301-
pub fn parse_located_fstring(source: &str, location: Location) -> Result<Expr, FStringError> {
303+
pub fn parse_located_fstring(source: &str, location: Location) -> Result<Vec<Expr>, FStringError> {
302304
FStringParser::new(source, location, 0)
303305
.parse()
304306
.map_err(|error| FStringError { error, location })
@@ -308,7 +310,7 @@ pub fn parse_located_fstring(source: &str, location: Location) -> Result<Expr, F
308310
mod tests {
309311
use super::*;
310312

311-
fn parse_fstring(source: &str) -> Result<Expr, FStringErrorType> {
313+
fn parse_fstring(source: &str) -> Result<Vec<Expr>, FStringErrorType> {
312314
FStringParser::new(source, Location::default(), 0).parse()
313315
}
314316

compiler/parser/src/snapshots/rustpython_parser__fstring__tests__fstring_parse_selfdocumenting_base.snap

Lines changed: 44 additions & 53 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)