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