1 #!/usr/bin/env python 2 3 """ 4 Common classes. 5 6 Copyright (C) 2007, 2008, 2009, 2010 Paul Boddie <paul@boddie.org.uk> 7 8 This program is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free Software 10 Foundation; either version 3 of the License, or (at your option) any later 11 version. 12 13 This program is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 details. 17 18 You should have received a copy of the GNU General Public License along with 19 this program. If not, see <http://www.gnu.org/licenses/>. 20 """ 21 22 import compiler.visitor 23 24 try: 25 set 26 except NameError: 27 from sets import Set as set 28 29 def merge_set_dicts(dicts): 30 31 "Merge the given 'dicts' mapping keys to sets of objects." 32 33 new_dict = {} 34 35 for old_dict in dicts: 36 for key, values in old_dict.items(): 37 if not new_dict.has_key(key): 38 new_dict[key] = set(values) 39 else: 40 new_dict[key].update(values) 41 42 return new_dict 43 44 # Visitors and activities related to node annotations. 45 46 class ASTVisitor(compiler.visitor.ASTVisitor): 47 48 "A base class for visitors." 49 50 def dispatch(self, node, *args): 51 52 "Dispatch using 'node', annotating any raised exceptions." 53 54 try: 55 return compiler.visitor.ASTVisitor.dispatch(self, node, *args) 56 except NodeProcessingError, exc: 57 if exc.astnode is None: 58 exc.astnode = node 59 60 # NOTE: Should perhaps specialise the subclasses appropriately. 61 62 if hasattr(self, "unit"): 63 exc.unit_name = self.unit.full_name() 64 else: 65 exc.unit_name = self.full_name() 66 raise 67 68 def possible_accessor_types(self, node): 69 70 """ 71 Given annotations made during the inspection process, return all possible 72 types for a 'node' involved in attribute access, or return None if no 73 annotations are available. 74 """ 75 76 if hasattr(node, "_attrusers"): 77 target_names = set() 78 79 # Visit each attribute user. 80 81 for user in node._attrusers: 82 83 # Since users such as branches may not provide type information, 84 # attempt to find defining users. 85 86 for def_user in user._attrdefs or [user]: 87 for target_name, is_static in def_user._attrtypes.get(node._username, []): 88 target_names.add(target_name) 89 90 return target_names 91 92 else: 93 return None 94 95 def used_by_unit(node): 96 97 """ 98 Return whether the definition made by a 'node' is actually employed by the 99 program unit within which it is found. 100 """ 101 102 return hasattr(node, "unit") and node.unit.parent.has_key(node.unit.name) 103 104 # Errors. 105 106 class ProcessingError(Exception): 107 108 "A processing error." 109 110 pass 111 112 class TableError(ProcessingError): 113 114 "An error occurring during access to a lookup table." 115 116 pass 117 118 class TableGenerationError(ProcessingError): 119 120 "An error occurring when generating a lookup table." 121 122 pass 123 124 class NodeProcessingError(ProcessingError): 125 126 "A processing error associated with a particular program node." 127 128 def __init__(self, message): 129 self.message = message 130 self.unit_name = None 131 self.astnode = None 132 133 def get_lineno(self, node): 134 lineno = node.lineno 135 if lineno is not None: 136 return lineno 137 else: 138 for child in node.getChildNodes(): 139 lineno = self.get_lineno(child) 140 if lineno is not None: 141 return lineno 142 return None 143 144 def __repr__(self): 145 return "Error in %r at line %r: %s" % (self.unit_name, self.get_lineno(self.astnode), self.message) 146 147 def __str__(self): 148 return repr(self) 149 150 class InspectError(NodeProcessingError): 151 152 "An error during the module inspection process." 153 154 pass 155 156 class TranslateError(NodeProcessingError): 157 158 "An error during the module translation process." 159 160 pass 161 162 class TranslationNotImplementedError(TranslateError): 163 164 "An error caused by a node not being supported in translation." 165 166 pass 167 168 # Special representations. 169 170 class AtLeast: 171 172 "A special representation for numbers of a given value or greater." 173 174 def __init__(self, count): 175 self.count = count 176 177 def __eq__(self, other): 178 return 0 179 180 __lt__ = __le__ = __eq__ 181 182 def __ne__(self, other): 183 return 1 184 185 def __gt__(self, other): 186 if isinstance(other, AtLeast): 187 return 0 188 else: 189 return self.count > other 190 191 def __ge__(self, other): 192 if isinstance(other, AtLeast): 193 return 0 194 else: 195 return self.count >= other 196 197 def __iadd__(self, other): 198 if isinstance(other, AtLeast): 199 self.count += other.count 200 else: 201 self.count += other 202 return self 203 204 def __radd__(self, other): 205 if isinstance(other, AtLeast): 206 return AtLeast(self.count + other.count) 207 else: 208 return AtLeast(self.count + other) 209 210 def __repr__(self): 211 return "AtLeast(%r)" % self.count 212 213 # Useful data. 214 215 comparison_methods = { 216 "==" : ("__eq__", "__eq__"), 217 "!=" : ("__ne__", "__ne__"), 218 "<" : ("__lt__", "__gt__"), 219 "<=" : ("__le__", "__ge__"), 220 ">=" : ("__ge__", "__le__"), 221 ">" : ("__gt__", "__lt__"), 222 "is" : None, 223 "is not" : None, 224 "in" : None, 225 "not in" : None 226 } 227 228 augassign_methods = { 229 "+=" : ("__iadd__", ("__add__", "__radd__")), 230 "-=" : ("__isub__", ("__sub__", "__rsub__")), 231 "*=" : ("__imul__", ("__mul__", "__rmul__")), 232 "/=" : ("__idiv__", ("__div__", "__rdiv__")), 233 "//=" : ("__ifloordiv__", ("__floordiv__", "__rfloordiv__")), 234 "%=" : ("__imod__", ("__mod__", "__rmod__")), 235 "**=" : ("__ipow__", ("__pow__", "__rpow__")), 236 "<<=" : ("__ilshift__", ("__lshift__", "__rlshift__")), 237 ">>=" : ("__irshift__", ("__rshift__", "__rrshift__")), 238 "&=" : ("__iand__", ("__and__", "__rand__")), 239 "^=" : ("__ixor__", ("__xor__", "__rxor__")), 240 "|=" : ("__ior__", ("__or__", "__ror__")) 241 } 242 243 binary_methods = { 244 "Add" : ("__add__", "__radd__"), 245 "Bitand" : ("__and__", "__rand__"), 246 "Bitor" : ("__or__", "__ror__"), 247 "Bitxor" : ("__xor__", "__rxor__"), 248 "Div" : ("__div__", "__rdiv__"), 249 "FloorDiv" : ("__floordiv__", "__rfloordiv__"), 250 "LeftShift" : ("__lshift__", "__rlshift__"), 251 "Mod" : ("__mod__", "__rmod__"), 252 "Mul" : ("__mul__", "__rmul__"), 253 "Power" : ("__pow__", "__rpow__"), 254 "RightShift" : ("__rshift__", "__rrshift__"), 255 "Sub" : ("__sub__", "__rsub__") 256 } 257 258 unary_methods = { 259 "Invert" : "__invert__", 260 "UnaryAdd" : "__pos__", 261 "UnarySub" : "__neg__" 262 } 263 264 operator_functions = { 265 266 # Binary operations. 267 268 "Add" : "add", 269 "Bitand" : "and_", 270 "Bitor" : "or_", 271 "Bitxor" : "xor", 272 "Div" : "div", 273 "FloorDiv" : "floordiv", 274 "LeftShift" : "lshift", 275 "Mod" : "mod", 276 "Mul" : "mul", 277 "Power" : "pow", 278 "RightShift" : "rshift", 279 "Sub" : "sub", 280 281 # Unary operations. 282 283 "Invert" : "invert", 284 "UnaryAdd" : "pos", 285 "UnarySub" : "neg", 286 287 # Augmented assignment. 288 289 "+=" : "iadd", 290 "-=" : "isub", 291 "*=" : "imul", 292 "/=" : "idiv", 293 "//=" : "ifloordiv", 294 "%=" : "imod", 295 "**=" : "ipow", 296 "<<=" : "ilshift", 297 ">>=" : "irshift", 298 "&=" : "iand", 299 "^=" : "ixor", 300 "|=" : "ior", 301 302 # Comparisons. 303 304 "==" : "eq", 305 "!=" : "ne", 306 "<" : "lt", 307 "<=" : "le", 308 ">=" : "ge", 309 ">" : "gt", 310 311 # Access and slicing. 312 313 "AssSlice" : "setslice", 314 "Slice" : "getslice", 315 "AssSubscript" : "setitem", 316 "Subscript" : "getitem", 317 } 318 319 # vim: tabstop=4 expandtab shiftwidth=4