This commit is contained in:
Oleg Shpynov
2010-01-20 17:25:37 +03:00
parent 7238fc92de
commit 4f34e4d574
33 changed files with 759 additions and 12 deletions
@@ -0,0 +1,11 @@
package com.jetbrains.python.codeInsight.controlflow;
import com.intellij.psi.PsiElement;
/**
* @author oleg
*/
public interface ConditionInstruction extends Instruction {
boolean getResult();
PsiElement getCondition();
}
@@ -0,0 +1,8 @@
package com.jetbrains.python.codeInsight.controlflow;
/**
* @author oleg
*/
public interface ControlFlow {
Instruction[] getInstructions();
}
@@ -0,0 +1,10 @@
package com.jetbrains.python.codeInsight.controlflow;
import com.jetbrains.python.psi.PyElement;
/**
* @author oleg
*/
public interface ControlFlowOwner extends PyElement {
ControlFlow getControlFlow();
}
@@ -0,0 +1,22 @@
package com.jetbrains.python.codeInsight.controlflow;
import com.jetbrains.python.psi.PyElement;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
/**
* @author oleg
*/
public interface Instruction {
@Nullable
public PyElement getElement();
public Collection<Instruction> allSucc();
public Collection<Instruction> allPred();
String getElementPresentation();
public int num();
}
@@ -0,0 +1,523 @@
package com.jetbrains.python.codeInsight.controlflow;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.codeInsight.controlflow.impl.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* @author oleg
*/
public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
// Here we store all the instructions
private List<Instruction> myInstructions;
private Instruction myPrevInstruction;
// Here we store all the pending instructions with their scope
private List<Pair<PsiElement, Instruction>> myPending;
private int myInstructionNumber;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//// Control flow builder staff
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public ControlFlow buildControlFlow(@NotNull final ControlFlowOwner owner) {
myInstructions = new ArrayList<Instruction>();
myPending = new ArrayList<Pair<PsiElement, Instruction>>();
myInstructionNumber = 0;
// create start pseudo node
startNode(null);
owner.acceptChildren(this);
// create end pseudo node and close all pending edges
checkPending(startNode(null));
return new ControlFlowImpl(myInstructions.toArray(new Instruction[myInstructions.size()]));
}
@Nullable
private Instruction findInstructionByElement(final PsiElement element) {
for (int i = myInstructions.size() - 1; i >= 0; i--) {
final Instruction instruction = myInstructions.get(i);
if (element.equals(instruction.getElement())) {
return instruction;
}
}
return null;
}
/**
* Adds edge between 2 edges
*
* @param beginInstruction Begin of new edge
* @param endInstruction End of new edge
*/
private static void addEdge(final Instruction beginInstruction, final Instruction endInstruction) {
if (beginInstruction == null || endInstruction == null) {
return;
}
if (!beginInstruction.allSucc().contains(endInstruction)) {
beginInstruction.allSucc().add(endInstruction);
}
if (!endInstruction.allPred().contains(beginInstruction)) {
endInstruction.allPred().add(beginInstruction);
}
}
/**
* Add new node and set prev instruction pointing to this instruction
*
* @param instruction new instruction
*/
private void addNode(final Instruction instruction) {
myInstructions.add(instruction);
if (myPrevInstruction != null) {
addEdge(myPrevInstruction, instruction);
}
myPrevInstruction = instruction;
}
/**
* Stops control flow, used for break, next, redo
*/
private void flowAbrupted() {
myPrevInstruction = null;
}
/**
* Adds pending edge in pendingScope
*
* @param pendingScope Scope for instruction
* @param instruction "Last" pending instruction
*/
private void addPendingEdge(final PsiElement pendingScope, final Instruction instruction) {
if (instruction == null) {
return;
}
int i = 0;
// another optimization! Place pending before first scope, not contained in pendingScope
// the same logic is used in checkPending
if (pendingScope != null) {
for (; i < myPending.size(); i++) {
final Pair<PsiElement, Instruction> pair = myPending.get(i);
final PsiElement scope = pair.getFirst();
if (scope == null) {
continue;
}
if (!PsiTreeUtil.isAncestor(scope, pendingScope, true)) {
break;
}
}
}
myPending.add(i, Pair.create(pendingScope, instruction));
}
private void checkPending(@NotNull final Instruction instruction) {
final PsiElement element = instruction.getElement();
if (element == null) {
// if element is null (fake element, we just process all pending)
for (Pair<PsiElement, Instruction> pair : myPending) {
addEdge(pair.getSecond(), instruction);
}
myPending.clear();
}
else {
// else we just all the pending with scope containing in element
// reverse order is just an optimization
for (int i = myPending.size() - 1; i >= 0; i--) {
final Pair<PsiElement, Instruction> pair = myPending.get(i);
final PsiElement scopeWhenToAdd = pair.getFirst();
if (scopeWhenToAdd == null) {
continue;
}
if (!PsiTreeUtil.isAncestor(scopeWhenToAdd, element, false)) {
addEdge(pair.getSecond(), instruction);
myPending.remove(i);
}
else {
break;
}
}
}
}
/**
* Creates instruction for given element, and adds it to myInstructionsStack
* Warning! Always call finishNode after startNode
*
* @param element Element to create instruction for
* @return new instruction
*/
private Instruction startNode(final PyElement element) {
final Instruction instruction = new InstructionImpl(element, myInstructionNumber++);
addNode(instruction);
checkPending(instruction);
return instruction;
}
/**
* Creates conditional instruction for given element, and adds it to myInstructionsStack
* Warning! Always call finishNode after startNode
*
* @param element Element to create instruction for
* @return new instruction
*/
private Instruction startConditionalNode(final PyElement element, final PyElement condition, final boolean result) {
final ConditionInstruction instruction = new ConditionInstructionImpl(element, myInstructionNumber++, condition, result);
addNode(instruction);
checkPending(instruction);
return instruction;
}
@Override
public void visitPyFunction(final PyFunction node) {
// Stop here
}
@Override
public void visitPyClass(final PyClass node) {
// Stop here
}
@Override
public void visitPyStatement(final PyStatement node) {
startNode(node);
super.visitPyStatement(node);
}
@Override
public void visitPyAssignmentStatement(final PyAssignmentStatement node) {
startNode(node);
final PyExpression value = node.getAssignedValue();
if (value != null) {
value.accept(this);
}
for (PyExpression expression : node.getTargets()) {
expression.accept(this);
}
}
@Override
public void visitPyTargetExpression(final PyTargetExpression node) {
final WriteInstruction instruction = new WriteInstructionImpl(node, node.getName(), myInstructionNumber++);
addNode(instruction);
checkPending(instruction);
}
@Override
public void visitPyNamedParameter(final PyNamedParameter node) {
final WriteInstruction instruction = new WriteInstructionImpl(node, node.getName(), myInstructionNumber++);
addNode(instruction);
checkPending(instruction);
}
private Instruction getPrevInstruction(final PyElement condition) {
final Ref<Instruction> head = new Ref<Instruction>(myPrevInstruction);
processPending(new PendingProcessor() {
public void process(final PsiElement pendingScope, final Instruction instruction) {
if (pendingScope != null && PsiTreeUtil.isAncestor(condition, pendingScope, false)) {
head.set(instruction);
}
else {
addPendingEdge(pendingScope, instruction);
}
}
});
return head.get();
}
@Override
public void visitPyIfStatement(final PyIfStatement node) {
startNode(node);
final PyIfPart ifPart = node.getIfPart();
PyExpression condition = ifPart.getCondition();
if (condition != null) {
condition.accept(this);
}
// Set the head as the last instruction of condition
Instruction head = getPrevInstruction(condition);
myPrevInstruction = head;
final PyStatementList thenStatements = ifPart.getStatementList();
if (thenStatements != null) {
startConditionalNode(thenStatements, condition, true);
thenStatements.accept(this);
processPending(new PendingProcessor() {
public void process(final PsiElement pendingScope, final Instruction instruction) {
if (pendingScope != null && PsiTreeUtil.isAncestor(thenStatements, pendingScope, false)) {
addPendingEdge(node, instruction);
}
else {
addPendingEdge(pendingScope, instruction);
}
}
});
addPendingEdge(node, myPrevInstruction);
}
for (PyIfPart part : node.getElifParts()) {
// restore head
myPrevInstruction = head;
condition = part.getCondition();
if (condition != null) {
condition.accept(this);
}
// Set the head as the last instruction of condition
head = getPrevInstruction(condition);
myPrevInstruction = head;
startConditionalNode(ifPart, condition, true);
final PyStatementList statementList = part.getStatementList();
if (statementList != null) {
statementList.accept(this);
}
processPending(new PendingProcessor() {
public void process(final PsiElement pendingScope, final Instruction instruction) {
if (pendingScope != null && PsiTreeUtil.isAncestor(ifPart, pendingScope, false)) {
addPendingEdge(node, instruction);
}
else {
addPendingEdge(pendingScope, instruction);
}
}
});
addPendingEdge(node, myPrevInstruction);
}
// restore head
myPrevInstruction = head;
final PyElsePart elseBranch = node.getElsePart();
if (elseBranch != null) {
startConditionalNode(elseBranch, condition, false);
elseBranch.accept(this);
addPendingEdge(node, myPrevInstruction);
}
}
@Override
public void visitPyWhileStatement(final PyWhileStatement node) {
final Instruction instruction = startNode(node);
final PyWhilePart whilePart = node.getWhilePart();
final PyExpression condition = whilePart.getCondition();
if (condition != null) {
condition.accept(this);
}
final Instruction head = getPrevInstruction(condition);
myPrevInstruction = head;
// if condition was false
final PyElsePart elsePart = node.getElsePart();
if (elsePart == null) {
addPendingEdge(node, myPrevInstruction);
}
final PyStatementList statementList = whilePart.getStatementList();
if (statementList != null) {
startConditionalNode(statementList, condition, true);
statementList.accept(this);
}
if (myPrevInstruction != null) {
addEdge(myPrevInstruction, instruction); //loop
}
// else part
if (elsePart != null) {
startConditionalNode(statementList, condition, false);
elsePart.accept(this);
addPendingEdge(node, myPrevInstruction);
}
flowAbrupted();
checkPending(instruction); //check for breaks targeted here
}
@Override
public void visitPyForStatement(final PyForStatement node) {
startNode(node);
final PyForPart forPart = node.getForPart();
final PyExpression source = forPart.getSource();
if (source != null) {
source.accept(this);
}
final Instruction head = myPrevInstruction;
final PyElsePart elsePart = node.getElsePart();
if (elsePart == null) {
addPendingEdge(node, myPrevInstruction);
}
final PyStatementList list = forPart.getStatementList();
if (list != null) {
Instruction bodyInstruction = startNode(list);
final PyExpression target = forPart.getTarget();
if (target != null) {
target.accept(this);
}
list.accept(this);
if (myPrevInstruction != null) {
addEdge(myPrevInstruction, bodyInstruction); //loop
addPendingEdge(node, myPrevInstruction); // exit
}
}
myPrevInstruction = head;
if (elsePart != null) {
elsePart.accept(this);
addPendingEdge(node, myPrevInstruction); // exit
}
flowAbrupted();
}
@Override
public void visitPyBreakStatement(final PyBreakStatement node) {
final Instruction breakInstruction = new InstructionImpl(node, myInstructionNumber++);
addNode(breakInstruction);
checkPending(breakInstruction);
final PyLoopStatement loop = node.getLoopStatement();
if (loop != null) {
addPendingEdge(loop, myPrevInstruction);
flowAbrupted();
}
}
@Override
public void visitPyContinueStatement(final PyContinueStatement node) {
final Instruction nextInstruction = new InstructionImpl(node, myInstructionNumber++);
addNode(nextInstruction);
checkPending(nextInstruction);
final PyLoopStatement loop = node.getLoop();
if (loop != null) {
final Instruction instruction = findInstructionByElement(loop);
if (instruction != null) {
addEdge(myPrevInstruction, instruction);
flowAbrupted();
}
}
}
@Override
public void visitPyReturnStatement(final PyReturnStatement node) {
final Instruction instruction = new InstructionImpl(node, myInstructionNumber++);
addNode(instruction);
checkPending(instruction);
final PyExpression expression = node.getExpression();
if (expression != null) {
expression.accept(this);
}
// Here we process pending instructions!!!
final List<Pair<PsiElement, Instruction>> pending = myPending;
myPending = new ArrayList<Pair<PsiElement, Instruction>>();
for (Pair<PsiElement, Instruction> pair : pending) {
final PsiElement pendingScope = pair.getFirst();
if (pendingScope != null && PsiTreeUtil.isAncestor(node, pendingScope, false)) {
final Instruction pendingInstruction = pair.getSecond();
addPendingEdge(null, pendingInstruction);
}
else {
myPending.add(pair);
}
}
addPendingEdge(null, myPrevInstruction);
flowAbrupted();
}
@Override
public void visitPyTryExceptStatement(final PyTryExceptStatement node) {
startNode(node);
// process body
final PyTryPart tryPart = node.getTryPart();
startNode(tryPart);
tryPart.accept(this);
final Instruction lastBlockInstruction = myPrevInstruction;
// Goto else block after execution, or exit
final PyElsePart elsePart = node.getElsePart();
if (elsePart != null) {
startNode(elsePart);
elsePart.accept(this);
addPendingEdge(node, myPrevInstruction);
} else {
addPendingEdge(node, myPrevInstruction);
}
final ArrayList<Instruction> rescueInstructions = new ArrayList<Instruction>();
for (PyExceptPart exceptPart : node.getExceptParts()) {
myPrevInstruction = lastBlockInstruction;
final Instruction rescueInstruction = startNode(exceptPart);
rescueInstructions.add(rescueInstruction);
exceptPart.accept(this);
addPendingEdge(node, myPrevInstruction);
}
final PyFinallyPart finallyPart = node.getFinallyPart();
Instruction finallyInstruction = null;
Instruction lastFinallyInstruction = null;
if (finallyPart != null) {
flowAbrupted();
finallyInstruction = startNode(finallyPart);
finallyPart.accept(this);
lastFinallyInstruction = myPrevInstruction;
addPendingEdge(finallyPart, lastFinallyInstruction);
}
final Ref<Instruction> finallyRef = new Ref<Instruction>(finallyInstruction);
final Ref<Instruction> lastFinallyRef = new Ref<Instruction>(lastFinallyInstruction);
processPending(new PendingProcessor() {
public void process(final PsiElement pendingScope, final Instruction instruction) {
final PyElement pendingElement = instruction.getElement();
// handle raise instructions inside compound statement
if (pendingElement instanceof PyRaiseStatement &&
PsiTreeUtil.isAncestor(tryPart, pendingElement, false)){
for (Instruction rescueInstruction : rescueInstructions) {
addEdge(instruction, rescueInstruction);
}
return;
}
// handle return pending instructions inside body if ensure block exists
if (pendingElement instanceof PyReturnStatement && !finallyRef.isNull() &&
PsiTreeUtil.isAncestor(node, pendingElement, false)) {
addEdge(instruction, finallyRef.get());
addPendingEdge(null, lastFinallyRef.get());
return;
}
// Handle pending instructions inside body with ensure block
if (pendingElement != null && finallyPart!=null && pendingScope !=finallyPart &&
PsiTreeUtil.isAncestor(node, pendingElement, false)) {
addEdge(instruction, finallyRef.get());
return;
}
addPendingEdge(pendingScope, instruction);
}
});
}
@Override
public void visitPyListCompExpression(final PyListCompExpression node) {
super.visitPyListCompExpression(node);
}
private static interface PendingProcessor {
void process(PsiElement pendingScope, Instruction instruction);
}
private void processPending(final PendingProcessor processor) {
final List<Pair<PsiElement, Instruction>> pending = myPending;
myPending = new ArrayList<Pair<PsiElement, Instruction>>();
for (Pair<PsiElement, Instruction> pair : pending) {
processor.process(pair.getFirst(), pair.getSecond());
}
}
}
@@ -0,0 +1,8 @@
package com.jetbrains.python.codeInsight.controlflow;
/**
* @author oleg
*/
public interface WriteInstruction extends Instruction {
String getName();
}
@@ -3,7 +3,7 @@ package com.jetbrains.python.psi;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.StubBasedPsiElement;
import com.jetbrains.python.psi.controlflow.ControlFlowOwner;
import com.jetbrains.python.codeInsight.controlflow.ControlFlowOwner;
import com.jetbrains.python.psi.stubs.PyClassStub;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -6,7 +6,7 @@ package com.jetbrains.python.psi;
import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.jetbrains.python.psi.controlflow.ControlFlowOwner;
import com.jetbrains.python.codeInsight.controlflow.ControlFlowOwner;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -3,7 +3,7 @@ package com.jetbrains.python.psi;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.StubBasedPsiElement;
import com.jetbrains.python.psi.controlflow.ControlFlowOwner;
import com.jetbrains.python.codeInsight.controlflow.ControlFlowOwner;
import com.jetbrains.python.psi.stubs.PyFunctionStub;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -13,8 +13,8 @@ import com.jetbrains.python.PyNames;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.PythonDosStringFinder;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.controlflow.ControlFlow;
import com.jetbrains.python.psi.controlflow.PyControlFlowBuilder;
import com.jetbrains.python.codeInsight.controlflow.ControlFlow;
import com.jetbrains.python.codeInsight.controlflow.PyControlFlowBuilder;
import com.jetbrains.python.psi.resolve.PyResolveUtil;
import com.jetbrains.python.psi.resolve.VariantsProcessor;
import com.jetbrains.python.psi.stubs.PyClassStub;
@@ -17,8 +17,8 @@ import com.jetbrains.python.PythonDosStringFinder;
import com.jetbrains.python.PythonFileType;
import com.jetbrains.python.PythonLanguage;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.controlflow.ControlFlow;
import com.jetbrains.python.psi.controlflow.PyControlFlowBuilder;
import com.jetbrains.python.codeInsight.controlflow.ControlFlow;
import com.jetbrains.python.codeInsight.controlflow.PyControlFlowBuilder;
import com.jetbrains.python.psi.resolve.PyResolveUtil;
import com.jetbrains.python.psi.resolve.ResolveProcessor;
import com.jetbrains.python.psi.types.PyModuleType;
@@ -28,8 +28,8 @@ import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.PythonDosStringFinder;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.controlflow.ControlFlow;
import com.jetbrains.python.psi.controlflow.PyControlFlowBuilder;
import com.jetbrains.python.codeInsight.controlflow.ControlFlow;
import com.jetbrains.python.codeInsight.controlflow.PyControlFlowBuilder;
import com.jetbrains.python.psi.stubs.PyClassStub;
import com.jetbrains.python.psi.stubs.PyFunctionStub;
import com.jetbrains.python.toolbox.SingleIterable;
@@ -0,0 +1,4 @@
while foo
if condition
break
puts "Hello"
@@ -0,0 +1,9 @@
0(1) element: null
1(2,8) element: PyWhileStatement
2(3) element: PyStatementList. Condition: foo:true
3(4,6) element: PyIfStatement
4(5) element: PyStatementList. Condition: condition:true
5(8) element: PyBreakStatement
6(7) element: PyExpressionStatement
7(1) element: PyExpressionStatement
8() element: null
@@ -0,0 +1,4 @@
while foo
if condition
continue
puts "Hello"
@@ -0,0 +1,9 @@
0(1) element: null
1(2,8) element: PyWhileStatement
2(3) element: PyStatementList. Condition: foo:true
3(4,6) element: PyIfStatement
4(5) element: PyStatementList. Condition: condition:true
5(1) element: PyContinueStatement
6(7) element: PyExpressionStatement
7(1) element: PyExpressionStatement
8() element: null
@@ -0,0 +1,2 @@
aaa = 12
print(aaa)
@@ -0,0 +1,5 @@
0(1) element: null
1(2) element: PyAssignmentStatement
2(3) WRITE ACCESS: aaa
3(4) element: PyPrintStatement
4() element: null
@@ -0,0 +1,4 @@
for i in range(10)
print(i)
else
print "Something went wrong"
@@ -0,0 +1,7 @@
0(1) element: null
1(2,5) element: PyForStatement
2(3) element: PyStatementList
3(4) WRITE ACCESS: i
4(2,6) element: PyPrintStatement
5(6) element: PyPrintStatement
6() element: null
@@ -0,0 +1,14 @@
def help(object, spacing=10, collapse=1):
"""Выводит методы и строки документации.
В качестве аргумента может использоваться модуль, класс, список, словарь
или строка."""
methodList = [method for method in dir(object) if callable(getattr(object, method))]
processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
print "\n".join(["%s %s" %
(method.ljust(spacing),
processFunc(str(getattr(object, method).__doc__)))
for method in methodList])
if __name__ == "__main__":
print help.__doc__
@@ -0,0 +1,15 @@
0(1) element: null
1(2) WRITE ACCESS: object
2(3) WRITE ACCESS: spacing
3(4) WRITE ACCESS: collapse
4(5) element: PyExpressionStatement
5(6) element: PyAssignmentStatement
6(7) WRITE ACCESS: method
7(8) WRITE ACCESS: methodList
8(9) element: PyAssignmentStatement
9(10) WRITE ACCESS: s
10(11) WRITE ACCESS: s
11(12) WRITE ACCESS: processFunc
12(13) element: PyPrintStatement
13(14) WRITE ACCESS: method
14() element: null
@@ -0,0 +1,19 @@
if 0:
pass
if 1:
pass
else:
pass
if 2:
pass
elif 3:
pass
if 4:
pass
elif 5:
pass
else:
1
@@ -0,0 +1,15 @@
0(1) element: null
1(2,3) element: PyIfStatement
2(3) element: PyStatementList. Condition: 0:true
3(4,5) element: PyIfStatement
4(6) element: PyStatementList. Condition: 1:true
5(6) element: PyElsePart. Condition: 1:false
6(7,8,9) element: PyIfStatement
7(9) element: PyStatementList. Condition: 2:true
8(9) element: PyIfPartIf. Condition: 3:true
9(10,11,12) element: PyIfStatement
10(14) element: PyStatementList. Condition: 4:true
11(14) element: PyIfPartIf. Condition: 5:true
12(13) element: PyElsePart. Condition: 5:false
13(14) element: PyExpressionStatement
14() element: null
@@ -0,0 +1 @@
[k for k, v in params.items()]
@@ -0,0 +1,4 @@
while foo
if condition
return "Result"
puts "Hello"
@@ -0,0 +1,9 @@
0(1) element: null
1(2,8) element: PyWhileStatement
2(3) element: PyStatementList. Condition: foo:true
3(4,6) element: PyIfStatement
4(5) element: PyStatementList. Condition: condition:true
5(8) element: PyReturnStatement
6(7) element: PyExpressionStatement
7(1) element: PyExpressionStatement
8() element: null
@@ -0,0 +1,13 @@
import sys
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except IOError as (errno, strerror):
print "I/O error({0}): {1}".format(errno, strerror)
except ValueError:
print "Could not convert data to an integer."
except:
print "Unexpected error:", sys.exc_info()[0]
raise
@@ -0,0 +1,20 @@
0(1) element: null
1(2) element: PyImportStatement
2(3) element: PyTryExceptStatement
3(4) element: PyTryPart
4(5) element: PyAssignmentStatement
5(6) WRITE ACCESS: f
6(7) element: PyAssignmentStatement
7(8) WRITE ACCESS: s
8(9) element: PyAssignmentStatement
9(10,14,16,19) WRITE ACCESS: i
10(11) element: PyExceptPart
11(12) WRITE ACCESS: errno
12(13) WRITE ACCESS: strerror
13(19) element: PyPrintStatement
14(15) element: PyExceptPart
15(19) element: PyPrintStatement
16(17) element: PyExceptPart
17(18) element: PyPrintStatement
18(19) element: PyRaiseStatement
19() element: null
@@ -0,0 +1,4 @@
while condition
print("Alloha!")
else:
print("Bye")
@@ -0,0 +1,7 @@
0(1) element: null
1(2) element: PyWhileStatement
2(3) element: PyStatementList. Condition: condition:true
3(1,4) element: PyPrintStatement
4(5) element: PyStatementList. Condition: condition:false
5(6) element: PyPrintStatement
6() element: null
@@ -7,8 +7,8 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.jetbrains.python.fixtures.LightMarkedTestCase;
import com.jetbrains.python.psi.PyFile;
import com.jetbrains.python.psi.PyFunction;
import com.jetbrains.python.psi.controlflow.ControlFlow;
import com.jetbrains.python.psi.controlflow.Instruction;
import com.jetbrains.python.codeInsight.controlflow.ControlFlow;
import com.jetbrains.python.codeInsight.controlflow.Instruction;
import java.io.File;
import java.io.IOException;
@@ -19,7 +19,7 @@ import java.io.IOException;
public class PyControlFlowBuilderTest extends LightMarkedTestCase {
public String getTestDataPath() {
return PythonTestUtil.getTestDataPath() + "/psi/controlflow/";
return PythonTestUtil.getTestDataPath() + "/codeInsight/controlflow/";
}
private void doTest() throws Exception {