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__, self.name, id(self)) 98 if hasattr(self, "index"): 99 return "%s (%s) (at %x)" % (self.__class__, self.index, id(self)) 100 elif hasattr(self, "value"): 101 return "%s %s (at %x)" % (self.__class__, repr(self.value), id(self)) 102 elif hasattr(self, "ref"): 103 return "%s '%x' (at %x)" % (self.__class__, id(self.ref), id(self)) 104 else: 105 return "%s (at %x)" % (self.__class__, id(self)) 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, "| ", "%s: %s" % (ref, attributes)) 168 self._pprint(indent, "", "--------") 169 170 class Module(Node): "A Python module." 171 class Subprogram(Node): "A subprogram: functions, methods and loops." 172 class Pass(Node): "A placeholder node corresponding to pass." 173 class Invoke(Node): "A function, method or loop invocation." 174 class Return(Node): "Return an evaluated expression." 175 class Assign(Node): "A grouping node for assignment-related operations." 176 class Keyword(Node): "A grouping node for keyword arguments." 177 class Global(Node): "A global name designator." 178 class Import(Node): "A module import operation." 179 class LoadTemp(Node): "Load a previously-stored temporary value." 180 class LoadName(Node): "Load a named object." 181 class LoadAttr(Node): "Load an object attribute." 182 class LoadRef(Node): "Load a reference, typically a subprogram or a constant." 183 class LoadExc(Node): "Load a handled exception." 184 class StoreTemp(Node): "Store a temporary value." 185 class StoreName(Node): "Associate a name with an object." 186 class StoreAttr(Node): "Associate an object's attribute with a value." 187 class ReleaseTemp(Node): "Release a temporary value." 188 class Conditional(Node): "A conditional node consisting of a test and outcomes." 189 class Try(Node): "A try...except...else...finally grouping node." 190 class Raise(Node): "An exception raising node." 191 class Not(Node): "A negation of an expression." 192 class Choice(Node): "A special node which indicates a choice of expressions." 193 194 # Special non-program nodes. 195 196 class Structure: 197 198 "A non-program node containing some kind of namespace." 199 200 def __init__(self, **kw): 201 for name, value in kw.items(): 202 setattr(self, name, value) 203 204 def __repr__(self): 205 if hasattr(self, "name"): 206 return "%s '%s' (at %x)" % (self.__class__, self.name, id(self)) 207 else: 208 return "%s (at %x)" % (self.__class__, id(self)) 209 210 class Class(Structure): 211 212 "A Python class." 213 214 pass 215 216 class Instance(Structure): 217 218 "An instance." 219 220 def __init__(self, **kw): 221 Structure.__init__(self, **kw) 222 223 class Constant(Instance): 224 225 "A constant initialised with a type name for future processing." 226 227 def __init__(self, **kw): 228 Instance.__init__(self, **kw) 229 self.typename = self.value.__class__.__name__ 230 231 # vim: tabstop=4 expandtab shiftwidth=4