Fixed bugs in control flow for Python list comprehensions (PY-2574)

This commit is contained in:
Andrey Vlasovskikh
2011-04-25 17:06:10 +04:00
parent 46edd8e13b
commit 99941e03ff
6 changed files with 139 additions and 75 deletions
@@ -506,36 +506,75 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
@Override
public void visitPyComprehensionElement(final PyComprehensionElement node) {
myBuilder.startNode(node);
PyExpression prevCondition = null;
for (ComprhIfComponent component : node.getIfComponents()) {
final PyExpression condition = component.getTest();
if (condition != null) {
condition.accept(this);
final Instruction head = myBuilder.prevInstruction;
final Instruction prevInstruction =
prevCondition != null ? myBuilder.startConditionalNode(condition, prevCondition, true) : myBuilder.startNode(condition);
prevCondition = condition;
// restore head
myBuilder.prevInstruction = head;
myBuilder.addPendingEdge(node, head); // false condition
myBuilder.prevInstruction = prevInstruction;
}
}
myBuilder.startNode(node);
List<Instruction> iterators = new ArrayList<Instruction>();
for (ComprhForComponent forComponent : node.getForComponents()) {
final PyExpression iteratedList = forComponent.getIteratedList();
if (prevCondition != null) {
myBuilder.startConditionalNode(iteratedList, prevCondition, true);
prevCondition = null;
for (ComprehensionComponent component : node.getComponents()) {
if (component instanceof ComprhForComponent) {
final ComprhForComponent c = (ComprhForComponent) component;
final PyExpression iteratedList = c.getIteratedList();
final PyExpression iteratorVariable = c.getIteratorVariable();
if (prevCondition != null) {
myBuilder.startConditionalNode(iteratedList, prevCondition, true);
prevCondition = null;
}
else {
myBuilder.startNode(iteratedList);
}
iteratedList.accept(this);
// for-loop continue and exit
for (Instruction i : iterators) {
myBuilder.addEdge(myBuilder.prevInstruction, i);
}
myBuilder.addPendingEdge(node, myBuilder.prevInstruction);
final Instruction iterator = myBuilder.startNode(iteratorVariable);
iteratorVariable.accept(this);
// Inner "for" and "if" constructs will be linked to all outer iterators
iterators.add(iterator);
}
else if (component instanceof ComprhIfComponent) {
final ComprhIfComponent c = (ComprhIfComponent) component;
final PyExpression condition = c.getTest();
if (condition == null) {
continue;
}
if (prevCondition != null) {
myBuilder.startConditionalNode(condition, prevCondition, true);
}
else {
myBuilder.startNode(condition);
}
condition.accept(this);
// Condition is true for nested "for" and "if" constructs, next startNode() should create a conditional node
prevCondition = condition;
// for-loop continue and exit
for (Instruction i : iterators) {
myBuilder.addEdge(myBuilder.prevInstruction, i);
}
myBuilder.addPendingEdge(node, myBuilder.prevInstruction);
}
iteratedList.accept(this);
forComponent.getIteratorVariable().accept(this);
}
final PyExpression result = node.getResultExpression();
if (result != null) {
if (prevCondition != null) {
myBuilder.startConditionalNode(result, prevCondition, true);
}
else {
myBuilder.startNode(result);
}
result.accept(this);
// for-loop continue
for (Instruction i : iterators) {
myBuilder.addEdge(myBuilder.prevInstruction, i);
}
}
}
@@ -5,35 +5,40 @@
4(5) element: PyExpressionStatement
5(6) element: PyAssignmentStatement
6(7) element: PyListCompExpression
7(8) READ ACCESS: callable
8(9) READ ACCESS: getattr
9(10) READ ACCESS: object
10(11,17) READ ACCESS: method
11(12) element: PyCallExpression: callable
12(13) element: PyCallExpression: dir. Condition: callable(getattr(object, method)):true
13(14) READ ACCESS: dir
14(15) READ ACCESS: object
15(16) WRITE ACCESS: method
16(17) READ ACCESS: method
17(18) WRITE ACCESS: methodList
18(19) element: PyAssignmentStatement
19(20) READ ACCESS: collapse
20(21) element: PyLambdaExpression
21(22) WRITE ACCESS: s
22(23) READ ACCESS: s
23(24) element: PyLambdaExpression
24(25) WRITE ACCESS: s
25(26) READ ACCESS: s
26(27) WRITE ACCESS: processFunc
27(28) element: PyPrintStatement
28(29) element: PyListCompExpression
29(30) READ ACCESS: methodList
30(31) WRITE ACCESS: method
31(32) READ ACCESS: method
32(33) READ ACCESS: spacing
33(34) READ ACCESS: processFunc
34(35) READ ACCESS: str
35(36) READ ACCESS: getattr
36(37) READ ACCESS: object
37(38) READ ACCESS: method
38() element: null
7(8) element: PyCallExpression: dir
8(9) READ ACCESS: dir
9(10,19) READ ACCESS: object
10(11) element: PyTargetExpression: method
11(12) WRITE ACCESS: method
12(13) element: PyCallExpression: callable
13(14) READ ACCESS: callable
14(15) READ ACCESS: getattr
15(16) READ ACCESS: object
16(10,17,19) READ ACCESS: method
17(18) element: PyReferenceExpression: method. Condition: callable(getattr(object, method)):true
18(10,19) READ ACCESS: method
19(20) WRITE ACCESS: methodList
20(21) element: PyAssignmentStatement
21(22) READ ACCESS: collapse
22(23) element: PyLambdaExpression
23(24) WRITE ACCESS: s
24(25) READ ACCESS: s
25(26) element: PyLambdaExpression
26(27) WRITE ACCESS: s
27(28) READ ACCESS: s
28(29) WRITE ACCESS: processFunc
29(30) element: PyPrintStatement
30(31) element: PyListCompExpression
31(32) element: PyReferenceExpression: methodList
32(33,43) READ ACCESS: methodList
33(34) element: PyTargetExpression: method
34(35) WRITE ACCESS: method
35(36) element: PyBinaryExpression
36(37) READ ACCESS: method
37(38) READ ACCESS: spacing
38(39) READ ACCESS: processFunc
39(40) READ ACCESS: str
40(41) READ ACCESS: getattr
41(42) READ ACCESS: object
42(33,43) READ ACCESS: method
43() element: null
@@ -1,10 +1,13 @@
0(1) element: null
1(2) element: PyExpressionStatement
2(3) element: PySetCompExpression
3(4) READ ACCESS: range
4(5) WRITE ACCESS: i
5(6) element: PyLambdaExpression
6(7) READ ACCESS: i
7(8) WRITE ACCESS: i
8(9) READ ACCESS: i
9() element: null
3(4) element: PyCallExpression: range
4(5,12) READ ACCESS: range
5(6) element: PyTargetExpression: i
6(7) WRITE ACCESS: i
7(8) element: PyParenthesizedExpression
8(9) element: PyLambdaExpression
9(10) READ ACCESS: i
10(11) WRITE ACCESS: i
11(5,12) READ ACCESS: i
12() element: null
@@ -1 +1,4 @@
[k for k, v in params.items() if foo]
[(x, y) for k, v in params.items()
if k
for x, y in v
if x > y]
@@ -1,11 +1,22 @@
0(1) element: null
1(2) element: PyExpressionStatement
2(3) element: PyListCompExpression
3(4,10) READ ACCESS: foo
4(5) element: PyReferenceExpression: foo
5(6) element: PyCallExpression: params.items. Condition: foo:true
6(7) READ ACCESS: params
7(8) WRITE ACCESS: k
8(9) WRITE ACCESS: v
9(10) READ ACCESS: k
10() element: null
3(4) element: PyCallExpression: params.items
4(5,21) READ ACCESS: params
5(6) element: PyTupleExpression
6(7) WRITE ACCESS: k
7(8) WRITE ACCESS: v
8(9) element: PyReferenceExpression: k
9(5,10,21) READ ACCESS: k
10(11) element: PyReferenceExpression: v. Condition: k:true
11(5,12,21) READ ACCESS: v
12(13) element: PyTupleExpression
13(14) WRITE ACCESS: x
14(15) WRITE ACCESS: y
15(16) element: PyBinaryExpression
16(17) READ ACCESS: x
17(5,12,18,21) READ ACCESS: y
18(19) element: PyParenthesizedExpression. Condition: x > y:true
19(20) READ ACCESS: x
20(5,12,21) READ ACCESS: y
21() element: null
@@ -2,8 +2,11 @@
1(2) element: PyReturnStatement
2(3) READ ACCESS: dict
3(4) element: PyGeneratorExpression
4(5) WRITE ACCESS: name
5(6) WRITE ACCESS: val
6(7) READ ACCESS: name
7(8) READ ACCESS: val
8() element: null
4(5,11) element: PyDictLiteralExpression
5(6) element: PyTupleExpression
6(7) WRITE ACCESS: name
7(8) WRITE ACCESS: val
8(9) element: PyParenthesizedExpression
9(10) READ ACCESS: name
10(5,11) READ ACCESS: val
11() element: null