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 # Exceptions. 28 29 class SimplifiedError(Exception): 30 31 "An error in the annotation process." 32 33 def __init__(self, exc, node, *args): 34 35 """ 36 Initialise the error with an existing exception 'exc', the 'node' at 37 which this error occurs, along with additional optional arguments. 38 """ 39 40 Exception.__init__(self, *args) 41 self.nodes = [node] 42 self.exc = exc 43 44 def add(self, node): 45 46 "Add the given 'node' to the path of nodes leading from the exception." 47 48 self.nodes.append(node) 49 50 def __str__(self): 51 52 "Return a string showing the principal exception details." 53 54 return "%s, %s" % (self.exc, self.nodes) 55 56 # Unique name registration. 57 58 class Naming: 59 60 "Maintain records of unique names for each simple name." 61 62 index_separator = "-" 63 64 def __init__(self): 65 self.obj_to_name = {} 66 self.names = {} 67 68 def get(self, obj): 69 return self.obj_to_name[obj] 70 71 def set(self, obj, name): 72 if self.obj_to_name.has_key(obj): 73 return 74 if not self.names.has_key(name): 75 self.names[name] = 0 76 n = self.names[name] + 1 77 self.names[name] = n 78 self.obj_to_name[obj] = "%s%s%d" % (name, self.index_separator, n) 79 80 naming = Naming() 81 82 def name(obj, name): 83 84 "Return a unique name for the given 'obj', indicating the base 'name'." 85 86 naming.set(obj, name) 87 return naming.get(obj) 88 89 # Elementary visitor support. 90 91 class Visitor(ASTVisitor): 92 93 "A visitor base class." 94 95 def __init__(self): 96 ASTVisitor.__init__(self) 97 98 def default(self, node, *args): 99 raise ValueError, node.__class__ 100 101 def dispatch(self, node, *args): 102 return ASTVisitor.dispatch(self, node, *args) 103 104 def dispatches(self, nodes, *args): 105 results = [] 106 for node in nodes: 107 results.append(self.dispatch(node, *args)) 108 return results 109 110 def dispatch_dict(self, d, *args): 111 results = {} 112 for name, node in d.items(): 113 results[name] = self.dispatch(node, *args) 114 return results 115 116 # Simplified program nodes. 117 118 class Node: 119 120 """ 121 A result node with common attributes: 122 123 original The original node from which this node was created. 124 defining Whether the node defines something in the original program. 125 name Any name involved (variable or attribute). 126 index Any index involved (temporary variable name). 127 value Any constant value. 128 ref Any reference to (for example) subprograms. 129 nstype Any indication of the namespace type involved in a name access. 130 131 Expression-related attributes: 132 133 expr Any contributing expression. 134 lvalue Any target expression. 135 test Any test expression in a conditional instruction. 136 137 Invocation and subprogram attributes: 138 139 args Any collection of argument nodes. 140 params Any collection of parameter nodes and defaults. 141 142 Statement-grouping attributes: 143 144 body Any conditional code depending on the success of a test. 145 else_ Any conditional code depending on the failure of a test. 146 handler Any exception handler code. 147 finally_ Any code which will be executed regardless. 148 code Any unconditional code. 149 choices Any choices which may be included in the final program. 150 """ 151 152 def __init__(self, original=None, defining=0, **kw): 153 154 """ 155 Initialise a program node with a link to an optional 'original' AST 156 node. An optional 'defining' parameter (if set to a true value), sets 157 this node as the defining node in the original. 158 """ 159 160 self.original = original 161 self.defining = defining 162 163 if self.original is not None and defining: 164 self.original._node = self 165 for name, value in kw.items(): 166 setattr(self, name, value) 167 168 def __repr__(self): 169 170 "Return a readable representation." 171 172 if hasattr(self, "full_name"): 173 s = "%s '%s'" % (self.__class__.__name__, self.full_name()) 174 elif hasattr(self, "name"): 175 s = "%s '%s'" % (self.__class__.__name__, self.name) 176 elif hasattr(self, "index"): 177 s = "%s (%s)" % (self.__class__.__name__, self.index) 178 elif hasattr(self, "value"): 179 s = "%s %s" % (self.__class__.__name__, repr(self.value)) 180 elif hasattr(self, "ref"): 181 s = "%s '%s'" % (self.__class__.__name__, name(self.ref, self.ref.name)) 182 else: 183 s = "%s" % (self.__class__.__name__,) 184 185 # Annotations. 186 187 if hasattr(self, "types"): 188 return "%s -> %s" % (s, self.types) 189 else: 190 return s 191 192 def _pprint(self, indent, continuation, s, stream=None): 193 194 """ 195 Print, at the given 'indent' level, with the given 'continuation' text, 196 the string 's', either to the given, optional 'stream' or to standard 197 output, this node's "pretty" representation. 198 """ 199 200 stream = stream or sys.stdout 201 if continuation: 202 print >>stream, (" " * max(0, indent - len(continuation))) + continuation + s 203 else: 204 print >>stream, (" " * indent) + s 205 206 def pprint(self, indent=0, continuation=None, stream=None): 207 208 """ 209 Print, at the given, optional 'indent', with the given optional 210 'continuation' text, either to the given, optional 'stream' or to 211 standard output, this node's "pretty" representation along with its 212 children and their "pretty" representation (and so on). 213 """ 214 215 stream = stream or sys.stdout 216 self._pprint(indent, continuation, repr(self), stream) 217 218 # Subprogram-related details. 219 220 if hasattr(self, "params"): 221 for name, default in self.params: 222 self._pprint(indent + 2, "( ", "%s default %s" % (name, default), stream=stream) 223 if hasattr(self, "star") and self.star: 224 name, default = self.star 225 self._pprint(indent + 2, "( ", "%s default %s" % (name, default), stream=stream) 226 if hasattr(self, "dstar") and self.dstar: 227 name, default = self.dstar 228 self._pprint(indent + 2, "( ", "%s default %s" % (name, default), stream=stream) 229 if getattr(self, "acquire_locals", 0): 230 self._pprint(indent + 2, "( ", "acquiring locals", stream=stream) 231 if getattr(self, "structure", 0): 232 self._pprint(indent + 2, "( ", "structure '%s'" % self.structure.name, stream=stream) 233 234 # Statement-related details. 235 236 if hasattr(self, "test"): 237 self.test.pprint(indent + 2, "? ", stream=stream) 238 for attr in "code", "body", "else_", "handler", "finally_", "choices": 239 if hasattr(self, attr) and getattr(self, attr): 240 self._pprint(indent, "", "%s {" % attr, stream=stream) 241 for node in getattr(self, attr): 242 node.pprint(indent + 2, stream=stream) 243 self._pprint(indent, "", "}", stream=stream) 244 245 # Expression-related details. 246 247 if hasattr(self, "expr"): 248 self.expr.pprint(indent + 2, "- ", stream=stream) 249 if hasattr(self, "nodes"): 250 for node in self.nodes: 251 node.pprint(indent + 2, "- ", stream=stream) 252 if hasattr(self, "lvalue"): 253 self.lvalue.pprint(indent + 2, "->", stream=stream) 254 if hasattr(self, "nstype"): 255 self._pprint(indent + 2, "", self.nstype, stream=stream) 256 if hasattr(self, "args"): 257 for arg in self.pos_args: 258 arg.pprint(indent + 2, "( ", stream=stream) 259 for name, arg in self.kw_args.items(): 260 arg.pprint(indent + 2, "( %s=" % name, stream=stream) 261 if hasattr(self, "star") and self.star: 262 self.star.pprint(indent + 2, "( ", stream=stream) 263 if hasattr(self, "dstar") and self.dstar: 264 self.dstar.pprint(indent + 2, "( ", stream=stream) 265 266 # Annotations. 267 268 if hasattr(self, "accesses"): 269 self._pprint(indent, "", "--------", stream=stream) 270 for ref, attributes in self.accesses.items(): 271 self._pprint(indent + 2, "| ", "when %s: %s" % (ref, ", ".join([("%s via %s" % attr_acc) for attr_acc in attributes])), stream=stream) 272 self._pprint(indent, "", "--------", stream=stream) 273 if hasattr(self, "writes"): 274 self._pprint(indent, "", "--------", stream=stream) 275 for ref, attribute in self.writes.items(): 276 self._pprint(indent + 2, "| ", "when %s: %s" % (ref, attribute), stream=stream) 277 self._pprint(indent, "", "--------", stream=stream) 278 279 class Pass(Node): "A placeholder node corresponding to pass." 280 class Return(Node): "Return an evaluated expression." 281 class Assign(Node): "A grouping node for assignment-related operations." 282 class Keyword(Node): "A grouping node for keyword arguments." 283 class Global(Node): "A global name designator." 284 class Import(Node): "A module import operation." 285 class LoadTemp(Node): "Load a previously-stored temporary value." 286 class LoadName(Node): "Load a named object." 287 class LoadAttr(Node): "Load an object attribute." 288 class LoadRef(Node): "Load a reference, typically a subprogram or a constant." 289 class LoadExc(Node): "Load a handled exception." 290 class StoreTemp(Node): "Store a temporary value." 291 class StoreName(Node): "Associate a name with an object." 292 class StoreAttr(Node): "Associate an object's attribute with a value." 293 class ReleaseTemp(Node): "Release a temporary value." 294 class Conditional(Node): "A conditional node consisting of a test and outcomes." 295 class Try(Node): "A try...except...else...finally grouping node." 296 class Raise(Node): "An exception raising node." 297 class Not(Node): "A negation of an expression." 298 class Choice(Node): "A special node which indicates a choice of expressions." 299 300 # Invocations involve some more work to process calculated attributes. 301 302 class Invoke(Node): "An invocation." 303 304 class InvokeFunction(Invoke): 305 306 "A function or method invocation." 307 308 def __init__(self, *args, **kw): 309 Node.__init__(self, *args, **kw) 310 if hasattr(self, "args"): 311 self.set_args(self.args) 312 313 def set_args(self, args): 314 315 "Sort the 'args' into positional and keyword arguments." 316 317 self.pos_args = [] 318 self.kw_args = {} 319 add_kw = 0 320 for arg in args: 321 if not add_kw: 322 if not isinstance(arg, Keyword): 323 self.pos_args.append(arg) 324 else: 325 add_kw = 1 326 if add_kw: 327 if isinstance(arg, Keyword): 328 self.kw_args[arg.name] = arg 329 else: 330 raise TypeError, "Positional argument appears after keyword arguments in '%s'." % self 331 332 class InvokeBlock(Invoke): "A block or loop invocation." 333 334 # Named nodes are those which can be referenced in some way. 335 336 class WithName: 337 338 "Node naming." 339 340 def __init__(self): 341 self._full_name = name(self, self.name or "$untitled") 342 343 def full_name(self): 344 return self._full_name 345 346 class Module(Node): 347 348 "A Python module." 349 350 def full_name(self): 351 return "module %s" % self.name 352 353 class Subprogram(Node, WithName): 354 355 "A subprogram: functions, methods and loops." 356 357 def __init__(self, *args, **kw): 358 Node.__init__(self, *args, **kw) 359 WithName.__init__(self) 360 361 # Special non-program nodes. 362 363 class Structure(Node): "A non-program node containing some kind of namespace." 364 365 class Class(Structure, WithName): 366 367 "A Python class." 368 369 def __init__(self, *args, **kw): 370 Structure.__init__(self, *args, **kw) 371 WithName.__init__(self) 372 self.instances = [] 373 374 def full_name(self): 375 return "class %s" % self._full_name 376 377 class Instance(Structure): 378 379 "An instance." 380 381 def full_name(self): 382 # NOTE: Wrap the result in a call to name(self, ...) where multiple 383 # NOTE: instances per class can occur. 384 return self.namespace.load("__class__")[0].type._full_name 385 386 def __repr__(self): 387 return "Instance of type '%s'" % self.full_name() 388 389 def __eq__(self, other): 390 # NOTE: Assuming that multiple instances of the same class are equal. 391 return self.full_name() == other.full_name() 392 393 def __hash__(self): 394 return id(self) 395 396 class Constant(Instance): 397 398 "A constant initialised with a type name for future processing." 399 400 def __init__(self, *args, **kw): 401 Instance.__init__(self, *args, **kw) 402 self.typename = self.value.__class__.__name__ 403 404 # vim: tabstop=4 expandtab shiftwidth=4