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