Trees | Indices | Help |
|
---|
|
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 """contains classes that allow to configure code generation for free\\member functions, operators and etc.""" 7 8 import os 9 import user_text 10 import algorithm 11 import decl_wrapper 12 from pyplusplus import messages 13 from pygccxml import declarations 14 from pyplusplus import function_transformers as ft17 """base class, for code generator configration, for function declaration classes.""" 18 19 BOOST_PYTHON_MAX_ARITY = 10 20 """Boost.Python configuration macro value. 21 22 A function has more than BOOST_PYTHON_MAX_ARITY arguments, will not compile. 23 You should adjust BOOST_PYTHON_MAX_ARITY macro. 24 For more information see: http://mail.python.org/pipermail/c++-sig/2002-June/001554.html 25 """ 26203 msgs = [] 204 #TODO: functions that takes as argument pointer to pointer to smth, could not be exported 205 #see http://www.boost.org/libs/python/doc/v2/faq.html#funcptr 206 207 if len( self.arguments ) > calldef_t.BOOST_PYTHON_MAX_ARITY: 208 msgs.append( messages.W1007 % ( calldef_t.BOOST_PYTHON_MAX_ARITY, len( self.arguments ) ) ) 209 210 if self.transformations: 211 #if user defined transformation, than I think it took care of the problems 212 ft = self.transformations[0] 213 if ft.alias == ft.unique_name: 214 msgs.append( messages.W1044 % ft.alias ) 215 return msgs 216 217 if suspicious_type( self.return_type ) and None is self.call_policies: 218 msgs.append( messages.W1008 ) 219 220 if ( declarations.is_pointer( self.return_type ) or is_double_ptr( self.return_type ) ) \ 221 and None is self.call_policies: 222 msgs.append( messages.W1050 % str(self.return_type) ) 223 224 for index, arg in enumerate( self.arguments ): 225 if suspicious_type( arg.type ): 226 msgs.append( messages.W1009 % ( arg.name, index ) ) 227 if is_double_ptr( arg.type ): 228 msgs.append( messages.W1051 % ( arg.name, index, str(arg.type) ) ) 229 230 if False == self.overridable: 231 msgs.append( self._non_overridable_reason) 232 233 problematics = algorithm.registration_order.select_problematics( self ) 234 if problematics: 235 tmp = [] 236 for f in problematics: 237 tmp.append( os.linesep + '\t' + str(f) ) 238 msgs.append( messages.W1010 % os.linesep.join( tmp ) ) 239 return msgs 24028 decl_wrapper.decl_wrapper_t.__init__( self, *arguments, **keywords ) 29 30 self._call_policies = None 31 self._use_keywords = True 32 self._use_default_arguments = True 33 self._create_with_signature = None 34 self._overridable = None 35 self._non_overridable_reason = None 36 self._transformations = None3741 self._call_policies = call_policies42 call_policies = property( get_call_policies, set_call_policies 43 , doc="reference to L{call policies<call_policy_t>} class." \ 44 +"Default value is calculated at runtime, based on return value.") 4547 return self._use_keywords and bool( self.arguments )49 self._use_keywords = use_keywords50 use_keywords = property( _get_use_keywords, _set_use_keywords 51 , doc="boolean, if True, allows to call function from Python using keyword arguments." \ 52 +"Default value is True.") 5355 if None is self._create_with_signature: 56 self._create_with_signature = bool( self.overloads ) 57 58 if not self._create_with_signature and declarations.templates.is_instantiation( self.name ): 59 self._create_with_signature = True 60 61 if not self._create_with_signature and isinstance( self.parent, declarations.class_t ): 62 for hi in self.parent.recursive_bases: 63 if hi.access_type == 'private': 64 continue 65 funcs = hi.related_class.calldefs( self.name, recursive=False, allow_empty=True ) 66 for f in funcs: 67 if f.argument_types != self.argument_types: 68 self._create_with_signature = True 69 break 70 if self._create_with_signature: 71 break 72 if not self._create_with_signature: 73 self._create_with_signature \ 74 = bool( self.parent.calldefs( self.name, recursive=False, allow_empty=True ) ) 75 return self._create_with_signature7678 self._create_with_signature = create_with_signature79 create_with_signature = property( _get_create_with_signature, _set_create_with_signature 80 , doc="boolean, if True Py++ will generate next code: def( ..., function type( function ref )"\ 81 +"Thus, the generated code is safe, when a user creates function overloading." \ 82 +"Default value is computed, based on information from the declarations tree" ) 8387 self._use_default_arguments = use_default_arguments88 use_default_arguments = property( _get_use_default_arguments, _set_use_default_arguments 89 , doc="boolean, if True Py++ will generate code that will set default arguments" \ 90 +"Default value is True.") 9193 """returns True, if function - wrapper is needed 94 95 The functionality by this function is uncomplete. So please don't 96 use it in your code. 97 """ 98 if not isinstance( self, declarations.member_calldef_t ): 99 return False 100 elif self.virtuality == declarations.VIRTUALITY_TYPES.PURE_VIRTUAL: 101 return True 102 elif self.access_type == declarations.ACCESS_TYPES.PROTECTED: 103 return True 104 else: 105 return False106108 """Check if the method can be overridden.""" 109 if None is self._overridable: 110 if isinstance( self, declarations.member_calldef_t ) \ 111 and self.virtuality != declarations.VIRTUALITY_TYPES.NOT_VIRTUAL \ 112 and declarations.is_reference( self.return_type ): 113 self._overridable = False 114 self._non_overridable_reason = messages.W1049 115 else: 116 self._overridable = True 117 self._non_overridable_reason = "" 118 return self._overridable119121 self._overridable = overridable122 123 overridable = property( get_overridable, set_overridable 124 , doc = get_overridable.__doc__ ) 125 126 @property128 """returns the reason the function could not be overriden""" 129 return self._non_overridable_reason130132 """mark this function as non-overridable 133 134 Not all fucntions could be overrided from Python, for example virtual function 135 that returns non const reference to a member variable. Py++ allows you to 136 mark these functions and provide and explanation to the user. 137 """ 138 self.overridable = False 139 self._non_overridable_reason = messages.W0000 % reason140 141 @property143 """return list of function transformations that should be applied on the function""" 144 if None is self._transformations: 145 #TODO: for trivial cases get_size( int&, int& ) Py++ should guess 146 #function transformers 147 self._transformations = [] 148 return self._transformations149151 """add new function transformation. 152 153 transformer_creators - list of transformer creators, which should be applied on the function 154 keywd - keyword arguments for L{function_transformation_t} class initialization 155 """ 156 self.transformations.append( ft.function_transformation_t( self, transformer_creators, **keywd ) )157 160162 if not self.parent.name: 163 return messages.W1057 % str( self ) 164 all_types = [ arg.type for arg in self.arguments ] 165 all_types.append( self.return_type ) 166 for some_type in all_types: 167 if isinstance( some_type, declarations.ellipsis_t ): 168 return messages.W1053 % str( self ) 169 units = declarations.decompose_type( some_type ) 170 ptr2functions = filter( lambda unit: isinstance( unit, declarations.calldef_type_t ) 171 , units ) 172 if ptr2functions: 173 return messages.W1004 174 #Function that take as agrument some instance of non public class 175 #will not be exported. Same to the return variable 176 if isinstance( units[-1], declarations.declarated_t ): 177 dtype = units[-1] 178 if isinstance( dtype.declaration.parent, declarations.class_t ): 179 if dtype.declaration not in dtype.declaration.parent.public_members: 180 return messages.W1005 181 no_ref = declarations.remove_reference( some_type ) 182 no_ptr = declarations.remove_pointer( no_ref ) 183 no_const = declarations.remove_const( no_ptr ) 184 if declarations.is_array( no_const ): 185 return messages.W1006 186 return self._exportable_impl_derived()187189 def is_double_ptr( type_ ): 190 #check for X** 191 if not declarations.is_pointer( type_ ): 192 return False 193 base = declarations.remove_pointer( type_ ) 194 return declarations.is_pointer( base )195 196 def suspicious_type( type_ ): 197 if not declarations.is_reference( type_ ): 198 return False 199 type_no_ref = declarations.remove_reference( type_ ) 200 return not declarations.is_const( type_no_ref ) \ 201 and ( declarations.is_fundamental( type_no_ref ) 202 or declarations.is_enum( type_no_ref ) )242 """defines a set of properties, that will instruct Py++ how to expose the member function"""288244 declarations.member_function_t.__init__( self, *arguments, **keywords ) 245 calldef_t.__init__( self ) 246 self._use_overload_macro = False 247 self._override_precall_code = [] 248 self._default_precall_code = []249251 """add code, which should be executed, before overrided member function call""" 252 self._override_precall_code.append( code )253 254 @property256 """code, which should be executed, before overrided member function call""" 257 return self._override_precall_code258260 """add code, which should be executed, before this member function call""" 261 self._default_precall_code.append( code )262 263 @property265 """code, which should be executed, before this member function call""" 266 return self._default_precall_code267 272 use_overload_macro = property( get_use_overload_macro, set_use_overload_macro 273 , doc="boolean, if True, will use BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS macro to expose declarations" \ 274 +"Default value is False.") 275277 if self.access_type == declarations.ACCESS_TYPES.PRIVATE \ 278 and self.virtuality == declarations.VIRTUALITY_TYPES.NOT_VIRTUAL: 279 return messages.W1011 280 return ''281283 msgs = super( member_function_t, self )._readme_impl() 284 if self.does_throw == False \ 285 and self.virtuality != declarations.VIRTUALITY_TYPES.NOT_VIRTUAL: 286 msgs.append( messages.W1046 ) 287 return msgs290 """defines a set of properties, that will instruct Py++ how to expose the constructor"""337292 declarations.constructor_t.__init__( self, *arguments, **keywords ) 293 calldef_t.__init__( self ) 294 self._body = '' 295 self._allow_implicit_conversion = True296300 self._body = body301 body = property( _get_body, _set_body 302 , doc="string, class-wrapper constructor body" ) 303305 if self.is_artificial: 306 return messages.W1012 307 if self.access_type == declarations.ACCESS_TYPES.PRIVATE: 308 return messages.W1013 309 return ''310312 """ returns true if the constructor can take part in implicit conversions. 313 314 For more information see: 315 316 * http://boost.org/libs/python/doc/v2/implicit.html#implicitly_convertible-spec 317 318 * http://msdn2.microsoft.com/en-us/library/h1y7x448.aspx 319 """ 320 if self.parent.is_abstract: #user is not able to create an instance of the class 321 return False 322 if self.is_copy_constructor: 323 return False 324 if 1 != len( self.arguments ): 325 return False 326 if self.parent.find_out_member_access_type( self ) != declarations.ACCESS_TYPES.PUBLIC: 327 return False 328 return True329331 return self._allow_implicit_conversion and self.does_define_implicit_conversion()333 self._allow_implicit_conversion = allow_implicit_conversion334 allow_implicit_conversion = property( _get_allow_implicit_conversion, _set_allow_implicit_conversion 335 , doc="boolean, indicates whether Py++ should generate implicitly_convertible code or not" \ 336 "Default value is calculated from the constructor type." )339 """you may ignore this class for he time being. 340 341 In future it will contain "body" property, that will allow to insert user 342 code to class-wrapper destructor. 343 """ 344 #TODO: add body property348346 declarations.destructor_t.__init__( self, *arguments, **keywords ) 347 calldef_t.__init__( self )350 """helps Py++ to deal with C++ operators""" 351 inplace = [ '+=', '-=', '*=', '/=', '%=', '>>=', '<<=', '&=', '^=', '|=' ] 352 comparison = [ '==', '!=', '<', '>', '<=', '>=' ] 353 non_member = [ '+', '-', '*', '/', '%', '&', '^', '|', ] 354 unary = [ '!', '~', '+', '-' ] 355 356 all = inplace + comparison + non_member + unary 357 358 @staticmethod405360 """returns True if Boost.Python support the operator""" 361 if oper.symbol == '*' and len( oper.arguments ) == 0: 362 #dereference does not make sense 363 return False 364 if oper.symbol != '<<': 365 return oper.symbol in operators_helper.all 366 367 args_len = len( oper.arguments ) 368 if isinstance( oper, declarations.member_operator_t ):# and args_len != 1: 369 return False #Boost.Python does not support member operator<< :-( 370 if isinstance( oper, declarations.free_operator_t ) and args_len != 2: 371 return False 372 if not declarations.is_same( oper.return_type, oper.arguments[0].type ): 373 return False 374 type_ = oper.return_type 375 if not declarations.is_reference( type_ ): 376 return False 377 type_ = declarations.remove_reference( type_ ) 378 if declarations.is_const( type_ ): 379 return False 380 if args_len == 2: 381 #second argument should has "T const &" type, otherwise the code will not compile 382 tmp = oper.arguments[1].type 383 if not declarations.is_reference( tmp ): 384 return False 385 tmp = declarations.remove_reference( tmp ) 386 if not declarations.is_const( tmp ): 387 return False 388 return declarations.is_std_ostream( type_ ) or declarations.is_std_wostream( type_ )389 390 @staticmethod392 """returns True if Boost.Python or Py++ know how to export the operator""" 393 if isinstance( oper, declarations.member_operator_t ) and oper.symbol in ( '()', '[]', '=' ): 394 return '' 395 if not operators_helper.is_supported( oper ): 396 return messages.W1014 % oper.name 397 if isinstance( oper, declarations.free_operator_t ): 398 #Py++ should find out whether the relevant class is exposed to Python 399 #and if not, than this operator should not be exposed too 400 included = filter( lambda decl: decl.ignore == False, oper.class_types ) 401 if not included: 402 return messages.W1052 % str(oper) 403 404 return ''407 """defines a set of properties, that will instruct Py++ how to expose the member operator"""448409 declarations.member_operator_t.__init__( self, *arguments, **keywords ) 410 calldef_t.__init__( self ) 411 self._override_precall_code = [] 412 self._default_precall_code = []413415 self._override_precall_code.append( code )416 417 @property 420422 self._default_precall_code.append( code )423 424 @property 427429 alias = super( member_operator_t, self )._get_alias() 430 if alias == self.name: 431 if self.symbol == '()': 432 alias = '__call__' 433 elif self.symbol == '[]': 434 alias = '__getitem__' 435 elif self.symbol == '=': 436 alias = 'assign' 437 else: 438 pass 439 return alias440 alias = property( _get_alias, decl_wrapper.decl_wrapper_t._set_alias 441 , doc="Gives right alias for operator()( __call__ ) and operator[]( __getitem__ )" ) 442444 if self.access_type == declarations.ACCESS_TYPES.PRIVATE \ 445 and self.virtuality == declarations.VIRTUALITY_TYPES.NOT_VIRTUAL: 446 return messages.W1015 447 return operators_helper.exportable( self )451 """defines a set of properties, that will instruct Py++ how to expose the casting operator""" 452523454 """ 455 Creates a map of special cases ( aliases ) for casting operator. 456 """ 457 special_cases = {} 458 const_t = declarations.const_t 459 pointer_t = declarations.pointer_t 460 for type_ in declarations.FUNDAMENTAL_TYPES.values(): 461 alias = None 462 if declarations.is_same( type_, declarations.bool_t() ): 463 alias = '__int__' 464 elif declarations.is_integral( type_ ): 465 if 'long' in type_.decl_string: 466 alias = '__long__' 467 else: 468 alias = '__int__' 469 elif declarations.is_floating_point( type_ ): 470 alias = '__float__' 471 else: 472 continue #void 473 if alias: 474 special_cases[ type_ ] = alias 475 special_cases[ const_t( type_ ) ] = alias 476 special_cases[ pointer_t( const_t( declarations.char_t() ) ) ] = '__str__' 477 std_string = '::std::basic_string<char,std::char_traits<char>,std::allocator<char> >' 478 std_wstring1 = '::std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >' 479 std_wstring2 = '::std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >' 480 special_cases[ std_string ] = '__str__' 481 special_cases[ std_wstring1 ] = '__str__' 482 special_cases[ std_wstring2 ] = '__str__' 483 special_cases[ '::std::string' ] = '__str__' 484 special_cases[ '::std::wstring' ] = '__str__' 485 486 #TODO: add 487 # std::complex<SomeType> some type should be converted to double 488 return special_cases489 490 SPECIAL_CASES = prepare_special_cases() 491 #casting_member_operator_t.prepare_special_cases() 492494 declarations.casting_operator_t.__init__( self, *arguments, **keywords ) 495 calldef_t.__init__( self )496498 if not self._alias or self.name == super( casting_operator_t, self )._get_alias(): 499 return_type = declarations.remove_alias( self.return_type ) 500 decl_string = return_type.decl_string 501 for type_, alias in self.SPECIAL_CASES.items(): 502 if isinstance( type_, declarations.type_t ): 503 if declarations.is_same( return_type, type_ ): 504 self._alias = alias 505 break 506 else: 507 if decl_string == type_: 508 self._alias = alias 509 break 510 else: 511 self._alias = 'as_' + self._generate_valid_name(self.return_type.decl_string) 512 return self._alias513 alias = property( _get_alias, decl_wrapper.decl_wrapper_t._set_alias 514 , doc="Gives right alias for casting operators: __int__, __long__, __str__." \ 515 +"If there is no built-in type, creates as_xxx alias" ) 516518 if not declarations.is_fundamental( self.return_type ) and not self.has_const: 519 return messages.W1016 520 if self.access_type != declarations.ACCESS_TYPES.PUBLIC: 521 return messages.W1017 522 return ''526 """defines a set of properties, that will instruct Py++ how to expose the free function"""553528 declarations.free_function_t.__init__( self, *arguments, **keywords ) 529 calldef_t.__init__( self ) 530 self._use_overload_macro = False 531 self._declaration_code = []532534 """adds the code to the declaration section""" 535 self.declaration_code.append( user_text.user_text_t( code ) )536 537 @property539 """ 540 List of strings, that contains valid C++ code, that will be added to 541 the same file in which the registration code for the function will be 542 generated 543 """ 544 return self._declaration_code545 550 use_overload_macro = property( get_use_overload_macro, set_use_overload_macro 551 , doc="boolean, if True, will use BOOST_PYTHON_FUNCTION_OVERLOADS macro to expose declarations" \ 552 +"Default value is False.")556 """defines a set of properties, that will instruct Py++ how to expose the free operator"""563558 declarations.free_operator_t.__init__( self, *arguments, **keywords ) 559 calldef_t.__init__( self )560
Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0.1 on Mon Oct 20 08:51:38 2008 | http://epydoc.sourceforge.net |