Package pyplusplus :: Package file_writers :: Module class_multiple_files |

# Source Code for Module pyplusplus.file_writers.class_multiple_files

      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  """defines a class that writes L{code_creators.module_t} to multiple files, the class
      7  also splits huge C++ classes to few source files
      8  """
      9
     10  import os
     11  import writer
     12  import multiple_files
     13  from pygccxml import declarations
     14  from pyplusplus import decl_wrappers
     15  from pyplusplus import code_creators
     16  from pyplusplus import utils as pypp_utils
     17
     18  #TODO: to add namespace_alias_t classes
     19 -class class_multiple_files_t(multiple_files.multiple_files_t):
     20      """
     21      This class will split code, generated for huge classes, to few files.
     22      Next strategy will be used:
     23      1. New directory with class alias name will be created.
     24      2. pyplusplus will generate
     25         wrapper header - header that will contain code generated for class wrappers
     26         classes h/cpp - will contain registration code for internal classes
     27         memfun h/cpp - will contain registration code for member functions
     28
     29         alias + _main h/cpp this class will contain main registration function.
     30      """
     31
     32 -    def __init__( self
     33                    , extmodule
     34                    , directory_path
     35                    , huge_classes
     36                    , num_of_functions_per_file=20
     37                    , files_sum_repository=None
     38                    , encoding='ascii'):
     39          multiple_files.multiple_files_t.__init__(self
     40                                                   , extmodule
     41                                                   , directory_path
     42                                                   , files_sum_repository=files_sum_repository
     43                                                   , encoding=encoding)
     44          self.huge_classes = huge_classes
     45          self.num_of_functions_per_file = num_of_functions_per_file
     46          self.internal_splitters = [
     47              self.split_internal_enums
     48              , self.split_internal_unnamed_enums
     49              , self.split_internal_classes
     50              , self.split_internal_memfuns
     51              , self.split_internal_v_memfuns
     52              , self.split_internal_pv_memfuns
     53              , self.split_internal_protected_memfuns
     54              #not supported yet
     55              #, self.split_internal_member_variables
     56          ]
     57
     58 -    def create_base_fname( self, class_creator, pattern ):
     59          return "_%s__%s" % ( class_creator.alias, pattern )
     60
     61 -    def wrapper_header( self, class_creator ):
     62          return self.create_base_fname( class_creator, 'wrapper' + self.HEADER_EXT )
     63
     64 -    def write_wrapper( self, class_creator ):
     65          answer = []
     66          if self.extmodule.license:
     67              answer.append( self.extmodule.license.create() )
     68
     69          creators = [class_creator]
     70          if class_creator.wrapper:
     71              creators.append( class_creator.wrapper )
     72
     73          answer.append( self.create_include_code( creators ) )
     74          answer.append( '' )
     75          answer.append( self.create_namespaces_code( creators ) )
     76
     77          if class_creator.wrapper:
     78              answer.append( class_creator.wrapper.create() )
     79              class_creator.wrapper.create = lambda: ''
     80
     81          answer.append( '' )
     82          answer.append( class_creator.create_typedef_code() )
     83
     84          code = os.linesep.join( answer )
     85          wrapper_code = self.create_header( self.create_base_fname(class_creator, 'wrapper'), code )
     86          header_file = os.path.join( self.directory_path, self.wrapper_header(class_creator) )
     87          self.write_file( header_file, wrapper_code )
     88
     89 -    def split_internal_creators( self, class_creator, creators, pattern ):
     90          file_path = os.path.join( self.directory_path
     91                                    , self.create_base_fname( class_creator, pattern ) )
     92
     93          function_name = 'register_%(cls_alias)s_%(pattern)s' \
     94                          % { 'cls_alias' : class_creator.alias, 'pattern' : pattern }
     95
     96          function_decl = 'void %(fname)s( %(exposer_type)s& %(var_name)s )' \
     97                          % { 'fname' : function_name
     98                              , 'exposer_type' : class_creator.typedef_name
     99                              , 'var_name' : class_creator.class_var_name }
    100
    101          #writting header file
    102          header_code = [ '#include "%s"' % self.wrapper_header( class_creator ) ]
    103          header_code.append( '' )
    104          header_code.append( function_decl + ';' )
    105          self.write_file( file_path + self.HEADER_EXT
    106                           , self.create_header( class_creator.alias + '_' + pattern
    107                                                 , os.linesep.join(header_code) ) )
    108
    109          #writting source file
    110          source_code = []
    111          if self.extmodule.license:
    112              source_code.append( self.extmodule.license.create() )
    113
    114          #relevant header file
    115          head_headers = [ self.create_base_fname( class_creator, pattern + self.HEADER_EXT ) ]
    116          source_code.append( self.create_include_code( creators, tail_headers=head_headers ) )
    117
    118          source_code.append( '' )
    119          source_code.append( self.create_namespaces_code( creators ) )
    120
    121          for creator in creators:
    122              for decl_creator in self.associated_decl_creators( creator ):
    123                  source_code.append( '' )
    124                  source_code.append( decl_creator.create() )
    125                  if not isinstance( decl_creator, self.ref_count_creators ):
    126                      decl_creator.create = lambda: ''
    127
    128          # Write the register() function...
    129          source_code.append( '' )
    130          source_code.append( '%s{' % function_decl )
    131          source_code.append( '' )
    132          for index, creator in enumerate( creators ):
    133              source_code.append( code_creators.code_creator_t.indent( creator.create() ) )
    134              source_code.append( '' )
    135              if 0 == index:
    136                  creator.create = lambda: function_name + '(%s);' % class_creator.class_var_name
    137              else:
    138                  creator.create = lambda: ''
    139          source_code.append( '}' )
    140          self.write_file( file_path + self.SOURCE_EXT, os.linesep.join( source_code ) )
    141
    142 -    def split_internal_enums( self, class_creator ):
    143          """Write all enumerations into a separate .h/.cpp file.
    144          """
    145          enums_creators = filter( lambda x: isinstance(x, code_creators.enum_t )
    146                                   , class_creator.creators )
    147          self.split_internal_creators( class_creator, enums_creators, 'enums' )
    148          return 'enums'
    149
    150 -    def split_internal_unnamed_enums( self, class_creator ):
    151          creators = filter( lambda x: isinstance(x, code_creators.unnamed_enum_t )
    152                             , class_creator.creators )
    153          self.split_internal_creators( class_creator, creators, 'unnamed_enums' )
    154          return 'unnamed_enums'
    155
    156 -    def split_internal_calldefs( self, class_creator, calldef_types, pattern ):
    157          creators = filter( lambda x: isinstance(x, calldef_types ), class_creator.creators )
    158          grouped_creators = pypp_utils.split_sequence( creators, self.num_of_functions_per_file )
    159          if len( grouped_creators ) == 1:
    160              for creator in creators:
    161                  creator.works_on_instance = False
    162              self.split_internal_creators( class_creator, creators, pattern )
    163              return pattern
    164          else:
    165              patterns = []
    166              for index, group in enumerate( grouped_creators ):
    167                  pattern_tmp = pattern + str( index )
    168                  patterns.append( pattern_tmp )
    169                  for creator in group:
    170                      creator.works_on_instance = False
    171                  self.split_internal_creators( class_creator, group, pattern_tmp )
    172              return patterns
    173
    174 -    def split_internal_memfuns( self, class_creator ):
    175          calldef_types = ( code_creators.mem_fun_t, code_creators.mem_fun_overloads_t )
    176          return self.split_internal_calldefs( class_creator, calldef_types, 'memfuns' )
    177
    178 -    def split_internal_v_memfuns( self, class_creator ):
    179          calldef_types = ( code_creators.mem_fun_v_t )
    180          return self.split_internal_calldefs( class_creator, calldef_types, 'memfuns_virtual' )
    181
    182 -    def split_internal_pv_memfuns( self, class_creator ):
    183          calldef_types = ( code_creators.mem_fun_pv_t )
    184          return self.split_internal_calldefs( class_creator, calldef_types, 'memfuns_pvirtual' )
    185
    186 -    def split_internal_protected_memfuns( self, class_creator ):
    187          calldef_types = (
    188              code_creators.mem_fun_protected_t
    189              , code_creators.mem_fun_protected_s_t
    190              , code_creators.mem_fun_protected_v_t
    191              , code_creators.mem_fun_protected_pv_t )
    192          return self.split_internal_calldefs( class_creator, calldef_types, 'protected_memfuns' )
    193
    194 -    def split_internal_classes( self, class_creator ):
    195          class_types = ( code_creators.class_t, code_creators.class_declaration_t )
    196          creators = filter( lambda x: isinstance(x, class_types ), class_creator.creators )
    197          self.split_internal_creators( class_creator, creators, 'classes' )
    198          return 'classes'
    199
    200 -    def split_internal_member_variables( self, class_creator ):
    201          creators = filter( lambda x: isinstance(x, code_creators.member_variable_base_t)
    202                             , class_creator.creators )
    203          self.split_internal_creators( class_creator, creators, 'memvars' )
    204          return 'memvars'
    205
    206 -    def split_class_impl( self, class_creator):
    207          if not class_creator.declaration in self.huge_classes:
    208              return super( class_multiple_files_t, self ).split_class_impl( class_creator )
    209
    210          class_creator.declaration.always_expose_using_scope = True
    211
    212          function_name = 'register_%s_class' % class_creator.alias
    213          file_path = os.path.join( self.directory_path, class_creator.alias )
    214          # Write the .h file...
    215          header_name = file_path + self.HEADER_EXT
    216          self.write_file( header_name
    217                           , self.create_header( class_creator.alias
    218                                                 , self.create_function_code( function_name ) ) )
    219
    220          self.write_wrapper( class_creator )
    221
    222          tail_headers = []
    223          for splitter in self.internal_splitters:
    224              pattern = splitter( class_creator )
    225              if not pattern:
    226                  continue
    227              if isinstance( pattern, str ):
    228                  tail_headers.append( self.create_base_fname( class_creator, pattern + self.HEADER_EXT ) )
    229              else:
    230                  assert( isinstance( pattern, list ) )
    231                  for p in pattern:
    232                      tail_headers.append( self.create_base_fname( class_creator, p + self.HEADER_EXT ) )
    233          #writting source file
    234          source_code = []
    235          if self.extmodule.license:
    236              source_code.append( self.extmodule.license.create() )
    237
    238          source_code.append( self.create_include_code( [class_creator], tail_headers=tail_headers ) )
    239
    240          source_code.append( '' )
    241          source_code.append( self.create_namespaces_code( [class_creator] ) )
    242
    243          for creator in class_creator.associated_decl_creators:
    244              source_code.append( '' )
    245              source_code.append( creator.create() )
    246              if not isinstance( creator, self.ref_count_creators ):
    247                  creator.create = lambda: ''
    248
    249          # Write the register() function...
    250          source_code.append( '' )
    251          source_code.append( 'void %s(){' % function_name )
    252          source_code.append( '' )
    253          source_code.append( class_creator.create() )
    254          source_code.append( '' )
    255          source_code.append( '}' )
    256          self.write_file( file_path + self.SOURCE_EXT, os.linesep.join( source_code ) )
    257
    258          # Replace the create() method so that only the register() method is called
    259          # (this is called later for the main source file).
    260          class_creator.create = lambda: function_name +'();'
    261          self.include_creators.append( code_creators.include_t( header_name ) )
    262          self.split_header_names.append(header_name)
    263          self.split_method_names.append(function_name)
    264