Converts an AST to CFGs. A separate CFG will be constructed for each function.
| 611 | |
| 612 | |
| 613 | class AstToCfg(gast.NodeVisitor): |
| 614 | """Converts an AST to CFGs. |
| 615 | |
| 616 | A separate CFG will be constructed for each function. |
| 617 | """ |
| 618 | |
| 619 | def __init__(self): |
| 620 | super(AstToCfg, self).__init__() |
| 621 | |
| 622 | self.builder_stack = [] |
| 623 | self.builder = None |
| 624 | self.cfgs = {} |
| 625 | |
| 626 | self.lexical_scopes = [] |
| 627 | |
| 628 | def _enter_lexical_scope(self, node): |
| 629 | self.lexical_scopes.append(node) |
| 630 | |
| 631 | def _exit_lexical_scope(self, node): |
| 632 | leaving_node = self.lexical_scopes.pop() |
| 633 | assert node == leaving_node |
| 634 | |
| 635 | def _get_enclosing_finally_scopes(self, stop_at): |
| 636 | included = [] |
| 637 | for node in reversed(self.lexical_scopes): |
| 638 | if isinstance(node, gast.Try) and node.finalbody: |
| 639 | included.append(node) |
| 640 | if isinstance(node, stop_at): |
| 641 | return node, included |
| 642 | return None, included |
| 643 | |
| 644 | def _process_basic_statement(self, node): |
| 645 | self.generic_visit(node) |
| 646 | self.builder.add_ordinary_node(node) |
| 647 | |
| 648 | def _process_exit_statement(self, node, *exits_nodes_of_type): |
| 649 | # Note: this is safe because we process functions separately. |
| 650 | try_node, guards = self._get_enclosing_finally_scopes( |
| 651 | tuple(exits_nodes_of_type)) |
| 652 | if try_node is None: |
| 653 | raise ValueError( |
| 654 | '%s that is not enclosed by any of %s' % (node, exits_nodes_of_type)) |
| 655 | self.builder.add_exit_node(node, try_node, guards) |
| 656 | |
| 657 | def _process_continue_statement(self, node, *loops_to_nodes_of_type): |
| 658 | # Note: this is safe because we process functions separately. |
| 659 | try_node, guards = self._get_enclosing_finally_scopes( |
| 660 | tuple(loops_to_nodes_of_type)) |
| 661 | if try_node is None: |
| 662 | raise ValueError('%s that is not enclosed by any of %s' % |
| 663 | (node, loops_to_nodes_of_type)) |
| 664 | self.builder.add_continue_node(node, try_node, guards) |
| 665 | |
| 666 | def visit_ClassDef(self, node): |
| 667 | # We also keep the ClassDef node in the CFG, since it technically is a |
| 668 | # statement. |
| 669 | # For example, this is legal and allows executing user code: |
| 670 | # |