51 def dot_id(self): |
51 def dot_id(self): |
52 return id(self) |
52 return id(self) |
53 |
53 |
54 |
54 |
55 class PathGraph(object): |
55 class PathGraph(object): |
56 def __init__(self, name, entity, lineno): |
56 def __init__(self, name, entity, lineno, column=0): |
57 self.name = name |
57 self.name = name |
58 self.entity = entity |
58 self.entity = entity |
59 self.lineno = lineno |
59 self.lineno = lineno |
|
60 self.column = column |
60 self.nodes = collections.defaultdict(list) |
61 self.nodes = collections.defaultdict(list) |
61 |
62 |
62 def connect(self, n1, n2): |
63 def connect(self, n1, n2): |
63 self.nodes[n1].append(n2) |
64 self.nodes[n1].append(n2) |
64 # Ensure that the destination node is always counted. |
65 # Ensure that the destination node is always counted. |
118 bottom = PathNode("", look='point') |
119 bottom = PathNode("", look='point') |
119 self.graph.connect(self.tail, bottom) |
120 self.graph.connect(self.tail, bottom) |
120 self.graph.connect(pathnode, bottom) |
121 self.graph.connect(pathnode, bottom) |
121 self.tail = bottom |
122 self.tail = bottom |
122 else: |
123 else: |
123 self.graph = PathGraph(name, entity, node.lineno) |
124 self.graph = PathGraph(name, entity, node.lineno, node.col_offset) |
124 pathnode = PathNode(name) |
125 pathnode = PathNode(name) |
125 self.tail = pathnode |
126 self.tail = pathnode |
126 self.dispatch_list(node.body) |
127 self.dispatch_list(node.body) |
127 self.graphs["%s%s" % (self.classname, node.name)] = self.graph |
128 self.graphs["%s%s" % (self.classname, node.name)] = self.graph |
128 self.reset() |
129 self.reset() |
149 else: |
150 else: |
150 lineno = node.lineno |
151 lineno = node.lineno |
151 name = "Stmt %d" % lineno |
152 name = "Stmt %d" % lineno |
152 self.appendPathNode(name) |
153 self.appendPathNode(name) |
153 |
154 |
154 visitAssert = visitAssign = visitAugAssign = visitDelete = visitPrint = \ |
155 def default(self, node, *args): |
155 visitRaise = visitYield = visitImport = visitCall = visitSubscript = \ |
156 if isinstance(node, ast.stmt): |
156 visitPass = visitContinue = visitBreak = visitGlobal = visitReturn = \ |
157 self.visitSimpleStatement(node) |
157 visitSimpleStatement |
158 else: |
|
159 super(PathGraphingAstVisitor, self).default(node, *args) |
158 |
160 |
159 def visitLoop(self, node): |
161 def visitLoop(self, node): |
160 name = "Loop %d" % node.lineno |
162 name = "Loop %d" % node.lineno |
161 self._subgraph(node, name) |
163 self._subgraph(node, name) |
162 |
164 |
163 visitFor = visitAsyncFor = visitWhile = visitLoop |
165 visitAsyncFor = visitFor = visitWhile = visitLoop |
164 |
166 |
165 def visitIf(self, node): |
167 def visitIf(self, node): |
166 name = "If %d" % node.lineno |
168 name = "If %d" % node.lineno |
167 self._subgraph(node, name) |
169 self._subgraph(node, name) |
168 |
170 |
169 def _subgraph(self, node, name, extra_blocks=()): |
171 def _subgraph(self, node, name, extra_blocks=()): |
170 """create the subgraphs representing any `if` and `for` statements""" |
172 """create the subgraphs representing any `if` and `for` statements""" |
171 if self.graph is None: |
173 if self.graph is None: |
172 # global loop |
174 # global loop |
173 self.graph = PathGraph(name, name, node.lineno) |
175 self.graph = PathGraph(name, name, node.lineno, node.col_offset) |
174 pathnode = PathNode(name) |
176 pathnode = PathNode(name) |
175 self._subgraph_parse(node, pathnode, extra_blocks) |
177 self._subgraph_parse(node, pathnode, extra_blocks) |
176 self.graphs["%s%s" % (self.classname, name)] = self.graph |
178 self.graphs["%s%s" % (self.classname, name)] = self.graph |
177 self.reset() |
179 self.reset() |
178 else: |
180 else: |