Parse the online documentation for compiler.ast and generate code for a skeletal ASTVisitor class that includes stubs for all of the various visitNODE functions you might need in a visitor, along with comments in each function that list that node type's attributes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | #!/usr/bin/env python
# AST Visitor generator recipe
#
# Lonnie Princehouse, 2004
import re
# Set this to the current location of the compiler ast module HTML doc
# (the page that has a table of AST Node types and attributes)
compiler_ast_doc_url = 'http://docs.python.org/lib/module-compiler.ast.html'
klass = '<tt class="class">(?P<klass>\S+?)</tt></td>'
member = '<td><tt class="member">(?P<member>\S+)</tt></td>\s+<td>(?P<doc>.*?)</td>'
finder = re.compile("%s|%s" % (klass, member))
nodes = []
class ASTDocNode:
def __init__(self, name):
self.name = name
self.attributes = []
def add_attribute(self, attribute, comment):
self.attributes.append( (attribute, comment) )
def __str__(self):
atlist = []
for a,c in self.attributes:
if a:
if c == ' ':
c = ''
atlist.append(" # %-16s %s" % (a,c))
attribute_list = '\n'.join(atlist)
name = self.name
return """
def visit%(name)s(self, node):
# %(name)s attributes
%(attribute_list)s
raise NotImplementedException('visit%(name)s')""" % locals()
def generate_visitor_skeleton(output_stream, url = compiler_ast_doc_url, node_class = ASTDocNode, visitor_class_name = 'VisitorSkeleton'):
import urllib
document = urllib.urlopen(url)
html_source = document.read()
document.close()
header = """
import compiler.visitor
class NotImplementedException(Exception): pass
class %s(compiler.visitor.ASTVisitor): """ % visitor_class_name
for klass, attribute, comment in finder.findall(html_source):
if klass not in ('', ' '):
nodes.append(node_class(klass))
else:
nodes[-1].add_attribute(attribute, comment)
print >> output_stream, header
for n in nodes:
print >> output_stream, str(n)
if __name__ == '__main__':
import sys
# Optional command line argument is the URL of the Node doc.
# This argument might be useful if (a) you don't have network access, but have a local copy of the docs.
# or (b) you want to build a visitor for an old version of Python (at the time of this writing, current
# docs are for 2.3.4)
if len(sys.argv) > 1:
url = sys.argv[1]
else:
url = compiler_ast_doc_url
generate_visitor_skeleton(sys.stdout, url)
|
If you are writing an AST Visitor, this might save you from referring back to the docs every five seconds.
I'll include a separate recipe that is simply the output of this program, but dynamically generating the visitor has the advantage of using the most up-to-date python docs (er, at least so long as they don't change the format of the doc page :P)
[side note- this doesn't have anything to do with Python generators.. I mean generator in a more general sense]