Skip to content

Commit f8da501

Browse files
committed
Clean up FStringParser
1 parent b1db1be commit f8da501

File tree

1 file changed

+61
-67
lines changed

1 file changed

+61
-67
lines changed

compiler/parser/src/fstring.rs

Lines changed: 61 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -6,63 +6,72 @@ use crate::{
66
};
77
use std::{iter, mem, str};
88

9-
struct FStringParser {
9+
struct FStringParser<'a> {
10+
source: iter::Peekable<str::Chars<'a>>,
1011
str_start: Location,
1112
str_end: Location,
1213
}
1314

14-
impl FStringParser {
15-
fn new(str_start: Location, str_end: Location) -> Self {
16-
Self { str_start, str_end }
15+
impl<'a> FStringParser<'a> {
16+
fn new(source: &'a str, str_start: Location, str_end: Location) -> Self {
17+
Self {
18+
source: source.chars().peekable(),
19+
str_start,
20+
str_end,
21+
}
22+
}
23+
24+
fn next_char(&mut self) -> Option<char> {
25+
self.source.next()
26+
}
27+
28+
fn peek(&mut self) -> Option<&char> {
29+
self.source.peek()
1730
}
1831

1932
#[inline]
2033
fn expr(&self, node: ExprKind) -> Expr {
2134
Expr::new(self.str_start, self.str_end, node)
2235
}
2336

24-
fn parse_formatted_value<'a>(
25-
&mut self,
26-
mut chars: iter::Peekable<str::Chars<'a>>,
27-
nested: u8,
28-
) -> Result<(Vec<Expr>, iter::Peekable<str::Chars<'a>>), FStringErrorType> {
37+
fn parse_formatted_value(&mut self, nested: u8) -> Result<Vec<Expr>, FStringErrorType> {
2938
let mut expression = String::new();
3039
let mut spec = None;
3140
let mut delims = Vec::new();
3241
let mut conversion = ConversionFlag::None;
3342
let mut self_documenting = false;
3443
let mut trailing_seq = String::new();
3544

36-
while let Some(ch) = chars.next() {
45+
while let Some(ch) = self.next_char() {
3746
match ch {
3847
// can be integrated better with the remainign code, but as a starting point ok
3948
// in general I would do here a tokenizing of the fstrings to omit this peeking.
40-
'!' if chars.peek() == Some(&'=') => {
49+
'!' if self.peek() == Some(&'=') => {
4150
expression.push_str("!=");
42-
chars.next();
51+
self.next_char();
4352
}
4453

45-
'=' if chars.peek() == Some(&'=') => {
54+
'=' if self.peek() == Some(&'=') => {
4655
expression.push_str("==");
47-
chars.next();
56+
self.next_char();
4857
}
4958

50-
'>' if chars.peek() == Some(&'=') => {
59+
'>' if self.peek() == Some(&'=') => {
5160
expression.push_str(">=");
52-
chars.next();
61+
self.next_char();
5362
}
5463

55-
'<' if chars.peek() == Some(&'=') => {
64+
'<' if self.peek() == Some(&'=') => {
5665
expression.push_str("<=");
57-
chars.next();
66+
self.next_char();
5867
}
5968

60-
'!' if delims.is_empty() && chars.peek() != Some(&'=') => {
69+
'!' if delims.is_empty() && self.peek() != Some(&'=') => {
6170
if expression.trim().is_empty() {
6271
return Err(EmptyExpression);
6372
}
6473

65-
conversion = match chars.next() {
74+
conversion = match self.next_char() {
6675
Some('s') => ConversionFlag::Str,
6776
Some('a') => ConversionFlag::Ascii,
6877
Some('r') => ConversionFlag::Repr,
@@ -82,7 +91,7 @@ impl FStringParser {
8291
}
8392
};
8493

85-
if let Some(&peek) = chars.peek() {
94+
if let Some(&peek) = self.peek() {
8695
if peek != '}' && peek != ':' {
8796
return Err(if expression.trim().is_empty() {
8897
EmptyExpression
@@ -101,17 +110,16 @@ impl FStringParser {
101110

102111
// match a python 3.8 self documenting expression
103112
// format '{' PYTHON_EXPRESSION '=' FORMAT_SPECIFIER? '}'
104-
'=' if chars.peek() != Some(&'=') && delims.is_empty() => {
113+
'=' if self.peek() != Some(&'=') && delims.is_empty() => {
105114
self_documenting = true;
106115
}
107116

108117
':' if delims.is_empty() => {
109-
let (parsed_spec, remaining_chars) = self.parse_spec(chars, nested)?;
118+
let parsed_spec = self.parse_spec(nested)?;
110119

111120
spec = Some(Box::new(self.expr(ExprKind::JoinedStr {
112121
values: parsed_spec,
113122
})));
114-
chars = remaining_chars;
115123
}
116124
'(' | '{' | '[' => {
117125
expression.push(ch);
@@ -194,21 +202,21 @@ impl FStringParser {
194202
}),
195203
]
196204
};
197-
return Ok((ret, chars));
205+
return Ok(ret);
198206
}
199207
'"' | '\'' => {
200208
expression.push(ch);
201-
let mut string_ended = false;
202-
for next in &mut chars {
203-
expression.push(next);
204-
if next == ch {
205-
string_ended = true;
206-
break;
209+
loop {
210+
match self.next_char() {
211+
Some(c) => {
212+
expression.push(c);
213+
if c == ch {
214+
break;
215+
}
216+
}
217+
None => return Err(UnterminatedString),
207218
}
208219
}
209-
if !string_ended {
210-
return Err(UnterminatedString);
211-
}
212220
}
213221
' ' if self_documenting => {
214222
trailing_seq.push(ch);
@@ -230,14 +238,10 @@ impl FStringParser {
230238
})
231239
}
232240

233-
fn parse_spec<'a>(
234-
&mut self,
235-
mut chars: iter::Peekable<str::Chars<'a>>,
236-
nested: u8,
237-
) -> Result<(Vec<Expr>, iter::Peekable<str::Chars<'a>>), FStringErrorType> {
241+
fn parse_spec(&mut self, nested: u8) -> Result<Vec<Expr>, FStringErrorType> {
238242
let mut spec_constructor = Vec::new();
239243
let mut constant_piece = String::new();
240-
while let Some(&next) = chars.peek() {
244+
while let Some(&next) = self.peek() {
241245
match next {
242246
'{' => {
243247
if !constant_piece.is_empty() {
@@ -247,9 +251,8 @@ impl FStringParser {
247251
}));
248252
constant_piece.clear();
249253
}
250-
let (parsed_expr, remaining_chars) = self.parse(chars, nested + 1)?;
254+
let parsed_expr = self.parse(nested + 1)?;
251255
spec_constructor.extend(parsed_expr);
252-
chars = remaining_chars;
253256
continue;
254257
}
255258
'}' => {
@@ -259,7 +262,7 @@ impl FStringParser {
259262
constant_piece.push(next);
260263
}
261264
}
262-
chars.next();
265+
self.next_char();
263266
}
264267
if !constant_piece.is_empty() {
265268
spec_constructor.push(self.expr(ExprKind::Constant {
@@ -268,29 +271,25 @@ impl FStringParser {
268271
}));
269272
constant_piece.clear();
270273
}
271-
Ok((spec_constructor, chars))
274+
Ok(spec_constructor)
272275
}
273276

274-
fn parse<'a>(
275-
&mut self,
276-
mut chars: iter::Peekable<str::Chars<'a>>,
277-
nested: u8,
278-
) -> Result<(Vec<Expr>, iter::Peekable<str::Chars<'a>>), FStringErrorType> {
277+
fn parse(&mut self, nested: u8) -> Result<Vec<Expr>, FStringErrorType> {
279278
if nested >= 2 {
280279
return Err(ExpressionNestedTooDeeply);
281280
}
282281

283282
let mut content = String::new();
284283
let mut values = vec![];
285284

286-
while let Some(&ch) = chars.peek() {
285+
while let Some(&ch) = self.peek() {
287286
match ch {
288287
'{' => {
289-
chars.next();
288+
self.next_char();
290289
if nested == 0 {
291-
match chars.peek() {
290+
match self.peek() {
292291
Some('{') => {
293-
chars.next();
292+
self.next_char();
294293
content.push('{');
295294
continue;
296295
}
@@ -305,26 +304,24 @@ impl FStringParser {
305304
}));
306305
}
307306

308-
let (parsed_values, remaining_chars) =
309-
self.parse_formatted_value(chars, nested)?;
307+
let parsed_values = self.parse_formatted_value(nested)?;
310308
values.extend(parsed_values);
311-
chars = remaining_chars;
312309
}
313310
'}' => {
314311
if nested > 0 {
315312
break;
316313
}
317-
chars.next();
318-
if let Some('}') = chars.peek() {
319-
chars.next();
314+
self.next_char();
315+
if let Some('}') = self.peek() {
316+
self.next_char();
320317
content.push('}');
321318
} else {
322319
return Err(SingleRbrace);
323320
}
324321
}
325322
_ => {
326323
content.push(ch);
327-
chars.next();
324+
self.next_char();
328325
}
329326
}
330327
}
@@ -336,7 +333,7 @@ impl FStringParser {
336333
}))
337334
}
338335

339-
Ok((values, chars))
336+
Ok(values)
340337
}
341338
}
342339

@@ -352,9 +349,8 @@ pub fn parse_located_fstring(
352349
start: Location,
353350
end: Location,
354351
) -> Result<Vec<Expr>, FStringError> {
355-
FStringParser::new(start, end)
356-
.parse(source.chars().peekable(), 0)
357-
.map(|(e, _)| e)
352+
FStringParser::new(source, start, end)
353+
.parse(0)
358354
.map_err(|error| FStringError {
359355
error,
360356
location: start,
@@ -366,9 +362,7 @@ mod tests {
366362
use super::*;
367363

368364
fn parse_fstring(source: &str) -> Result<Vec<Expr>, FStringErrorType> {
369-
FStringParser::new(Location::default(), Location::default())
370-
.parse(source.chars().peekable(), 0)
371-
.map(|(e, _)| e)
365+
FStringParser::new(source, Location::default(), Location::default()).parse(0)
372366
}
373367

374368
#[test]

0 commit comments

Comments
 (0)