Skip to content

Commit 935227f

Browse files
committed
Allow tuple unpacking in return and yield statements (bpo-32117)
fd97d1f1af910a6222ea12aec42c456b64f9aee4
1 parent 7e8eed6 commit 935227f

File tree

2 files changed

+40
-39
lines changed

2 files changed

+40
-39
lines changed

src/expressions.rs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,28 @@ named!(pub possibly_empty_testlist<StrSpan, Vec<Expression>>,
375375
)
376376
);
377377

378+
// testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [',']
379+
named!(pub testlist_star_expr<StrSpan, Vec<Expression>>,
380+
do_parse!(
381+
list: separated_nonempty_list!(
382+
ws_auto!(char!(',')),
383+
map!(alt!(
384+
call!(Self::test)
385+
| call!(Self::star_expr)
386+
), |e| *e)
387+
) >>
388+
trailing_comma: opt!(ws_auto!(char!(','))) >> (
389+
if trailing_comma.is_some() && list.len() < 2 {
390+
// This prevents "foo, =" from being parsed as "foo ="
391+
vec![Expression::TupleLiteral(list.into_iter().map(SetItem::Unique).collect())]
392+
}
393+
else {
394+
list
395+
}
396+
)
397+
)
398+
);
399+
378400
} // end ExpressionParser
379401

380402
/*********************************************************************
@@ -568,13 +590,13 @@ named_args!(comp_if(acc: Vec<ComprehensionChunk>) <StrSpan, Vec<ComprehensionChu
568590

569591

570592
// yield_expr: 'yield' [yield_arg]
571-
// yield_arg: 'from' test | testlist
593+
// yield_arg: 'from' test | testlist_star_expr
572594
named!(pub yield_expr<StrSpan, Expression>,
573595
ws_auto!(preceded!(
574596
keyword!("yield"),
575597
ws_auto!(alt!(
576598
preceded!(ws_auto!(keyword!("from")), call!(Self::test)) => { |e| Expression::YieldFrom(e) }
577-
| call!(Self::testlist) => { |e| Expression::Yield(e) }
599+
| call!(Self::testlist_star_expr) => { |e| Expression::Yield(e) }
578600
| tag!("") => { |_| Expression::Yield(Vec::new()) }
579601
))
580602
))
@@ -1652,4 +1674,16 @@ mod tests {
16521674
))
16531675
)));
16541676
}
1677+
1678+
#[test]
1679+
fn test_unpack() {
1680+
let testlist_star_expr = ExpressionParser::<NewlinesAreNotSpaces>::testlist_star_expr;
1681+
assert_parse_eq(testlist_star_expr(make_strspan("foo,")), Ok((make_strspan(""),
1682+
vec![
1683+
Expression::TupleLiteral(vec![
1684+
SetItem::Unique(Expression::Name("foo".to_string())),
1685+
]),
1686+
]
1687+
)));
1688+
}
16551689
}

src/statements.rs

Lines changed: 4 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ named!(small_stmt<StrSpan, Statement>,
6262
// annassign: ':' test ['=' test]
6363
named!(expr_stmt<StrSpan, Statement>,
6464
do_parse!(
65-
lhs: testlist_star_expr >>
65+
lhs: call!(ExpressionParser::<NewlinesAreNotSpaces>::testlist_star_expr) >>
6666
r: ws_nonl!(alt!(
6767
// Case 1: "foo: bar = baz"
6868
do_parse!(
@@ -89,7 +89,7 @@ named!(expr_stmt<StrSpan, Statement>,
8989
do_parse!(
9090
rhs: many0!(ws_nonl!(preceded!(char!('='), alt!(
9191
call!(ExpressionParser::<NewlinesAreNotSpaces>::yield_expr) => { |e| vec![e] }
92-
| testlist_star_expr
92+
| call!(ExpressionParser::<NewlinesAreNotSpaces>::testlist_star_expr)
9393
)))) >> (
9494
Statement::Assignment(lhs, rhs)
9595
)
@@ -99,28 +99,6 @@ named!(expr_stmt<StrSpan, Statement>,
9999
)
100100
);
101101

102-
// testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [',']
103-
named!(testlist_star_expr<StrSpan, Vec<Expression>>,
104-
do_parse!(
105-
list: separated_nonempty_list!(
106-
ws_nonl!(char!(',')),
107-
map!(alt!(
108-
call!(ExpressionParser::<NewlinesAreNotSpaces>::test)
109-
| call!(ExpressionParser::<NewlinesAreNotSpaces>::star_expr)
110-
), |e| *e)
111-
) >>
112-
trailing_comma: opt!(ws_nonl!(char!(','))) >> (
113-
if trailing_comma.is_some() && list.len() < 2 {
114-
// This prevents "foo, =" from being parsed as "foo ="
115-
vec![Expression::TupleLiteral(list.into_iter().map(SetItem::Unique).collect())]
116-
}
117-
else {
118-
list
119-
}
120-
)
121-
)
122-
);
123-
124102
// augassign: ('+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' |
125103
// '<<=' | '>>=' | '**=' | '//=')
126104
named!(augassign<StrSpan, AugAssignOp>,
@@ -159,15 +137,15 @@ named!(pass_stmt<StrSpan, Statement>,
159137
// flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt
160138
// break_stmt: 'break'
161139
// continue_stmt: 'continue'
162-
// return_stmt: 'return' [testlist]
140+
// return_stmt: 'return' [testlist_star_expr]
163141
// yield_stmt: yield_expr
164142
named!(flow_stmt<StrSpan, Statement>,
165143
alt!(
166144
keyword!("break") => { |_| Statement::Break }
167145
| keyword!("continue") => { |_| Statement::Continue }
168146
| preceded!(
169147
tuple!(keyword!("return"), spaces_nonl),
170-
return_error!(ws_nonl!(call!(ExpressionParser::<NewlinesAreNotSpaces>::possibly_empty_testlist)))
148+
return_error!(ws_nonl!(call!(ExpressionParser::<NewlinesAreNotSpaces>::testlist_star_expr)))
171149
) => { |e| Statement::Return(e) }
172150
| raise_stmt
173151
| call!(ExpressionParser::<NewlinesAreNotSpaces>::yield_expr)
@@ -1192,15 +1170,4 @@ mod tests {
11921170
})]
11931171
)));
11941172
}
1195-
1196-
#[test]
1197-
fn test_unpack() {
1198-
assert_parse_eq(testlist_star_expr(make_strspan("foo,")), Ok((make_strspan(""),
1199-
vec![
1200-
Expression::TupleLiteral(vec![
1201-
SetItem::Unique(Expression::Name("foo".to_string())),
1202-
]),
1203-
]
1204-
)));
1205-
}
12061173
}

0 commit comments

Comments
 (0)