[pygccxml-commit] SF.net SVN: pygccxml: [613] pyplusplus_dev
                
                Brought to you by:
                
                    mbaas,
                    
                
                    roman_yakovenko
                    
                
            
            
        
        
        
    | 
      
      
      From: <rom...@us...> - 2006-10-04 01:40:24
      
     | 
| Revision: 613
          http://svn.sourceforge.net/pygccxml/?rev=613&view=rev
Author:   roman_yakovenko
Date:     2006-10-02 13:45:21 -0700 (Mon, 02 Oct 2006)
Log Message:
-----------
adding small algorithm that will discover class properties
Modified Paths:
--------------
    pyplusplus_dev/pyplusplus/decl_wrappers/class_wrapper.py
    pyplusplus_dev/pyplusplus/decl_wrappers/properties.py
    pyplusplus_dev/unittests/data/properties_to_be_exported.hpp
    pyplusplus_dev/unittests/properties_tester.py
Modified: pyplusplus_dev/pyplusplus/decl_wrappers/class_wrapper.py
===================================================================
--- pyplusplus_dev/pyplusplus/decl_wrappers/class_wrapper.py	2006-10-01 19:49:39 UTC (rev 612)
+++ pyplusplus_dev/pyplusplus/decl_wrappers/class_wrapper.py	2006-10-02 20:45:21 UTC (rev 613)
@@ -333,6 +333,10 @@
         """
         self._properties.append( properties.property_t( name, fget, fset, doc ) )
 
+    def add_properties( self, recognizer=None, exclude_accessors=False ):
+        props = properties.find_properties( self, recognizer, exclude_accessors )
+        self.properties.extend( props )
+                        
     def add_static_property( self, name, fget, fset=None, doc='' ):
         """adds new static property to the class"""
         self._properties.append( properties.property_t( name, fget, fset, doc, True ) )
Modified: pyplusplus_dev/pyplusplus/decl_wrappers/properties.py
===================================================================
--- pyplusplus_dev/pyplusplus/decl_wrappers/properties.py	2006-10-01 19:49:39 UTC (rev 612)
+++ pyplusplus_dev/pyplusplus/decl_wrappers/properties.py	2006-10-02 20:45:21 UTC (rev 613)
@@ -43,15 +43,224 @@
             desc.append( 'fset=%s' % declarations.full_name( self.fset ) )
         return "property [%s]"% ''.join( desc )
 
-def find_properties( cls ):
-    """this function should return a list of possible properties for the class"""
-    #get* set*
-    #get_* set_*
-    #*, set*
-    #*, set_*
-    #get defined on [derived|base], set defined on [base|derived]
 
-    raise NotImplemented()
+class property_recognizer_i(object):
+    def __init__( self ):
+        object.__init__( self )
+        
+    def create_property( self, fget, fset ):
+        raise NotImplementedError()
 
+    def create_read_only_property( sefl, fget ):
+        raise NotImplementedError()
+    
+class name_based_recognizer_t( property_recognizer_i ):
+    def __init__( self ):
+        property_recognizer_i.__init__( self )
+        self.__prefixes = ( 
+            (  'is', 'set' )
+          , ( 'get', 'set' )
+          , ( 'has', 'set' )
+          , (    '', 'set' ) )
 
+    def check_prefix( self, name, prefix ):
+        if len( prefix ) >= len( name ):
+            return False
+        if not name.startswith( prefix ):
+            return False
+        return True
+        
+    def check_name_compatibility( self, gname, sname, gprefix, sprefix ):
+        if not self.check_prefix( gname, gprefix ):
+            return False
+        if not self.check_prefix( sname, sprefix ):
+            return False
+        if gname[ len( gprefix ): ] != sname[ len( sprefix ): ]:
+            return False
+        return True
 
+    def make_std_convention( self, gprefix, sprefix ):
+        convert = lambda x: x + '_'
+        if gprefix:
+            gprefix = convert( gprefix )
+        return ( gprefix, convert( sprefix ) )
+    
+    def make_u_camel_convention( self, gprefix, sprefix ):
+        convert = lambda x: x[0].upper() + x[1:]
+        if gprefix:
+            gprefix = convert( gprefix )
+        return ( gprefix, convert( sprefix ) )
+    
+    def make_l_camel_convention( self, gprefix, sprefix ):
+        convert = lambda x: x[0].lower() + x[1:]
+        if gprefix:
+            gprefix = convert( gprefix )
+        return ( gprefix, convert( sprefix ) )
+
+    def find_out_prefixes( self, gname, sname ):
+        convention_makers = [ 
+            self.make_std_convention #longest first
+          , self.make_u_camel_convention
+          , self.make_l_camel_convention ]
+
+        for convention_maker in convention_makers:
+            for g, s in self.__prefixes:
+                gc, sc = convention_maker( g, s )
+                if self.check_name_compatibility( gname, sname, gc, sc ):
+                    return ( gc, sc )
+        return None
+
+    def find_out_ro_prefixes( self, gname ):
+        convention_makers = [ 
+            self.make_std_convention #longest first
+          , self.make_u_camel_convention
+          , self.make_l_camel_convention ]
+
+        for convention_maker in convention_makers:
+            for g, unused in self.__prefixes:
+                gc, unused = convention_maker( g, 'set' )
+                if self.check_prefix( gname, gc ):
+                    return gc
+        return None
+
+    def check_type_compatibility( self, fget, fset ):
+        #algorithms allows "const" differences between types
+        t1 = fget.return_type
+        t2 = fset.arguments[0].type
+
+        if declarations.is_same( t1, t2 ):
+            return True
+        elif declarations.is_pointer( t1 ) and declarations.is_pointer( t2 ):
+            t1 = declarations.remove_cv( declarations.remove_pointer( t1 ) )
+            t2 = declarations.remove_cv( declarations.remove_pointer( t2 ) )
+            return declarations.is_same( t1, t2 )
+        elif declarations.is_reference( t1 ) and declarations.is_reference( t2 ):
+            t1 = declarations.remove_cv( declarations.remove_reference( t1 ) )
+            t2 = declarations.remove_cv( declarations.remove_reference( t2 ) )
+            return declarations.is_same( t1, t2 )
+        else:
+            return False
+    
+    def create_property( self, fget, fset ):
+        if not self.check_type_compatibility( fget, fset ):
+            return None
+        found = self.find_out_prefixes( fget.name, fset.name )
+        if not found:
+            return None
+        return property_t( fget.name[len(found[0]):], fget, fset )
+
+    def create_read_only_property( self, fget ):
+        found = self.find_out_ro_prefixes( fget.name )
+        if found:
+            return property_t( fget.name[len(found[0]):], fget )
+        else:
+            return None
+
+class properties_finder_t:
+    def __init__( self, cls, recognizer=None, exclude_accessors=False ):
+        self.cls = cls
+        if None is recognizer:
+            recognizer = name_based_recognizer_t()
+        self.recognizer = recognizer
+        self.exclude_accessors = exclude_accessors
+        self.getters, self.setters \
+            = self.__get_accessors( cls.member_functions( recursive=False, allow_empty=True ) )
+
+        inherted_mem_funs = []
+        for hierarchy_info in cls.recursive_bases:
+            if hierarchy_info.related_class.ignore: #don't scan excluded classes
+                continue
+            if 'public' != hierarchy_info.access_type: #don't scan non public hierarchy
+                continue
+            base_cls = hierarchy_info.related_class
+            inherted_mem_funs.extend( base_cls.member_functions( recursive=False, allow_empty=True ) )
+
+        self.inherited_getters, self.inherited_setters \
+            = self.__get_accessors( inherted_mem_funs )
+        
+    def __is_getter( self, mem_fun ):
+        if mem_fun.arguments:
+            return False
+        if declarations.is_void( mem_fun.return_type ):
+            return False
+        if not mem_fun.has_const:
+            return False
+        return True
+    
+    def __is_setter( self, mem_fun ):
+        if len( mem_fun.arguments ) != 1:
+            return False
+        if not declarations.is_void( mem_fun.return_type ):
+            return False
+        if mem_fun.has_const:
+            return False
+        return True
+    
+    def __get_accessors( self, mem_funs ):
+        getters = []
+        setters = []
+        for mem_fun in mem_funs:
+            if mem_fun.ignore:
+                continue
+            elif mem_fun.access_type != 'public':
+                continue
+            elif mem_fun.has_static:
+                continue #TODO: should be supported
+            elif mem_fun.virtuality == declarations.VIRTUALITY_TYPES.PURE_VIRTUAL:
+                continue
+            elif self.__is_getter( mem_fun ):
+                getters.append( mem_fun )
+            elif self.__is_setter( mem_fun ):
+                setters.append( mem_fun )
+            else:
+                continue
+        return ( getters, setters )
+
+    def find_properties( self, getters, setters, used_getters, used_setters ):
+        properties = []
+        for fget in getters:
+            if fget in used_getters:
+                continue
+            for fset in setters:
+                if fset in used_setters:
+                    continue
+                property_ = self.recognizer.create_property( fget, fset )
+                if property_:
+                    used_getters.add( fget )
+                    used_setters.add( fset )
+                    properties.append( property_ )
+                    break
+        return properties
+        
+    def __call__( self ):
+        used_getters = set()
+        used_setters = set()
+        properties = []
+        #this get, this set
+        properties.extend( 
+            self.find_properties( self.getters, self.setters, used_getters, used_setters ) )
+        #this get, base set
+        properties.extend( 
+            self.find_properties( self.getters, self.inherited_setters, used_getters, used_setters ) )
+        #base get, this set
+        properties.extend( 
+            self.find_properties( self.inherited_getters, self.setters, used_getters, used_setters ) )
+        
+        for fget in self.getters:
+            if fget in used_getters:
+                continue
+            property_ = self.recognizer.create_read_only_property( fget )
+            if property_:
+                used_getters.add( fget )
+                properties.append( property_ )
+                
+        if self.exclude_accessors:
+            map( lambda accessor: accessor.exclude(), used_getters )
+            map( lambda accessor: accessor.exclude(), used_setters )
+            
+        return properties
+    
+def find_properties( cls, recognizer=None, exclude_accessors=False ):
+    pf = properties_finder_t( cls, recognizer, exclude_accessors )
+    properties = pf()
+    return properties 
\ No newline at end of file
Modified: pyplusplus_dev/unittests/data/properties_to_be_exported.hpp
===================================================================
--- pyplusplus_dev/unittests/data/properties_to_be_exported.hpp	2006-10-01 19:49:39 UTC (rev 612)
+++ pyplusplus_dev/unittests/data/properties_to_be_exported.hpp	2006-10-02 20:45:21 UTC (rev 613)
@@ -24,16 +24,31 @@
     void set_count( int x )
     { m_count = x; }
 
-    nested& get_nested()
+    const nested& get_nested() const
     { return m_nested; }
 
     void set_nested( nested x )
     { m_nested = x; }
-
+    
     int m_count;
     nested m_nested;
 };
 
+struct properties_finder_tester_t{
+
+    int count() const { return 0; }
+    void set_count( int ){}
+    
+    int get_size() const { return 0; }
+    void set_size( int ){}
+    
+    int getWidth() const { return 0; }
+    void setWidth(int) {}
+    
+    int GetHeight() const { return 0; }
+    void SetHeight(int){}
+    
+};
 }
 
 
Modified: pyplusplus_dev/unittests/properties_tester.py
===================================================================
--- pyplusplus_dev/unittests/properties_tester.py	2006-10-01 19:49:39 UTC (rev 612)
+++ pyplusplus_dev/unittests/properties_tester.py	2006-10-02 20:45:21 UTC (rev 613)
@@ -33,6 +33,10 @@
         cls.add_property( "nested_", get_nested, set_nested )
 
         cls.add_property( "nested_ro", get_nested )
+        
+        cls = mb.class_( 'properties_finder_tester_t' )
+        cls.add_properties( exclude_accessors=True )
+        self.failUnless( 4 == len( cls.properties ) )
 
     def run_tests(self, module):
         pt = module.properties_tester_t()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
 |