Skip to content

Commit 7176eab

Browse files
committed
Fix various issues.
1 parent b3d83c8 commit 7176eab

File tree

6 files changed

+122
-26
lines changed

6 files changed

+122
-26
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ path = "src/main.rs"
1515
[dependencies]
1616
nom = "^4.0"
1717
#nom_locate = { path = "../nom_locate/" }
18-
nom_locate = { git = "https://github.com/ProgVal/nom_locate", branch = "nom4" }
18+
nom_locate = { git = "https://github.com/fflorent/nom_locate" }
1919
unicode-xid = "^0.1"
2020
#unicode_names = "^0.1.7"
2121
num-traits = { version="^0.2.4", optional=true }

src/expressions.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -602,10 +602,11 @@ named_args!(comp_if(acc: Vec<ComprehensionChunk>) <StrSpan, Vec<ComprehensionChu
602602
// yield_arg: 'from' test | testlist
603603
named!(pub yield_expr<StrSpan, Expression>,
604604
preceded!(
605-
tuple!(tag!("yield"), space_sep!()),
605+
tag!("yield"),
606606
alt!(
607-
preceded!(tuple!(tag!("from"), space_sep!()), call!(Self::test)) => { |e| Expression::YieldFrom(e) }
608-
| call!(Self::testlist) => { |e| Expression::Yield(e) }
607+
preceded!(tuple!(space_sep!(), tag!("from"), space_sep!()), call!(Self::test)) => { |e| Expression::YieldFrom(e) }
608+
| preceded!(space_sep!(), call!(Self::testlist)) => { |e| Expression::Yield(e) }
609+
| ws3!(tag!("")) => { |_| Expression::Yield(Vec::new()) }
609610
)
610611
)
611612
);
@@ -1730,4 +1731,16 @@ mod tests {
17301731
))
17311732
)));
17321733
}
1734+
1735+
#[test]
1736+
fn test_yield() {
1737+
let test = ExpressionParser::<NewlinesAreNotSpaces>::test;
1738+
1739+
assert_parse_eq(test(make_strspan("lambda: (yield)")), Ok((make_strspan(""),
1740+
Box::new(Expression::Lambdef(
1741+
Default::default(),
1742+
Box::new(Expression::Yield(Vec::new())),
1743+
))
1744+
)));
1745+
}
17331746
}

