@@ -67,25 +67,35 @@ impl FStringParser {
67
67
Some ( 'a' ) => ConversionFlag :: Ascii ,
68
68
Some ( 'r' ) => ConversionFlag :: Repr ,
69
69
Some ( _) => {
70
- return Err ( InvalidConversionFlag ) ;
70
+ return Err ( if expression[ 1 ..] . trim ( ) . is_empty ( ) {
71
+ EmptyExpression
72
+ } else {
73
+ InvalidConversionFlag
74
+ } ) ;
71
75
}
72
76
None => {
73
- return Err ( ExpectedRbrace ) ;
77
+ return Err ( if expression[ 1 ..] . trim ( ) . is_empty ( ) {
78
+ EmptyExpression
79
+ } else {
80
+ UnclosedLbrace
81
+ } ) ;
74
82
}
75
83
} ;
76
84
77
85
if let Some ( & peek) = chars. peek ( ) {
78
86
if peek != '}' && peek != ':' {
79
- if expression[ 1 ..] . trim ( ) . is_empty ( ) {
80
- return Err ( EmptyExpression ) ;
87
+ return Err ( if expression[ 1 ..] . trim ( ) . is_empty ( ) {
88
+ EmptyExpression
81
89
} else {
82
- return Err ( ExpectedRbrace ) ;
83
- }
90
+ UnclosedLbrace
91
+ } ) ;
84
92
}
85
- } else if expression[ 1 ..] . trim ( ) . is_empty ( ) {
86
- return Err ( EmptyExpression ) ;
87
93
} else {
88
- return Err ( ExpectedRbrace ) ;
94
+ return Err ( if expression[ 1 ..] . trim ( ) . is_empty ( ) {
95
+ EmptyExpression
96
+ } else {
97
+ UnclosedLbrace
98
+ } ) ;
89
99
}
90
100
}
91
101
@@ -108,22 +118,42 @@ impl FStringParser {
108
118
delims. push ( ch) ;
109
119
}
110
120
')' => {
111
- if delims. pop ( ) != Some ( '(' ) {
112
- return Err ( MismatchedDelimiter ) ;
121
+ let last_delim = delims. pop ( ) ;
122
+ match last_delim {
123
+ Some ( '(' ) => {
124
+ expression. push ( ch) ;
125
+ }
126
+ Some ( c) => {
127
+ return Err ( MismatchedDelimiter ( c, ')' ) ) ;
128
+ }
129
+ None => {
130
+ return Err ( Unmatched ( ')' ) ) ;
131
+ }
113
132
}
114
- expression. push ( ch) ;
115
133
}
116
134
']' => {
117
- if delims. pop ( ) != Some ( '[' ) {
118
- return Err ( MismatchedDelimiter ) ;
135
+ let last_delim = delims. pop ( ) ;
136
+ match last_delim {
137
+ Some ( '[' ) => {
138
+ expression. push ( ch) ;
139
+ }
140
+ Some ( c) => {
141
+ return Err ( MismatchedDelimiter ( c, ']' ) ) ;
142
+ }
143
+ None => {
144
+ return Err ( Unmatched ( ']' ) ) ;
145
+ }
119
146
}
120
- expression. push ( ch) ;
121
147
}
122
148
'}' if !delims. is_empty ( ) => {
123
- if delims. pop ( ) != Some ( '{' ) {
124
- return Err ( MismatchedDelimiter ) ;
149
+ let last_delim = delims. pop ( ) ;
150
+ match last_delim {
151
+ Some ( '{' ) => {
152
+ expression. push ( ch) ;
153
+ }
154
+ Some ( c) => return Err ( MismatchedDelimiter ( c, '}' ) ) ,
155
+ None => { }
125
156
}
126
- expression. push ( ch) ;
127
157
}
128
158
'}' => {
129
159
if expression[ 1 ..] . trim ( ) . is_empty ( ) {
@@ -171,26 +201,36 @@ impl FStringParser {
171
201
}
172
202
'"' | '\'' => {
173
203
expression. push ( ch) ;
204
+ let mut string_ended = false ;
174
205
for next in & mut chars {
175
206
expression. push ( next) ;
176
207
if next == ch {
208
+ string_ended = true ;
177
209
break ;
178
210
}
179
211
}
212
+ if !string_ended {
213
+ return Err ( UnterminatedString ) ;
214
+ }
180
215
}
181
216
' ' if self_documenting => {
182
217
trailing_seq. push ( ch) ;
183
218
}
219
+ '\\' => return Err ( ExpressionCannotInclude ( '\\' ) ) ,
184
220
_ => {
185
221
if self_documenting {
186
- return Err ( ExpectedRbrace ) ;
222
+ return Err ( UnclosedLbrace ) ;
187
223
}
188
224
189
225
expression. push ( ch) ;
190
226
}
191
227
}
192
228
}
193
- Err ( UnclosedLbrace )
229
+ Err ( if expression[ 1 ..] . trim ( ) . is_empty ( ) {
230
+ EmptyExpression
231
+ } else {
232
+ UnclosedLbrace
233
+ } )
194
234
}
195
235
196
236
fn parse_spec < ' a > (
@@ -251,10 +291,14 @@ impl FStringParser {
251
291
'{' => {
252
292
chars. next ( ) ;
253
293
if nested == 0 {
254
- if let Some ( '{' ) = chars. peek ( ) {
255
- chars. next ( ) ;
256
- content. push ( '{' ) ;
257
- continue ;
294
+ match chars. peek ( ) {
295
+ Some ( '{' ) => {
296
+ chars. next ( ) ;
297
+ content. push ( '{' ) ;
298
+ continue ;
299
+ }
300
+ None => return Err ( UnclosedLbrace ) ,
301
+ _ => { }
258
302
}
259
303
}
260
304
if !content. is_empty ( ) {
@@ -278,7 +322,7 @@ impl FStringParser {
278
322
chars. next ( ) ;
279
323
content. push ( '}' ) ;
280
324
} else {
281
- return Err ( UnopenedRbrace ) ;
325
+ return Err ( SingleRbrace ) ;
282
326
}
283
327
}
284
328
_ => {
@@ -385,9 +429,9 @@ mod tests {
385
429
386
430
#[ test]
387
431
fn test_parse_invalid_fstring ( ) {
388
- assert_eq ! ( parse_fstring( "{5!a" ) , Err ( ExpectedRbrace ) ) ;
389
- assert_eq ! ( parse_fstring( "{5!a1}" ) , Err ( ExpectedRbrace ) ) ;
390
- assert_eq ! ( parse_fstring( "{5!" ) , Err ( ExpectedRbrace ) ) ;
432
+ assert_eq ! ( parse_fstring( "{5!a" ) , Err ( UnclosedLbrace ) ) ;
433
+ assert_eq ! ( parse_fstring( "{5!a1}" ) , Err ( UnclosedLbrace ) ) ;
434
+ assert_eq ! ( parse_fstring( "{5!" ) , Err ( UnclosedLbrace ) ) ;
391
435
assert_eq ! ( parse_fstring( "abc{!a 'cat'}" ) , Err ( EmptyExpression ) ) ;
392
436
assert_eq ! ( parse_fstring( "{!a" ) , Err ( EmptyExpression ) ) ;
393
437
assert_eq ! ( parse_fstring( "{ !a}" ) , Err ( EmptyExpression ) ) ;
@@ -397,8 +441,8 @@ mod tests {
397
441
398
442
assert_eq ! ( parse_fstring( "{a:{a:{b}}}" ) , Err ( ExpressionNestedTooDeeply ) ) ;
399
443
400
- assert_eq ! ( parse_fstring( "{a:b}}" ) , Err ( UnopenedRbrace ) ) ;
401
- assert_eq ! ( parse_fstring( "}" ) , Err ( UnopenedRbrace ) ) ;
444
+ assert_eq ! ( parse_fstring( "{a:b}}" ) , Err ( SingleRbrace ) ) ;
445
+ assert_eq ! ( parse_fstring( "}" ) , Err ( SingleRbrace ) ) ;
402
446
assert_eq ! ( parse_fstring( "{a:{b}" ) , Err ( UnclosedLbrace ) ) ;
403
447
assert_eq ! ( parse_fstring( "{" ) , Err ( UnclosedLbrace ) ) ;
404
448
0 commit comments