Package pygccxml :: Package declarations :: Module algorithm

Source Code for Module pygccxml.declarations.algorithm

  1  # Copyright 2004-2008 Roman Yakovenko. 
  2  # Distributed under the Boost Software License, Version 1.0. (See 
  3  # accompanying file LICENSE_1_0.txt or copy at 
  4  # http://www.boost.org/LICENSE_1_0.txt) 
  5   
  6  """defines few unrelated algorithms, that works on declarations""" 
  7   
  8  import types 
  9   
10 -def declaration_path( decl, with_defaults=True ):
11 """ 12 returns a list of parent declarations names 13 14 @param decl: declaration for which declaration path should be calculated 15 @type decl: L{declaration_t} 16 17 @return: [names], where first item contains top parent name and last item 18 contains decl name 19 """ 20 if not decl: 21 return [] 22 if not decl.cache.declaration_path: 23 result = [ decl.name ] 24 parent = decl.parent 25 while parent: 26 if parent.cache.declaration_path: 27 result.reverse() 28 decl.cache.declaration_path = parent.cache.declaration_path + result 29 return decl.cache.declaration_path 30 else: 31 result.append( parent.name ) 32 parent = parent.parent 33 result.reverse() 34 decl.cache.declaration_path = result 35 return result 36 else: 37 return decl.cache.declaration_path
38
39 -def partial_declaration_path( decl ):
40 """ 41 returns a list of parent declarations names without template arguments that 42 have default value 43 44 @param decl: declaration for which declaration path should be calculated 45 @type decl: L{declaration_t} 46 47 @return: [names], where first item contains top parent name and last item 48 contains decl name 49 """ 50 #TODO: 51 #If parent declaration cache already has declaration_path, reuse it for 52 #calculation. 53 if not decl: 54 return [] 55 if not decl.cache.partial_declaration_path: 56 result = [ decl.partial_name ] 57 parent = decl.parent 58 while parent: 59 if parent.cache.partial_declaration_path: 60 result.reverse() 61 decl.cache.partial_declaration_path \ 62 = parent.cache.partial_declaration_path + result 63 return decl.cache.partial_declaration_path 64 else: 65 result.append( parent.partial_name ) 66 parent = parent.parent 67 result.reverse() 68 decl.cache.partial_declaration_path = result 69 return result 70 else: 71 return decl.cache.partial_declaration_path
72
73 -def get_named_parent( decl ):
74 """ 75 returns a reference to a named parent declaration 76 77 @param decl: the child declaration 78 @type decl: L{declaration_t} 79 80 @return: reference to L{declaration_t} or None if not found 81 """ 82 if not decl: 83 return None 84 85 parent = decl.parent 86 while parent and ( not parent.name or parent.name == '::' ): 87 parent = parent.parent 88 return parent
89 90
91 -def full_name_from_declaration_path( dpath ):
92 ##Here I have lack of knowledge: 93 ##TODO: "What is the full name of declaration declared in unnamed namespace?" 94 result = filter( None, dpath ) 95 result = result[0] + '::'.join( result[1:] ) 96 return result
97
98 -def full_name( decl, with_defaults=True ):
99 """ 100 returns full name of the declaration 101 @param decl: declaration for which full name should be calculated. If decl 102 belongs to unnamed namespace, then L{full_name} is not valid C++ full name. 103 104 @type decl: L{declaration_t} 105 106 @return: full name of declarations. 107 """ 108 if None is decl: 109 raise RuntimeError( "Unable to generate full name for None object!" ) 110 if with_defaults: 111 if not decl.cache.full_name: 112 decl.cache.full_name = full_name_from_declaration_path( declaration_path( decl ) ) 113 return decl.cache.full_name 114 else: 115 if not decl.cache.full_partial_name: 116 decl.cache.full_partial_name \ 117 = full_name_from_declaration_path( partial_declaration_path( decl ) ) 118 return decl.cache.full_partial_name
119
120 -def make_flatten( decl_or_decls ):
121 """ 122 converts tree representation of declarations to flatten one. 123 124 @param decl_or_decls: reference to list of declaration's or single declaration 125 @type decl_or_decls: L{declaration_t} or [ L{declaration_t} ] 126 127 @return: [ all internal declarations ] 128 """ 129 import pygccxml.declarations #prevent cyclic import 130 def proceed_single( decl ): 131 answer = [ decl ] 132 if not isinstance( decl, pygccxml.declarations.scopedef_t ): 133 return answer 134 for elem in decl.declarations: 135 if isinstance( elem, pygccxml.declarations.scopedef_t ): 136 answer.extend( proceed_single( elem ) ) 137 else: 138 answer.append( elem ) 139 return answer
140 141 decls = [] 142 if isinstance( decl_or_decls, types.ListType ): 143 decls.extend( decl_or_decls ) 144 else: 145 decls.append( decl_or_decls ) 146 answer = [] 147 for decl in decls: 148 answer.extend( proceed_single( decl ) ) 149 return answer 150
151 -def __make_flatten_generator( decl_or_decls ):
152 """ 153 converts tree representation of declarations to flatten one. 154 155 @param decl_or_decls: reference to list of declaration's or single declaration 156 @type decl_or_decls: L{declaration_t} or [ L{declaration_t} ] 157 158 @return: [ all internal declarations ] 159 """ 160 161 import pygccxml.declarations 162 def proceed_single( decl ): 163 yield decl 164 if not isinstance( decl, pygccxml.declarations.scopedef_t): 165 return 166 for internal in decl.declarations: 167 if isinstance( internal, pygccxml.declarations.scopedef_t): 168 for internal_internal in proceed_single( internal ): 169 yield internal_internal 170 else: 171 yield internal
172 173 if isinstance( decl_or_decls, types.ListType ): 174 for creator in decl_or_decls: 175 for internal in proceed_single( creator ): 176 yield internal 177 else: 178 for internal in proceed_single( decl_or_decls ): 179 yield internal 180
181 -def get_global_namespace(decls):
182 import pygccxml.declarations 183 found = filter( lambda decl: decl.name == '::' 184 and isinstance( decl, pygccxml.declarations.namespace_t ) 185 , make_flatten( decls ) ) 186 if len( found ) == 1: 187 return found[0] 188 raise RuntimeError( "Unable to find global namespace." )
189
190 -class match_declaration_t:
191 """ 192 helper class for different search algorithms. 193 194 This class will help developer to match declaration by: 195 - declaration type, for example L{class_t} or L{operator_t}. 196 - declaration name 197 - declaration full name 198 - reference to parent declaration 199 """ 200
201 - def __init__( self, type=None, name=None, fullname=None, parent=None ):
202 self.type = type 203 self.name = name 204 self.fullname = fullname 205 self.parent = parent
206
207 - def does_match_exist(self, inst):
208 """ 209 returns True if inst do match one of specified criteria 210 211 @param inst: declaration instance 212 @type inst: L{declaration_t} 213 214 @return: bool 215 """ 216 answer = True 217 if None != self.type: 218 answer &= isinstance( inst, self.type) 219 if None != self.name: 220 answer &= inst.name == self.name 221 if None != self.parent: 222 answer &= self.parent is inst.parent 223 if None != self.fullname: 224 if inst.name: 225 answer &= self.fullname == full_name( inst ) 226 else: 227 answer = False 228 return answer
229
230 - def __call__(self, inst):
231 """C{return self.does_match_exist(inst)}""" 232 return self.does_match_exist(inst)
233
234 -def find_all_declarations( declarations 235 , type=None 236 , name=None 237 , parent=None 238 , recursive=True 239 , fullname=None ):
240 """ 241 returns a list of all declarations that match criteria, defined by developer 242 243 For more information about arguments see L{match_declaration_t} class. 244 245 @return: [ matched declarations ] 246 """ 247 decls = [] 248 if recursive: 249 decls = make_flatten( declarations ) 250 else: 251 decls = declarations 252 253 return filter( match_declaration_t(type, name, fullname, parent), decls )
254
255 -def find_declaration( declarations 256 , type=None 257 , name=None 258 , parent=None 259 , recursive=True 260 , fullname=None ):
261 """ 262 returns single declaration that match criteria, defined by developer. 263 If more the one declaration was found None will be returned. 264 265 For more information about arguments see L{match_declaration_t} class. 266 267 @return: matched declaration L{declaration_t} or None 268 """ 269 decl = find_all_declarations( declarations, type=type, name=name, parent=parent, recursive=recursive, fullname=fullname ) 270 if len( decl ) == 1: 271 return decl[0]
272
273 -def find_first_declaration( declarations, type=None, name=None, parent=None, recursive=True, fullname=None ):
274 """ 275 returns first declaration that match criteria, defined by developer 276 277 For more information about arguments see L{match_declaration_t} class. 278 279 @return: matched declaration L{declaration_t} or None 280 """ 281 matcher = match_declaration_t(type, name, fullname, parent) 282 if recursive: 283 decls = make_flatten( declarations ) 284 else: 285 decls = declarations 286 for decl in decls: 287 if matcher( decl ): 288 return decl 289 return None
290
291 -def declaration_files(decl_or_decls):
292 """ 293 returns set of files 294 295 Every declaration is declared in some file. This function returns set, that 296 contains all file names of declarations. 297 298 @param decl_or_decls: reference to list of declaration's or single declaration 299 @type decl_or_decls: L{declaration_t} or [ L{declaration_t} ] 300 301 @return: set( declaration file names ) 302 """ 303 files = set() 304 decls = make_flatten( decl_or_decls ) 305 for decl in decls: 306 if decl.location: 307 files.add( decl.location.file_name ) 308 return files
309
310 -class visit_function_has_not_been_found_t( RuntimeError ):
311 """ 312 exception that is raised, from L{apply_visitor}, when a visitor could not be 313 applied. 314 315 """
316 - def __init__( self, visitor, decl_inst ):
317 RuntimeError.__init__( self ) 318 self.__msg = \ 319 "Unable to find visit function. Visitor class: %s. Declaration instance class: %s'" \ 320 % ( visitor.__class__.__name__, decl_inst.__class__.__name__ )
321 - def __str__(self):
322 return self.__msg
323
324 -def apply_visitor( visitor, decl_inst):
325 """ 326 applies a visitor on declaration instance 327 328 @param visitor: instance 329 @type visitor: L{type_visitor_t} or L{decl_visitor_t} 330 """ 331 fname = 'visit_' + decl_inst.__class__.__name__[:-2] #removing '_t' from class name 332 if not hasattr(visitor, fname ): 333 raise visit_function_has_not_been_found_t( visitor, decl_inst ) 334 getattr( visitor, fname )()
335