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