1.1 --- a/compiler/visitor.py Fri May 18 23:35:21 2012 +0200
1.2 +++ b/compiler/visitor.py Fri May 18 23:39:33 2012 +0200
1.3 @@ -1,39 +1,24 @@
1.4 -from compiler import ast
1.5 +#!/usr/bin/env python
1.6
1.7 -# XXX should probably rename ASTVisitor to ASTWalker
1.8 -# XXX can it be made even more generic?
1.9 +from compiler import ast
1.10
1.11 class ASTVisitor:
1.12 - """Performs a depth-first walk of the AST
1.13
1.14 - The ASTVisitor will walk the AST, performing either a preorder or
1.15 - postorder traversal depending on which method is called.
1.16 -
1.17 - methods:
1.18 - preorder(tree, visitor)
1.19 - postorder(tree, visitor)
1.20 - tree: an instance of ast.Node
1.21 - visitor: an instance with visitXXX methods
1.22 + """
1.23 + Performs a depth-first walk of the AST.
1.24
1.25 - The ASTVisitor is responsible for walking over the tree in the
1.26 - correct order. For each node, it checks the visitor argument for
1.27 - a method named 'visitNodeType' where NodeType is the name of the
1.28 - node's class, e.g. Class. If the method exists, it is called
1.29 - with the node as its sole argument.
1.30 + The ASTVisitor is responsible for walking over the tree in the correct
1.31 + order. For each node, it calls the 'visit' method on the node, and this
1.32 + method is then responsible to calling an appropriate method on the visitor.
1.33
1.34 - The visitor method for a particular node type can control how
1.35 - child nodes are visited during a preorder walk. (It can't control
1.36 - the order during a postorder walk, because it is called _after_
1.37 - the walk has occurred.) The ASTVisitor modifies the visitor
1.38 - argument by adding a visit method to the visitor; this method can
1.39 - be used to visit a child node of arbitrary type.
1.40 + For example, where 'Class' is the name of the node's class, the node's
1.41 + 'visit' method might invoke a 'visitClass' method on the visitor, although
1.42 + it need not follow this particular naming convention.
1.43 """
1.44
1.45 - VERBOSE = 0
1.46 -
1.47 def __init__(self):
1.48 self.node = None
1.49 - self._cache = {}
1.50 + self.visitor = self
1.51
1.52 def default(self, node, *args):
1.53 for child in node.getChildNodes():
1.54 @@ -41,73 +26,28 @@
1.55
1.56 def dispatch(self, node, *args):
1.57 self.node = node
1.58 - klass = node.__class__
1.59 - meth = self._cache.get(klass, None)
1.60 - if meth is None:
1.61 - className = klass.__name__
1.62 - meth = getattr(self.visitor, 'visit' + className, self.default)
1.63 - self._cache[klass] = meth
1.64 -## if self.VERBOSE > 0:
1.65 -## className = klass.__name__
1.66 -## if self.VERBOSE == 1:
1.67 -## if meth == 0:
1.68 -## print "dispatch", className
1.69 -## else:
1.70 -## print "dispatch", className, (meth and meth.__name__ or '')
1.71 - return meth(node, *args)
1.72 + try:
1.73 + return node.visit(self.visitor, *args)
1.74 + except AttributeError:
1.75 + return self.visitor.default(node, *args)
1.76
1.77 def preorder(self, tree, visitor, *args):
1.78 - """Do preorder walk of tree using visitor"""
1.79 +
1.80 + "Do preorder walk of tree using visitor."
1.81 +
1.82 self.visitor = visitor
1.83 visitor.visit = self.dispatch
1.84 - self.dispatch(tree, *args) # XXX *args make sense?
1.85 -
1.86 -class ExampleASTVisitor(ASTVisitor):
1.87 - """Prints examples of the nodes that aren't visited
1.88 -
1.89 - This visitor-driver is only useful for development, when it's
1.90 - helpful to develop a visitor incrementally, and get feedback on what
1.91 - you still have to do.
1.92 - """
1.93 - examples = {}
1.94
1.95 - def dispatch(self, node, *args):
1.96 - self.node = node
1.97 - meth = self._cache.get(node.__class__, None)
1.98 - className = node.__class__.__name__
1.99 - if meth is None:
1.100 - meth = getattr(self.visitor, 'visit' + className, 0)
1.101 - self._cache[node.__class__] = meth
1.102 - if self.VERBOSE > 1:
1.103 - print "dispatch", className, (meth and meth.__name__ or '')
1.104 - if meth:
1.105 - meth(node, *args)
1.106 - elif self.VERBOSE > 0:
1.107 - klass = node.__class__
1.108 - if klass not in self.examples:
1.109 - self.examples[klass] = klass
1.110 - print
1.111 - print self.visitor
1.112 - print klass
1.113 - for attr in dir(node):
1.114 - if attr[0] != '_':
1.115 - print "\t", "%-12.12s" % attr, getattr(node, attr)
1.116 - print
1.117 - return self.default(node, *args)
1.118 + # NOTE: *args not exposed by the walk function.
1.119
1.120 -# XXX this is an API change
1.121 + self.dispatch(tree, *args)
1.122
1.123 _walker = ASTVisitor
1.124 -def walk(tree, visitor, walker=None, verbose=None):
1.125 +
1.126 +def walk(tree, visitor, walker=None):
1.127 if walker is None:
1.128 walker = _walker()
1.129 - if verbose is not None:
1.130 - walker.VERBOSE = verbose
1.131 walker.preorder(tree, visitor)
1.132 return walker.visitor
1.133
1.134 -def dumpNode(node):
1.135 - print node.__class__
1.136 - for attr in dir(node):
1.137 - if attr[0] != '_':
1.138 - print "\t", "%-10.10s" % attr, getattr(node, attr)
1.139 +# vim: tabstop=4 expandtab shiftwidth=4