Skip to content

Commit 04886d8

Browse files
committed
Allow brackets in f-string format spec
1 parent 2edfb17 commit 04886d8

4 files changed

Lines changed: 119 additions & 55 deletions

parser/src/fstring.rs

Lines changed: 37 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -91,52 +91,56 @@ impl<'a> FStringParser<'a> {
9191
}
9292

9393
':' if delims.is_empty() => {
94-
let mut nested = false;
9594
let mut in_nested = false;
96-
let mut spec_expression = String::new();
95+
let mut spec_constructor = Vec::new();
96+
let mut constant_piece = String::new();
97+
let mut formatted_value_piece = String::new();
9798
while let Some(&next) = self.chars.peek() {
9899
match next {
100+
'{' if in_nested => return Err(ExpressionNestedTooDeeply),
101+
'}' if in_nested => {
102+
in_nested = false;
103+
spec_constructor.push(self.expr(ExprKind::FormattedValue {
104+
value:
105+
Box::new(
106+
parse_fstring_expr(&formatted_value_piece).map_err(
107+
|e| InvalidExpression(Box::new(e.error)),
108+
)?,
109+
),
110+
conversion: None,
111+
format_spec: None,
112+
}));
113+
formatted_value_piece.clear();
114+
}
115+
_ if in_nested => {
116+
formatted_value_piece.push(next);
117+
}
99118
'{' => {
100-
if in_nested {
101-
return Err(ExpressionNestedTooDeeply);
102-
}
103119
in_nested = true;
104-
nested = true;
105-
self.chars.next();
106-
continue;
120+
spec_constructor.push(self.expr(ExprKind::Constant {
121+
value: constant_piece.to_owned().into(),
122+
kind: None,
123+
}));
124+
constant_piece.clear();
107125
}
108-
'}' => {
109-
if in_nested {
110-
in_nested = false;
111-
self.chars.next();
112-
}
113-
break;
126+
'}' => break,
127+
_ => {
128+
constant_piece.push(next);
114129
}
115-
_ => (),
116130
}
117-
spec_expression.push(next);
118131
self.chars.next();
119132
}
133+
spec_constructor.push(self.expr(ExprKind::Constant {
134+
value: constant_piece.to_owned().into(),
135+
kind: None,
136+
}));
137+
constant_piece.clear();
120138
if in_nested {
121139
return Err(UnclosedLbrace);
122140
}
123-
spec = Some(if nested {
124-
Box::new(
125-
self.expr(ExprKind::FormattedValue {
126-
value: Box::new(
127-
parse_fstring_expr(&spec_expression)
128-
.map_err(|e| InvalidExpression(Box::new(e.error)))?,
129-
),
130-
conversion: None,
131-
format_spec: None,
132-
}),
133-
)
134-
} else {
135-
Box::new(self.expr(ExprKind::Constant {
136-
value: spec_expression.to_owned().into(),
137-
kind: None,
138-
}))
139-
})
141+
spec = Some(Box::new(self.expr(ExprKind::JoinedStr {
142+
values: spec_constructor,
143+
})))
140144
}
141145
'(' | '{' | '[' => {
142146
expression.push(ch);

parser/src/snapshots/rustpython_parser__fstring__tests__fstring_parse_selfdocumenting_format.snap

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
source: parser/src/fstring.rs
33
expression: parse_ast
4+
45
---
56
Located {
67
location: Location {
@@ -62,11 +63,22 @@ Located {
6263
column: 0,
6364
},
6465
custom: (),
65-
node: Constant {
66-
value: Str(
67-
">10",
68-
),
69-
kind: None,
66+
node: JoinedStr {
67+
values: [
68+
Located {
69+
location: Location {
70+
row: 0,
71+
column: 0,
72+
},
73+
custom: (),
74+
node: Constant {
75+
value: Str(
76+
">10",
77+
),
78+
kind: None,
79+
},
80+
},
81+
],
7082
},
7183
},
7284
),

parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_nested_spec.snap

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,20 +37,57 @@ Located {
3737
column: 0,
3838
},
3939
custom: (),
40-
node: FormattedValue {
41-
value: Located {
42-
location: Location {
43-
row: 1,
44-
column: 2,
40+
node: JoinedStr {
41+
values: [
42+
Located {
43+
location: Location {
44+
row: 0,
45+
column: 0,
46+
},
47+
custom: (),
48+
node: Constant {
49+
value: Str(
50+
"",
51+
),
52+
kind: None,
53+
},
4554
},
46-
custom: (),
47-
node: Name {
48-
id: "spec",
49-
ctx: Load,
55+
Located {
56+
location: Location {
57+
row: 0,
58+
column: 0,
59+
},
60+
custom: (),
61+
node: FormattedValue {
62+
value: Located {
63+
location: Location {
64+
row: 1,
65+
column: 2,
66+
},
67+
custom: (),
68+
node: Name {
69+
id: "spec",
70+
ctx: Load,
71+
},
72+
},
73+
conversion: None,
74+
format_spec: None,
75+
},
5076
},
51-
},
52-
conversion: None,
53-
format_spec: None,
77+
Located {
78+
location: Location {
79+
row: 0,
80+
column: 0,
81+
},
82+
custom: (),
83+
node: Constant {
84+
value: Str(
85+
"",
86+
),
87+
kind: None,
88+
},
89+
},
90+
],
5491
},
5592
},
5693
),

parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_not_nested_spec.snap

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,22 @@ Located {
3737
column: 0,
3838
},
3939
custom: (),
40-
node: Constant {
41-
value: Str(
42-
"spec",
43-
),
44-
kind: None,
40+
node: JoinedStr {
41+
values: [
42+
Located {
43+
location: Location {
44+
row: 0,
45+
column: 0,
46+
},
47+
custom: (),
48+
node: Constant {
49+
value: Str(
50+
"spec",
51+
),
52+
kind: None,
53+
},
54+
},
55+
],
4556
},
4657
},
4758
),

0 commit comments

Comments
 (0)