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