1 #!/usr/bin/env python 2 3 """ 4 Common classes. 5 6 Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 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 compiler.ast import AssAttr, Getattr, Name 23 import compiler.ast 24 from micropython.data import Attr, Class, Module 25 from micropython.errors import * 26 27 try: 28 set 29 except NameError: 30 from sets import Set as set 31 32 # Visitors and activities related to node annotations. 33 34 class ASTVisitor: 35 36 "A base class for visitors." 37 38 def default(self, node, *args): 39 for n in node.getChildNodes(): 40 self.dispatch(n) 41 42 def dispatch(self, node, *args): 43 44 "Dispatch using 'node', annotating any raised exceptions." 45 46 # Dispatch via a generic visit method. 47 48 try: 49 return node.visit(self, *args) 50 51 # Annotate the exception in case of failure. 52 53 except NodeProcessingError, exc: 54 if exc.astnode is None: 55 exc.astnode = node 56 57 # NOTE: Should perhaps specialise the subclasses appropriately. 58 59 if isinstance(self, (compiler.ast.Class, compiler.ast.Function, compiler.ast.Module)): 60 exc.unit_name = self.unit.full_name() 61 else: 62 exc.unit_name = self.full_name() 63 raise 64 65 def possible_accessor_types(self, node, defining_users=1): 66 67 """ 68 Given annotations made during the inspection process, return all possible 69 type names and indications of static usage for a 'node' involved in 70 attribute access. 71 72 If 'defining_users' is set to a false value, attempt to get the type 73 names specifically applicable to the node, rather than retrieving more 74 general definition-based type observations. 75 """ 76 77 all_target_names = [] 78 79 # Where an attribute could already be detected and where its nature is 80 # not that of a general instance or an unresolved name, attempt to 81 # identify it. 82 83 if isinstance(node, (AssAttr, Getattr, Name)): 84 85 # Use any explicit attribute annotation. 86 87 if isinstance(node._attr, Attr): 88 attr = node._attr 89 all_target_names.append(set([(attr.parent.full_name(), attr.is_static_attribute())])) 90 91 # Otherwise, try and use an expression annotation. 92 93 if isinstance(node, (AssAttr, Getattr)): 94 expr = node._expr 95 96 # Permitting multiple expression types if they provide the 97 # attribute. 98 99 if isinstance(expr, Attr): 100 exprs = expr.get_values() 101 elif expr: 102 exprs = [expr] 103 else: 104 exprs = None 105 106 if exprs: 107 target_names = set() 108 109 # For each expression value try and get a concrete 110 # attribute. 111 112 for expr in exprs: 113 attr = expr.all_attributes().get(node.attrname) 114 115 # Where an attribute can be obtained, record its 116 # details. 117 118 if attr: 119 target_names.add((attr.parent.full_name(), attr.is_static_attribute())) 120 121 if target_names: 122 all_target_names.append(target_names) 123 124 # Otherwise, attempt to employ the attribute usage observations. 125 126 if node._attrusers: 127 target_names = set() 128 129 # Visit each attribute user. 130 131 for user in node._attrusers: 132 133 # Since users such as branches may not provide type information, 134 # attempt to find defining users. 135 136 if defining_users: 137 for def_user in user._attrdefs or [user]: 138 for target_name, is_static in def_user._attrtypes.get(node._username, []): 139 target_names.add((target_name, is_static)) 140 else: 141 for target_name, is_static in user._attrspecifictypes.get(node._username, []): 142 target_names.add((target_name, is_static)) 143 144 if target_names: 145 all_target_names.append(target_names) 146 147 # Return the smallest set of target names. 148 149 all_target_names.sort(key=lambda x: len(x)) 150 151 return all_target_names and all_target_names[0] 152 153 def used_by_unit(node): 154 155 """ 156 Return whether the definition made by a 'node' is actually employed by the 157 program unit within which it is found. 158 """ 159 160 return node.unit and node.unit.parent.has_key(node.unit.name) 161 162 # Useful data. 163 164 operator_functions = { 165 166 # Binary operations. 167 168 "Add" : "add", 169 "Bitand" : "and_", 170 "Bitor" : "or_", 171 "Bitxor" : "xor", 172 "Div" : "div", 173 "FloorDiv" : "floordiv", 174 "LeftShift" : "lshift", 175 "Mod" : "mod", 176 "Mul" : "mul", 177 "Power" : "pow", 178 "RightShift" : "rshift", 179 "Sub" : "sub", 180 181 # Unary operations. 182 183 "Invert" : "invert", 184 "UnaryAdd" : "pos", 185 "UnarySub" : "neg", 186 187 # Augmented assignment. 188 189 "+=" : "iadd", 190 "-=" : "isub", 191 "*=" : "imul", 192 "/=" : "idiv", 193 "//=" : "ifloordiv", 194 "%=" : "imod", 195 "**=" : "ipow", 196 "<<=" : "ilshift", 197 ">>=" : "irshift", 198 "&=" : "iand", 199 "^=" : "ixor", 200 "|=" : "ior", 201 202 # Comparisons. 203 204 "==" : "eq", 205 "!=" : "ne", 206 "<" : "lt", 207 "<=" : "le", 208 ">=" : "ge", 209 ">" : "gt", 210 211 # Access and slicing. 212 213 "AssSlice" : "setslice", 214 "Slice" : "getslice", 215 "AssSubscript" : "setitem", 216 "Subscript" : "getitem", 217 } 218 219 # vim: tabstop=4 expandtab shiftwidth=4