PyXR

c:\python24\lib \ compiler \ visitor.py



0001 from compiler import ast
0002 
0003 # XXX should probably rename ASTVisitor to ASTWalker
0004 # XXX can it be made even more generic?
0005 
0006 class ASTVisitor:
0007     """Performs a depth-first walk of the AST
0008 
0009     The ASTVisitor will walk the AST, performing either a preorder or
0010     postorder traversal depending on which method is called.
0011 
0012     methods:
0013     preorder(tree, visitor)
0014     postorder(tree, visitor)
0015         tree: an instance of ast.Node
0016         visitor: an instance with visitXXX methods
0017 
0018     The ASTVisitor is responsible for walking over the tree in the
0019     correct order.  For each node, it checks the visitor argument for
0020     a method named 'visitNodeType' where NodeType is the name of the
0021     node's class, e.g. Class.  If the method exists, it is called
0022     with the node as its sole argument.
0023 
0024     The visitor method for a particular node type can control how
0025     child nodes are visited during a preorder walk.  (It can't control
0026     the order during a postorder walk, because it is called _after_
0027     the walk has occurred.)  The ASTVisitor modifies the visitor
0028     argument by adding a visit method to the visitor; this method can
0029     be used to visit a child node of arbitrary type.
0030     """
0031 
0032     VERBOSE = 0
0033 
0034     def __init__(self):
0035         self.node = None
0036         self._cache = {}
0037 
0038     def default(self, node, *args):
0039         for child in node.getChildNodes():
0040             self.dispatch(child, *args)
0041 
0042     def dispatch(self, node, *args):
0043         self.node = node
0044         klass = node.__class__
0045         meth = self._cache.get(klass, None)
0046         if meth is None:
0047             className = klass.__name__
0048             meth = getattr(self.visitor, 'visit' + className, self.default)
0049             self._cache[klass] = meth
0050 ##        if self.VERBOSE > 0:
0051 ##            className = klass.__name__
0052 ##            if self.VERBOSE == 1:
0053 ##                if meth == 0:
0054 ##                    print "dispatch", className
0055 ##            else:
0056 ##                print "dispatch", className, (meth and meth.__name__ or '')
0057         return meth(node, *args)
0058 
0059     def preorder(self, tree, visitor, *args):
0060         """Do preorder walk of tree using visitor"""
0061         self.visitor = visitor
0062         visitor.visit = self.dispatch
0063         self.dispatch(tree, *args) # XXX *args make sense?
0064 
0065 class ExampleASTVisitor(ASTVisitor):
0066     """Prints examples of the nodes that aren't visited
0067 
0068     This visitor-driver is only useful for development, when it's
0069     helpful to develop a visitor incrementally, and get feedback on what
0070     you still have to do.
0071     """
0072     examples = {}
0073 
0074     def dispatch(self, node, *args):
0075         self.node = node
0076         meth = self._cache.get(node.__class__, None)
0077         className = node.__class__.__name__
0078         if meth is None:
0079             meth = getattr(self.visitor, 'visit' + className, 0)
0080             self._cache[node.__class__] = meth
0081         if self.VERBOSE > 1:
0082             print "dispatch", className, (meth and meth.__name__ or '')
0083         if meth:
0084             meth(node, *args)
0085         elif self.VERBOSE > 0:
0086             klass = node.__class__
0087             if not self.examples.has_key(klass):
0088                 self.examples[klass] = klass
0089                 print
0090                 print self.visitor
0091                 print klass
0092                 for attr in dir(node):
0093                     if attr[0] != '_':
0094                         print "\t", "%-12.12s" % attr, getattr(node, attr)
0095                 print
0096             return self.default(node, *args)
0097 
0098 # XXX this is an API change
0099 
0100 _walker = ASTVisitor
0101 def walk(tree, visitor, walker=None, verbose=None):
0102     if walker is None:
0103         walker = _walker()
0104     if verbose is not None:
0105         walker.VERBOSE = verbose
0106     walker.preorder(tree, visitor)
0107     return walker.visitor
0108 
0109 def dumpNode(node):
0110     print node.__class__
0111     for attr in dir(node):
0112         if attr[0] != '_':
0113             print "\t", "%-10.10s" % attr, getattr(node, attr)
0114 

Generated by PyXR 0.9.4
SourceForge.net Logo