def test_is_base_and_derived(self): ns = declarations.find_declaration( self.declarations, type=declarations.namespace_t, name='is_base_and_derived') self.failUnless(ns, "unable to find 'is_base_and_derived' namespace") base = declarations.find_declaration( ns.declarations, type=declarations.class_t, name='base') derived = declarations.find_declaration( ns.declarations, type=declarations.class_t, name='derived') self.failUnless( base and derived and declarations.is_base_and_derived( base, derived)) self.failUnless( base and derived and declarations.is_base_and_derived(base, (derived, derived))) unrelated1 = declarations.find_declaration( ns.declarations, type=declarations.class_t, name='unrelated1') unrelated2 = declarations.find_declaration( ns.declarations, type=declarations.class_t, name='unrelated2') self.failUnless( base and derived and not declarations.is_base_and_derived( unrelated1, unrelated2))
def test_is_base_and_derived(self): ns = declarations.find_declaration(self.declarations, decl_type=declarations.namespace_t, name='is_base_and_derived') self.assertTrue(ns, "unable to find 'is_base_and_derived' namespace") base = declarations.find_declaration(ns.declarations, decl_type=declarations.class_t, name='base') derived = declarations.find_declaration(ns.declarations, decl_type=declarations.class_t, name='derived') self.assertTrue(base and derived and declarations.is_base_and_derived(base, derived)) self.assertTrue( base and derived and declarations.is_base_and_derived(base, (derived, derived))) unrelated1 = declarations.find_declaration( ns.declarations, decl_type=declarations.class_t, name='unrelated1') unrelated2 = declarations.find_declaration( ns.declarations, decl_type=declarations.class_t, name='unrelated2') self.assertTrue( base and derived and not declarations.is_base_and_derived(unrelated1, unrelated2))
def redefined_funcs( self ): """ returns list of member functions that should be defined in the class wrapper It comes useful in 3 tier hierarchy: .. code-block:: c++ struct base{ virtual void do_nothing() = 0; }; struct derived{ virtual void do_something() = 0; }; struct concrete{ virtual void do_nothing(){} virtual void do_something(){} }; The wrapper for class `derived`, should define `do_nothing` function, otherwise the generated code will not compile """ if isinstance( self._redefined_funcs, list ): return self._redefined_funcs all_included = declarations.custom_matcher_t( lambda decl: decl.ignore == False and decl.exportable ) all_protected = declarations.access_type_matcher_t( 'protected' ) & all_included all_pure_virtual = declarations.virtuality_type_matcher_t( VIRTUALITY_TYPES.PURE_VIRTUAL ) all_virtual = declarations.virtuality_type_matcher_t( VIRTUALITY_TYPES.VIRTUAL ) \ & ( declarations.access_type_matcher_t( 'public' ) \ | declarations.access_type_matcher_t( 'protected' )) all_not_pure_virtual = ~all_pure_virtual query = all_protected | all_pure_virtual mf_query = query | all_virtual relevant_opers = declarations.custom_matcher_t( lambda decl: decl.symbol in ('()', '[]') ) funcs = [] defined_funcs = [] for base in self.recursive_bases: if base.access == ACCESS_TYPES.PRIVATE: continue base_cls = base.related_class funcs.extend( base_cls.member_functions( mf_query, recursive=False, allow_empty=True ) ) funcs.extend( base_cls.member_operators( relevant_opers & query, recursive=False, allow_empty=True ) ) defined_funcs.extend( base_cls.member_functions( all_not_pure_virtual, recursive=False, allow_empty=True ) ) defined_funcs.extend( base_cls.member_operators( all_not_pure_virtual & relevant_opers, recursive=False, allow_empty=True ) ) not_reimplemented_funcs = set() is_same_function = declarations.is_same_function for f in funcs: cls_fs = self.calldefs( name=f.name, recursive=False, allow_empty=True ) for cls_f in cls_fs: if is_same_function( f, cls_f ): break else: #should test whether this function has been added or not for f_impl in not_reimplemented_funcs: if is_same_function( f, f_impl ): if declarations.is_base_and_derived( f_impl.parent, f.parent ): #add function from the most derived class not_reimplemented_funcs.remove( f_impl ) not_reimplemented_funcs.add( f ) break else: #should test whether this function is implemented in base class if f.virtuality != VIRTUALITY_TYPES.PURE_VIRTUAL: not_reimplemented_funcs.add( f ) else: for f_defined in defined_funcs: if is_same_function( f, f_defined ): break else: not_reimplemented_funcs.add( f ) functions = [f for f in list( not_reimplemented_funcs ) if ( False == f.ignore and True == f.exportable ) or all_pure_virtual( f )] #Boost.Python is not able to call for non-virtual function, from the base #class if there is a virtual function with the same within base class #See override_bug tester for more information def buggy_bpl_filter( f ): if f.parent is self: return False if f.access_type != ACCESS_TYPES.PUBLIC: return False if f.virtuality != VIRTUALITY_TYPES.NOT_VIRTUAL: return False #we need to check that we don't have "same" function in this class this_funs = self.decls( name=f.name , decl_type=declarations.calldef_t , recursive=False , allow_empty=True ) for this_f in this_funs: if is_same_function( this_f, f ): #there is already the function in the class, so no need to redefined it return False else: return True tmp = {} # id : f for redefined_f in functions: #redefined is virtual, I am not interested in virtual functions for rfo in redefined_f.overloads: if id(rfo) in tmp: continue if buggy_bpl_filter( rfo ): tmp[ id(rfo) ] = rfo functions.extend( list(tmp.values()) ) functions.sort( key=lambda f: ( f.name, f.location.as_tuple() ) ) self._redefined_funcs = functions return self._redefined_funcs
def redefined_funcs( self ): """returns list of member functions that should be defined in class wrapper It comes useful in 3 tier hierarchy: struct base{ virtual void do_nothing() = 0; }; struct derived{ virtual void do_something() = 0; }; struct concrete{ virtual void do_nothing(){} virtual void do_something(){} }; derived_wrapper should define do_nothing function, otherwise the generated code will not compile """ if isinstance( self._redefined_funcs, list ): return self._redefined_funcs all_included = declarations.custom_matcher_t( lambda decl: decl.ignore == False and decl.exportable ) all_protected = declarations.access_type_matcher_t( 'protected' ) & all_included all_pure_virtual = declarations.virtuality_type_matcher_t( VIRTUALITY_TYPES.PURE_VIRTUAL ) all_not_pure_virtual = ~all_pure_virtual query = all_protected | all_pure_virtual relevant_opers = declarations.custom_matcher_t( lambda decl: decl.symbol in ('()', '[]') ) funcs = set() defined_funcs = set() for base in self.recursive_bases: if base.access == ACCESS_TYPES.PRIVATE: continue base_cls = base.related_class funcs.update( base_cls.member_functions( query, recursive=False, allow_empty=True ) ) funcs.update( base_cls.member_operators( relevant_opers & query, recursive=False, allow_empty=True ) ) defined_funcs.update( base_cls.member_functions( all_not_pure_virtual, recursive=False, allow_empty=True ) ) defined_funcs.update( base_cls.member_operators( all_not_pure_virtual & relevant_opers, recursive=False, allow_empty=True ) ) not_reimplemented_funcs = set() is_same_function = declarations.is_same_function for f in funcs: cls_fs = self.calldefs( name=f.name, recursive=False, allow_empty=True ) for cls_f in cls_fs: if is_same_function( f, cls_f ): break else: #should test whether this function has been added or not for f_impl in not_reimplemented_funcs: if is_same_function( f, f_impl ): if declarations.is_base_and_derived( f_impl.parent, f.parent ): #add function from the most derived class not_reimplemented_funcs.remove( f_impl ) not_reimplemented_funcs.add( f ) break else: #should test whether this function is implemented in base class if f.virtuality != VIRTUALITY_TYPES.PURE_VIRTUAL: not_reimplemented_funcs.add( f ) else: for f_defined in defined_funcs: if is_same_function( f, f_defined ): break else: not_reimplemented_funcs.add( f ) functions = list( not_reimplemented_funcs ) functions.sort( cmp=lambda f1, f2: cmp( ( f1.name, f1.location.as_tuple() ) , ( f2.name, f2.location.as_tuple() ) ) ) self._redefined_funcs = functions return self._redefined_funcs
def redefined_funcs(self): """ returns list of member functions that should be defined in the class wrapper It comes useful in 3 tier hierarchy: .. code-block:: c++ struct base{ virtual void do_nothing() = 0; }; struct derived{ virtual void do_something() = 0; }; struct concrete{ virtual void do_nothing(){} virtual void do_something(){} }; The wrapper for class `derived`, should define `do_nothing` function, otherwise the generated code will not compile """ if isinstance(self._redefined_funcs, list): return self._redefined_funcs all_included = declarations.custom_matcher_t( lambda decl: decl.ignore == False and decl.exportable) all_protected = declarations.access_type_matcher_t( 'protected') & all_included all_pure_virtual = declarations.virtuality_type_matcher_t( VIRTUALITY_TYPES.PURE_VIRTUAL) all_virtual = declarations.virtuality_type_matcher_t( VIRTUALITY_TYPES.VIRTUAL ) \ & ( declarations.access_type_matcher_t( 'public' ) \ | declarations.access_type_matcher_t( 'protected' )) all_not_pure_virtual = ~all_pure_virtual query = all_protected | all_pure_virtual mf_query = query | all_virtual relevant_opers = declarations.custom_matcher_t( lambda decl: decl.symbol in ('()', '[]')) funcs = [] defined_funcs = [] for base in self.recursive_bases: if base.access == ACCESS_TYPES.PRIVATE: continue base_cls = base.related_class funcs.extend( base_cls.member_functions(mf_query, recursive=False, allow_empty=True)) funcs.extend( base_cls.member_operators(relevant_opers & query, recursive=False, allow_empty=True)) defined_funcs.extend( base_cls.member_functions(all_not_pure_virtual, recursive=False, allow_empty=True)) defined_funcs.extend( base_cls.member_operators(all_not_pure_virtual & relevant_opers, recursive=False, allow_empty=True)) not_reimplemented_funcs = set() is_same_function = declarations.is_same_function for f in funcs: cls_fs = self.calldefs(name=f.name, recursive=False, allow_empty=True) for cls_f in cls_fs: if is_same_function(f, cls_f): break else: #should test whether this function has been added or not for f_impl in not_reimplemented_funcs: if is_same_function(f, f_impl): if declarations.is_base_and_derived( f_impl.parent, f.parent): #add function from the most derived class not_reimplemented_funcs.remove(f_impl) not_reimplemented_funcs.add(f) break else: #should test whether this function is implemented in base class if f.virtuality != VIRTUALITY_TYPES.PURE_VIRTUAL: not_reimplemented_funcs.add(f) else: for f_defined in defined_funcs: if is_same_function(f, f_defined): break else: not_reimplemented_funcs.add(f) functions = filter( lambda f: (False == f.ignore and True == f.exportable) or all_pure_virtual(f), list(not_reimplemented_funcs)) #Boost.Python is not able to call for non-virtual function, from the base #class if there is a virtual function with the same within base class #See override_bug tester for more information def buggy_bpl_filter(f): if f.parent is self: return False if f.access_type != ACCESS_TYPES.PUBLIC: return False if f.virtuality != VIRTUALITY_TYPES.NOT_VIRTUAL: return False #we need to check that we don't have "same" function in this class this_funs = self.decls(name=f.name, decl_type=declarations.calldef_t, recursive=False, allow_empty=True) for this_f in this_funs: if is_same_function(this_f, f): #there is already the function in the class, so no need to redefined it return False else: return True tmp = {} # id : f for redefined_f in functions: #redefined is virtual, I am not interested in virtual functions for rfo in redefined_f.overloads: if id(rfo) in tmp: continue if buggy_bpl_filter(rfo): tmp[id(rfo)] = rfo functions.extend(tmp.values()) functions.sort(cmp=lambda f1, f2: cmp((f1.name, f1.location.as_tuple( )), (f2.name, f2.location.as_tuple()))) self._redefined_funcs = functions return self._redefined_funcs
def customize_decls( mb ): classes = mb.classes() classes.always_expose_using_scope = True #better error reporting from compiler classes.redefine_operators = True #redefine all operators found in base classes for class_ in classes: if class_.name in aliases.db: class_.alias = aliases.db[ class_.name ] class_.wrapper_alias = class_.alias + '_wrapper' # Fix up default parameter use of null strings for func in mb.calldefs(): for arg in func.arguments: if arg.default_value == 'FX::FXString::null': arg.default_value = 'FX::FXString::nullStr()' # Insert custom code into wrappers for FXObject subclasses fxobject = mb.class_( 'FXObject' ) fxobjectclasses = mb.classes( lambda decl: decl==fxobject or declarations.is_base_and_derived( fxobject, decl ) ) for fxobjectclass in fxobjectclasses: # Redirect handle() to point to python dispatcher fxobjectclass.member_function( 'handle' ).exclude() fxobjectclass.add_code( 'def("handle", &::FX::'+fxobjectclass.name+'::handle, &'+fxobjectclass.name+'_wrapper::default_handle, bp::default_call_policies() )' ) # Make it so TnFOX objects and their python mirrors can be detached fxobjectclass.held_type = 'std::auto_ptr<'+fxobjectclass.name+'_wrapper>' # Add in runtime support for detaching and msg handling fxobjectclass.set_constructors_body( ' FX::FXPython::int_pythonObjectCreated((int_decouplingFunctor=FX::Generic::BindObjN(*this, &FX::'+fxobjectclass.name+'::decouplePythonObject)));' ) fxobjectclass.add_wrapper_code(""" // TnFOX runtime support virtual long int handle( ::FX::FXObject * sender, ::FX::FXSelector sel, void * ptr ) { if( bp::override func_handle = this->get_override( "handle" ) ) return func_handle( boost::python::ptr(sender), sel, ptr ); else return default_handle( sender, sel, ptr ); } long int default_handle( ::FX::FXObject * sender, ::FX::FXSelector sel, void * ptr ) { long ret=0; if( FX::FXPython::int_FXObjectHandle( &ret, this, sender, sel, ptr ) ) return ret; return FX::"""+fxobjectclass.name+"""::handle( sender, sel, ptr ); } ~"""+fxobjectclass.name+"""_wrapper( ) { FX::FXPython::int_pythonObjectDeleted(int_decouplingFunctor); using namespace boost::python; using namespace std; PyObject *py_self=get_owner(*this); // We must be careful not to reinvoke object destruction! py_self->ob_refcnt=1<<16; { object me(boost::python::handle<>(borrowed(py_self))); auto_ptr<"""+fxobjectclass.name+"""_wrapper> &autoptr=extract<auto_ptr<"""+fxobjectclass.name+"""_wrapper> &>(me); autoptr.release(); } py_self->ob_refcnt=0; } virtual void *getPythonObject() const { return (void *) get_owner(*this); } virtual void decouplePythonObject() const { using namespace boost::python; using namespace std; PyObject *py_self=get_owner(*this); object me(boost::python::handle<>(borrowed(py_self))); auto_ptr<"""+fxobjectclass.name+"""_wrapper> &autoptr=extract<auto_ptr<"""+fxobjectclass.name+"""_wrapper> &>(me); autoptr.reset(0); } private: Generic::BoundFunctorV *int_decouplingFunctor;""") # Patch in custom FXApp::init() implementation fxapp = mb.class_( 'FXApp' ) fxapp.member_functions( 'init' ).exclude() fxapp.add_code( 'def("init", &FXApp_init)' ) fxapp.add_code( 'def("init", &FXApp_init2)' ) fxapp.add_code( 'def("getArgv", &FXApp_getArgv)' ) # Patch in custom FXGLTriangleMesh implementations fxgltrianglemesh = mb.class_( 'FXGLTriangleMesh' ) fxgltrianglemesh.member_functions( 'getVertexBuffer' ).exclude() fxgltrianglemesh.add_code ( 'def("getVertexBuffer", &FXGLTriangleMesh_getVertexBuffer)' ) fxgltrianglemesh.member_functions( 'getColorBuffer' ).exclude() fxgltrianglemesh.add_code ( 'def("getColorBuffer", &FXGLTriangleMesh_getColorBuffer)' ) fxgltrianglemesh.member_functions( 'getNormalBuffer' ).exclude() fxgltrianglemesh.add_code ( 'def("getNormalBuffer", &FXGLTriangleMesh_getNormalBuffer)' ) fxgltrianglemesh.member_functions( 'getTextureCoordBuffer' ).exclude() fxgltrianglemesh.add_code ( 'def("getTextureCoordBuffer", &FXGLTriangleMesh_getTextureCoordBuffer)' ) # Patch in custom FXGLViewer implementations fxglviewer = mb.class_( 'FXGLViewer' ) fxglviewer.member_functions( 'lasso' ).exclude() fxglviewer.add_code ( 'def("lasso", &FXGLViewer_lasso, bp::return_value_policy< bp::manage_new_object, bp::default_call_policies >() )' ) fxglviewer.member_functions( 'select' ).exclude() fxglviewer.add_code ( 'def("select", &FXGLViewer_select, bp::return_value_policy< bp::manage_new_object, bp::default_call_policies >() )' ) # Patch image & bitmap getData() functions getdatafuncs = mb.calldefs( lambda decl: decl.name == 'getData' and not declarations.is_void_pointer( decl.return_type ) and ('Icon' in decl.parent.name or 'Image' in decl.parent.name or 'Bitmap' in decl.parent.name) ) getdatafuncs.exclude() for getdatafunc in getdatafuncs: getdatafunc.parent.add_code( 'def("getData", &'+getdatafunc.parent.name+'_getData)' ) # Patch sort functions sortfuncs = mb.calldefs( lambda decl: 'SortFunc' in decl.name and 'set' in decl.name ) for sortfunc in sortfuncs: sortfunc.parent.add_code( 'def("'+sortfunc.name+'", &FX::FXPython::set'+sortfunc.parent.name+'SortFunc)' ) # Patch QIODevice wrapper with missing pure virtual functions qiodevice = mb.class_( 'QIODevice' ) qiodevice.add_wrapper_code(""" virtual ::FX::FXuval readBlock( char * data, ::FX::FXuval maxlen ){ bp::override func_readBlock = this->get_override( "readBlock" ); return func_readBlock( data, maxlen ); } virtual ::FX::FXuval writeBlock( char const * data, ::FX::FXuval maxlen ){ bp::override func_writeBlock = this->get_override( "writeBlock" ); return func_writeBlock( data, maxlen ); } virtual ::FX::FXuval readBlockFrom( char * data, ::FX::FXuval maxlen, ::FX::FXfval pos ){ bp::override func_readBlockFrom = this->get_override( "readBlockFrom" ); return func_readBlockFrom( data, maxlen, pos ); } virtual ::FX::FXuval writeBlockTo( ::FX::FXfval pos, char const * data, ::FX::FXuval maxlen ){ bp::override func_writeBlockTo = this->get_override( "writeBlockTo" ); return func_writeBlockTo( pos, data, maxlen ); } """) qiodevices = mb.class_( 'QIODeviceS' ) qiodevices.add_wrapper_code(""" virtual ::FX::FXuval readBlock( char * data, ::FX::FXuval maxlen ){ bp::override func_readBlock = this->get_override( "readBlock" ); return func_readBlock( data, maxlen ); } virtual ::FX::FXuval writeBlock( char const * data, ::FX::FXuval maxlen ){ bp::override func_writeBlock = this->get_override( "writeBlock" ); return func_writeBlock( data, maxlen ); } virtual void *int_getOSHandle() const{ return 0; } """)