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))
Example #3
0
    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
Example #5
0
    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
Example #6
0
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;
    }
""")