1 #!/usr/bin/env python 2 3 """ 4 Common classes. 5 6 Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 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 from micropython.stdcompiler import compiler 23 from micropython.basicdata import Constant, TypedInstance, Instance 24 from micropython.data import BaseAttr, Class 25 from micropython.errors import * 26 from os.path import split 27 28 try: 29 set 30 except NameError: 31 from sets import Set as set 32 33 # Visitors and activities related to node annotations. 34 35 class ASTVisitor: 36 37 "A base class for visitors." 38 39 def process_definitions(self, node): 40 41 """ 42 Process and return all definitions beneath 'node', but not definitions 43 within definitions. 44 """ 45 46 definitions = [] 47 for n in node.getChildNodes(): 48 if isinstance(n, (compiler.ast.Class, compiler.ast.Function)): 49 self.current_definition = n 50 definitions.append(self.dispatch(n)) 51 else: 52 definitions += self.process_definitions(n) 53 return definitions 54 55 def processing_definition(self, n): 56 return self.current_definition is n 57 58 # Visitor support methods. 59 60 def default(self, node, *args): 61 for n in node.getChildNodes(): 62 self.dispatch(n) 63 64 def dispatch(self, node, *args): 65 66 "Dispatch using 'node', annotating any raised exceptions." 67 68 # Dispatch via a generic visit method. 69 70 try: 71 return node.visit(self, *args) 72 73 # Annotate the exception in case of failure. 74 75 except NodeProcessingError, exc: 76 if exc.astnode is None: 77 exc.astnode = node 78 exc.unit_name = self.get_unit().full_name() 79 raise 80 81 def get_attributes(self, targets, attrname): 82 83 "Return a list of attributes for 'targets' supporting 'attrname'." 84 85 attributes = set() 86 87 for target in targets: 88 try: 89 attributes.add(self.objtable.access(target.full_name(), attrname)) 90 except TableError: 91 pass 92 93 return attributes 94 95 def get_attribute_and_value(self, obj): 96 97 """ 98 Return (attribute, value) details for the given 'obj', where an 99 attribute of None can be returned for constant objects, and where None 100 can be returned as the result where no concrete details can be provided. 101 """ 102 103 if isinstance(obj, (Constant, TypedInstance)): 104 return None, obj 105 106 if isinstance(obj, BaseAttr): 107 return obj, obj.get_value() 108 109 return None 110 111 def get_type_for_attribute(self, attr, value): 112 113 """ 114 For an attribute 'attr' and 'value', return the "parent" type of the 115 attribute if possible. Otherwise, return None. 116 """ 117 118 if attr: 119 return attr.get_type() 120 elif value and not isinstance(value, Instance) and value.parent: 121 return value.parent 122 else: 123 return None 124 125 def get_values_for_attribute(self, attr, value): 126 127 """ 128 Return values defined for the given attribute 'attr' unless a specific 129 'value' is provided, in which case a list containing that value is 130 returned. Where no values are defined, return None in a list. 131 """ 132 133 return value and [value] or attr and attr.get_values() or [None] 134 135 def get_module_name(node, module): 136 137 """ 138 Using the given From 'node' and 'module' in which it is found, calculate 139 any relative import information, returning a tuple containing a module 140 to import along with any names to import based on the node's name 141 information. 142 143 Where the returned module is given as None, whole module imports should 144 be performed for the returned modules using the returned names. 145 """ 146 147 # Absolute import. 148 149 if node.level == 0: 150 return node.modname, node.names 151 152 # Relative to an ancestor of this module. 153 154 else: 155 path = module.full_name().split(".") 156 level = node.level 157 158 # Relative imports treat package roots as submodules. 159 160 if split(module.filename)[-1] == "__init__.py": 161 level -= 1 162 163 if level > len(path): 164 raise InspectError("Relative import %r involves too many levels up from module %r" % ( 165 ("%s%s" % ("." * node.level, node.modname or "")), module.full_name())) 166 167 basename = ".".join(path[:len(path)-level]) 168 169 # Name imports from a module. 170 171 if node.modname: 172 return "%s.%s" % (basename, node.modname), node.names 173 174 # Relative whole module imports. 175 176 else: 177 return None, [("%s.%s" % (basename, name), alias or name) for name, alias in node.names] 178 179 def used_by_unit(node): 180 181 """ 182 Return whether the definition made by a 'node' is actually employed by the 183 program unit within which it is found. 184 """ 185 186 return node.unit and node.unit.parent.has_key(node.unit.original_name) 187 188 # Useful data. 189 190 operator_functions = { 191 192 # Fundamental operations. 193 194 "in" : "in_", 195 "not in" : "not_in", 196 197 # Binary operations. 198 199 "Add" : "add", 200 "Bitand" : "and_", 201 "Bitor" : "or_", 202 "Bitxor" : "xor", 203 "Div" : "div", 204 "FloorDiv" : "floordiv", 205 "LeftShift" : "lshift", 206 "Mod" : "mod", 207 "Mul" : "mul", 208 "Power" : "pow", 209 "RightShift" : "rshift", 210 "Sub" : "sub", 211 212 # Unary operations. 213 214 "Invert" : "invert", 215 "UnaryAdd" : "pos", 216 "UnarySub" : "neg", 217 218 # Augmented assignment. 219 220 "+=" : "iadd", 221 "-=" : "isub", 222 "*=" : "imul", 223 "/=" : "idiv", 224 "//=" : "ifloordiv", 225 "%=" : "imod", 226 "**=" : "ipow", 227 "<<=" : "ilshift", 228 ">>=" : "irshift", 229 "&=" : "iand", 230 "^=" : "ixor", 231 "|=" : "ior", 232 233 # Comparisons. 234 235 "==" : "eq", 236 "!=" : "ne", 237 "<" : "lt", 238 "<=" : "le", 239 ">=" : "ge", 240 ">" : "gt", 241 242 # Access and slicing. 243 244 "AssSlice" : "setslice", # Python 2.7 245 "Slice" : "getslice", 246 "AssSubscript" : "setitem", # Python 2.7 247 "Subscript" : "getitem", 248 } 249 250 # vim: tabstop=4 expandtab shiftwidth=4