paul@4 | 1 | #!/usr/bin/env python |
paul@0 | 2 | |
paul@4 | 3 | from compiler import ast |
paul@0 | 4 | |
paul@0 | 5 | class ASTVisitor: |
paul@0 | 6 | |
paul@4 | 7 | """ |
paul@4 | 8 | Performs a depth-first walk of the AST. |
paul@0 | 9 | |
paul@4 | 10 | The ASTVisitor is responsible for walking over the tree in the correct |
paul@4 | 11 | order. For each node, it calls the 'visit' method on the node, and this |
paul@4 | 12 | method is then responsible to calling an appropriate method on the visitor. |
paul@0 | 13 | |
paul@4 | 14 | For example, where 'Class' is the name of the node's class, the node's |
paul@4 | 15 | 'visit' method might invoke a 'visitClass' method on the visitor, although |
paul@4 | 16 | it need not follow this particular naming convention. |
paul@0 | 17 | """ |
paul@0 | 18 | |
paul@0 | 19 | def __init__(self): |
paul@0 | 20 | self.node = None |
paul@4 | 21 | self.visitor = self |
paul@0 | 22 | |
paul@0 | 23 | def default(self, node, *args): |
paul@0 | 24 | for child in node.getChildNodes(): |
paul@0 | 25 | self.dispatch(child, *args) |
paul@0 | 26 | |
paul@0 | 27 | def dispatch(self, node, *args): |
paul@0 | 28 | self.node = node |
paul@4 | 29 | try: |
paul@4 | 30 | return node.visit(self.visitor, *args) |
paul@4 | 31 | except AttributeError: |
paul@4 | 32 | return self.visitor.default(node, *args) |
paul@0 | 33 | |
paul@0 | 34 | def preorder(self, tree, visitor, *args): |
paul@4 | 35 | |
paul@4 | 36 | "Do preorder walk of tree using visitor." |
paul@4 | 37 | |
paul@0 | 38 | self.visitor = visitor |
paul@0 | 39 | visitor.visit = self.dispatch |
paul@0 | 40 | |
paul@4 | 41 | # NOTE: *args not exposed by the walk function. |
paul@0 | 42 | |
paul@4 | 43 | self.dispatch(tree, *args) |
paul@0 | 44 | |
paul@0 | 45 | _walker = ASTVisitor |
paul@4 | 46 | |
paul@4 | 47 | def walk(tree, visitor, walker=None): |
paul@0 | 48 | if walker is None: |
paul@0 | 49 | walker = _walker() |
paul@0 | 50 | walker.preorder(tree, visitor) |
paul@0 | 51 | return walker.visitor |
paul@0 | 52 | |
paul@4 | 53 | # vim: tabstop=4 expandtab shiftwidth=4 |