Package pygccxml :: Package parser :: Module scanner

# Source Code for Module pygccxml.parser.scanner

      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 pprint
      9  import xml.sax
     10  import warnings
     11  import xml.sax.handler
     12  from pygccxml.declarations import *
     13  from pygccxml import utils
     14
     15  ##convention
     16  #XML_NN - XML Node Name
     17  #XML_AN - XML Attribute Name
     18  #also those constants are sorted for easy searching.
     19  XML_AN_ABSTRACT = "abstract"
     20  XML_AN_ACCESS = "access"
     21  XML_AN_ALIGN = "align"
     22  XML_AN_ARTIFICIAL = "artificial"
     23  XML_AN_ATTRIBUTES = "attributes"
     24  XML_AN_BASE_TYPE = "basetype"
     25  XML_AN_BASES = "bases"
     26  XML_AN_BITS = "bits"
     27  XML_AN_CONST = "const"
     28  XML_AN_CONTEXT = "context"
     29  XML_AN_CVS_REVISION = "cvs_revision"
     30  XML_AN_DEFAULT = "default"
     31  XML_AN_DEMANGLED = "demangled"
     32  XML_AN_EXTERN = "extern"
     33  XML_AN_FILE = "file"
     34  XML_AN_ID = "id"
     35  XML_AN_INCOMPLETE = "incomplete"
     36  XML_AN_INIT = "init"
     37  XML_AN_LINE = "line"
     38  XML_AN_MANGLED = "mangled"
     39  XML_AN_MAX = "max"
     40  XML_AN_MEMBERS = "members"
     41  XML_AN_MUTABLE = "mutable"
     42  XML_AN_NAME = "name"
     43  XML_AN_OFFSET = "offset"
     44  XML_AN_PURE_VIRTUAL = "pure_virtual"
     45  XML_AN_RESTRICT = "restrict"
     46  XML_AN_RETURNS = "returns"
     47  XML_AN_SIZE = "size"
     48  XML_AN_STATIC = "static"
     49  XML_AN_THROW = "throw"
     50  XML_AN_TYPE = "type"
     51  XML_AN_VIRTUAL = "virtual"
     52  XML_AN_VOLATILE = "volatile"
     53  XML_NN_ARGUMENT = "Argument"
     54  XML_NN_ARRAY_TYPE = "ArrayType"
     55  XML_NN_CASTING_OPERATOR = "Converter"
     56  XML_NN_CLASS = "Class"
     57  XML_NN_CONSTRUCTOR = "Constructor"
     58  XML_NN_CV_QUALIFIED_TYPE = "CvQualifiedType"
     59  XML_NN_DESTRUCTOR = "Destructor"
     60  XML_NN_ELLIPSIS = "Ellipsis"
     61  XML_NN_ENUMERATION = "Enumeration"
     62  XML_NN_ENUMERATION_VALUE = "EnumValue"
     63  XML_NN_FIELD = "Field"
     64  XML_NN_FILE = "File"
     65  XML_NN_FUNCTION = "Function"
     66  XML_NN_FUNCTION_TYPE = "FunctionType"
     67  XML_NN_FUNDAMENTAL_TYPE = "FundamentalType"
     68  XML_NN_FREE_OPERATOR = "OperatorFunction"
     69  XML_NN_GCC_XML = "GCC_XML"
     70  XML_NN_MEMBER_OPERATOR = "OperatorMethod"
     71  XML_NN_METHOD = "Method"
     72  XML_NN_METHOD_TYPE = "MethodType"
     73  XML_NN_NAMESPACE = "Namespace"
     74  XML_NN_OFFSET_TYPE = "OffsetType"
     75  XML_NN_POINTER_TYPE = "PointerType"
     76  XML_NN_REFERENCE_TYPE = "ReferenceType"
     77  XML_NN_ROOT = "GCC_XML"
     78  XML_NN_STRUCT = "Struct"
     79  XML_NN_TYPEDEF = "Typedef"
     80  XML_NN_UNION = "Union"
     81  XML_NN_VARIABLE = "Variable"
     82
     83 -class scanner_t( xml.sax.handler.ContentHandler ):
     84 -    def __init__(self, gccxml_file, decl_factory, *args ):
     85          xml.sax.handler.ContentHandler.__init__(self, *args )
     86          self.logger = utils.loggers.gccxml
     87          self.gccxml_file = gccxml_file
     88          #defining parsing tables
     89          self.__readers = {
     90                 XML_NN_FILE : self.__read_file
     91                 , XML_NN_NAMESPACE : self.__read_namespace
     92                 , XML_NN_ENUMERATION : self.__read_enumeration
     93                 , XML_NN_ENUMERATION_VALUE : self.__read_enumeration_value
     94                 , XML_NN_ARRAY_TYPE : self.__read_array_type
     95                 , XML_NN_CV_QUALIFIED_TYPE : self.__read_cv_qualified_type
     96                 , XML_NN_POINTER_TYPE : self.__read_pointer_type
     97                 , XML_NN_REFERENCE_TYPE : self.__read_reference_type
     98                 , XML_NN_FUNDAMENTAL_TYPE : self.__read_fundamental_type
     99                 , XML_NN_ARGUMENT : self.__read_argument
    100                 , XML_NN_FUNCTION_TYPE : self.__read_function_type
    101                 , XML_NN_METHOD_TYPE : self.__read_method_type
    102                 , XML_NN_OFFSET_TYPE : self.__read_offset_type
    103                 , XML_NN_TYPEDEF : self.__read_typedef
    104                 , XML_NN_VARIABLE : self.__read_variable
    105                 , XML_NN_CLASS : self.__read_class
    106                 , XML_NN_STRUCT : self.__read_struct
    107                 , XML_NN_UNION : self.__read_union
    108                 , XML_NN_FIELD : self.__read_field
    109                 , XML_NN_CASTING_OPERATOR : self.__read_casting_operator
    110                 , XML_NN_CONSTRUCTOR : self.__read_constructor
    111                 , XML_NN_DESTRUCTOR : self.__read_destructor
    112                 , XML_NN_FUNCTION : self.__read_function
    113                 , XML_NN_FREE_OPERATOR : self.__read_free_operator
    114                 , XML_NN_MEMBER_OPERATOR : self.__read_member_operator
    115                 , XML_NN_METHOD : self.__read_method
    116                 , XML_NN_GCC_XML : self.__read_version
    117                 , XML_NN_ELLIPSIS : self.__read_ellipsis
    118          }
    119          self.deep_declarations = [
    120              XML_NN_CASTING_OPERATOR
    121              , XML_NN_CONSTRUCTOR
    122              , XML_NN_DESTRUCTOR
    123              , XML_NN_ENUMERATION
    124              , XML_NN_FILE
    125              , XML_NN_FUNCTION
    126              , XML_NN_FREE_OPERATOR
    127              , XML_NN_MEMBER_OPERATOR
    128              , XML_NN_METHOD
    129              , XML_NN_FUNCTION_TYPE
    130              , XML_NN_METHOD_TYPE
    131          ]
    132
    133          assert isinstance( decl_factory, decl_factory_t )
    134          self.__decl_factory = decl_factory
    135
    136          #mapping from id -> decl
    137          self.__declarations = {}
    138          #list of all read declarations
    139          self.__calldefs = []
    140          #list of enums I need later
    141          self.__enums = []
    142          #mapping from id -> type
    143          self.__types = {}
    144          #mapping from id -> file
    145          self.__files = {}
    146          #mapping between decl id -> access
    147          self.__access = {}
    148          #current object under construction
    149          self.__inst = None
    150          #mapping from id to members
    151          self.__members = {}
    152
    153          self.__compiler = None
    154
    155 -    def read( self ):
    156          xml.sax.parse( self.gccxml_file, self )
    157
    158 -    def endDocument( self ):
    159          #updating membership
    160          members_mapping = {}
    161          for gccxml_id, members in self.__members.iteritems():
    162              decl = self.__declarations.get( gccxml_id, None )
    163              if not decl or not isinstance( decl, scopedef_t):
    164                  continue
    165              members_mapping[ id( decl ) ] = members
    166          self.__members = members_mapping
    167
    168 -    def declarations(self):
    169          return self.__declarations
    170
    171 -    def calldefs( self ):
    172          return self.__calldefs
    173
    174 -    def enums(self):
    175          return self.__enums
    176
    177 -    def types(self):
    178          return self.__types
    179
    180 -    def files(self):
    181          return self.__files
    182
    183 -    def access(self):
    184          return self.__access
    185
    186 -    def members(self):
    187          return self.__members
    188
    189 -    def startElementNS(self, name, qname, attrs):
    190          return self.startElement( name[1], attrs )
    191
    192 -    def endElementNS(self, name, qname):
    193          return self.endElement( name[1] )
    194
    195 -    def startElement(self, name, attrs):
    196          try:
    197              if name not in self.__readers:
    198                  return
    199              obj = self.__readers[name]( attrs )
    200              if not obj:
    201                  return #it means that we worked on internals
    202                         #for example EnumValue of function argument
    203              if name in self.deep_declarations:
    204                  self.__inst = obj
    205              self.__read_access( attrs )
    206              element_id = attrs.get(XML_AN_ID, None)
    207              if isinstance( obj, declaration_t ):
    208                  obj.compiler = self.__compiler
    209                  self.__update_membership( attrs )
    210                  self.__declarations[ element_id ] = obj
    211                  if not isinstance( obj, namespace_t ):
    212                      self.__read_location( obj, attrs )
    213                  if isinstance( obj, class_t):
    214                      self.__read_bases( obj, attrs )
    215                  self.__read_artificial(obj, attrs)
    216                  self.__read_mangled( obj, attrs)
    217                  self.__read_demangled( obj, attrs)
    218                  self.__read_attributes(obj, attrs)
    219
    220              elif isinstance( obj, type_t ):
    221                  self.__types[ element_id ] = obj
    222                  self.__read_byte_size(obj, attrs)
    223                  self.__read_byte_align(obj, attrs)
    224              elif isinstance( obj, types.StringTypes ):
    225                  self.__files[ element_id ] = obj
    226              else:
    227                  self.logger.warning( 'Unknown object type has been found.'
    228                                       + ' Please report this bug to pygccxml development team.' )
    229          except Exception, error:
    230              msg = 'error occured, while parsing element with name "%s" and attrs "%s".'
    231              msg = msg + os.linesep + 'Error: %s.' % str( error )
    232              self.logger.error( msg % ( name, pprint.pformat( attrs.keys() ) ) )
    233              raise
    234
    235 -    def endElement(self, name):
    236          if name in self.deep_declarations:
    237              self.__inst = None
    238
    239 -    def __read_location(self, decl, attrs):
    240          decl.location = location_t( file_name=attrs[XML_AN_FILE], line=int(attrs[XML_AN_LINE]))
    241
    242 -    def __update_membership(self, attrs):
    243          parent = attrs.get( XML_AN_CONTEXT, None )
    244          if not parent:
    245              return
    246          if not self.__members.has_key( parent ):
    247              self.__members[ parent ] = []
    248          self.__members[parent].append( attrs[XML_AN_ID] )
    249
    250 -    def __read_members(self, decl, attrs ):
    251          decl.declarations = attrs.get(XML_AN_MEMBERS, "")
    252
    253 -    def __read_bases(self, decl, attrs ):
    254          decl.bases = attrs.get( XML_AN_BASES, "" )
    255
    256 -    def __read_artificial( self, decl, attrs ):
    257          decl.is_artificial = attrs.get( XML_AN_ARTIFICIAL, False )
    258
    259 -    def __read_mangled( self, decl, attrs ):
    260          decl.mangled = attrs.get( XML_AN_MANGLED, None )
    261
    262 -    def __read_demangled( self, decl, attrs ):
    263          decl.demangled = attrs.get( XML_AN_DEMANGLED, None )
    264
    265 -    def __read_attributes( self, decl, attrs ):
    266          decl.attributes = attrs.get( XML_AN_ATTRIBUTES, None )
    267
    268 -    def __read_access( self, attrs ):
    269          self.__access[ attrs[XML_AN_ID] ] = attrs.get( XML_AN_ACCESS, ACCESS_TYPES.PUBLIC )
    270
    271 -    def __read_byte_size (self, decl, attrs):
    272          "Using duck typing to set the size instead of in constructor"
    273          size = attrs.get(XML_AN_SIZE, 0)
    274          decl.byte_size = int(size)/8 # Make sure the size is in bytes instead of bits
    275
    276 -    def __read_byte_offset (self, decl, attrs):
    277          "Using duck typing to set the offset instead of in constructor"
    278          offset = attrs.get(XML_AN_OFFSET, 0)
    279          decl.byte_offset = int(offset)/8 # Make sure the size is in bytes instead of bits
    280
    281 -    def __read_byte_align (self, decl, attrs):
    282          "Using duck typing to set the alignment"
    283          align = attrs.get(XML_AN_ALIGN, 0)
    284          decl.byte_align = int(align)/8 # Make sure the size is in bytes instead of bits
    285
    286 -    def __read_root(self, attrs):
    287          pass
    288
    289 -    def __read_file( self, attrs ):
    290          return attrs.get( XML_AN_NAME, '' )
    291
    292 -    def __read_namespace(self, attrs):
    293          ns_name = attrs.get( XML_AN_NAME, '' )
    294          if '.' in ns_name:
    295              #if '.' in namespace then this is mangled namespace -> in c++ namespace{...}
    296              #that is almost true: gcc mangale name using top file name.
    297              #almost all files has '.' in name
    298              ns_name = ''
    299          return self.__decl_factory.create_namespace( name=ns_name )
    300
    301 -    def __read_enumeration(self, attrs):
    302          enum_name = attrs.get( XML_AN_NAME, '' )
    303          if '$_' in enum_name or '._' in enum_name:
    304              #it means that this is unnamed enum. in c++ enum{ x };
    305              enum_name = ''
    306          decl = self.__decl_factory.create_enumeration( name=enum_name )
    307          self.__read_byte_size(decl, attrs)
    308          self.__read_byte_align(decl, attrs)
    309          self.__enums.append( decl )
    310          return decl
    311
    312 -    def __read_enumeration_value( self, attrs ):
    313          name = attrs.get( XML_AN_NAME, '' )
    314          num = int(attrs[XML_AN_INIT])
    315          self.__inst.append_value(name, num)
    316
    317 -    def __guess_int_value( self, value_as_str ):
    318          #returns instance of int or None
    319          #if gcc compiled the code, than it is correct!
    320          numeric_suffix_letters = 'UuLlFf'
    321          for s in numeric_suffix_letters:
    322              value_as_str = value_as_str.replace( s, '' )
    323          try:
    324              return int( value_as_str )
    325          except ValueError:
    326              try:
    327                  return int( value_as_str, 16 )
    328              except ValueError:
    329                  return None
    330
    331 -    def __read_array_type( self, attrs ):
    332          type_ = attrs[ XML_AN_TYPE ]
    333          size = self.__guess_int_value( attrs.get(XML_AN_MAX, '' ) )
    334          if size is None:
    335              size = array_t.SIZE_UNKNOWN
    336              msg = 'unable to find out array size from expression "%s"' % attrs[ XML_AN_MAX ]
    337              warnings.warn( msg )
    338          return array_t( type_, size + 1 )
    339
    340 -    def __read_cv_qualified_type( self, attrs ):
    341          if attrs.has_key( XML_AN_CONST ):
    342              return const_t( attrs[XML_AN_TYPE] )
    343          elif attrs.has_key( XML_AN_VOLATILE ):
    344              return volatile_t( attrs[XML_AN_TYPE] )
    345          elif attrs.has_key( XML_AN_RESTRICT ):
    346              return restrict_t( attrs[XML_AN_TYPE] )
    347          else:
    348              assert 0
    349
    350 -    def __read_pointer_type( self, attrs ):
    351          return pointer_t( attrs[XML_AN_TYPE] )
    352
    353 -    def __read_reference_type( self, attrs ):
    354          return reference_t( attrs[XML_AN_TYPE] )
    355
    356 -    def __read_fundamental_type(self, attrs ):
    357          try:
    358              return FUNDAMENTAL_TYPES[ attrs.get( XML_AN_NAME, '' ) ]
    359          except KeyError:
    360              raise RuntimeError( "pygccxml error: unable to find fundamental type with name '%s'."
    361                                  % attrs.get( XML_AN_NAME, '' ) )
    362
    363 -    def __read_offset_type( self,attrs ):
    364          base = attrs[ XML_AN_BASE_TYPE ]
    365          type_ = attrs[ XML_AN_TYPE ]
    366          if '0.9' in self.__compiler:
    367              return pointer_t( member_variable_type_t( class_inst=base, variable_type=type_ ) )
    368          else:
    369              return member_variable_type_t( class_inst=base, variable_type=type_ )
    370
    371 -    def __read_argument( self, attrs ):
    372          if isinstance( self.__inst, calldef_type_t ):
    373              self.__inst.arguments_types.append( attrs[XML_AN_TYPE] )
    374          else:
    375              argument = argument_t()
    376              argument.name = attrs.get( XML_AN_NAME, 'arg%d' % len(self.__inst.arguments) )
    377              argument.type = attrs[XML_AN_TYPE]
    378              argument.default_value = attrs.get( XML_AN_DEFAULT, None )
    379              self.__read_attributes( argument, attrs )
    380              if argument.default_value == '<gccxml-cast-expr>':
    381                  argument.default_value = None
    382              self.__inst.arguments.append( argument )
    383
    384 -    def __read_ellipsis( self, attrs ):
    385          if isinstance( self.__inst, calldef_type_t ):
    386              self.__inst.arguments_types.append( '...' )
    387          else:
    388              argument = argument_t( type='...' )
    389              self.__inst.arguments.append( argument )
    390
    391 -    def __read_calldef( self, calldef, attrs, is_declaration ):
    392          #destructor for example doesn't have return type
    393          calldef.return_type =  attrs.get( XML_AN_RETURNS, None )
    394          if is_declaration:
    395              self.__calldefs.append( calldef )
    396              calldef.name = attrs.get(XML_AN_NAME, '')
    397              calldef.has_extern = attrs.get( XML_AN_EXTERN, False )
    398              throw_stmt = attrs.get( XML_AN_THROW, None )
    399              if None is throw_stmt:
    400                  calldef.does_throw = True
    401                  calldef.exceptions = []
    402              elif "" == throw_stmt:
    403                  calldef.does_throw = False
    404                  calldef.exceptions = []
    405              else:
    406                  calldef.does_throw = True
    407                  calldef.exceptions = throw_stmt.split()
    408
    409 -    def __read_member_function( self, calldef, attrs, is_declaration ):
    410          self.__read_calldef( calldef, attrs, is_declaration )
    411          calldef.has_const = attrs.get( XML_AN_CONST, False )
    412          if is_declaration:
    413              calldef.has_static = attrs.get( XML_AN_STATIC, False )
    414              if attrs.has_key( XML_AN_PURE_VIRTUAL ):
    415                  calldef.virtuality = VIRTUALITY_TYPES.PURE_VIRTUAL
    416              elif attrs.has_key( XML_AN_VIRTUAL ):
    417                  calldef.virtuality = VIRTUALITY_TYPES.VIRTUAL
    418              else:
    419                  calldef.virtuality = VIRTUALITY_TYPES.NOT_VIRTUAL
    420          else:
    421              calldef.class_inst = attrs[XML_AN_BASE_TYPE]
    422
    423 -    def __read_function_type(self, attrs):
    424          answer = free_function_type_t()
    425          self.__read_calldef( answer, attrs, False )
    426          return answer
    427
    428 -    def __read_method_type(self, attrs):
    429          answer = member_function_type_t()
    430          self.__read_member_function( answer, attrs, False )
    431          return answer
    432
    433 -    def __read_typedef(self, attrs ):
    434          return self.__decl_factory.create_typedef( name=attrs.get( XML_AN_NAME, '' ), type=attrs[XML_AN_TYPE])
    435
    436 -    def __read_variable(self, attrs ):
    437          type_qualifiers = type_qualifiers_t()
    438          type_qualifiers.has_mutable = attrs.get(XML_AN_MUTABLE, False)
    439          type_qualifiers.has_static = attrs.get(XML_AN_EXTERN, False)
    440          bits = attrs.get( XML_AN_BITS, None )
    441          if bits:
    442              bits = int( bits )
    443          decl = self.__decl_factory.create_variable( name=attrs.get( XML_AN_NAME, '' )
    444                                                      , type=attrs[XML_AN_TYPE]
    445                                                      , type_qualifiers=type_qualifiers
    446                                                      , value=attrs.get( XML_AN_INIT, None )
    447                                                      , bits=bits)
    448          self.__read_byte_offset(decl, attrs)
    449          return decl
    450
    451      __read_field = __read_variable #just a synonim
    452
    453 -    def __read_class_impl(self, class_type, attrs):
    454          decl = None
    455          name = attrs.get(XML_AN_NAME, '')
    456          if '$' in name or '.' in name:
    457              name = ''
    458          if attrs.has_key( XML_AN_INCOMPLETE ):
    459              decl = self.__decl_factory.create_class_declaration(name=name)
    460          else:
    461              decl = self.__decl_factory.create_class( name=name, class_type=class_type )
    462              if attrs.get( XML_AN_ABSTRACT, False ):
    463                  decl.is_abstract = True
    464              else:
    465                  decl.is_abstract = False
    466          self.__read_byte_size(decl, attrs)
    467          self.__read_byte_align(decl, attrs)
    468          return decl
    469
    470 -    def __read_class( self, attrs ):
    471          return self.__read_class_impl( CLASS_TYPES.CLASS, attrs )
    472
    473 -    def __read_struct( self, attrs ):
    474          return self.__read_class_impl( CLASS_TYPES.STRUCT, attrs )
    475
    476 -    def __read_union( self, attrs ):
    477          return self.__read_class_impl( CLASS_TYPES.UNION, attrs )
    478
    479 -    def __read_casting_operator(self, attrs ):
    480          operator = self.__decl_factory.create_casting_operator()
    481          self.__read_member_function( operator, attrs, True )
    482          return operator
    483
    484 -    def __read_constructor( self, attrs ):
    485          constructor = self.__decl_factory.create_constructor()
    486          self.__read_member_function( constructor, attrs, True )
    487          return constructor
    488
    489 -    def __read_function(self, attrs):
    490          gfunction = self.__decl_factory.create_free_function()
    491          self.__read_calldef( gfunction, attrs, True )
    492          return gfunction
    493
    494 -    def __read_method(self, attrs):
    495          mfunction = self.__decl_factory.create_member_function()
    496          self.__read_member_function( mfunction, attrs, True )
    497          return mfunction
    498
    499 -    def __read_destructor(self, attrs):
    500          destructor = self.__decl_factory.create_destructor()
    501          self.__read_member_function( destructor, attrs, True )
    502          destructor.name = '~' + destructor.name
    503          return destructor
    504
    505 -    def __read_free_operator(self, attrs ):
    506          operator = self.__decl_factory.create_free_operator()
    507          self.__read_member_function( operator, attrs, True )
    508          if 'new' in operator.name or 'delete' in operator.name:
    509              operator.name = 'operator ' + operator.name
    510          else:
    511              operator.name = 'operator' + operator.name
    512          return operator
    513
    514 -    def __read_member_operator(self, attrs):
    515          operator = self.__decl_factory.create_member_operator()
    516          self.__read_member_function( operator, attrs, True )
    517          if 'new' in operator.name or 'delete' in operator.name:
    518              operator.name = 'operator ' + operator.name
    519          else:
    520              operator.name = 'operator' + operator.name
    521          return operator
    522
    523 -    def __read_version(self, attrs):
    524          logger = utils.loggers.cxx_parser
    525
    526          version = float( attrs.get(XML_AN_CVS_REVISION, 0.6) )
    527          if version is None:
    528              logger.info ( 'GCCXML version - 0.6' )
    529              self.__compiler = compilers.GCC_XML_06
    530          elif version <= 1.114:
    531              logger.info ( 'GCCXML version - 0.7' )
    532              self.__compiler = compilers.GCC_XML_07
    533          elif version in ( 1.115, 1.116, 1.117, 1.118, 1.119, 1.120, 1.121 ):
    534              logger.info ( 'GCCXML version - 0.9 BUGGY' )
    535              self.__compiler = compilers.GCC_XML_09_BUGGY
    536          else:
    537              logger.info ( 'GCCXML version - 0.9' )
    538              self.__compiler = compilers.GCC_XML_09
    539