src/functions.rs

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ impl IsItTyped for Typed {
116116

117117
named!(fpdef<StrSpan, Self::Return>,
118118
ws4!(tuple!(name,
119-
opt!(preceded!(char!(':'), call!(ExpressionParser::<NewlinesAreSpaces>::test)))
119+
opt!(ws4!(preceded!(char!(':'), call!(ExpressionParser::<NewlinesAreSpaces>::test))))
120120
))
121121
);
122122

@@ -212,8 +212,9 @@ impl<IIT: IsItTyped> ParamlistParser<IIT> {
212212
| do_parse!( // Parse this part: '*' [tfpdef] (',' tfpdef ['=' test])* [',' ['**' tfpdef [',']]]
213213
tag!("*") >>
214214
star_args: opt!(call!(IIT::fpdef)) >>
215-
keyword_args: separated_list!(char!(','), call!(IIT::fpdef_with_default)) >>
216-
star_kwargs: opt!(ws4!(preceded!(char!(','), opt!(ws4!(preceded!(tag!("**"), call!(IIT::fpdef))))))) >> (
215+
keyword_args: many0!(preceded!(char!(','), call!(IIT::fpdef_with_default))) >>
216+
star_kwargs: opt!(ws4!(preceded!(char!(','), opt!(ws4!(preceded!(tag!("**"), call!(IIT::fpdef))))))) >>
217+
opt!(ws4!(char!(','))) >> (
217218
IIT::make_list(Vec::new(), Some(star_args), keyword_args, star_kwargs.unwrap_or(None))
218219
)
219220
)
@@ -227,8 +228,8 @@ impl<IIT: IsItTyped> ParamlistParser<IIT> {
227228
* Parse positional arguments:
228229
* tfpdef ['=' test] (',' tfpdef ['=' test])*
229230
*/
230-
positional_args: separated_nonempty_list!(ws2!(char!(',')), call!(IIT::fpdef_with_default)) >>
231-
r: opt!(ws4!(preceded!(char!(','), opt!( // FIXME: ws! is needed here because it does not traverse opt!
231+
positional_args: separated_nonempty_list!(ws4!(char!(',')), call!(IIT::fpdef_with_default)) >>
232+
r: opt!(ws4!(preceded!(char!(','), opt!(ws4!(
232233

233234
alt!(
234235
/************
@@ -253,7 +254,7 @@ impl<IIT: IsItTyped> ParamlistParser<IIT> {
253254
)
254255

255256
)
256-
)))) >> (
257+
))))) >> (
257258
/************
258259
* Case 3c: positional arguments are not followed by anything
259260
*/
@@ -617,4 +618,30 @@ mod tests {
617618
}
618619
)));
619620
}
621+
622+
#[test]
623+
fn test_starargs_first() {
624+
assert_parse_eq(ParamlistParser::<Untyped>::parse(make_strspan("*foo, bar, **kwargs")), Ok((make_strspan(""),
625+
UntypedArgsList {
626+
positional_args: vec![
627+
],
628+
star_args: StarParams::Named("foo".to_string()),
629+
keyword_args: vec![
630+
("bar".to_string(), None),
631+
],
632+
star_kwargs: Some("kwargs".to_string()),
633+
}
634+
)));
635+
636+
assert_parse_eq(ParamlistParser::<Untyped>::parse(make_strspan("*foo, **kwargs")), Ok((make_strspan(""),
637+
UntypedArgsList {
638+
positional_args: vec![
639+
],
640+
star_args: StarParams::Named("foo".to_string()),
641+
keyword_args: vec![
642+
],
643+
star_kwargs: Some("kwargs".to_string()),
644+
}
645+
)));
646+
}
620647
}

src/helpers.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,17 @@ macro_rules! space_sep {
117117
}
118118
}
119119

120+
const KEYWORDS: [&'static str; 1] = ["yield"];
120121
named!(pub name<StrSpan, String>,
121-
map!(
122-
tuple!(
123-
alt!(char!('_') | verify!(call!(::nom::anychar), |c| UnicodeXID::is_xid_start(c))),
124-
take_while!(call!(|c| UnicodeXID::is_xid_continue(c)))
125-
), |(c, s)| format!("{}{}", c, s.fragment)
122+
do_parse!(
123+
name: map!(
124+
tuple!(
125+
alt!(char!('_') | verify!(call!(::nom::anychar), |c| UnicodeXID::is_xid_start(c))),
126+
take_while!(call!(|c| UnicodeXID::is_xid_continue(c)))
127+
), |(c, s)| format!("{}{}", c, s.fragment)
128+
) >>
129+
verify!(tag!(""), |_| !KEYWORDS.contains(&&name[..])) >>
130+
(name)
126131
)
127132
);
128133

src/statements.rs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,23 @@ named!(expr_stmt<StrSpan, Statement>,
9595

9696
// testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [',']
9797
named!(testlist_star_expr<StrSpan, Vec<Expression>>,
98-
terminated!(
99-
separated_nonempty_list!(
98+
do_parse!(
99+
list: separated_nonempty_list!(
100100
ws2!(char!(',')),
101101
map!(alt!(
102102
call!(ExpressionParser::<NewlinesAreNotSpaces>::test)
103103
| call!(ExpressionParser::<NewlinesAreNotSpaces>::star_expr)
104104
), |e| *e)
105-
),
106-
opt!(ws2!(char!(',')))
105+
) >>
106+
trailing_comma: opt!(ws2!(char!(','))) >> (
107+
if trailing_comma.is_some() && list.len() < 2 {
108+
// This prevents "foo, =" from being parsed as "foo ="
109+
vec![Expression::TupleLiteral(list.into_iter().map(SetItem::Unique).collect())]
110+
}
111+
else {
112+
list
113+
}
114+
)
107115
)
108116
);
109117

@@ -1079,4 +1087,15 @@ mod tests {
10791087
})]
10801088
)));
10811089
}
1090+
1091+
#[test]
1092+
fn test_unpack() {
1093+
assert_parse_eq(testlist_star_expr(make_strspan("foo,")), Ok((make_strspan(""),
1094+
vec![
1095+
Expression::TupleLiteral(vec![
1096+
SetItem::Unique(Expression::Name("foo".to_string())),
1097+
]),
1098+
]
1099+
)));
1100+
}
10821101
}

src/visitors/printer.rs

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,9 @@ fn format_decorators(indent: usize, decorators: &Vec<Decorator>) -> String {
258258
s.push_str("@");
259259
s.push_str(&dot_join(name));
260260
if let Some(ref arglist) = args {
261+
s.push_str("(");
261262
s.push_str(&format_args(arglist));
263+
s.push_str(")");
262264
}
263265
s.push_str("\n");
264266
}
@@ -531,12 +533,38 @@ fn format_expr(e: &Expression) -> String {
531533
Expression::Generator(e, ref comp) =>
532534
format!("({} {})", format_setitem(e), space_join(comp.iter().map(format_comp))),
533535

534-
Expression::Call(e, ref args) =>
535-
format!("{}({})", format_expr(e), format_args(args)),
536+
Expression::Call(e, ref args) => {
537+
match **e {
538+
Expression::Ellipsis | Expression::None | Expression::True |
539+
Expression::False | Expression::Int(_) |
540+
Expression::ImaginaryInt(_) | Expression::ImaginaryFloat(_) |
541+
Expression::Float(_) | Expression::String(_) | Expression::Bytes(_) |
542+
Expression::Name(_) | Expression::DictComp(_, _) | Expression::SetComp(_, _) |
543+
Expression::ListComp(_, _) | Expression::Generator(_, _) |
544+
Expression::DictLiteral(_) | Expression::SetLiteral(_) |
545+
Expression::ListLiteral(_) | Expression::TupleLiteral(_) |
546+
Expression::Attribute(_, _) | Expression::Call(_, _) =>
547+
format!("{}({})", format_expr(e), format_args(args)),
548+
_ => format!("({})({})", format_expr(e), format_args(args)),
549+
}
550+
},
536551
Expression::Subscript(e, ref sub) =>
537552
format!("{}[{}]", format_expr(e), comma_join(sub.iter().map(format_subscript))),
538-
Expression::Attribute(e, ref n) =>
539-
format!("{}.{}", format_expr(e), n),
553+
Expression::Attribute(e, ref n) => {
554+
match **e {
555+
Expression::Ellipsis | Expression::None | Expression::True |
556+
Expression::False | Expression::Int(_) |
557+
Expression::ImaginaryInt(_) | Expression::ImaginaryFloat(_) |
558+
Expression::Float(_) | Expression::String(_) | Expression::Bytes(_) |
559+
Expression::Name(_) | Expression::DictComp(_, _) | Expression::SetComp(_, _) |
560+
Expression::ListComp(_, _) | Expression::Generator(_, _) |
561+
Expression::DictLiteral(_) | Expression::SetLiteral(_) |
562+
Expression::ListLiteral(_) | Expression::TupleLiteral(_) |
563+
Expression::Attribute(_, _) | Expression::Call(_, _) =>
564+
format!("{}.{}", format_expr(e), n),
565+
_ => format!("({}).{}", format_expr(e), n),
566+
}
567+
},
540568
Expression::Uop(op, ref e) =>
541569
format!("{}({})", op, format_expr(e)),
542570
Expression::Bop(op, ref e1, ref e2) => {
@@ -548,7 +576,8 @@ fn format_expr(e: &Expression) -> String {
548576
Expression::Name(_) | Expression::DictComp(_, _) | Expression::SetComp(_, _) |
549577
Expression::ListComp(_, _) | Expression::Generator(_, _) |
550578
Expression::DictLiteral(_) | Expression::SetLiteral(_) |
551-
Expression::ListLiteral(_) | Expression::TupleLiteral(_) =>
579+
Expression::ListLiteral(_) | Expression::TupleLiteral(_) |
580+
Expression::Attribute(_, _) | Expression::Call(_, _) =>
552581
format!("{}", format_expr(e)),
553582
_ => format!("({})", format_expr(e)),
554583
};
@@ -572,9 +601,12 @@ fn format_expr(e: &Expression) -> String {
572601
format!("({}) if ({}) else ({})", format_expr(e1), format_expr(e2), format_expr(e3)),
573602
Expression::Star(ref e) =>
574603
format!("*{}", format_expr(e)),
604+
605+
// https://mail.python.org/pipermail/python-list/2013-August/653288.html
575606
Expression::Yield(ref items) =>
576-
format!("yield {}", comma_join(items.iter().map(format_expr))),
577-
Expression::YieldFrom(ref iterable) => format!("yield from {}", format_expr(iterable)),
607+
format!("(yield {})", comma_join(items.iter().map(format_expr))),
608+
Expression::YieldFrom(ref iterable) => format!("(yield from {})", format_expr(iterable)),
609+
578610
Expression::Lambdef(ref params, ref body) =>
579611
format!("lambda {}: {}", format_untyped_params(params), format_expr(body))
580612
}

0 commit comments

Comments
 (0)