Package pyplusplus :: Package code_creators :: Module class_declaration

# Source Code for Module pyplusplus.code_creators.class_declaration

      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  import os
      7  import types
      8  import scoped
      9  import calldef
     10  import algorithm
     11  import smart_pointers
     12  import declaration_based
     13  import registration_based
     14  from pygccxml import declarations
     15
     16 -class class_declaration_t( scoped.scoped_t
     17                             , registration_based.registration_based_t ):
     18 -    def __init__(self, class_inst ):
     19          scoped.scoped_t.__init__( self, declaration=class_inst )
     20          registration_based.registration_based_t.__init__( self )
     21          self.works_on_instance = False
     22
     23 -    def _generate_class_definition(self):
     24          class_identifier = algorithm.create_identifier( self, '::boost::python::class_' )
     25          return declarations.templates.join( class_identifier, [self.decl_identifier] )
     26
     27 -    def _generate_code_no_scope(self):
     28          result = []
     29          result.append( self._generate_class_definition() + '("%s")' % self.declaration.alias )
     30          for x in self.creators:
     31              code = x.create()
     32              tmpl = '%s.%s'
     33              if self.is_comment( code ):
     34                  tmpl = '%s%s'
     35              result.append( self.indent( tmpl % ( os.linesep, code ) ) )
     36          result.append( ';' )
     37          return ''.join( result )
     38
     39      @property
     40 -    def class_var_name(self):
     41          return self.declaration.class_var_name
     42
     43 -    def is_exposed_using_scope(self):
     44          if self.declaration.always_expose_using_scope:
     45              return True
     46          return bool( filter( lambda cc: not cc.works_on_instance, self.creators ) )
     47
     48      @property
     49 -    def typedef_name( self ):
     50          return self.class_var_name + '_t'
     51
     52 -    def _generate_code_with_scope(self):
     53          result = []
     54          scope_var_name = self.alias + '_scope'
     55          result.append( 'typedef ' + self._generate_class_definition() + ' ' + self.typedef_name + ';')
     56          result.append( self.typedef_name + ' ' + self.class_var_name )
     57          result[-1] = result[-1] + ' = '+ self.typedef_name + '("%s");' % self.declaration.alias
     58
     59          result.append( algorithm.create_identifier( self, '::boost::python::scope' ) )
     60          result[-1] = result[-1] + ' ' + scope_var_name
     61          result[-1] = result[-1] + '( %s );' % self.class_var_name
     62
     63          for x in self.creators:
     64              if not x.works_on_instance:
     65                  result.append( x.create() )
     66              else:
     67                  result.append( '%s.%s;' % ( self.class_var_name, x.create() ) )
     68
     69          code = os.linesep.join( result )
     70
     71          result = [ '{ //scope begin' ]
     72          result.append( self.indent( code ) )
     73          result.append( '} //scope end' )
     74
     75          return os.linesep.join( result )
     76
     77 -    def _create_impl(self):
     78          if self.declaration.already_exposed:
     79              return ''
     80          if self.is_exposed_using_scope():
     81              return self._generate_code_with_scope()
     82          else:
     83              return self._generate_code_no_scope()
     84
     85 -    def _get_system_headers_impl( self ):
     86          return []
     87
     88 -class class_t( scoped.scoped_t, registration_based.registration_based_t ):
     89      """
     90      Creates boost.python code that needed to export a class
     91      """
     92 -    def __init__(self, class_inst, wrapper=None ):
     93          scoped.scoped_t.__init__( self, declaration=class_inst )
     94          registration_based.registration_based_t.__init__( self )
     95          self._wrapper = wrapper
     96          self.works_on_instance = False
     97
     98 -    def _get_wrapper( self ):
     99          return self._wrapper
    100 -    def _set_wrapper( self, new_wrapper ):
    101          self._wrapper = new_wrapper
    102      wrapper = property( _get_wrapper, _set_wrapper )
    103
    104 -    def _get_held_type(self):
    105          return self.declaration.held_type
    106 -    def _set_held_type(self, held_type):
    107          assert isinstance( held_type, types.NoneType ) \
    108                 or isinstance( held_type, smart_pointers.held_type_t ) \
    109                 or isinstance( held_type, types.StringTypes )
    110          if isinstance( held_type, types.StringTypes ):
    111              assert held_type # should be non emptry string
    112          self.declaration.held_type = held_type
    113      held_type = property( _get_held_type, _set_held_type )
    114
    115 -    def _exported_base_classes(self):
    116          if not self.declaration.bases:
    117              return {}, {}
    118          base_classes = {}
    119          for hierarchy_info in self.declaration.recursive_bases:
    120              if hierarchy_info.access_type == declarations.ACCESS_TYPES.PRIVATE:
    121                  continue
    122              base_classes[ id( hierarchy_info.related_class ) ] = hierarchy_info
    123          base_classes_size = len( base_classes )
    124          creators = {}
    125          creators_len = 0
    126          for creator in algorithm.make_flatten_generator( self.top_parent.body.creators ):
    127              if isinstance( creator, class_t ) and id(creator.declaration) in base_classes:
    128                  creators[ id(creator.declaration) ] = creator
    129                  if len( creators ) == base_classes_size:
    130                      break #all classes has been found
    131          return base_classes, creators
    132
    133 -    def _get_base_operators(self, base_classes, base_creators):
    134          #May be in future I will redefine operators on wrapper class
    135          #thus I will support [protected|private] [ [not|pure|] virtual] operators.
    136          operator_creators = []
    137          for base_creator in base_creators.values():
    138              hierarchy_info = base_classes[ id( base_creator.declaration )]
    139              if hierarchy_info.access_type != declarations.ACCESS_TYPES.PUBLIC:
    140                  continue
    141              base_operator_creators = filter( lambda creator:
    142                                                  isinstance( creator, calldef.operator_t )
    143                                                  and isinstance( creator.declaration, declarations.member_operator_t )
    144                                                  and creator.declaration.access_type
    145                                                      == declarations.ACCESS_TYPES.PUBLIC
    146                                               , base_creator.creators )
    147              operator_creators.extend( base_operator_creators )
    148          return operator_creators
    149
    150 -    def _generate_noncopyable(self):
    151          noncopyable_vars = self.declaration.find_noncopyable_vars()
    152          copy_constr = self.declaration.find_copy_constructor()
    153
    154          if self.declaration.noncopyable \
    155             or copy_constr and copy_constr.is_artificial and noncopyable_vars:
    156              return algorithm.create_identifier( self, '::boost::noncopyable' )
    157
    158 -    def _generate_bases(self, base_creators):
    159          bases = []
    160          assert isinstance( self.declaration, declarations.class_t )
    161          for base_desc in self.declaration.bases:
    162              assert isinstance( base_desc, declarations.hierarchy_info_t )
    163              if base_desc.access != declarations.ACCESS_TYPES.PUBLIC:
    164                  continue
    165              if base_creators.has_key( id(base_desc.related_class) ):
    166                  bases.append( algorithm.create_identifier( self, base_desc.related_class.partial_decl_string ) )
    167              elif base_desc.related_class.already_exposed:
    168                  bases.append( base_desc.related_class.partial_decl_string )
    169          if not bases:
    170              return None
    171          bases_identifier = algorithm.create_identifier( self, '::boost::python::bases' )
    172          return declarations.templates.join( bases_identifier, bases )
    173
    174 -    def _generated_held_type(self):
    175          if isinstance( self.held_type, smart_pointers.held_type_t ):
    176              return self.held_type.create( self )
    177          elif isinstance( self.held_type, types.StringTypes):
    178              return self.held_type
    179          else:
    180              return None
    181
    182 -    def _generate_class_definition(self, base_creators):
    183          class_identifier = algorithm.create_identifier( self, '::boost::python::class_' )
    184          args = []
    185
    186          held_type = self._generated_held_type()
    187          if self.wrapper:
    188              if self.declaration.exposed_class_type == self.declaration.EXPOSED_CLASS_TYPE.WRAPPER:
    189                  args.append( self.wrapper.full_name )
    190              else:
    191                  if not self.target_configuration.boost_python_has_wrapper_held_type \
    192                     or self.declaration.require_self_reference:
    193                      args.append( self.decl_identifier )
    194                  if self.declaration.require_self_reference:
    195                      if not held_type:
    196                          args.append( self.wrapper.full_name )
    197                  else:
    198                      args.append( self.wrapper.full_name )
    199          else:
    200              args.append( self.decl_identifier )
    201
    202          bases = self._generate_bases(base_creators)
    203          if bases:
    204              args.append( bases )
    205
    206          if held_type:
    207              args.append( held_type )
    208          notcopyable = self._generate_noncopyable()
    209          if notcopyable:
    210              args.append( notcopyable )
    211          return declarations.templates.join( class_identifier, args)
    212
    213 -    def _generate_constructor(self):
    214          result = []
    215          result.append( '(' )
    216          result.append( ' "%s"' % self.alias )
    217          if self.documentation:
    218              result.append( ', %s' % self.documentation )
    219          used_init = None
    220          inits = filter( lambda x: isinstance( x, calldef.constructor_t ), self.creators )
    221
    222          trivial_constructor = self.declaration.find_trivial_constructor()
    223
    224          if self.declaration.no_init:
    225              result.append( ", " )
    226              result.append( algorithm.create_identifier( self, '::boost::python::no_init' ) )
    227          else:
    228              if inits:
    229                  used_init = inits[0]
    230                  result.append( ", " )
    231                  result.append( used_init.create_init_code() )
    232          result.append( ' )' )
    233          return ( ''.join( result ), used_init )
    234
    235 -    def _generate_code_no_scope(self):
    236          result = []
    237          base_classes, base_creators = self._exported_base_classes()
    238          result.append( self._generate_class_definition(base_creators) )
    239          class_constructor, used_init = self._generate_constructor()
    240          result.append( class_constructor )
    241          creators = self.creators
    242          if self.declaration.redefine_operators:
    243              creators = self.creators + self._get_base_operators(base_classes, base_creators)
    244          for x in creators:
    245              if not ( x is used_init ):
    246                  code = x.create()
    247                  tmpl = '%s.%s'
    248                  if self.is_comment( code ):
    249                      tmpl = '%s%s'
    250                  result.append( self.indent( tmpl % ( os.linesep, code ) ) )
    251          result.append( ';' )
    252          return ''.join( result )
    253
    254      @property
    255 -    def class_var_name(self):
    256          return self.declaration.class_var_name
    257
    258      @property
    259 -    def typedef_name( self ):
    260          return self.class_var_name + '_t'
    261
    262 -    def create_typedef_code( self ):
    263          base_classes, base_creators = self._exported_base_classes()
    264          return 'typedef ' + self._generate_class_definition(base_creators) + ' ' + self.typedef_name + ';'
    265
    266
    267 -    def _generate_code_with_scope(self):
    268          result = []
    269          scope_var_name = self.alias + '_scope'
    270          base_classes, base_creators = self._exported_base_classes()
    271          result.append( 'typedef ' + self._generate_class_definition(base_creators) + ' ' + self.typedef_name + ';')
    272          result.append( self.typedef_name + ' ' + self.class_var_name )
    273          result[-1] = result[-1] + ' = '
    274          class_constructor, used_init = self._generate_constructor()
    275          result[-1] = result[-1] + self.typedef_name + class_constructor
    276          result[-1] = result[-1] + ';'
    277
    278          result.append( algorithm.create_identifier( self, '::boost::python::scope' ) )
    279          result[-1] = result[-1] + ' ' + scope_var_name
    280          result[-1] = result[-1] + '( %s );' % self.class_var_name
    281
    282          creators = self.creators
    283          if self.declaration.redefine_operators:
    284              creators = self.creators + self._get_base_operators(base_classes, base_creators)
    285
    286          for x in creators:
    287              if x is used_init:
    288                  continue
    289              if isinstance( x, ( calldef.calldef_t, calldef.calldef_overloads_t ) ):
    290                  x.works_on_instance = False
    291                  code = x.create()
    292                  if code:
    293                      result.append( code )
    294                  continue
    295              if not x.works_on_instance:
    296                  code = x.create()
    297                  if code:
    298                      result.append( code )
    299              else:
    300                  result.append( '%s.%s;' % ( self.class_var_name, x.create() ) )
    301
    302          code = os.linesep.join( result )
    303
    304          result = [ '{ //%s' % declarations.full_name( self.declaration, with_defaults=False ) ]
    305          result.append( self.indent( code ) )
    306          result.append( '}' )
    307
    308          return os.linesep.join( result )
    309
    310 -    def is_exposed_using_scope(self):
    311          if self.declaration.always_expose_using_scope:
    312              return True
    313          return bool( filter( lambda cc: not cc.works_on_instance, self.creators ) )
    314
    315 -    def _create_impl(self):
    316          if self.declaration.already_exposed:
    317              return ''
    318          if self.is_exposed_using_scope():
    319              return self._generate_code_with_scope()
    320          else:
    321              return self._generate_code_no_scope()
    322
    323 -    def _get_system_headers_impl( self ):
    324          return []
    325
    326  #open question: should I put class wrapper under some specifiec namespace?
    327 -class class_wrapper_t( scoped.scoped_t ):
    328      """
    329      Creates C++ code that creates wrapper arround some class
    330      """
    331
    332 -    def __init__(self, declaration, class_creator ):
    333          scoped.scoped_t.__init__( self, declaration=declaration )
    334          self._class_creator = class_creator
    335          self._base_wrappers = []
    336
    337 -    def _get_wrapper_alias( self ):
    338          return self.declaration.wrapper_alias
    339 -    def _set_wrapper_alias( self, walias ):
    340          self.declaration.wrapper_alias = walias
    341      wrapper_alias = property( _get_wrapper_alias, _set_wrapper_alias )
    342
    343      @property
    344 -    def base_wrappers( self ):
    345          if self.declaration.is_abstract and not self._base_wrappers:
    346              bases = [ hi.related_class for hi in self.declaration.bases ]
    347              creators_before_me = algorithm.creators_affect_on_me( self )
    348              self._base_wrappers \
    349                  = filter( lambda creator: isinstance( creator, class_wrapper_t )
    350                                            and creator.declaration in bases
    351                            , creators_before_me )
    352          return self._base_wrappers
    353
    354      @property
    355 -    def exposed_identifier(self):
    356          return algorithm.create_identifier( self, self.declaration.partial_decl_string )
    357
    358      @property
    359 -    def class_creator(self):
    360          return self._class_creator
    361
    362      @property
    363 -    def full_name( self ):
    364          if not isinstance( self.parent, class_wrapper_t ):
    365              return self.declaration.wrapper_alias
    366          else:
    367              full_name = [self.wrapper_alias]
    368              #may be we deal with enum
    369              parent = self.parent
    370              while isinstance( parent, class_wrapper_t ):
    371                  full_name.append( parent.wrapper_alias )
    372                  parent = parent.parent
    373              full_name.reverse()
    374              return '::'.join( full_name )
    375
    376      @property
    377 -    def held_type(self):
    378          return self._class_creator.held_type
    379
    380      @property
    381 -    def boost_wrapper_identifier(self):
    382          boost_wrapper = algorithm.create_identifier( self, '::boost::python::wrapper' )
    383          return declarations.templates.join( boost_wrapper, [self.exposed_identifier] )
    384
    385 -    def _create_bases(self):
    386          return ', '.join( [self.exposed_identifier, self.boost_wrapper_identifier] )
    387
    388 -    def _create_impl(self):
    389          if self.declaration.already_exposed:
    390              return ''
    391          answer = ['struct %s : %s {' % ( self.wrapper_alias, self._create_bases() )]
    392          answer.append( '' )
    393          answer.append( self.create_internal_code( self.creators )  )
    394          answer.append( '' )
    395          answer.append( '};' )
    396          return os.linesep.join( answer )
    397
    398 -    def _get_system_headers_impl( self ):
    399          return []
    400