Package pygccxml :: Package declarations :: Module matchers

Source Code for Module pygccxml.declarations.matchers

  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  """ 
  7  defines all "built-in" classes that implement declarations compare functionality 
  8  according to some criteria 
  9  """ 
 10   
 11  import os 
 12  import re 
 13  import types 
 14  import algorithm 
 15  import variable 
 16  import namespace 
 17  import calldef 
 18  import cpptypes 
 19  import templates 
 20  import class_declaration 
 21  from pygccxml import utils 
 22   
23 -class matcher_base_t(object):
24 """matcher_base_t class defines interface for classes that will implement 25 compare functionality according to some criteria. 26 """
27 - def __init__( self ):
28 object.__init__( self )
29
30 - def __call__(self, decl):
31 raise NotImplementedError( "matcher must always implement the __call__() method." )
32
33 - def __invert__(self):
34 """not-operator (~)""" 35 return not_matcher_t(self)
36
37 - def __and__(self, other):
38 """and-operator (&)""" 39 return and_matcher_t([self, other])
40
41 - def __or__(self, other):
42 """or-operator (|)""" 43 return or_matcher_t([self, other])
44
45 - def __str__( self ):
46 return "base class for all matchers"
47
48 -class and_matcher_t(matcher_base_t):
49 """Combine several other matchers with "&". 50 51 For example: find all private functions with name XXX 52 53 C{ matcher = access_type_matcher_t( 'private' ) & calldef_matcher_t( name='XXX' ) } 54 """
55 - def __init__(self, matchers):
58
59 - def __call__(self, decl):
60 for matcher in self.matchers: 61 if not matcher(decl): 62 return False 63 return True
64
65 - def __str__(self):
66 return " & ".join( map( lambda x: "(%s)" % str( x ), self.matchers ) )
67 68
69 -class or_matcher_t(matcher_base_t):
70 """Combine several other matchers with "|". 71 72 For example: find all functions and variables with name 'XXX' 73 74 C{ matcher = variable_matcher_t( name='XXX' ) | calldef_matcher_t( name='XXX' ) } 75 76 """
77 - def __init__(self, matchers):
80
81 - def __call__(self, decl):
82 for matcher in self.matchers: 83 if matcher(decl): 84 return True 85 return False
86
87 - def __str__(self):
88 return " | ".join( map( lambda x: "(%s)" % str( x ), self.matchers ) )
89 90
91 -class not_matcher_t(matcher_base_t):
92 """Return the inverse result of matcher, using "~" 93 94 For example: find all private and protected declarations 95 96 C{ matcher = ~access_type_matcher_t( 'private' ) } 97 98 """
99 - def __init__(self, matcher):
100 matcher_base_t.__init__(self) 101 self.matcher = matcher
102
103 - def __call__(self, decl):
104 return not self.matcher(decl)
105
106 - def __str__(self):
107 return "~(%s)"%str(self.matcher)
108
109 -class declaration_matcher_t( matcher_base_t ):
110 """ 111 Instance of this class will match declarations by next criteria: 112 - declaration name, also could be fully qualified name 113 Example: wstring or ::std::wstring 114 - declaration type 115 Example: L{class_t}, L{namespace_t}, L{enumeration_t} 116 - location within file system ( file or directory ) 117 """
118 - def __init__( self, name=None, decl_type=None, header_dir=None, header_file=None ):
119 """ 120 @param decl_type: declaration type to match by. For example L{enumeration_t}. 121 @type decl_type: any class that derives from L{declarations.declaration_t} class 122 123 @param name: declaration name, could be full name. 124 @type name: str 125 126 @param header_dir: absolute directory path 127 @type header_dir: str 128 129 @param header_file: absolute file path 130 @type header_file: str 131 132 """ 133 #An other option is that pygccxml will create absolute path using 134 #os.path.abspath function. But I think this is just wrong, because abspath 135 #builds path using current working directory. This behavior is fragile 136 #and very difficult to find a bug. 137 matcher_base_t.__init__( self ) 138 self.decl_type = decl_type 139 self.__name = None 140 self.__opt_is_tmpl_inst = None 141 self.__opt_tmpl_name = None 142 self.__opt_is_full_name = None 143 self.__decl_name_only = None 144 145 self._set_name( name ) 146 147 self.header_dir = header_dir 148 self.header_file = header_file 149 150 if self.header_dir: 151 self.header_dir = utils.normalize_path( self.header_dir ) 152 if not os.path.isabs( self.header_dir ): 153 raise RuntimeError( "Path to header directory should be absolute!" ) 154 155 if self.header_file: 156 self.header_file = utils.normalize_path( self.header_file ) 157 if not os.path.isabs( self.header_file ): 158 raise RuntimeError( "Path to header file should be absolute!" )
159
160 - def _get_name(self):
161 return self.__name
162
163 - def _set_name( self, name ):
164 self.__name = name 165 if not self.__name: 166 self.__opt_is_tmpl_inst = None 167 self.__opt_tmpl_name = None 168 self.__opt_is_full_name = None 169 self.__decl_name_only = None 170 else: 171 self.__opt_is_tmpl_inst = templates.is_instantiation( self.__name ) 172 self.__opt_tmpl_name = templates.name( self.__name ) 173 if self.__opt_is_tmpl_inst: 174 if '::' in self.__opt_tmpl_name: 175 self.__opt_is_full_name = True 176 self.__decl_name_only = self.__opt_tmpl_name.split('::')[-1] 177 else: 178 self.__opt_is_full_name = False 179 self.__decl_name_only = self.__opt_tmpl_name 180 self.__name = templates.normalize( name ) 181 else: 182 if '::' in self.__name: 183 self.__opt_is_full_name = True 184 self.__decl_name_only = self.__name.split('::')[-1] 185 else: 186 self.__opt_is_full_name = False 187 self.__decl_name_only = self.__name
188 189 190 name = property( _get_name, _set_name ) 191
192 - def __str__( self ):
193 msg = [] 194 if not None is self.decl_type: 195 msg.append( '(decl type==%s)' % self.decl_type.__name__ ) 196 if not None is self.name: 197 msg.append( '(name==%s)' % self.name ) 198 if not None is self.header_dir: 199 msg.append( '(header dir==%s)' % self.header_dir ) 200 if not None is self.header_file: 201 msg.append( '(header file==%s)' % self.header_file ) 202 if not msg: 203 msg.append( 'any' ) 204 return ' and '.join( msg )
205
206 - def __call__( self, decl ):
207 if not None is self.decl_type: 208 if not isinstance( decl, self.decl_type ): 209 return False 210 if not None is self.name: 211 if not self.check_name( decl ): 212 return False 213 if not None is self.header_dir and decl.location: 214 decl_dir = os.path.abspath( os.path.dirname( decl.location.file_name ) ) 215 decl_dir = utils.normalize_path( decl_dir ) 216 if decl_dir[:len(self.header_dir)] != self.header_dir: 217 return False 218 if not None is self.header_file and decl.location: 219 decl_file = os.path.abspath( decl.location.file_name ) 220 decl_file = utils.normalize_path( decl_file ) 221 if decl_file != self.header_file: 222 return False 223 return True
224
225 - def check_name( self, decl ):
226 assert not None is self.name 227 if self.__opt_is_tmpl_inst: 228 if not self.__opt_is_full_name: 229 if self.name != templates.normalize( decl.name ) \ 230 and self.name != templates.normalize( decl.partial_name ): 231 return False 232 else: 233 if self.name != templates.normalize( algorithm.full_name( decl, with_defaults=True ) ) \ 234 and self.name != templates.normalize( algorithm.full_name( decl, with_defaults=False ) ): 235 return False 236 else: 237 if not self.__opt_is_full_name: 238 if self.name != decl.name and self.name != decl.partial_name: 239 return False 240 else: 241 if self.name != algorithm.full_name( decl, with_defaults=True ) \ 242 and self.name != algorithm.full_name( decl, with_defaults=False ): 243 return False 244 return True
245
246 - def is_full_name(self):
247 return self.__opt_is_full_name
248
249 - def _get_decl_name_only(self):
250 return self.__decl_name_only
251 decl_name_only = property( _get_decl_name_only )
252
253 -class variable_matcher_t( declaration_matcher_t ):
254 """ 255 Instance of this class will match variables by next criteria: 256 - L{declaration_matcher_t} criteria 257 - variable type. Example: L{int_t} or 'int' 258 """
259 - def __init__( self, name=None, type=None, header_dir=None, header_file=None ):
260 """ 261 @param type: variable type 262 @type type: string or instance of L{type_t} derived class 263 """ 264 declaration_matcher_t.__init__( self 265 , name=name 266 , decl_type=variable.variable_t 267 , header_dir=header_dir 268 , header_file=header_file ) 269 self.type = type
270
271 - def __call__( self, decl ):
272 if not super( variable_matcher_t, self ).__call__( decl ): 273 return False 274 if not None is self.type: 275 if isinstance( self.type, cpptypes.type_t ): 276 if self.type != decl.type: 277 return False 278 else: 279 if self.type != decl.type.decl_string: 280 return False 281 return True
282
283 - def __str__( self ):
284 msg = [ super( variable_matcher_t, self ).__str__() ] 285 if msg == [ 'any' ]: 286 msg = [] 287 if not None is self.type: 288 msg.append( '(value type==%s)' % str(self.type) ) 289 if not msg: 290 msg.append( 'any' ) 291 return ' and '.join( msg )
292 293
294 -class namespace_matcher_t( declaration_matcher_t ):
295 """Instance of this class will match namespaces by name.""" 296
297 - def __init__( self, name=None ):
299
300 - def __call__( self, decl ):
301 if self.name and decl.name == '': 302 #unnamed namespace have same name as thier parent, we should prevent 303 #this happens. The price is: user should search for unnamed namespace 304 #directly. 305 return False 306 return super( namespace_matcher_t, self ).__call__( decl )
307 308
309 -class calldef_matcher_t( declaration_matcher_t ):
310 """ 311 Instance of this class will match callable by next criteria: 312 - L{declaration_matcher_t} criteria 313 - return type. Example: L{int_t} or 'int' 314 - argument types 315 """ 316
317 - def __init__( self, name=None, return_type=None, arg_types=None, decl_type=None, header_dir=None, header_file=None):
318 """ 319 @param return_type: callable return type 320 @type return_type: string or instance of L{type_t} derived class 321 322 @param arg_types: list of function argument types. arg_types can contain. 323 Any item within the list could be string or instance of L{type_t} derived 324 class. If you don't want some argument to participate in match you can 325 put None. For example: 326 327 C{ calldef_matcher_t( arg_types=[ 'int &', None ] ) } 328 329 will match all functions that takes 2 arguments, where the first one is 330 reference to integer and second any 331 @type arg_types: list 332 """ 333 if None is decl_type: 334 decl_type = calldef.calldef_t 335 declaration_matcher_t.__init__( self 336 , name=name 337 , decl_type=decl_type 338 , header_dir=header_dir 339 , header_file=header_file ) 340 341 self.return_type = return_type 342 self.arg_types = arg_types
343
344 - def __call__( self, decl ):
345 if not super( calldef_matcher_t, self ).__call__( decl ): 346 return False 347 if not None is self.return_type \ 348 and not self.__compare_types( self.return_type, decl.return_type ): 349 return False 350 if self.arg_types: 351 if isinstance( self.arg_types, (types.ListType, types.TupleType)): 352 if len(self.arg_types) != len( decl.arguments ): 353 return False 354 for type_or_str, arg in zip( self.arg_types, decl.arguments ): 355 if None == type_or_str: 356 continue 357 else: 358 if not self.__compare_types( type_or_str, arg.type ): 359 return False 360 return True
361
362 - def __compare_types( self, type_or_str, type ):
363 assert type_or_str 364 if type is None: 365 return False 366 if isinstance( type_or_str, cpptypes.type_t ): 367 if type_or_str != type: 368 return False 369 else: 370 if type_or_str != type.decl_string: 371 return False 372 return True
373
374 - def __str__( self ):
375 msg = [ super( calldef_matcher_t, self ).__str__() ] 376 if msg == [ 'any' ]: 377 msg = [] 378 if not None is self.return_type: 379 msg.append( '(return type==%s)' % str(self.return_type) ) 380 if self.arg_types: 381 for i in range( len( self.arg_types ) ): 382 if self.arg_types[i] is None: 383 msg.append( '(arg %d type==any)' % i ) 384 else: 385 msg.append( '(arg %d type==%s)' % ( i, str( self.arg_types[i] ) ) ) 386 if not msg: 387 msg.append( 'any' ) 388 return ' and '.join( msg )
389 390
391 -class operator_matcher_t( calldef_matcher_t ):
392 """ 393 Instance of this class will match operators by next criteria: 394 - L{calldef_matcher_t} criteria 395 - operator symbol: =, !=, (), [] and etc 396 """
397 - def __init__( self, name=None, symbol=None, return_type=None, arg_types=None, decl_type=None, header_dir=None, header_file=None):
398 """ 399 @param symbol: operator symbol 400 @type symbol: str 401 """ 402 if None is decl_type: 403 decl_type = calldef.operator_t 404 calldef_matcher_t.__init__( self 405 , name=name 406 , return_type=return_type 407 , arg_types=arg_types 408 , decl_type=decl_type 409 , header_dir=header_dir 410 , header_file=header_file) 411 self.symbol = symbol
412
413 - def __call__( self, decl ):
414 if not super( operator_matcher_t, self ).__call__( decl ): 415 return False 416 if not None is self.symbol: 417 if self.symbol != decl.symbol: 418 return False 419 return True
420
421 - def __str__( self ):
422 msg = [ super( operator_matcher_t, self ).__str__() ] 423 if msg == [ 'any' ]: 424 msg = [] 425 if not None is self.symbol: 426 msg.append( '(symbol==%s)' % str(self.symbol) ) 427 if not msg: 428 msg.append( 'any' ) 429 return ' and '.join( msg )
430
431 -class regex_matcher_t( matcher_base_t ):
432 """ 433 Instance of this class will match declaration using regular expression. 434 User should supply a function that will extract from declaration desired 435 information as string. Later, this matcher will match that string using 436 user regular expression. 437 """
438 - def __init__( self, regex, function=None ):
439 """ 440 @param regex: regular expression 441 @type regex: string, an instance of this class will compile it for you 442 443 @param function: function that will be called to get an information from 444 declaration as string. As input this function takes 1 argument: reference 445 to declaration. Return value should be string. If function is None, then 446 the matcher will use declaration name. 447 448 """ 449 matcher_base_t.__init__(self) 450 self.regex = re.compile( regex ) 451 self.function = function 452 if None is self.function: 453 self.function = lambda decl: decl.name
454
455 - def __call__( self, decl ):
456 text = self.function( decl ) 457 return bool( self.regex.match( text ) )
458
459 - def __str__( self ):
460 return '(regex=%s)' % self.regex
461
462 -class access_type_matcher_t( matcher_base_t ):
463 """ 464 Instance of this class will match declaration by its access type: public, 465 private or protected. If declarations does not have access type, for example 466 free function, then False will be returned. 467 """ 468
469 - def __init__( self, access_type ):
470 """ 471 @param access_type: declaration access type 472 @type access_type: L{ACCESS_TYPES} defines few consts for your convinience. 473 Any way you can pass public, private or protected as argument to this function 474 """ 475 matcher_base_t.__init__( self ) 476 self.access_type = access_type
477
478 - def __call__( self, decl ):
479 if not isinstance( decl.parent, class_declaration.class_t ): 480 return False 481 return self.access_type == decl.parent.find_out_member_access_type( decl )
482
483 - def __str__( self ):
484 return '(access type=%s)' % self.access_type
485
486 -class virtuality_type_matcher_t( matcher_base_t ):
487 """ 488 Instance of this class will match declaration by its virtuality type: not virtual, 489 virtual or pure virtual. If declarations does not have virtuality type, for example 490 free function, then False will be returned. 491 """ 492
493 - def __init__( self, virtuality_type ):
494 """ 495 @param access_type: declaration access type 496 @type access_type: L{VIRTUALITY_TYPES} defines few consts for your convinience. 497 """ 498 matcher_base_t.__init__( self ) 499 self.virtuality_type = virtuality_type
500
501 - def __call__( self, decl ):
502 if not isinstance( decl.parent, class_declaration.class_t ): 503 return False 504 return self.virtuality_type == decl.virtuality
505
506 - def __str__( self ):
507 return '(virtuality type=%s)' % self.virtuality_type
508 509
510 -class custom_matcher_t( matcher_base_t ):
511 """ 512 Instance of this class will match declaration by user custom criteria. 513 """ 514
515 - def __init__( self, function ):
516 """ 517 @param function: callable, that takes single argument - declaration instance 518 should return True or False 519 """ 520 matcher_base_t.__init__( self ) 521 self.function = function
522
523 - def __call__( self, decl ):
524 return bool( self.function( decl ) )
525
526 - def __str__( self ):
527 return '(user criteria)'
528