# HG changeset patch # User Paul Boddie # Date 1337279134 -7200 # Node ID 5b1d239ec500751ad148f31084909ebc740d95e9 # Parent 160410d522daa9b7a309896378f0a95ab6d1e0c4 Changed the dispatch mechanism to use the visit methods provided by nodes. Removed obsolete classes and functions; tidied up the docstrings and comments. diff -r 160410d522da -r 5b1d239ec500 compiler/visitor.py --- a/compiler/visitor.py Thu May 17 20:22:53 2012 +0200 +++ b/compiler/visitor.py Thu May 17 20:25:34 2012 +0200 @@ -1,39 +1,24 @@ -from compiler import ast +#!/usr/bin/env python -# XXX should probably rename ASTVisitor to ASTWalker -# XXX can it be made even more generic? +from compiler import ast class ASTVisitor: - """Performs a depth-first walk of the AST - The ASTVisitor will walk the AST, performing either a preorder or - postorder traversal depending on which method is called. - - methods: - preorder(tree, visitor) - postorder(tree, visitor) - tree: an instance of ast.Node - visitor: an instance with visitXXX methods + """ + Performs a depth-first walk of the AST. - The ASTVisitor is responsible for walking over the tree in the - correct order. For each node, it checks the visitor argument for - a method named 'visitNodeType' where NodeType is the name of the - node's class, e.g. Class. If the method exists, it is called - with the node as its sole argument. + The ASTVisitor is responsible for walking over the tree in the correct + order. For each node, it calls the 'visit' method on the node, and this + method is then responsible to calling an appropriate method on the visitor. - The visitor method for a particular node type can control how - child nodes are visited during a preorder walk. (It can't control - the order during a postorder walk, because it is called _after_ - the walk has occurred.) The ASTVisitor modifies the visitor - argument by adding a visit method to the visitor; this method can - be used to visit a child node of arbitrary type. + For example, where 'Class' is the name of the node's class, the node's + 'visit' method might invoke a 'visitClass' method on the visitor, although + it need not follow this particular naming convention. """ - VERBOSE = 0 - def __init__(self): self.node = None - self._cache = {} + self.visitor = self def default(self, node, *args): for child in node.getChildNodes(): @@ -41,73 +26,28 @@ def dispatch(self, node, *args): self.node = node - klass = node.__class__ - meth = self._cache.get(klass, None) - if meth is None: - className = klass.__name__ - meth = getattr(self.visitor, 'visit' + className, self.default) - self._cache[klass] = meth -## if self.VERBOSE > 0: -## className = klass.__name__ -## if self.VERBOSE == 1: -## if meth == 0: -## print "dispatch", className -## else: -## print "dispatch", className, (meth and meth.__name__ or '') - return meth(node, *args) + try: + return node.visit(self.visitor, *args) + except AttributeError: + return self.visitor.default(node, *args) def preorder(self, tree, visitor, *args): - """Do preorder walk of tree using visitor""" + + "Do preorder walk of tree using visitor." + self.visitor = visitor visitor.visit = self.dispatch - self.dispatch(tree, *args) # XXX *args make sense? - -class ExampleASTVisitor(ASTVisitor): - """Prints examples of the nodes that aren't visited - - This visitor-driver is only useful for development, when it's - helpful to develop a visitor incrementally, and get feedback on what - you still have to do. - """ - examples = {} - def dispatch(self, node, *args): - self.node = node - meth = self._cache.get(node.__class__, None) - className = node.__class__.__name__ - if meth is None: - meth = getattr(self.visitor, 'visit' + className, 0) - self._cache[node.__class__] = meth - if self.VERBOSE > 1: - print "dispatch", className, (meth and meth.__name__ or '') - if meth: - meth(node, *args) - elif self.VERBOSE > 0: - klass = node.__class__ - if not self.examples.has_key(klass): - self.examples[klass] = klass - print - print self.visitor - print klass - for attr in dir(node): - if attr[0] != '_': - print "\t", "%-12.12s" % attr, getattr(node, attr) - print - return self.default(node, *args) + # NOTE: *args not exposed by the walk function. -# XXX this is an API change + self.dispatch(tree, *args) _walker = ASTVisitor -def walk(tree, visitor, walker=None, verbose=None): + +def walk(tree, visitor, walker=None): if walker is None: walker = _walker() - if verbose is not None: - walker.VERBOSE = verbose walker.preorder(tree, visitor) return walker.visitor -def dumpNode(node): - print node.__class__ - for attr in dir(node): - if attr[0] != '_': - print "\t", "%-10.10s" % attr, getattr(node, attr) +# vim: tabstop=4 expandtab shiftwidth=4