1 #!/usr/bin/env python 2 3 """ 4 Common classes. 5 6 Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 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 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_module_name(node, module): 112 113 """ 114 Using the given From 'node' and 'module' in which it is found, calculate 115 any relative import information, returning a tuple containing a module 116 to import along with any names to import based on the node's name 117 information. 118 119 Where the returned module is given as None, whole module imports should 120 be performed for the returned modules using the returned names. 121 """ 122 123 # Absolute import. 124 125 if node.level == 0: 126 return node.modname, node.names 127 128 # Relative to an ancestor of this module. 129 130 else: 131 path = module.full_name().split(".") 132 level = node.level 133 134 # Relative imports treat package roots as submodules. 135 136 if split(module.filename)[-1] == "__init__.py": 137 level -= 1 138 139 if level > len(path): 140 raise InspectError("Relative import %r involves too many levels up from module %r" % ( 141 ("%s%s" % ("." * node.level, node.modname or "")), module.full_name())) 142 143 basename = ".".join(path[:len(path)-level]) 144 145 # Name imports from a module. 146 147 if node.modname: 148 return "%s.%s" % (basename, node.modname), node.names 149 150 # Relative whole module imports. 151 152 else: 153 return None, [("%s.%s" % (basename, name), alias or name) for name, alias in node.names] 154 155 def used_by_unit(node): 156 157 """ 158 Return whether the definition made by a 'node' is actually employed by the 159 program unit within which it is found. 160 """ 161 162 return node.unit and node.unit.parent.has_key(node.unit.original_name) 163 164 # Useful data. 165 166 operator_functions = { 167 168 # Fundamental operations. 169 170 "in" : "in_", 171 "not in" : "not_in", 172 173 # Binary operations. 174 175 "Add" : "add", 176 "Bitand" : "and_", 177 "Bitor" : "or_", 178 "Bitxor" : "xor", 179 "Div" : "div", 180 "FloorDiv" : "floordiv", 181 "LeftShift" : "lshift", 182 "Mod" : "mod", 183 "Mul" : "mul", 184 "Power" : "pow", 185 "RightShift" : "rshift", 186 "Sub" : "sub", 187 188 # Unary operations. 189 190 "Invert" : "invert", 191 "UnaryAdd" : "pos", 192 "UnarySub" : "neg", 193 194 # Augmented assignment. 195 196 "+=" : "iadd", 197 "-=" : "isub", 198 "*=" : "imul", 199 "/=" : "idiv", 200 "//=" : "ifloordiv", 201 "%=" : "imod", 202 "**=" : "ipow", 203 "<<=" : "ilshift", 204 ">>=" : "irshift", 205 "&=" : "iand", 206 "^=" : "ixor", 207 "|=" : "ior", 208 209 # Comparisons. 210 211 "==" : "eq", 212 "!=" : "ne", 213 "<" : "lt", 214 "<=" : "le", 215 ">=" : "ge", 216 ">" : "gt", 217 218 # Access and slicing. 219 220 "AssSlice" : "setslice", # Python 2.7 221 "Slice" : "getslice", 222 "AssSubscript" : "setitem", # Python 2.7 223 "Subscript" : "getitem", 224 } 225 226 # vim: tabstop=4 expandtab shiftwidth=4