Skip to content

Commit 29ce0cf

Browse files
committed
Add support for if-filters in list comprehensions.
1 parent b03dd62 commit 29ce0cf

File tree

4 files changed

+45
-43
lines changed

4 files changed

+45
-43
lines changed

parser/src/parser.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ mod tests {
381381

382382
#[test]
383383
fn test_parse_double_list_comprehension() {
384-
let source = String::from("[x for y, y2 in z for a in b]");
384+
let source = String::from("[x for y, y2 in z for a in b if a < 5 if a > 10]");
385385
let parse_ast = parse_expression(&source).unwrap();
386386
assert_eq!(
387387
parse_ast,
@@ -415,7 +415,26 @@ mod tests {
415415
iter: ast::Expression::Identifier {
416416
name: "b".to_string()
417417
},
418-
ifs: vec![],
418+
ifs: vec![
419+
ast::Expression::Compare {
420+
a: Box::new(ast::Expression::Identifier {
421+
name: "a".to_string()
422+
}),
423+
op: ast::Comparison::Less,
424+
b: Box::new(ast::Expression::Number {
425+
value: ast::Number::Integer { value: 5 }
426+
}),
427+
},
428+
ast::Expression::Compare {
429+
a: Box::new(ast::Expression::Identifier {
430+
name: "a".to_string()
431+
}),
432+
op: ast::Comparison::Greater,
433+
b: Box::new(ast::Expression::Number {
434+
value: ast::Number::Integer { value: 10 }
435+
}),
436+
},
437+
],
419438
}
420439
],
421440
}

parser/src/python.lalrpop

Lines changed: 11 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -904,34 +904,16 @@ StarExpr: ast::Expression = {
904904
};
905905

906906
// Comprehensions:
907-
CompIter: (Option<Vec<ast::Comprehension>>, Option<ast::Expression>) = {
908-
// <e:CompIf> => (None, Some(e)),
909-
<c:CompFor> => (Some(c), None),
907+
CompFor: Vec<ast::Comprehension> = {
908+
<c:SingleForComprehension+> => c,
910909
};
911910

912-
CompFor: Vec<ast::Comprehension> = {
913-
"for" <e:ExpressionList> "in" <i:OrTest> <c2:CompIter?> => {
914-
match c2 {
915-
None => {
916-
vec![ast::Comprehension {
917-
target: e,
918-
iter: i,
919-
ifs: vec![],
920-
}]
921-
},
922-
Some((Some(mut cphs), None)) => {
923-
let mut res = vec![];
924-
res.push(ast::Comprehension {
925-
target: e,
926-
iter: i,
927-
ifs: vec![],
928-
});
929-
res.append(&mut cphs);
930-
res
931-
},
932-
_ => {
933-
panic!("TODO");
934-
},
911+
SingleForComprehension: ast::Comprehension = {
912+
"for" <e:ExpressionList> "in" <i:OrTest> <c2:ComprehensionIf*> => {
913+
ast::Comprehension {
914+
target: e,
915+
iter: i,
916+
ifs: c2,
935917
}
936918
}
937919
};
@@ -940,17 +922,9 @@ ExpressionNoCond: ast::Expression = {
940922
OrTest,
941923
};
942924

943-
//CompIf: ast::Expression = {
944-
// "if" <c:ExpressionNoCond> <c2:CompIter?> => {
945-
// match c2 {
946-
// None => {
947-
// vec![]
948-
// },
949-
// Some() => {
950-
// },
951-
// }
952-
// }
953-
//};
925+
ComprehensionIf: ast::Expression = {
926+
"if" <c:ExpressionNoCond> => c,
927+
};
954928

955929
ArgumentList: (Vec<ast::Expression>, Vec<ast::Keyword>) = {
956930
<e: Comma<FunctionArgument>> => {

tests/snippets/comprehensions.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
# TODO:
1919
#u = {str(b): b-2 for b in x}
2020

21-
# TODO: With if filtering:
22-
#y = [a+2 for a in x if a % 2]
23-
#print(y)
24-
#assert y == [3, 5]
21+
y = [a+2 for a in x if a % 2]
22+
print(y)
23+
assert y == [3, 5]

vm/src/compile.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,6 +1050,16 @@ impl Compiler {
10501050
self.emit(Instruction::ForIter);
10511051

10521052
self.compile_store(&generator.target)?;
1053+
1054+
// Now evaluate the ifs:
1055+
for if_condition in &generator.ifs {
1056+
self.compile_test(
1057+
if_condition,
1058+
None,
1059+
Some(start_label),
1060+
EvalContext::Statement,
1061+
)?
1062+
}
10531063
}
10541064

10551065
match kind {

0 commit comments

Comments
 (0)