Package pyplusplus :: Package function_transformers :: Module transformers

Source Code for Module pyplusplus.function_transformers.transformers

  1  # Copyright 2006 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  # Initial author: Matthias Baas 
  7   
  8  """This module contains the standard argument policy objects. 
  9   
 10  The following policies are available: 
 11   
 12   - L{output_t} 
 13   - L{input_t} 
 14   - L{inout_t} 
 15   - L{input_array_t} 
 16   - L{output_array_t} 
 17   - L{type_modifier_t} 
 18  """ 
 19  import os 
 20  import string 
 21  import transformer 
 22  import controllers 
 23  from pygccxml import declarations 
 24  from pyplusplus import code_repository 
 25   
 26  #TODO: pointers should be checked for NULL 
 27   
28 -def is_ref_or_ptr( type_ ):
29 return declarations.is_pointer( type_ ) or declarations.is_reference( type_ )
30
31 -def is_ptr_or_array( type_ ):
32 return declarations.is_pointer( type_ ) or declarations.is_array( type_ )
33
34 -def remove_ref_or_ptr( type_ ):
35 if declarations.is_pointer( type_ ): 36 return declarations.remove_pointer( type_ ) 37 elif declarations.is_reference( type_ ): 38 return declarations.remove_reference( type_ ) 39 else: 40 raise TypeError( 'Type should be reference or pointer, got %s.' % type_ )
41 42 43 # output_t
44 -class output_t( transformer.transformer_t ):
45 """Handles a single output variable. 46 47 The specified variable is removed from the argument list and is turned 48 into a return value. 49 50 void getValue(int& v) -> v = getValue() 51 """ 52
53 - def __init__(self, function, arg_ref):
54 transformer.transformer_t.__init__( self, function ) 55 """Constructor. 56 57 The specified argument must be a reference or a pointer. 58 59 @param arg_ref: Index of the argument that is an output value (the first arg has index 1). 60 @type arg_ref: int 61 """ 62 self.arg = self.get_argument( arg_ref ) 63 self.arg_index = self.function.arguments.index( self.arg ) 64 65 if not is_ref_or_ptr( self.arg.type ): 66 raise ValueError( '%s\nin order to use "output" transformation, argument %s type must be a reference or a pointer (got %s).' ) \ 67 % ( function, self.arg_ref.name, arg.type)
68
69 - def __str__(self):
70 return "output(%d)"%(self.arg.name)
71
72 - def required_headers( self ):
73 """Returns list of header files that transformer generated code depends on.""" 74 return [ code_repository.convenience.file_name ]
75
76 - def __configure_sealed( self, controller ):
77 #removing arg from the function wrapper definition 78 controller.remove_wrapper_arg( self.arg.name ) 79 #declaring new variable, which will keep result 80 var_name = controller.declare_variable( remove_ref_or_ptr( self.arg.type ), self.arg.name ) 81 #adding just declared variable to the original function call expression 82 controller.modify_arg_expression( self.arg_index, var_name ) 83 #adding the variable to return variables list 84 controller.return_variable( var_name )
85
86 - def __configure_v_mem_fun_default( self, controller ):
87 self.__configure_sealed( controller )
88
89 - def __configure_v_mem_fun_override( self, controller ):
90 controller.remove_py_arg( self.arg_index ) 91 tmpl = string.Template( 92 '$name = boost::python::extract< $type >( pyplus_conv::get_out_argument( $py_result, "$name" ) );' ) 93 store_py_result_in_arg = tmpl.substitute( name=self.arg.name 94 , type=remove_ref_or_ptr( self.arg.type ).decl_string 95 , py_result=controller.py_result_variable.name ) 96 controller.add_py_post_call_code( store_py_result_in_arg )
97
98 - def configure_mem_fun( self, controller ):
99 self.__configure_sealed( controller )
100
101 - def configure_free_fun(self, controller ):
102 self.__configure_sealed( controller )
103
104 - def configure_virtual_mem_fun( self, controller ):
105 self.__configure_v_mem_fun_default( controller.default_controller ) 106 self.__configure_v_mem_fun_override( controller.override_controller )
107 108 # input_t
109 -class type_modifier_t(transformer.transformer_t):
110 """Change/modify type of the argument. 111 112 Right now compiler should be able to use implicit conversion 113 """ 114
115 - def __init__(self, function, arg_ref, modifier):
116 """Constructor. 117 118 modifier is callable, which take the type of the argument and should return 119 new type 120 """ 121 transformer.transformer_t.__init__( self, function ) 122 self.arg = self.get_argument( arg_ref ) 123 self.arg_index = self.function.arguments.index( self.arg ) 124 self.modifier = modifier
125
126 - def __str__(self):
127 return "type_modifier(%s)" % self.arg.name
128
129 - def __configure_sealed( self, controller ):
130 w_arg = controller.find_wrapper_arg( self.arg.name ) 131 w_arg.type = self.modifier( self.arg.type ) 132 if not declarations.is_convertible( w_arg.type, self.arg.type ): 133 casting_code = 'reinterpret_cast< %s >( %s )' % ( self.arg.type, w_arg.name ) 134 controller.modify_arg_expression(self.arg_index, casting_code)
135
136 - def __configure_v_mem_fun_default( self, controller ):
137 self.__configure_sealed( controller )
138
139 - def configure_mem_fun( self, controller ):
140 self.__configure_sealed( controller )
141
142 - def configure_free_fun(self, controller ):
143 self.__configure_sealed( controller )
144
145 - def configure_virtual_mem_fun( self, controller ):
146 self.__configure_v_mem_fun_default( controller.default_controller )
147
148 - def required_headers( self ):
149 """Returns list of header files that transformer generated code depends on.""" 150 return []
151 152 # input_t
153 -class input_t(type_modifier_t):
154 """Handles a single input variable. 155 156 The reference on the specified variable is removed. 157 158 void setValue(int& v) -> setValue(v) 159 """ 160
161 - def __init__(self, function, arg_ref):
162 """Constructor. 163 164 The specified argument must be a reference or a pointer. 165 166 @param idx: Index of the argument that is an output value (the first arg has index 1). 167 @type idx: int 168 """ 169 type_modifier_t.__init__( self, function, arg_ref, remove_ref_or_ptr ) 170 171 if not is_ref_or_ptr( self.arg.type ): 172 raise ValueError( '%s\nin order to use "input" transformation, argument %s type must be a reference or a pointer (got %s).' ) \ 173 % ( function, self.arg_ref.name, arg.type)
174
175 - def __str__(self):
176 return "input(%s)"%(self.arg.name)
177 178 # input_t
179 -class from_address_t(type_modifier_t):
180 """Handles a single input variable. 181 182 Replaces the actual argument type with some integral type, so you 183 can use ctypes package. 184 185 void do_smth(int** image) -> do_smth(unsigned int addressof_image) 186 187 """ 188
189 - def __init__(self, function, arg_ref):
190 """Constructor. 191 192 The specified argument must be a reference or a pointer. 193 194 @param idx: Index of the argument that is an output value (the first arg has index 1). 195 @type idx: int 196 """ 197 modifier = lambda type_: declarations.FUNDAMENTAL_TYPES[ 'unsigned int' ] 198 type_modifier_t.__init__( self, function, arg_ref, modifier ) 199 200 if not is_ptr_or_array( self.arg.type ): 201 raise ValueError( '%s\nin order to use "from_address_t" transformation, argument %s type must be a pointer or a array (got %s).' ) \ 202 % ( function, self.arg_ref.name, arg.type)
203
204 - def __str__(self):
205 return "from_address(%s)"%(self.arg.name)
206 207 # inout_t
208 -class inout_t(transformer.transformer_t):
209 """Handles a single input/output variable. 210 211 void foo(int& v) -> v = foo(v) 212 """ 213
214 - def __init__(self, function, arg_ref):
215 """Constructor. 216 217 The specified argument must be a reference or a pointer. 218 219 @param idx: Index of the argument that is an in/out value (the first arg has index 1). 220 @type idx: int 221 """ 222 transformer.transformer_t.__init__( self, function ) 223 self.arg = self.get_argument( arg_ref ) 224 self.arg_index = self.function.arguments.index( self.arg ) 225 226 if not is_ref_or_ptr( self.arg.type ): 227 raise ValueError( '%s\nin order to use "inout" transformation, argument %s type must be a reference or a pointer (got %s).' ) \ 228 % ( function, self.arg_ref.name, arg.type)
229
230 - def __str__(self):
231 return "inout(%s)"%(self.arg.name)
232
233 - def __configure_sealed(self, controller):
234 w_arg = controller.find_wrapper_arg( self.arg.name ) 235 w_arg.type = remove_ref_or_ptr( self.arg.type ) 236 #adding the variable to return variables list 237 controller.return_variable( w_arg.name )
238
239 - def __configure_v_mem_fun_default( self, controller ):
240 self.__configure_sealed( controller )
241
242 - def __configure_v_mem_fun_override( self, controller ):
243 tmpl = string.Template( 244 '$name = boost::python::extract< $type >( pyplus_conv::get_out_argument( $py_result, "$name" ) );' ) 245 store_py_result_in_arg = tmpl.substitute( name=self.arg.name 246 , type=remove_ref_or_ptr( self.arg.type ).decl_string 247 , py_result=controller.py_result_variable.name ) 248 controller.add_py_post_call_code( store_py_result_in_arg )
249
250 - def configure_mem_fun( self, controller ):
251 self.__configure_sealed( controller )
252
253 - def configure_free_fun(self, controller ):
254 self.__configure_sealed( controller )
255
256 - def configure_virtual_mem_fun( self, controller ):
257 self.__configure_v_mem_fun_override( controller.override_controller ) 258 self.__configure_v_mem_fun_default( controller.default_controller )
259
260 - def required_headers( self ):
261 """Returns list of header files that transformer generated code depends on.""" 262 return [ code_repository.convenience.file_name ]
263 264 265 _seq2arr = string.Template( os.linesep.join([ 266 'pyplus_conv::ensure_uniform_sequence< $type >( $pylist, $array_size );' 267 , 'pyplus_conv::copy_sequence( $pylist, pyplus_conv::array_inserter( $native_array, $array_size ) );'])) 268 269 _seq2vector = string.Template( os.linesep.join([ 270 'pyplus_conv::ensure_uniform_sequence< $type >( $pylist );' 271 , 'pyplus_conv::copy_sequence( $pylist, std::back_inserter( $native_array), boost::type< $type >() );'])) 272 273 _arr2seq = string.Template( 274 'pyplus_conv::copy_container( $native_array, $native_array + $array_size, pyplus_conv::list_inserter( $pylist ) );' ) 275
276 -class input_static_array_t(transformer.transformer_t):
277 """Handles an input array with fixed size. 278 279 void setVec3(double* v) -> setVec3(object v) 280 # v must be a sequence of 3 floats 281 """ 282
283 - def __init__(self, function, arg_ref, size):
284 """Constructor. 285 286 @param size: The fixed size of the input array 287 @type size: int 288 """ 289 transformer.transformer_t.__init__( self, function ) 290 291 self.arg = self.get_argument( arg_ref ) 292 self.arg_index = self.function.arguments.index( self.arg ) 293 294 if not is_ptr_or_array( self.arg.type ): 295 raise ValueError( '%s\nin order to use "input_array" transformation, argument %s type must be a array or a pointer (got %s).' ) \ 296 % ( function, self.arg.name, self.arg.type) 297 298 self.array_size = size 299 self.array_item_type = declarations.remove_const( declarations.array_item_type( self.arg.type ) )
300
301 - def __str__(self):
302 return "input_array(%s,%d)"%( self.arg.name, self.array_size)
303
304 - def required_headers( self ):
305 """Returns list of header files that transformer generated code depends on.""" 306 return [ code_repository.convenience.file_name ]
307
308 - def __configure_sealed(self, controller):
309 global _seq2arr 310 w_arg = controller.find_wrapper_arg( self.arg.name ) 311 w_arg.type = declarations.dummy_type_t( "boost::python::object" ) 312 313 # Declare a variable that will hold the C array... 314 native_array = controller.declare_variable( self.array_item_type 315 , "native_" + self.arg.name 316 , '[%d]' % self.array_size ) 317 318 copy_pylist2arr = _seq2arr.substitute( type=self.array_item_type 319 , pylist=w_arg.name 320 , array_size=self.array_size 321 , native_array=native_array ) 322 323 controller.add_pre_call_code( copy_pylist2arr ) 324 325 controller.modify_arg_expression( self.arg_index, native_array )
326
327 - def __configure_v_mem_fun_default( self, controller ):
328 self.__configure_sealed( controller )
329
330 - def __configure_v_mem_fun_override( self, controller ):
331 global _arr2seq 332 pylist = controller.declare_py_variable( declarations.dummy_type_t( 'boost::python::list' ) 333 , 'py_' + self.arg.name ) 334 335 copy_arr2pylist = _arr2seq.substitute( native_array=self.arg.name 336 , array_size=self.array_size 337 , pylist=pylist ) 338 339 controller.add_py_pre_call_code( copy_arr2pylist )
340
341 - def configure_mem_fun( self, controller ):
342 self.__configure_sealed( controller )
343
344 - def configure_free_fun(self, controller ):
345 self.__configure_sealed( controller )
346
347 - def configure_virtual_mem_fun( self, controller ):
348 self.__configure_v_mem_fun_override( controller.override_controller ) 349 self.__configure_v_mem_fun_default( controller.default_controller )
350 351 352 # s - static
353 -class output_static_array_t(transformer.transformer_t):
354 """Handles an output array of a fixed size. 355 356 void getVec3(double* v) -> v = getVec3() 357 # v will be a list with 3 floats 358 """ 359
360 - def __init__(self, function, arg_ref, size):
361 """Constructor. 362 363 @param idx: Index of the argument that is an output array (the first arg has index 1). 364 @type idx: int 365 @param size: The fixed size of the output array 366 @type size: int 367 """ 368 transformer.transformer_t.__init__( self, function ) 369 self.arg = self.get_argument( arg_ref ) 370 self.arg_index = self.function.arguments.index( self.arg ) 371 372 if not is_ptr_or_array( self.arg.type ): 373 raise ValueError( '%s\nin order to use "input_array" transformation, argument %s type must be a array or a pointer (got %s).' ) \ 374 % ( function, self.arg.name, self.arg.type) 375 376 self.array_size = size 377 self.array_item_type = declarations.array_item_type( self.arg.type )
378
379 - def __str__(self):
380 return "output_array(%s,%d)"%( self.arg.name, self.array_size)
381
382 - def required_headers( self ):
383 """Returns list of header files that transformer generated code depends on.""" 384 return [ code_repository.convenience.file_name ]
385
386 - def __configure_sealed(self, controller):
387 global _arr2seq 388 #removing arg from the function wrapper definition 389 controller.remove_wrapper_arg( self.arg.name ) 390 391 # Declare a variable that will hold the C array... 392 native_array = controller.declare_variable( self.array_item_type 393 , "native_" + self.arg.name 394 , '[%d]' % self.array_size ) 395 396 #adding just declared variable to the original function call expression 397 controller.modify_arg_expression( self.arg_index, native_array ) 398 399 # Declare a Python list which will receive the output... 400 pylist = controller.declare_variable( declarations.dummy_type_t( "boost::python::list" ) 401 , 'py_' + self.arg.name ) 402 403 copy_arr2pylist = _arr2seq.substitute( native_array=native_array 404 , array_size=self.array_size 405 , pylist=pylist ) 406 407 controller.add_post_call_code( copy_arr2pylist ) 408 409 #adding the variable to return variables list 410 controller.return_variable( pylist )
411
412 - def __configure_v_mem_fun_default( self, controller ):
413 self.__configure_sealed( controller )
414
415 - def __configure_v_mem_fun_override( self, controller ):
416 global _seq2arr 417 seq = controller.declare_py_variable( declarations.dummy_type_t( 'boost::python::object' ) 418 , 'py_' + self.arg.name ) 419 controller.remove_py_arg( self.arg_index ) 420 tmpl = string.Template( '$seq = pyplus_conv::get_out_argument( $py_result, "$name" );' ) 421 get_ref_to_seq = tmpl.substitute( seq=seq 422 , py_result=controller.py_result_variable.name 423 , name=self.arg.name ) 424 controller.add_py_post_call_code( get_ref_to_seq ) 425 426 copy_pylist2arr = _seq2arr.substitute( type=self.array_item_type 427 , pylist=seq 428 , array_size=self.array_size 429 , native_array=self.arg.name ) 430 controller.add_py_post_call_code( copy_pylist2arr )
431
432 - def configure_mem_fun( self, controller ):
433 self.__configure_sealed( controller )
434
435 - def configure_free_fun(self, controller ):
436 self.__configure_sealed( controller )
437
438 - def configure_virtual_mem_fun( self, controller ):
439 self.__configure_v_mem_fun_override( controller.override_controller ) 440 self.__configure_v_mem_fun_default( controller.default_controller )
441 442
443 -class input_c_buffer_t(transformer.transformer_t):
444 """Handles an input of C buffere: 445 446 void write( byte *buffer, int size ) -> void write( python sequence ) 447 """ 448
449 - def __init__(self, function, buffer_arg_ref, size_arg_ref):
450 """Constructor. 451 452 @param buffer_arg_ref: "reference" to the buffer argument 453 @param buffer_arg_ref: "reference" to argument, which holds buffer size 454 """ 455 transformer.transformer_t.__init__( self, function ) 456 457 self.buffer_arg = self.get_argument( buffer_arg_ref ) 458 self.buffer_arg_index = self.function.arguments.index( self.buffer_arg ) 459 460 self.size_arg = self.get_argument( size_arg_ref ) 461 self.size_arg_index = self.function.arguments.index( self.size_arg ) 462 463 if not is_ptr_or_array( self.buffer_arg.type ): 464 raise ValueError( '%s\nin order to use "input_c_buffer" transformation, "buffer" argument %s type must be a array or a pointer (got %s).' ) \ 465 % ( function, self.buffer_arg.name, self.buffer_arg.type) 466 467 if not declarations.is_integral( self.size_arg.type ): 468 raise ValueError( '%s\nin order to use "input_c_buffer" transformation, "size" argument %s type must be an integral type (got %s).' ) \ 469 % ( function, self.size_arg.name, self.size_arg.type) 470 471 self.buffer_item_type = declarations.remove_const( declarations.array_item_type( self.buffer_arg.type ) )
472
473 - def __str__(self):
474 return "input_c_buffer(buffer arg=%s, size arg=%s)" \ 475 % ( self.buffer_arg.name, self.size_arg.name)
476
477 - def required_headers( self ):
478 """Returns list of header files that transformer generated code depends on.""" 479 return [ code_repository.convenience.file_name, '<vector>', '<iterator>' ]
480
481 - def __configure_sealed(self, controller):
482 global _seq2arr 483 w_buffer_arg = controller.find_wrapper_arg( self.buffer_arg.name ) 484 w_buffer_arg.type = declarations.dummy_type_t( "boost::python::object" ) 485 486 controller.remove_wrapper_arg( self.size_arg.name ) 487 488 size_var = controller.declare_variable( 489 declarations.remove_const( self.size_arg.type ) 490 , self.size_arg.name 491 , ' = boost::python::len(%s)' % w_buffer_arg.name ) 492 493 # Declare a variable that will hold the C array... 494 buffer_var = controller.declare_variable( 495 declarations.dummy_type_t( "std::vector< %s >" % self.buffer_item_type.decl_string ) 496 , "native_" + self.buffer_arg.name ) 497 498 controller.add_pre_call_code( '%s.reserve( %s );' % ( buffer_var, size_var ) ) 499 500 copy_pylist2arr = _seq2vector.substitute( type=self.buffer_item_type 501 , pylist=w_buffer_arg.name 502 , native_array=buffer_var ) 503 504 controller.add_pre_call_code( copy_pylist2arr ) 505 506 controller.modify_arg_expression( self.buffer_arg_index, '&%s[0]' % buffer_var ) 507 controller.modify_arg_expression( self.size_arg_index, '%s' % size_var )
508
509 - def __configure_v_mem_fun_default( self, controller ):
510 self.__configure_sealed( controller )
511
512 - def __configure_v_mem_fun_override( self, controller ):
513 raise NotImplementedError()
514 #global _arr2seq 515 #pylist = controller.declare_py_variable( declarations.dummy_type_t( 'boost::python::list' ) 516 #, 'py_' + self.arg.name ) 517 518 #copy_arr2pylist = _arr2seq.substitute( native_array=self.arg.name 519 #, array_size=self.array_size 520 #, pylist=pylist ) 521 522 #controller.add_py_pre_call_code( copy_arr2pylist ) 523
524 - def configure_mem_fun( self, controller ):
525 self.__configure_sealed( controller )
526
527 - def configure_free_fun(self, controller ):
528 self.__configure_sealed( controller )
529
530 - def configure_virtual_mem_fun( self, controller ):
531 self.__configure_v_mem_fun_override( controller.override_controller ) 532 self.__configure_v_mem_fun_default( controller.default_controller )
533 534
535 -class transfer_ownership_t(type_modifier_t):
536 """see http://boost.org/libs/python/doc/v2/faq.html#ownership 537 """
538 - def __init__(self, function, arg_ref):
539 """Constructor.""" 540 transformer.transformer_t.__init__( self, function ) 541 self.arg = self.get_argument( arg_ref ) 542 self.arg_index = self.function.arguments.index( self.arg ) 543 if not declarations.is_pointer( self.arg.type ): 544 raise ValueError( '%s\nin order to use "transfer ownership" transformation, argument %s type must be a pointer (got %s).' ) \ 545 % ( function, self.arg_ref.name, arg.type)
546
547 - def __str__(self):
548 return "transfer_ownership(%s)" % self.arg.name
549
550 - def __configure_sealed( self, controller ):
551 w_arg = controller.find_wrapper_arg( self.arg.name ) 552 naked_type = declarations.remove_pointer( self.arg.type ) 553 naked_type = declarations.remove_declarated( naked_type ) 554 w_arg.type = declarations.dummy_type_t( 'std::auto_ptr< %s >' % naked_type.decl_string ) 555 controller.modify_arg_expression(self.arg_index, w_arg.name + '.release()' )
556
557 - def __configure_v_mem_fun_default( self, controller ):
558 self.__configure_sealed( controller )
559
560 - def configure_mem_fun( self, controller ):
561 self.__configure_sealed( controller )
562
563 - def configure_free_fun(self, controller ):
564 self.__configure_sealed( controller )
565
566 - def configure_virtual_mem_fun( self, controller ):
567 raise NotImplementedError(self.__class__.__name__)
568 569 #TODO: FT for constructor 570 #~ def configure_constructor( self, controller ): 571 #~ self.__configure_sealed( controller ) 572
573 - def required_headers( self ):
574 """Returns list of header files that transformer generated code depends on.""" 575 return []
576