From: <rom...@us...> - 2006-05-02 05:17:12
|
Revision: 46 Author: roman_yakovenko Date: 2006-05-01 22:17:01 -0700 (Mon, 01 May 2006) ViewCVS: http://svn.sourceforge.net/pygccxml/?rev=46&view=rev Log Message: ----------- adding exportable functionality adding overridable property Virtual functions, that returns [const]reference, could not be overriden from Python. The reason is simple: in boost::python::override::operator(...) result of marshaling (Python 2 C++) is saved on stack, after function exit, the result will be reference to no where - access violetion. For example see temporal variable tester. Modified Paths: -------------- pyplusplus_dev/pyplusplus/decl_wrappers/calldef_wrapper.py Modified: pyplusplus_dev/pyplusplus/decl_wrappers/calldef_wrapper.py =================================================================== --- pyplusplus_dev/pyplusplus/decl_wrappers/calldef_wrapper.py 2006-05-02 05:04:56 UTC (rev 45) +++ pyplusplus_dev/pyplusplus/decl_wrappers/calldef_wrapper.py 2006-05-02 05:17:01 UTC (rev 46) @@ -22,6 +22,7 @@ self._use_keywords = True self._use_default_arguments = True self._create_with_signature = False + self._overridable = None def get_call_policies(self): return self._call_policies @@ -30,13 +31,13 @@ call_policies = property( get_call_policies, set_call_policies ) def _get_use_keywords(self): - return self._use_keywords + return self._use_keywords and bool( self.arguments ) def _set_use_keywords(self, use_keywords): self._use_keywords = use_keywords use_keywords = property( _get_use_keywords, _set_use_keywords ) def _get_create_with_signature(self): - return self._create_with_signature + return self._create_with_signature or bool( self.overloads ) def _set_create_with_signature(self, create_with_signature): self._create_with_signature = create_with_signature create_with_signature = property( _get_create_with_signature, _set_create_with_signature) @@ -67,7 +68,52 @@ else: pass - def readme( self ): + def get_overridable( self ): + """ + Virtual functions, that returns const reference, could not be overriden + from Python. The reason is simple: in boost::python::override::operator(...) + result of marshaling (Python 2 C++) is saved on stack, after function + exit, the result will be reference to no where - access violetion. + For example see temporal variable tester + """ + if None is self._overridable: + if isinstance( self, declarations.member_calldef_t ) \ + and self.virtuality != declarations.VIRTUALITY_TYPES.NOT_VIRTUAL \ + and declarations.is_reference( self.return_type ): + self._overridable = False + else: + self._overridable = True + return self._overridable + + def set_overridable( self, overridable ): + self._overridable = overridable + + overridable = property( get_overridable, set_overridable + , doc = get_overridable.__doc__ ) + + def _exportable_impl( self ): + #see http://www.boost.org/libs/python/doc/v2/faq.html#funcptr + if len( self.arguments ) > 10: + return "boost.python can not expose function with more then 10 arguments. ( impl details: boost.tuple is limited to 10 args )." + all_types = [ arg.type for arg in self.arguments ] + all_types.append( self.return_type ) + for some_type in all_types: + units = declarations.decompose_type( some_type ) + ptr2functions = filter( lambda unit: isinstance( unit, declarations.calldef_type_t ) + , units ) + if ptr2functions: + return "boost.python can not expose function, which takes as argument/returns pointer to function." \ + + " See http://www.boost.org/libs/python/doc/v2/faq.html#funcptr for more information." + #Function that take as agrument some instance of non public class + #will not be exported. Same to the return variable + if isinstance( units[-1], declarations.declarated_t ): + dtype = units[-1] + if isinstance( dtype.declaration.parent, declarations.class_t ): + if dtype.declaration not in dtype.declaration.parent.public_members: + return "pyplusplus can not expose fuction that takes as argument/returns instance of non public class. Generated code will not compile." + return '' + + def _readme_impl( self ): def suspicious_type( type_ ): if not declarations.is_reference( self.return_type ): return False @@ -83,23 +129,57 @@ + 'non-const reference to C++ fundamental type - ' \ + 'function could not be called from Python.' msg.append( tmpl % ( str( self ), arg.name, index ) ) + + if False == self.overridable: + msg.append( self.get_overridable.__doc__ ) return msg - + class member_function_t( declarations.member_function_t, calldef_t ): def __init__(self, *arguments, **keywords): declarations.member_function_t.__init__( self, *arguments, **keywords ) calldef_t.__init__( self ) - + class constructor_t( declarations.constructor_t, calldef_t ): def __init__(self, *arguments, **keywords): declarations.constructor_t.__init__( self, *arguments, **keywords ) calldef_t.__init__( self ) + + def _exportable_impl( self ): + if self.is_artificial: + return 'pyplusplus does not exports compiler generated constructors' + return '' + class destructor_t( declarations.destructor_t, calldef_t ): def __init__(self, *arguments, **keywords): declarations.destructor_t.__init__( self, *arguments, **keywords ) calldef_t.__init__( self ) - + +class operators_helper: + + inplace = [ '+=', '-=', '*=', '/=', '%=', '>>=', '<<=', '&=', '^=', '|=' ] + comparison = [ '==', '!=', '<', '>', '<=', '>=' ] + non_member = [ '+', '-', '*', '/', '%', '&', '^', '|' ] #'>>', '<<', not implemented + unary = [ '!', '~', '+', '-' ] + + all = inplace + comparison + non_member + unary + + def is_supported( oper ): + if oper.symbol == '*' and len( oper.arguments ) == 0: + #dereference does not make sense + return False + return oper.symbol in operators_helper.all + is_supported = staticmethod( is_supported ) + + def exportable( oper ): + if isinstance( oper, declarations.member_operator_t ) and oper.symbol in ( '()', '[]' ): + return '' + if not operators_helper.is_supported( oper ): + #see http://www.boost.org/libs/python/doc/v2/operators.html#introduction + return 'operator %s is not supported. Please take a look on http://www.boost.org/libs/python/doc/v2/operators.html#introduction.' + return '' + exportable = staticmethod( exportable ) + class member_operator_t( declarations.member_operator_t, calldef_t ): def __init__(self, *arguments, **keywords): declarations.member_operator_t.__init__( self, *arguments, **keywords ) @@ -117,11 +197,72 @@ return alias alias = property( _get_alias, decl_wrapper.decl_wrapper_t._set_alias ) + def _exportable_impl( self ): + return operators_helper.exportable( self ) + + class casting_operator_t( declarations.casting_operator_t, calldef_t ): + + def prepare_special_cases(): + """ + Creates a map of special cases ( aliases ) for casting operator. + """ + special_cases = {} + const_t = declarations.const_t + pointer_t = declarations.pointer_t + for type_ in declarations.FUNDAMENTAL_TYPES.values(): + alias = None + if declarations.is_same( type_, declarations.bool_t() ): + alias = '__int__' + elif declarations.is_integral( type_ ): + if 'long' in type_.decl_string: + alias = '__long__' + else: + alias = '__int__' + elif declarations.is_floating_point( type_ ): + alias = '__float__' + else: + continue #void + if alias: + special_cases[ type_ ] = alias + special_cases[ const_t( type_ ) ] = alias + special_cases[ pointer_t( const_t( declarations.char_t() ) ) ] = '__str__' + std_string = '::std::basic_string<char,std::char_traits<char>,std::allocator<char> >' + std_wstring = '::std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >' + special_cases[ std_string ] = '__str__' + special_cases[ std_wstring ] = '__str__' + special_cases[ '::std::string' ] = '__str__' + special_cases[ '::std::wstring' ] = '__str__' + + #TODO: add + # std::complex<SomeType> some type should be converted to double + return special_cases + + SPECIAL_CASES = prepare_special_cases() + #casting_member_operator_t.prepare_special_cases() + def __init__(self, *arguments, **keywords): declarations.casting_operator_t.__init__( self, *arguments, **keywords ) calldef_t.__init__( self ) + def _get_alias( self): + if not self._alias or self.name == super( member_operator_t, self )._get_alias(): + return_type = declarations.remove_alias( self.return_type ) + decl_string = return_type.decl_string + for type_, alias in self.SPECIAL_CASES.items(): + if isinstance( type_, declarations.type_t ): + if declarations.is_same( return_type, type_ ): + self._alias = alias + break + else: + if decl_string == type_: + self._alias = alias + break + else: + self._alias = 'as_' + self._generate_valid_name(self.return_type.decl_string) + return self._alias + alias = property( _get_alias, decl_wrapper.decl_wrapper_t._set_alias ) + class free_function_t( declarations.free_function_t, calldef_t ): def __init__(self, *arguments, **keywords): declarations.free_function_t.__init__( self, *arguments, **keywords ) @@ -131,3 +272,6 @@ def __init__(self, *arguments, **keywords): declarations.free_operator_t.__init__( self, *arguments, **keywords ) calldef_t.__init__( self ) + + def _exportable_impl( self ): + return operators_helper.exportable( self ) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |