0001 # Copyright 2003, Grant T. Olson, see License.txt for details 0002 0003 import types 0004 import parser 0005 import token 0006 import symbol 0007 import sys 0008 0009 class astCrawler: 0010 """ 0011 ABC for ast processing. 0012 0013 This turns input text into an ast and then crawls through it. 0014 0015 There are two types of nodes in a python AST: 0016 SYMBOLs are nonterminal nodes that consist of a SYMBOL_ID and a list of other nodes 0017 TOKENs are terminal nodes that consist of a TOKEN_ID and a string that represents token value 0018 0019 Process strips a node into two pieces, the ID and the list of nodes or tokenString 0020 it dispatches this to handler functions by looking up the nodeID in the self.handlers dict 0021 if no entry is found, it calls the default handler. 0022 0023 Calling process with no params starts at the top of the tree. 0024 """ 0025 def __init__(self, text): 0026 self.ast = parser.ast2tuple(parser.suite(text)) 0027 self.handlers = {} 0028 self.registerHandlers() 0029 0030 def simplify(self, tuple): 0031 """ 0032 Python uses alot of intermediate nodes to simplify tree construction. 0033 This will factor out intermediate nodes that only contain a single child 0034 to give us humans some chance at being able to interpret junk 0035 """ 0036 if type(tuple) == types.IntType: 0037 return tuple 0038 elif type(tuple) == types.StringType: 0039 return tuple 0040 elif type(tuple) == types.TupleType: 0041 if len(tuple) == 2 and type(tuple[0]) == types.IntType and type(tuple[1]) == types.TupleType: 0042 return self.simplify(tuple[1]) 0043 else: 0044 return map(self.simplify, tuple) 0045 else: 0046 raise Exception("Invalid type") 0047 0048 0049 0050 def simplifyWithName(self, tuple): 0051 """ 0052 Same as simplify, but it shows the symbol or token name instead of ID number 0053 """ 0054 if type(tuple) == types.IntType: 0055 return self.numberToName(tuple) 0056 elif type(tuple) == types.StringType: 0057 return tuple 0058 elif type(tuple) == types.TupleType: 0059 if len(tuple) == 2 and type(tuple[0]) == types.IntType and type(tuple[1]) == types.TupleType: 0060 return self.simplifyWithName(tuple[1]) 0061 else: 0062 return map(self.simplifyWithName, tuple) 0063 else: 0064 raise Exception("Invalid type") 0065 0066 def numberToName(self, number): 0067 """ 0068 Turns a node ID number into the string description from token and symbol packages 0069 """ 0070 if token.tok_name.has_key(number): 0071 return token.tok_name[number] 0072 elif symbol.sym_name.has_key(number): 0073 return symbol.sym_name[number] 0074 else: 0075 return "UNKNOWN SYMBOL %d" % tuple 0076 0077 def process(self, ast=None): 0078 """ 0079 Recursively process the ast tree and dispatch to whatever handlers we've instituted in subclasses 0080 """ 0081 if not ast: 0082 ast = self.ast 0083 if type(ast) == types.TupleType: 0084 nodeType = ast[0] 0085 nodeParams = ast[1:] 0086 nodeHandler = self.handlers.get(nodeType, self.defaultHandler) 0087 nodeHandler(nodeParams) 0088 else: 0089 raise Exception("Process error: Type is not a tuple %s" % ast) 0090 0091 ### 0092 ### HANDLERS 0093 ### 0094 0095 def registerHandlers(self): 0096 """ 0097 break registration logic out of the constructor so we can 0098 deal with subclasses properly 0099 """ 0100 pass 0101 0102 def defaultHandler(self, params): 0103 """ 0104 process all nodes that we don't know about 0105 """ 0106 for item in params: 0107 if type(item) == types.TupleType: # recursively process nodes 0108 self.process(item) 0109 elif type(item) == types.StringType: # this is the value of a token 0110 self.defaultHandleToken(item) 0111 else: 0112 raise Exception("Invalid node parameters") 0113 0114 def defaultHandleToken(self, item): 0115 """Override this function so we can keep default handler core logic""" 0116 pass 0117 0118 0119 0120 0121
Generated by PyXR 0.9.4