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, **kw): 114 115 """ 116 Initialise a program node with an optional link to an 'original' AST 117 node. 118 """ 119 120 self.original = original 121 if self.original is not None: 122 self.original._node = self 123 for name, value in kw.items(): 124 setattr(self, name, value) 125 126 def __repr__(self): 127 if hasattr(self, "full_name"): 128 s = "%s '%s'" % (self.__class__.__name__, self.full_name) 129 elif hasattr(self, "name"): 130 s = "%s '%s'" % (self.__class__.__name__, self.name) 131 elif hasattr(self, "index"): 132 s = "%s (%s)" % (self.__class__.__name__, self.index) 133 elif hasattr(self, "value"): 134 s = "%s %s" % (self.__class__.__name__, repr(self.value)) 135 elif hasattr(self, "ref"): 136 s = "%s '%s'" % (self.__class__.__name__, name(self.ref, self.ref.name)) 137 else: 138 s = "%s" % (self.__class__.__name__,) 139 140 # Annotations. 141 142 if hasattr(self, "types"): 143 return "%s -> %s" % (s, self.types) 144 else: 145 return s 146 147 def _pprint(self, indent, continuation, s, stream=None): 148 stream = stream or sys.stdout 149 if continuation: 150 print >>stream, (" " * max(0, indent - len(continuation))) + continuation + s 151 else: 152 print >>stream, (" " * indent) + s 153 154 def pprint(self, indent=0, continuation=None, stream=None): 155 stream = stream or sys.stdout 156 self._pprint(indent, continuation, repr(self), stream) 157 158 # Subprogram-related details. 159 160 if hasattr(self, "params"): 161 for name, default in self.params: 162 self._pprint(indent + 2, "( ", "%s default %s" % (name, default), stream=stream) 163 if hasattr(self, "star") and self.star: 164 name, default = self.star 165 self._pprint(indent + 2, "( ", "%s default %s" % (name, default), stream=stream) 166 if hasattr(self, "dstar") and self.dstar: 167 name, default = self.dstar 168 self._pprint(indent + 2, "( ", "%s default %s" % (name, default), stream=stream) 169 if getattr(self, "acquire_locals", 0): 170 self._pprint(indent + 2, "( ", "acquiring locals", stream=stream) 171 if getattr(self, "structure", 0): 172 self._pprint(indent + 2, "( ", "structure '%s'" % self.structure.name, stream=stream) 173 174 # Statement-related details. 175 176 if hasattr(self, "test"): 177 self.test.pprint(indent + 2, "? ", stream=stream) 178 for attr in "code", "body", "else_", "handler", "finally_", "choices": 179 if hasattr(self, attr) and getattr(self, attr): 180 self._pprint(indent, "", "%s {" % attr, stream=stream) 181 for node in getattr(self, attr): 182 node.pprint(indent + 2, stream=stream) 183 self._pprint(indent, "", "}", stream=stream) 184 185 # Expression-related details. 186 187 if hasattr(self, "expr"): 188 self.expr.pprint(indent + 2, "- ", stream=stream) 189 if hasattr(self, "nodes"): 190 for node in self.nodes: 191 node.pprint(indent + 2, "- ", stream=stream) 192 if hasattr(self, "lvalue"): 193 self.lvalue.pprint(indent + 2, "->", stream=stream) 194 if hasattr(self, "nstype"): 195 self._pprint(indent + 2, "", self.nstype, stream=stream) 196 if hasattr(self, "args"): 197 for arg in self.args: 198 arg.pprint(indent + 2, "( ", stream=stream) 199 if hasattr(self, "star") and self.star: 200 self.star.pprint(indent + 2, "( ", stream=stream) 201 if hasattr(self, "dstar") and self.dstar: 202 self.dstar.pprint(indent + 2, "( ", stream=stream) 203 204 # Annotations. 205 206 if hasattr(self, "accesses"): 207 self._pprint(indent, "", "--------", stream=stream) 208 for ref, attributes in self.accesses.items(): 209 self._pprint(indent + 2, "| ", "when %s: %s" % (ref, ", ".join([("%s via %s" % attr_acc) for attr_acc in attributes])), stream=stream) 210 self._pprint(indent, "", "--------", stream=stream) 211 if hasattr(self, "writes"): 212 self._pprint(indent, "", "--------", stream=stream) 213 for ref, attribute in self.writes.items(): 214 self._pprint(indent + 2, "| ", "when %s: %s" % (ref, attribute), stream=stream) 215 self._pprint(indent, "", "--------", stream=stream) 216 217 class Pass(Node): "A placeholder node corresponding to pass." 218 class Return(Node): "Return an evaluated expression." 219 class Assign(Node): "A grouping node for assignment-related operations." 220 class Keyword(Node): "A grouping node for keyword arguments." 221 class Global(Node): "A global name designator." 222 class Import(Node): "A module import operation." 223 class LoadTemp(Node): "Load a previously-stored temporary value." 224 class LoadName(Node): "Load a named object." 225 class LoadAttr(Node): "Load an object attribute." 226 class LoadRef(Node): "Load a reference, typically a subprogram or a constant." 227 class LoadExc(Node): "Load a handled exception." 228 class StoreTemp(Node): "Store a temporary value." 229 class StoreName(Node): "Associate a name with an object." 230 class StoreAttr(Node): "Associate an object's attribute with a value." 231 class ReleaseTemp(Node): "Release a temporary value." 232 class Conditional(Node): "A conditional node consisting of a test and outcomes." 233 class Try(Node): "A try...except...else...finally grouping node." 234 class Raise(Node): "An exception raising node." 235 class Not(Node): "A negation of an expression." 236 class Choice(Node): "A special node which indicates a choice of expressions." 237 238 # Invocations involve some more work to process calculated attributes. 239 240 class Invoke(Node): "An invocation." 241 242 class InvokeFunction(Invoke): 243 244 "A function or method invocation." 245 246 def __init__(self, *args, **kw): 247 Node.__init__(self, *args, **kw) 248 if hasattr(self, "args"): 249 self.set_args(self.args) 250 251 def set_args(self, args): 252 253 "Sort the 'args' into positional and keyword arguments." 254 255 self.pos_args = [] 256 self.kw_args = [] 257 add_kw = 0 258 for arg in args: 259 if not add_kw: 260 if not isinstance(arg, Keyword): 261 self.pos_args.append(arg) 262 else: 263 add_kw = 1 264 if add_kw: 265 if isinstance(arg, Keyword): 266 self.kw_args.append(arg) 267 else: 268 raise TypeError, "Positional argument appears after keyword arguments in '%s'." % self 269 270 class InvokeBlock(Invoke): "A block or loop invocation." 271 272 # Named nodes are those which can be referenced in some way. 273 274 class WithName: 275 276 "Node naming." 277 278 def __init__(self): 279 self.full_name = name(self, self.name or "$untitled") 280 281 class Module(Node, WithName): 282 283 "A Python module." 284 285 def __init__(self, *args, **kw): 286 Node.__init__(self, *args, **kw) 287 WithName.__init__(self) 288 289 class Subprogram(Node, WithName): 290 291 "A subprogram: functions, methods and loops." 292 293 def __init__(self, *args, **kw): 294 Node.__init__(self, *args, **kw) 295 WithName.__init__(self) 296 297 # Special non-program nodes. 298 299 class Structure(Node): "A non-program node containing some kind of namespace." 300 301 class Class(Structure, WithName): 302 303 "A Python class." 304 305 def __init__(self, *args, **kw): 306 Structure.__init__(self, *args, **kw) 307 WithName.__init__(self) 308 309 class Instance(Structure): 310 311 "An instance." 312 313 def __repr__(self): 314 return "Instance of type '%s'" % self.namespace.load("__class__")[0].type.full_name 315 316 class Constant(Instance): 317 318 "A constant initialised with a type name for future processing." 319 320 def __init__(self, *args, **kw): 321 Instance.__init__(self, *args, **kw) 322 self.typename = self.value.__class__.__name__ 323 324 # vim: tabstop=4 expandtab shiftwidth=4