Package pygccxml :: Package parser :: Module patcher

Source Code for Module pygccxml.parser.patcher

  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  from pygccxml import utils 
  7  from pygccxml import declarations 
  8   
  9   
10 -class default_argument_patcher_t( object ):
11 - def __init__( self, enums ):
12 object.__init__( self ) 13 self.__enums = enums
14
15 - def __call__(self, decl):
16 for arg in decl.arguments: 17 if not arg.default_value: 18 continue 19 fixer = self.__find_fixer( decl, arg ) 20 if fixer: 21 arg.default_value = fixer( decl, arg )
22
23 - def __find_fixer(self, func, arg):
24 if not arg.default_value: 25 return False 26 elif self.__is_unqualified_enum( func, arg ): 27 return self.__fix_unqualified_enum 28 elif self.__is_double_call( func, arg ): 29 return self.__fix_double_call 30 elif self.__is_invalid_integral( func, arg ): 31 return self.__fix_invalid_integral 32 elif self.__is_constructor_call( func, arg ): 33 return self.__fix_constructor_call 34 else: 35 return None
36
37 - def __join_names( self, prefix, suffix ):
38 if prefix == '::': 39 return '::' + suffix 40 else: 41 return prefix + '::' + suffix
42
43 - def __is_unqualified_enum(self, func, arg):
44 type_ = declarations.remove_reference( declarations.remove_cv( arg.type ) ) 45 if not declarations.is_enum( type_ ): 46 return False 47 enum_type = declarations.enum_declaration( type_ ) 48 return enum_type.has_value_name( arg.default_value )
49
50 - def __fix_unqualified_enum( self, func, arg):
51 type_ = declarations.remove_reference( declarations.remove_cv( arg.type ) ) 52 enum_type = declarations.enum_declaration( type_ ) 53 return self.__join_names( enum_type.parent.decl_string, arg.default_value )
54
55 - def __is_invalid_integral(self, func, arg):
56 type_ = declarations.remove_reference( declarations.remove_cv( arg.type ) ) 57 if not declarations.is_integral( type_ ): 58 return False 59 try: 60 int( arg.default_value ) 61 return False 62 except: 63 return True
64
65 - def __fix_invalid_integral(self, func, arg):
66 try: 67 int( arg.default_value ) 68 return arg.default_value 69 except: 70 pass 71 72 try: 73 int( arg.default_value, 16 ) 74 if 64 == utils.get_architecture(): 75 #on 64 bit architecture, gccxml reports 0fffff, which is valid number 76 #the problem is that in this case it is so buggy so pygccxml can not fix it 77 #users will have to fix the default value manually 78 return arg.default_value 79 default_value = arg.default_value.lower() 80 found_hex = filter( lambda ch: ch in 'abcdef', default_value ) 81 if found_hex and not default_value.startswith( '0x' ): 82 int( '0x' + default_value, 16 ) 83 return '0x' + default_value 84 except: 85 pass 86 87 #may be we deal with enum 88 parent = func.parent 89 while parent: 90 found = self.__find_enum( parent, arg.default_value ) 91 if found: 92 if declarations.is_fundamental( arg.type ) and ' ' in arg.type.decl_string: 93 template = '(%s)(%s)' 94 else: 95 template = '%s(%s)' 96 return template % ( arg.type.decl_string 97 , self.__join_names( found.parent.decl_string, arg.default_value ) ) 98 else: 99 parent = parent.parent 100 return arg.default_value
101
102 - def __find_enum( self, scope, default_value ):
103 #this algorithm could be improved: it could take into account 104 #1. unnamed namespaced 105 #2. location within files 106 107 for enum in self.__enums: 108 if enum.parent is scope and enum.has_value_name( default_value ): 109 return enum 110 return None
111
112 - def __is_double_call( self, func, arg ):
113 call_invocation = declarations.call_invocation 114 dv = arg.default_value 115 found1 = call_invocation.find_args( dv ) 116 if found1 == call_invocation.NOT_FOUND: 117 return False 118 found2 = call_invocation.find_args( dv, found1[1] + 1 ) 119 if found2 == call_invocation.NOT_FOUND: 120 return False 121 args1 = call_invocation.args( dv[ found1[0] : found1[1] + 1 ] ) 122 args2 = call_invocation.args( dv[ found2[0] : found2[1] + 1 ] ) 123 return len(args1) == len(args2)
124
125 - def __fix_double_call( self, func, arg ):
126 call_invocation = declarations.call_invocation 127 dv = arg.default_value 128 found1 = call_invocation.find_args( dv ) 129 found2 = call_invocation.find_args( dv, found1[1] + 1 ) 130 #args1 = call_invocation.args( dv[ found1[0] : found1[1] + 1 ] ) 131 args2 = call_invocation.args( dv[ found2[0] : found2[1] + 1 ] ) 132 return call_invocation.join( dv[:found1[0]], args2 )
133
134 - def __is_constructor_call( self, func, arg ):
135 #if '0.9' in func.compiler: 136 # return False 137 call_invocation = declarations.call_invocation 138 dv = arg.default_value 139 if not call_invocation.is_call_invocation( dv ): 140 return False 141 name = call_invocation.name( dv ) 142 base_type = declarations.base_type( arg.type ) 143 if not isinstance( base_type, declarations.declarated_t ): 144 return False 145 decl = base_type.declaration 146 return decl.name == name \ 147 or ( isinstance( decl, declarations.class_t ) \ 148 and name in map( lambda typedef: typedef.name, decl.aliases ) )
149
150 - def __fix_constructor_call( self, func, arg ):
151 call_invocation = declarations.call_invocation 152 dv = arg.default_value 153 if not call_invocation.is_call_invocation( dv ): 154 return False 155 base_type = declarations.base_type( arg.type ) 156 decl = base_type.declaration 157 name, args = call_invocation.split( dv ) 158 if decl.name != name: 159 #we have some alias to the class 160 relevant_typedefs = filter( lambda typedef: typedef.name == name 161 , decl.aliases ) 162 if 1 == len( relevant_typedefs ): 163 f_q_name = self.__join_names( declarations.full_name( relevant_typedefs[0].parent ) 164 , name ) 165 else:#in this case we can not say which typedef user uses: 166 f_q_name = self.__join_names( declarations.full_name( decl.parent ) 167 , decl.name ) 168 else: 169 f_q_name = self.__join_names( declarations.full_name( decl.parent ), name ) 170 171 return call_invocation.join( f_q_name, args )
172
173 -class casting_operator_patcher_t( object ):
174 - def __init__( self ):
175 object.__init__( self )
176
177 - def __call__(self, decl):
178 decl.name = 'operator ' + decl.return_type.decl_string
179 180 _casting_oper_patcher_ = casting_operator_patcher_t() 181
182 -def fix_calldef_decls(decls, enums):
183 default_arg_patcher = default_argument_patcher_t(enums) 184 #decls should be flat list of all declarations, you want to apply patch on 185 for decl in decls: 186 default_arg_patcher( decl ) 187 if isinstance( decl, declarations.casting_operator_t): 188 _casting_oper_patcher_( decl )
189