1 #!/usr/bin/env python 2 3 """ 4 Simplified AST nodes for easier type propagation and analysis. 5 6 Copyright (C) 2006 Paul Boddie <paul@boddie.org.uk> 7 8 This software is free software; you can redistribute it and/or 9 modify it under the terms of the GNU General Public License as 10 published by the Free Software Foundation; either version 2 of 11 the License, or (at your option) any later version. 12 13 This software is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public 19 License along with this library; see the file LICENCE.txt 20 If not, write to the Free Software Foundation, Inc., 21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 22 """ 23 24 from compiler.visitor import ASTVisitor 25 import sys 26 27 # Unique name registration. 28 29 class Naming: 30 def __init__(self): 31 self.obj_to_name = {} 32 self.names = {} 33 def get(self, obj): 34 return self.obj_to_name[obj] 35 def set(self, obj, name): 36 if self.obj_to_name.has_key(obj): 37 return 38 if not self.names.has_key(name): 39 self.names[name] = 0 40 n = self.names[name] + 1 41 self.names[name] = n 42 self.obj_to_name[obj] = "%s#%d" % (name, n) 43 44 naming = Naming() 45 46 def name(obj, name): 47 naming.set(obj, name) 48 return naming.get(obj) 49 50 # Elementary visitor support. 51 52 class Visitor(ASTVisitor): 53 54 "A visitor base class." 55 56 def __init__(self): 57 ASTVisitor.__init__(self) 58 59 def default(self, node, *args): 60 raise ValueError, node.__class__ 61 62 def dispatch(self, node, *args): 63 return ASTVisitor.dispatch(self, node, *args) 64 65 def dispatches(self, nodes, *args): 66 results = [] 67 for node in nodes: 68 results.append(self.dispatch(node, *args)) 69 return results 70 71 # Simplified program nodes. 72 73 class Node: 74 75 """ 76 A result node with common attributes: 77 78 original The original node from which this node was created. 79 name Any name involved (variable or attribute). 80 index Any index involved (temporary variable name). 81 value Any constant value. 82 ref Any reference to (for example) subprograms. 83 nstype Any indication of the namespace type involved in a name access. 84 85 Expression-related attributes: 86 87 expr Any contributing expression. 88 lvalue Any target expression. 89 test Any test expression in a conditional instruction. 90 91 Invocation and subprogram attributes: 92 93 args Any collection of argument nodes. 94 params Any collection of parameter nodes and defaults. 95 96 Statement-grouping attributes: 97 98 body Any conditional code depending on the success of a test. 99 else_ Any conditional code depending on the failure of a test. 100 handler Any exception handler code. 101 finally_ Any code which will be executed regardless. 102 code Any unconditional code. 103 choices Any choices which may be included in the final program. 104 """ 105 106 def __init__(self, original=None, **kw): 107 108 """ 109 Initialise a program node with an optional link to an 'original' AST 110 node. 111 """ 112 113 self.original = original 114 if self.original is not None: 115 self.original._node = self 116 for name, value in kw.items(): 117 setattr(self, name, value) 118 119 def __repr__(self): 120 if hasattr(self, "full_name"): 121 return "%s '%s'" % (self.__class__.__name__, self.full_name) 122 elif hasattr(self, "name"): 123 return "%s '%s'" % (self.__class__.__name__, self.name) 124 elif hasattr(self, "index"): 125 return "%s (%s)" % (self.__class__.__name__, self.index) 126 elif hasattr(self, "value"): 127 return "%s %s" % (self.__class__.__name__, repr(self.value)) 128 elif hasattr(self, "ref"): 129 return "%s '%s'" % (self.__class__.__name__, name(self.ref, self.ref.name)) 130 else: 131 return "%s" % (self.__class__.__name__,) 132 133 def _pprint(self, indent, continuation, s, stream=None): 134 stream = stream or sys.stdout 135 if continuation: 136 print >>stream, (" " * max(0, indent - len(continuation))) + continuation + s 137 else: 138 print >>stream, (" " * indent) + s 139 140 def pprint(self, indent=0, continuation=None, stream=None): 141 stream = stream or sys.stdout 142 self._pprint(indent, continuation, repr(self), stream) 143 144 # Subprogram-related details. 145 146 if hasattr(self, "params"): 147 for name, default in self.params: 148 self._pprint(indent + 2, "( ", "%s -> %s" % (name, default), stream=stream) 149 if hasattr(self, "star") and self.star: 150 name, default = self.star 151 self._pprint(indent + 2, "( ", "%s -> %s" % (name, default), stream=stream) 152 if hasattr(self, "dstar") and self.dstar: 153 name, default = self.dstar 154 self._pprint(indent + 2, "( ", "%s -> %s" % (name, default), stream=stream) 155 if getattr(self, "acquire_locals", 0): 156 self._pprint(indent + 2, "( ", "acquiring locals", stream=stream) 157 if getattr(self, "structure", 0): 158 self._pprint(indent + 2, "( ", "structure '%s'" % self.structure.name, stream=stream) 159 160 # Statement-related details. 161 162 if hasattr(self, "test"): 163 self.test.pprint(indent + 2, "? ", stream=stream) 164 for attr in "code", "body", "else_", "handler", "finally_", "choices": 165 if hasattr(self, attr) and getattr(self, attr): 166 self._pprint(indent, "", "%s {" % attr, stream=stream) 167 for node in getattr(self, attr): 168 node.pprint(indent + 2, stream=stream) 169 self._pprint(indent, "", "}", stream=stream) 170 171 # Expression-related details. 172 173 if hasattr(self, "expr"): 174 self.expr.pprint(indent + 2, "- ", stream=stream) 175 if hasattr(self, "nodes"): 176 for node in self.nodes: 177 node.pprint(indent + 2, "- ", stream=stream) 178 if hasattr(self, "lvalue"): 179 self.lvalue.pprint(indent + 2, "->", stream=stream) 180 if hasattr(self, "nstype"): 181 self._pprint(indent + 2, "", self.nstype, stream=stream) 182 if hasattr(self, "args"): 183 for arg in self.args: 184 arg.pprint(indent + 2, "( ", stream=stream) 185 if hasattr(self, "star") and self.star: 186 self.star.pprint(indent + 2, "( ", stream=stream) 187 if hasattr(self, "dstar") and self.dstar: 188 self.dstar.pprint(indent + 2, "( ", stream=stream) 189 190 # Annotations. 191 192 if hasattr(self, "accesses"): 193 self._pprint(indent, "", "--------", stream=stream) 194 for ref, attributes in self.accesses.items(): 195 self._pprint(indent + 2, "| ", "when %s: %s" % (ref, ", ".join([("%s via %s" % attr_acc) for attr_acc in attributes])), stream=stream) 196 self._pprint(indent, "", "--------", stream=stream) 197 if hasattr(self, "writes"): 198 self._pprint(indent, "", "--------", stream=stream) 199 for ref, attribute in self.writes.items(): 200 self._pprint(indent + 2, "| ", "when %s: %s" % (ref, attribute), stream=stream) 201 self._pprint(indent, "", "--------", stream=stream) 202 203 class NamedNode(Node): 204 205 "A named node." 206 207 def __init__(self, *args, **kw): 208 Node.__init__(self, *args, **kw) 209 self.full_name = name(self, self.name or "$untitled") 210 211 class Module(NamedNode): "A Python module." 212 class Subprogram(NamedNode): "A subprogram: functions, methods and loops." 213 214 class Pass(Node): "A placeholder node corresponding to pass." 215 216 class Invoke(Node): "An invocation." 217 class InvokeFunction(Invoke): "A function or method invocation." 218 class InvokeBlock(Invoke): "A block or loop invocation." 219 220 class Return(Node): "Return an evaluated expression." 221 class Assign(Node): "A grouping node for assignment-related operations." 222 class Keyword(Node): "A grouping node for keyword arguments." 223 class Global(Node): "A global name designator." 224 class Import(Node): "A module import operation." 225 class LoadTemp(Node): "Load a previously-stored temporary value." 226 class LoadName(Node): "Load a named object." 227 class LoadAttr(Node): "Load an object attribute." 228 class LoadRef(Node): "Load a reference, typically a subprogram or a constant." 229 class LoadExc(Node): "Load a handled exception." 230 class StoreTemp(Node): "Store a temporary value." 231 class StoreName(Node): "Associate a name with an object." 232 class StoreAttr(Node): "Associate an object's attribute with a value." 233 class ReleaseTemp(Node): "Release a temporary value." 234 class Conditional(Node): "A conditional node consisting of a test and outcomes." 235 class Try(Node): "A try...except...else...finally grouping node." 236 class Raise(Node): "An exception raising node." 237 class Not(Node): "A negation of an expression." 238 class Choice(Node): "A special node which indicates a choice of expressions." 239 240 # Special non-program nodes. 241 242 class Structure: 243 244 "A non-program node containing some kind of namespace." 245 246 def __init__(self, original=None, **kw): 247 self.original = original 248 for name, value in kw.items(): 249 setattr(self, name, value) 250 251 def __repr__(self): 252 if hasattr(self, "name"): 253 return "%s '%s'" % (self.__class__.__name__, name(self, self.name)) 254 else: 255 return "%s" % (self.__class__.__name__,) 256 257 class Class(Structure): 258 259 "A Python class." 260 261 pass 262 263 class Instance(Structure): 264 265 "An instance." 266 267 def __init__(self, *args, **kw): 268 Structure.__init__(self, *args, **kw) 269 270 class Constant(Instance): 271 272 "A constant initialised with a type name for future processing." 273 274 def __init__(self, *args, **kw): 275 Instance.__init__(self, *args, **kw) 276 self.typename = self.value.__class__.__name__ 277 278 # vim: tabstop=4 expandtab shiftwidth=4