pygccxml-commit Mailing List for C++ Python language bindings (Page 53)
Brought to you by:
mbaas,
roman_yakovenko
You can subscribe to this list here.
2006 |
Jan
|
Feb
|
Mar
(190) |
Apr
(166) |
May
(170) |
Jun
(75) |
Jul
(105) |
Aug
(131) |
Sep
(99) |
Oct
(84) |
Nov
(67) |
Dec
(54) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2007 |
Jan
(66) |
Feb
(49) |
Mar
(25) |
Apr
(62) |
May
(21) |
Jun
(34) |
Jul
(9) |
Aug
(21) |
Sep
(5) |
Oct
|
Nov
(63) |
Dec
(34) |
2008 |
Jan
(10) |
Feb
(42) |
Mar
(26) |
Apr
(25) |
May
(6) |
Jun
(40) |
Jul
(18) |
Aug
(29) |
Sep
(6) |
Oct
(32) |
Nov
(14) |
Dec
(56) |
2009 |
Jan
(127) |
Feb
(52) |
Mar
(2) |
Apr
(10) |
May
(29) |
Jun
(3) |
Jul
|
Aug
(16) |
Sep
(4) |
Oct
(11) |
Nov
(8) |
Dec
(14) |
2010 |
Jan
(31) |
Feb
(1) |
Mar
(7) |
Apr
(9) |
May
(1) |
Jun
|
Jul
(2) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2011 |
Jan
|
Feb
(8) |
Mar
(4) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2014 |
Jan
|
Feb
|
Mar
(1) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <rom...@us...> - 2006-09-14 05:23:19
|
Revision: 540 http://svn.sourceforge.net/pygccxml/?rev=540&view=rev Author: roman_yakovenko Date: 2006-09-13 22:23:14 -0700 (Wed, 13 Sep 2006) Log Message: ----------- fixing minor bug Modified Paths: -------------- pyplusplus_dev/pyplusplus/module_builder/builder.py Modified: pyplusplus_dev/pyplusplus/module_builder/builder.py =================================================================== --- pyplusplus_dev/pyplusplus/module_builder/builder.py 2006-09-14 05:09:55 UTC (rev 539) +++ pyplusplus_dev/pyplusplus/module_builder/builder.py 2006-09-14 05:23:14 UTC (rev 540) @@ -234,7 +234,7 @@ warnings.warn(msg, DeprecationWarning, stacklevel=2) if create_castinig_constructor: - self.global_ns.constructors().allow_implicit_conversion = True + self.global_ns.constructors(allow_empty=True).allow_implicit_conversion = True creator = mcreator_package.creator_t( self.global_ns , module_name This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <rom...@us...> - 2006-09-14 05:10:09
|
Revision: 539 http://svn.sourceforge.net/pygccxml/?rev=539&view=rev Author: roman_yakovenko Date: 2006-09-13 22:09:55 -0700 (Wed, 13 Sep 2006) Log Message: ----------- fixing "create_castinig_constructor" functionality. Py++ will do generate them by default Modified Paths: -------------- pyplusplus_dev/pyplusplus/decl_wrappers/calldef_wrapper.py pyplusplus_dev/pyplusplus/module_builder/builder.py pyplusplus_dev/unittests/casting_tester.py Modified: pyplusplus_dev/pyplusplus/decl_wrappers/calldef_wrapper.py =================================================================== --- pyplusplus_dev/pyplusplus/decl_wrappers/calldef_wrapper.py 2006-09-13 11:08:13 UTC (rev 538) +++ pyplusplus_dev/pyplusplus/decl_wrappers/calldef_wrapper.py 2006-09-14 05:09:55 UTC (rev 539) @@ -216,7 +216,7 @@ declarations.constructor_t.__init__( self, *arguments, **keywords ) calldef_t.__init__( self ) self._body = '' - self._allow_implicit_conversion = False + self._allow_implicit_conversion = True def _get_body(self): return self._body @@ -255,7 +255,7 @@ self._allow_implicit_conversion = allow_implicit_conversion allow_implicit_conversion = property( _get_allow_implicit_conversion, _set_allow_implicit_conversion , doc="boolean, indicates whether Py++ should generate implicitly_convertible code or not" \ - "Default value is calculated from the constructor type" ) + "Default value is calculated from the constructor type." ) class destructor_t( declarations.destructor_t, calldef_t ): """you may ignore this class for he time being. Modified: pyplusplus_dev/pyplusplus/module_builder/builder.py =================================================================== --- pyplusplus_dev/pyplusplus/module_builder/builder.py 2006-09-13 11:08:13 UTC (rev 538) +++ pyplusplus_dev/pyplusplus/module_builder/builder.py 2006-09-14 05:09:55 UTC (rev 539) @@ -203,7 +203,7 @@ def build_code_creator( self , module_name , boost_python_ns_name='bp' - , create_castinig_constructor=False + , create_castinig_constructor=True , call_policies_resolver_=None , types_db=None , target_configuration=None @@ -226,13 +226,14 @@ and returns documentation string @type doc_extractor: callable or None """ - if create_castinig_constructor: - msg = os.linesep.join([ + msg = os.linesep.join([ "create_castinig_constructor argument is deprecated and should not be used." , "If you still want Py++ to generate implicitly_convertible code, consider to use allow_implicit_conversion constructor property" , "mb = module_builder_t(...)" , "mb.constructors().allow_implicit_conversion = True"]) - warnings.warn(msg, DeprecationWarning, stacklevel=2) + warnings.warn(msg, DeprecationWarning, stacklevel=2) + + if create_castinig_constructor: self.global_ns.constructors().allow_implicit_conversion = True creator = mcreator_package.creator_t( self.global_ns Modified: pyplusplus_dev/unittests/casting_tester.py =================================================================== --- pyplusplus_dev/unittests/casting_tester.py 2006-09-13 11:08:13 UTC (rev 538) +++ pyplusplus_dev/unittests/casting_tester.py 2006-09-14 05:09:55 UTC (rev 539) @@ -17,9 +17,6 @@ , tester_t.EXTENSION_NAME , *args ) - def customize( self, mb ): - mb.constructors().allow_implicit_conversion = True - def run_tests( self, module): x_inst = module.x() x_inst.value = 25 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <rom...@us...> - 2006-09-13 11:08:29
|
Revision: 538 http://svn.sourceforge.net/pygccxml/?rev=538&view=rev Author: roman_yakovenko Date: 2006-09-13 04:08:13 -0700 (Wed, 13 Sep 2006) Log Message: ----------- preventing default_call_policies to be generated Modified Paths: -------------- pyplusplus_dev/pyplusplus/code_creators/array_1_registrator.py pyplusplus_dev/pyplusplus/code_creators/calldef.py pyplusplus_dev/pyplusplus/code_creators/global_variable.py pyplusplus_dev/pyplusplus/code_creators/indexing_suites.py pyplusplus_dev/pyplusplus/code_creators/member_variable.py pyplusplus_dev/pyplusplus/decl_wrappers/__init__.py pyplusplus_dev/pyplusplus/decl_wrappers/call_policies.py Modified: pyplusplus_dev/pyplusplus/code_creators/array_1_registrator.py =================================================================== --- pyplusplus_dev/pyplusplus/code_creators/array_1_registrator.py 2006-09-13 09:24:37 UTC (rev 537) +++ pyplusplus_dev/pyplusplus/code_creators/array_1_registrator.py 2006-09-13 11:08:13 UTC (rev 538) @@ -21,7 +21,7 @@ self._array_type = array_type self._call_policies = self._guess_call_policies() self.works_on_instance = False - + def _get_array_type( self ): return self._array_type def _set_array_type( self, new_array_type ): @@ -37,8 +37,8 @@ def _create_name( self ): item_type = declarations.array_item_type(self.array_type) return "__array_1_%(type)s_%(size)d" \ - % dict( type=algorithm.create_valid_name( item_type.decl_string ) - , size=declarations.array_size(self.array_type) ) + % dict( type=algorithm.create_valid_name( item_type.decl_string ) + , size=declarations.array_size(self.array_type) ) def _guess_call_policies(self): item_type = declarations.array_item_type( self.array_type ) @@ -55,8 +55,10 @@ fn_name = 'register_const_array_1' else: fn_name = 'register_array_1' - fn_def = templates.join( '::'.join( [ns_name, fn_name] ) - , [ declarations.array_item_type(self.array_type).decl_string - , str( declarations.array_size(self.array_type) ) - , self.call_policies.create(self, call_policies.CREATION_POLICY.AS_TEMPLATE_ARGUMENT )]) - return call_invocation.join( fn_def, [ '"%s"' % self._create_name() ] ) + ';' \ No newline at end of file + + fn_def_tmpl_args = [ declarations.array_item_type(self.array_type).decl_string + , str( declarations.array_size(self.array_type) ) + , self.call_policies.create(self, call_policies.CREATION_POLICY.AS_TEMPLATE_ARGUMENT )] + + fn_def = templates.join( '::'.join( [ns_name, fn_name] ), fn_def_tmpl_args ) + return call_invocation.join( fn_def, [ '"%s"' % self._create_name() ] ) + ';' Modified: pyplusplus_dev/pyplusplus/code_creators/calldef.py =================================================================== --- pyplusplus_dev/pyplusplus/code_creators/calldef.py 2006-09-13 09:24:37 UTC (rev 537) +++ pyplusplus_dev/pyplusplus/code_creators/calldef.py 2006-09-13 11:08:13 UTC (rev 538) @@ -9,7 +9,7 @@ import declaration_based import class_declaration from pygccxml import declarations -from pyplusplus.decl_wrappers import python_traits +from pyplusplus import decl_wrappers import pyplusplus.function_transformers as function_transformers #virtual functions that returns const reference to something @@ -120,8 +120,11 @@ result.append( self.keywords_args() ) if self.declaration.call_policies: - result.append( self.param_sep() ) - result.append( self.declaration.call_policies.create( self ) ) + if not self.declaration.call_policies.is_default(): + result.append( self.param_sep() ) + result.append( self.declaration.call_policies.create( self ) ) + else: + pass#don't generate default_call_policies else: result.append( os.linesep + self.indent( '/* undefined call policies */', 2 ) ) @@ -175,11 +178,11 @@ params = [] for index in range( len( self.declaration.arguments ) ): arg_type = declarations.remove_alias( self.declaration.arguments[index].type ) - if python_traits.is_immutable( arg_type ): + if decl_wrappers.python_traits.is_immutable( arg_type ): params.append( self.argument_name( index ) ) elif declarations.is_reference( arg_type ): no_ref = declarations.remove_reference( arg_type ) - if python_traits.is_immutable( no_ref ): + if decl_wrappers.python_traits.is_immutable( no_ref ): #pass by value params.append( self.argument_name( index ) ) else: @@ -187,7 +190,7 @@ params.append( 'boost::ref(%s)' % self.argument_name( index ) ) elif declarations.is_pointer( arg_type ) \ and not declarations.is_pointer( arg_type.base ) \ - and not python_traits.is_immutable( arg_type.base ): + and not decl_wrappers.python_traits.is_immutable( arg_type.base ): params.append( 'boost::python::ptr(%s)' % self.argument_name( index ) ) else: params.append( self.argument_name( index ) ) @@ -1130,11 +1133,8 @@ answer.append( ', ' ) answer.append( self.documentation ) answer.append( ')' ) - if self.declaration.call_policies: + if self.declaration.call_policies and not self.declaration.call_policies.is_default(): answer.append('[%s]' % self.declaration.call_policies.create( self ) ) - #I think it better not to print next line - #else: - # answer.append( '/*[ undefined call policies ]*/' ) return ''.join( answer ) def _create_impl( self ): @@ -1369,7 +1369,6 @@ def __init__( self, operator ): declaration_based.declaration_based_t.__init__( self, declaration=operator ) - self._call_policies = None def _create_impl(self): template = 'def( "%(function_name)s", &%(class_name)s::operator %(destination_type)s %(call_policies)s%(doc)s )' @@ -1377,9 +1376,12 @@ class_name = algorithm.create_identifier( self , declarations.full_name( self.declaration.parent ) ) - policies = '/*, undefined call policies */' + policies = '' if self.declaration.call_policies: - policies = ',' + self.declaration.call_policies.create( self ) + if not self.declaration.call_policies.is_default(): + policies = ',' + self.declaration.call_policies.create( self ) + else: + policies = '/*, undefined call policies */' doc = '' if self.documentation: @@ -1537,7 +1539,8 @@ result.append( os.linesep + self.indent( self.PARAM_SEPARATOR, 3 ) ) result.append( self.overloads_class.max_function.documentation ) result.append( ' )' ) - if self.overloads_class.max_function.call_policies: + if self.overloads_class.max_function.call_policies \ + and not self.overloads_class.max_function.call_policies.is_default(): result.append( os.linesep + self.indent('', 3) ) result.append('[ %s ]' % self.overloads_class.max_function.call_policies.create( self ) ) return ''.join( result ) Modified: pyplusplus_dev/pyplusplus/code_creators/global_variable.py =================================================================== --- pyplusplus_dev/pyplusplus/code_creators/global_variable.py 2006-09-13 09:24:37 UTC (rev 537) +++ pyplusplus_dev/pyplusplus/code_creators/global_variable.py 2006-09-13 11:08:13 UTC (rev 538) @@ -9,31 +9,30 @@ import declaration_based from pygccxml import declarations from pyplusplus import code_repository -from pyplusplus.decl_wrappers import call_policies #TODO: if variable is not const, then export it using boost::python::ptr class global_variable_base_t( declaration_based.declaration_based_t ): """ - Base class for all global variables code creators. Mainly exists to + Base class for all global variables code creators. Mainly exists to simplify file writers algorithms. """ def __init__(self, variable, wrapper=None ): declaration_based.declaration_based_t.__init__( self, declaration=variable) - self._wrapper = wrapper + self._wrapper = wrapper def _get_wrapper( self ): return self._wrapper def _set_wrapper( self, new_wrapper ): self._wrapper = new_wrapper wrapper = property( _get_wrapper, _set_wrapper ) - + class global_variable_t( global_variable_base_t ): """ Creates boost.python code that exposes global variable. """ def __init__(self, variable ): global_variable_base_t.__init__( self, variable=variable ) - + def _create_impl(self): assert isinstance( self.declaration, pygccxml.declarations.variable_t ) result = [] @@ -42,7 +41,7 @@ full_name = pygccxml.declarations.full_name( self.declaration ) result.append( ' = %s;' % algorithm.create_identifier( self, full_name ) ) return ''.join( result ) - + class array_gv_t( global_variable_base_t ): """ Creates boost.python code that exposes array global variable. @@ -51,7 +50,7 @@ _PARAM_SEPARATOR = ', ' def __init__(self, variable, wrapper ): global_variable_base_t.__init__( self, variable=variable, wrapper=wrapper ) - + def _create_impl( self ): answer = [] answer.append( algorithm.create_identifier( self, '::boost::python::scope' ) ) @@ -60,7 +59,7 @@ answer.append( self.wrapper.wrapper_creator_full_name ) answer.append( '();' ) return ''.join( answer ) - + class array_gv_wrapper_t( declaration_based.declaration_based_t ): """ Creates C++ code that register array class. @@ -75,22 +74,22 @@ class_name = 'const_array_1_t' else: class_name = 'array_1_t' - - decl_string = declarations.templates.join( + + decl_string = declarations.templates.join( '::'.join( [ns_name, class_name] ) , [ declarations.array_item_type( self.declaration.type ).decl_string , str( declarations.array_size( self.declaration.type ) ) ]) - + return declarations.dummy_type_t( decl_string ) wrapper_type = property( _get_wrapper_type ) - + def _get_wrapper_creator_type(self): return declarations.free_function_type_t.create_decl_string( return_type=self.wrapper_type , arguments_types=[] ) wrapper_creator_type = property( _get_wrapper_creator_type ) - + def _get_wrapper_creator_name(self): return '_'.join( [self.declaration.name, 'wrapper'] ) wrapper_creator_name = property( _get_wrapper_creator_name ) @@ -100,7 +99,7 @@ if len(ns_names) > 1 and ns_names[0] == '::': ns_names = ns_names[1:] return ns_names - + def _get_wrapper_creator_full_name(self): names = self._create_namespaces() names.append( self.wrapper_creator_name ) @@ -112,7 +111,7 @@ for ns_name in self._create_namespaces(): temp.append( ''.join( ['namespace ', ns_name, '{ '] ) ) return ''.join( temp ) - + def _create_impl( self ): answer = [self._create_namespaces_name()] answer.append( self.wrapper_type.decl_string ) @@ -126,4 +125,3 @@ answer.append('}') answer.append( '}' * len( self._create_namespaces() ) ) return os.linesep.join( answer ) - \ No newline at end of file Modified: pyplusplus_dev/pyplusplus/code_creators/indexing_suites.py =================================================================== --- pyplusplus_dev/pyplusplus/code_creators/indexing_suites.py 2006-09-13 09:24:37 UTC (rev 537) +++ pyplusplus_dev/pyplusplus/code_creators/indexing_suites.py 2006-09-13 11:08:13 UTC (rev 538) @@ -5,21 +5,21 @@ import os import types -import algorithm +import algorithm import code_creator import declaration_based from pygccxml import declarations class indexing_suite1_t( declaration_based.declaration_based_t ): - def __init__(self, container ): + def __init__(self, container ): declaration_based.declaration_based_t.__init__( self, declaration=container ) - + def _get_configuration( self ): return self.declaration.indexing_suite configuration = property( _get_configuration ) def _get_container( self ): - return self.declaration + return self.declaration container = property( _get_container ) def guess_suite_name( self ): @@ -40,19 +40,19 @@ args.append( self.configuration.derived_policies ) else: if 'true' == no_proxy: - args.append( no_proxy) - return declarations.templates.join( suite_identifier, args ) + args.append( no_proxy) + return declarations.templates.join( suite_identifier, args ) def _create_impl(self): return "def( %s() )" % self._create_suite_declaration() - + class indexing_suite2_t( declaration_based.declaration_based_t ): - def __init__(self, container ): + def __init__(self, container ): declaration_based.declaration_based_t.__init__( self, declaration=container ) self.__method_mask_var_name = "methods_mask" self.works_on_instance = not self.does_user_disable_methods() - + def does_user_disable_methods( self ): return bool( self.declaration.indexing_suite.disabled_methods_groups ) \ or bool( self.declaration.indexing_suite.disable_methods ) @@ -76,7 +76,7 @@ answer.append( ' ) ' ) answer.append( ';' ) return ''.join( answer ) - + def _create_impl( self ): answer = [] if self.does_user_disable_methods(): @@ -93,8 +93,9 @@ answer.append( self.PARAM_SEPARATOR ) answer.append( self.__method_mask_var_name ) answer.append( ' >' ) - if self.declaration.indexing_suite.call_policies: - answer.append( '::with_policies(%s)' + if self.declaration.indexing_suite.call_policies \ + and not self.declaration.indexing_suite.call_policies.is_default(): + answer.append( '::with_policies(%s)' % self.declaration.indexing_suite.call_policies.create( self ) ) else: answer.append( '()' ) @@ -121,7 +122,7 @@ , self.indent( "%(less)s" ) , "" , self.indent( "template<typename PythonClass, typename Policy>" ) - , self.indent( "static void visit_container_class(PythonClass &, Policy const &){" ) + , self.indent( "static void visit_container_class(PythonClass &, Policy const &){" ) , self.indent( "%(visitor_helper_body)s", 2 ) , self.indent( "}" ) , "" @@ -147,7 +148,7 @@ def generate_value_class_fwd_declaration( self ): pass # for inner class this code will generate error :-(((( - + def _create_impl( self ): return self.generate_value_traits() Modified: pyplusplus_dev/pyplusplus/code_creators/member_variable.py =================================================================== --- pyplusplus_dev/pyplusplus/code_creators/member_variable.py 2006-09-13 09:24:37 UTC (rev 537) +++ pyplusplus_dev/pyplusplus/code_creators/member_variable.py 2006-09-13 11:08:13 UTC (rev 538) @@ -13,20 +13,20 @@ class member_variable_base_t( declaration_based.declaration_based_t ): """ - Base class for all member variables code creators. Mainly exists to + Base class for all member variables code creators. Mainly exists to simplify file writers algorithms. """ def __init__(self, variable, wrapper=None ): declaration_based.declaration_based_t.__init__( self, declaration=variable) - self._wrapper = wrapper + self._wrapper = wrapper def _get_wrapper( self ): return self._wrapper def _set_wrapper( self, new_wrapper ): self._wrapper = new_wrapper wrapper = property( _get_wrapper, _set_wrapper ) - + class member_variable_t( member_variable_base_t ): """ Creates boost.python code that exposes member variable. @@ -36,7 +36,7 @@ #> On Wednesday, 19. April 2006 23:05, Ralf W. Grosse-Kunstleve wrote: #> .add_property("p", make_function(&A::get_p, return_value_policy<reference_existing_object>())) - def _generate_for_pointer( self ): + def _generate_for_pointer( self ): doc = '' #static property does not support documentation if self.declaration.type_qualifiers.has_static: add_property = 'add_static_property' @@ -48,11 +48,11 @@ answer.append( '( ' ) answer.append('"%s"' % self.alias) answer.append( self.PARAM_SEPARATOR ) - + call_pol = call_policies.return_value_policy( call_policies.reference_existing_object ).create( self ) make_function = algorithm.create_identifier( self, '::boost::python::make_function' ) - answer.append( '%(mk_func)s( (%(getter_type)s)(&%(wfname)s), %(call_pol)s )' + answer.append( '%(mk_func)s( (%(getter_type)s)(&%(wfname)s), %(call_pol)s )' % { 'mk_func' : make_function , 'getter_type' : self.wrapper.getter_type , 'wfname' : self.wrapper.getter_full_name @@ -61,11 +61,10 @@ #don't generate setter method, right now I don't know how to do it. if False and self.wrapper.has_setter: answer.append( self.PARAM_SEPARATOR ) - if self.declaration.type_qualifiers.has_static: - call_pol = call_policies.default_call_policies().create(self) - else: - call_pol = call_policies.with_custodian_and_ward_postcall( 0, 1 ).create(self) - answer.append( '%(mk_func)s( (%(setter_type)s)(&%(wfname)s), %(call_pol)s )' + call_pol = '' + if not self.declaration.type_qualifiers.has_static: + call_pol = ", " + call_policies.with_custodian_and_ward_postcall( 0, 1 ).crate(self) + answer.append( '%(mk_func)s( (%(setter_type)s)(&%(wfname)s)%(call_pol)s )' % { 'mk_func' : make_function , 'setter_type' : self.wrapper.setter_type , 'wfname' : self.wrapper.setter_full_name @@ -74,7 +73,7 @@ answer.append( self.PARAM_SEPARATOR ) answer.append( doc ) answer.append( ' ) ' ) - + code = ''.join( answer ) if len( code ) <= self.LINE_LENGTH: return code @@ -82,27 +81,27 @@ for i in range( len( answer ) ): if answer[i] == self.PARAM_SEPARATOR: answer[i] = os.linesep + self.indent( self.indent( self.indent( answer[i] ) ) ) - return ''.join( answer ) - + return ''.join( answer ) + def _generate_for_none_pointer( self ): tmpl = None if self.declaration.type_qualifiers.has_static: - tmpl = '%(access)s( "%(alias)s", %(name)s%(doc)s )' + tmpl = '%(access)s( "%(alias)s", %(name)s%(doc)s )' else: tmpl = '%(access)s( "%(alias)s", &%(name)s%(doc)s )' - + access = 'def_readwrite' if self.is_read_only(): access = 'def_readonly' doc = '' if self.documentation: - doc = ', %s' % self.documentation - result = tmpl % { + doc = ', %s' % self.documentation + result = tmpl % { 'access' : access , 'alias' : self.alias , 'name' : algorithm.create_identifier( self, self.declaration.decl_string ) , 'doc' : doc } - + return result def is_read_only( self ): @@ -110,13 +109,13 @@ if declarations.is_pointer( type_ ): type_ = declarations.remove_pointer( type_ ) return isinstance( type_, declarations.const_t ) - + if declarations.is_reference( type_ ): - type_ = declarations.remove_reference( type_ ) + type_ = declarations.remove_reference( type_ ) if isinstance( type_, declarations.const_t ): return True - + if isinstance( type_, declarations.declarated_t ) \ and isinstance( type_.declaration, declarations.class_t ) \ and not declarations.has_public_assign( type_.declaration ): @@ -142,29 +141,29 @@ MV_GET_TEMPLATE = os.linesep.join([ 'static %(type)s get_%(name)s(%(cls_type)s inst ){' , indent( 'return inst.%(name)s;' ) - , '}' + , '}' , '' ]) MV_STATIC_GET_TEMPLATE = os.linesep.join([ 'static %(type)s get_%(name)s(){' , indent( 'return %(cls_type)s::%(name)s;' ) - , '}' + , '}' , '' ]) MV_SET_TEMPLATE = os.linesep.join([ 'static void set_%(name)s( %(cls_type)s inst, %(type)s new_value ){ ' , indent( 'inst.%(name)s = new_value;' ) - , '}' - , '' + , '}' + , '' ]) MV_STATIC_SET_TEMPLATE = os.linesep.join([ 'static void set_%(name)s( %(type)s new_value ){ ' , indent( '%(cls_type)s::%(name)s = new_value;' ) - , '}' - , '' + , '}' + , '' ]) def __init__(self, variable ): @@ -180,28 +179,28 @@ inst_arg_type = declarations.const_t(inst_arg_type) inst_arg_type = declarations.reference_t(inst_arg_type) return inst_arg_type - + def _get_getter_type(self): if self.declaration.type_qualifiers.has_static: - arguments_types=[] + arguments_types=[] else: - arguments_types=[ self.inst_arg_type(True) ] - + arguments_types=[ self.inst_arg_type(True) ] + return declarations.free_function_type_t.create_decl_string( return_type=self.declaration.type , arguments_types=arguments_types ) getter_type = property( _get_getter_type ) - + def _get_setter_full_name(self): return self.parent.full_name + '::' + 'set_' + self.declaration.name setter_full_name = property(_get_setter_full_name) - + def _get_setter_type(self): if self.declaration.type_qualifiers.has_static: - arguments_types=[ self.declaration.type ] + arguments_types=[ self.declaration.type ] else: - arguments_types=[ self.inst_arg_type(False), self.declaration.type ] - + arguments_types=[ self.inst_arg_type(False), self.declaration.type ] + return declarations.free_function_type_t.create_decl_string( return_type=declarations.void_t() , arguments_types=arguments_types ) @@ -210,14 +209,14 @@ def _get_has_setter( self ): return not declarations.is_const( self.declaration.type ) has_setter = property( _get_has_setter ) - + def _create_impl(self): answer = [] if self.declaration.type_qualifiers.has_static: substitutions = { 'type' : self.declaration.type.decl_string , 'name' : self.declaration.name - , 'cls_type' : declarations.full_name( self.declaration.parent ) + , 'cls_type' : declarations.full_name( self.declaration.parent ) } answer.append( self.MV_STATIC_GET_TEMPLATE % substitutions) if self.has_setter: @@ -253,18 +252,18 @@ answer.append( '( ' ) answer.append('"%s"' % self.alias) answer.append( self.PARAM_SEPARATOR ) - answer.append( '(%s)(&%s)' + answer.append( '(%s)(&%s)' % ( self.wrapper.getter_type, self.wrapper.getter_full_name ) ) if self.wrapper.has_setter: answer.append( self.PARAM_SEPARATOR ) - answer.append( '(%s)(&%s)' + answer.append( '(%s)(&%s)' % ( self.wrapper.setter_type, self.wrapper.setter_full_name ) ) if doc: answer.append( self.PARAM_SEPARATOR ) answer.append( doc ) answer.append( ' ) ' ) - + code = ''.join( answer ) if len( code ) <= self.LINE_LENGTH: return code @@ -283,15 +282,15 @@ BF_GET_TEMPLATE = os.linesep.join([ '%(type)s get_%(name)s() const {' , indent( 'return %(name)s;' ) - , '}' + , '}' , '' ]) - + BF_SET_TEMPLATE = os.linesep.join([ 'void set_%(name)s( %(type)s new_value ){ ' , indent( '%(name)s = new_value;' ) - , '}' - , '' + , '}' + , '' ]) def __init__(self, variable ): @@ -300,7 +299,7 @@ def _get_getter_full_name(self): return self.parent.full_name + '::' + 'get_' + self.declaration.name getter_full_name = property( _get_getter_full_name ) - + def _get_getter_type(self): return declarations.member_function_type_t.create_decl_string( return_type=self.declaration.type @@ -308,11 +307,11 @@ , arguments_types=[] , has_const=True ) getter_type = property( _get_getter_type ) - + def _get_setter_full_name(self): return self.parent.full_name + '::' + 'set_' + self.declaration.name setter_full_name = property(_get_setter_full_name) - + def _get_setter_type(self): return declarations.member_function_type_t.create_decl_string( return_type=declarations.void_t() @@ -324,11 +323,11 @@ def _get_has_setter( self ): return not declarations.is_const( self.declaration.type ) has_setter = property( _get_has_setter ) - + def _create_impl(self): answer = [] substitutions = dict( type=self.declaration.type.decl_string - , name=self.declaration.name ) + , name=self.declaration.name ) answer.append( self.BF_GET_TEMPLATE % substitutions ) if self.has_setter: answer.append( self.BF_SET_TEMPLATE % substitutions ) @@ -340,7 +339,7 @@ """ def __init__(self, variable, wrapper ): member_variable_base_t.__init__( self, variable=variable, wrapper=wrapper ) - + def _create_impl( self ): assert isinstance( self.wrapper, array_mv_wrapper_t ) doc = '' @@ -355,7 +354,7 @@ answer.append( os.linesep + self.indent( self.PARAM_SEPARATOR ) ) temp = [ algorithm.create_identifier( self, "::boost::python::make_function" ) ] temp.append( '( ' ) - temp.append( '(%s)(&%s)' + temp.append( '(%s)(&%s)' % ( self.wrapper.wrapper_creator_type , self.wrapper.wrapper_creator_full_name ) ) if not self.declaration.type_qualifiers.has_static: @@ -366,16 +365,16 @@ if doc: answer.append( self.PARAM_SEPARATOR ) answer.append( doc ) - answer.append( ' );' ) + answer.append( ' );' ) return ''.join( answer ) - + #TODO: generated fucntion should be static and take instance of the wrapped class #as first argument. class array_mv_wrapper_t( declaration_based.declaration_based_t ): """ Creates C++ code that register array class. """ - + def __init__(self, variable ): declaration_based.declaration_based_t.__init__( self, declaration=variable) @@ -385,16 +384,16 @@ class_name = 'const_array_1_t' else: class_name = 'array_1_t' - - decl_string = declarations.templates.join( + + decl_string = declarations.templates.join( '::'.join( [ns_name, class_name] ) , [ declarations.array_item_type( self.declaration.type ).decl_string , str( declarations.array_size( self.declaration.type ) ) ]) - + return declarations.dummy_type_t( decl_string ) wrapper_type = property( _get_wrapper_type ) - + def _get_wrapper_creator_type(self): return declarations.member_function_type_t.create_decl_string( return_type=self.wrapper_type @@ -402,7 +401,7 @@ , arguments_types=[] , has_const=False ) wrapper_creator_type = property( _get_wrapper_creator_type ) - + def _get_wrapper_creator_name(self): return '_'.join( ['pyplusplus', self.declaration.name, 'wrapper'] ) wrapper_creator_name = property( _get_wrapper_creator_name ) @@ -417,13 +416,13 @@ temp = ''.join([ 'return ' , self.wrapper_type.decl_string , '( ' - , self.declaration.name + , self.declaration.name , ' );']) answer.append( self.indent( temp ) ) answer.append('}') return os.linesep.join( answer ) - + class mem_var_ref_t( member_variable_base_t ): """ Creates C++ code that creates accessor for class member variable, that has type reference. @@ -438,34 +437,36 @@ answer.append( '( ' ) answer.append( '"get_%s"' % self.alias) answer.append( self.param_sep ) - answer.append( '(%s)(&%s)' + answer.append( '(%s)(&%s)' % ( self.wrapper.getter_type.decl_string, self.wrapper.getter_full_name ) ) if self.declaration.getter_call_policies: - answer.append( self.param_sep ) - answer.append( self.declaration.getter_call_policies.create( self ) ) + if not self.declaration.getter_call_policies.is_default(): + answer.append( self.param_sep ) + answer.append( self.declaration.getter_call_policies.create( self ) ) else: - answer.append( os.linesep + self.indent( '/* undefined call policies */', 2 ) ) + answer.append( os.linesep + self.indent( '/* undefined call policies */', 2 ) ) if self.documentation: answer.append( self.param_sep ) answer.append( self.documentation ) answer.append( ' )' ) return ''.join( answer ) - + def _create_setter( self ): answer = ['def'] answer.append( '( ' ) answer.append( '"set_%s"' % self.alias) answer.append( self.param_sep ) - answer.append( '(%s)(&%s)' + answer.append( '(%s)(&%s)' % ( self.wrapper.setter_type.decl_string, self.wrapper.setter_full_name ) ) if self.declaration.setter_call_policies: - answer.append( self.param_sep ) - answer.append( self.declaration.setter_call_policies.create( self ) ) + if not self.declaration.setter_call_policies.is_default(): + answer.append( self.param_sep ) + answer.append( self.declaration.setter_call_policies.create( self ) ) else: - answer.append( os.linesep + self.indent( '/* undefined call policies */', 2 ) ) + answer.append( os.linesep + self.indent( '/* undefined call policies */', 2 ) ) answer.append( ' )' ) return ''.join( answer ) - + def _create_impl( self ): #TODO: fix me, should not force class scope usage answer = [] @@ -475,25 +476,25 @@ answer.append( os.linesep ) answer.append( "%s.%s;" % (class_var_name, self._create_setter() ) ) return ''.join( answer ) - + class mem_var_ref_wrapper_t( declaration_based.declaration_based_t ): """ Creates C++ code that creates accessor for class member variable, that has type reference. """ - + indent = declaration_based.declaration_based_t.indent GET_TEMPLATE = os.linesep.join([ 'static %(type)s get_%(name)s( %(class_type)s& inst ) {' , indent( 'return inst.%(name)s;' ) - , '}' + , '}' , '' ]) - + SET_TEMPLATE = os.linesep.join([ 'static void set_%(name)s( %(class_type)s& inst, %(type)s new_value ){ ' , indent( 'inst.%(name)s = new_value;' ) - , '}' - , '' + , '}' + , '' ]) def __init__(self, variable ): @@ -519,11 +520,11 @@ return_type=self._get_exported_var_type() , arguments_types=[ declarations.reference_t( self._get_class_inst_type() ) ] ) getter_type = property( _get_getter_type ) - + def _get_setter_full_name(self): return self.parent.full_name + '::' + 'set_' + self.declaration.name setter_full_name = property(_get_setter_full_name) - + def _get_setter_type(self): return declarations.free_function_type_t( return_type=declarations.void_t() @@ -531,37 +532,37 @@ , self._get_exported_var_type() ] ) setter_type = property( _get_setter_type ) - def _get_has_setter( self ): + def _get_has_setter( self ): if declarations.is_const( declarations.remove_reference( self.declaration.type ) ): return False elif python_traits.is_immutable( self._get_exported_var_type() ): return True else: pass - + no_ref = declarations.remove_reference( self.declaration.type ) - no_const = declarations.remove_const( no_ref ) + no_const = declarations.remove_const( no_ref ) base_type = declarations.remove_alias( no_const ) if not isinstance( base_type, declarations.declarated_t ): return True #TODO ???? decl = base_type.declaration if decl.is_abstract: return False - if declarations.has_destructor( decl ) and not declarations.has_public_destructor( decl ): + if declarations.has_destructor( decl ) and not declarations.has_public_destructor( decl ): return False if not declarations.has_trivial_copy(decl): return False return True has_setter = property( _get_has_setter ) - + def _create_impl(self): answer = [] cls_type = algorithm.create_identifier( self, self.declaration.parent.decl_string ) - + substitutions = dict( type=self._get_exported_var_type().decl_string , class_type=cls_type - , name=self.declaration.name ) + , name=self.declaration.name ) answer.append( self.GET_TEMPLATE % substitutions ) if self.has_setter: answer.append( self.SET_TEMPLATE % substitutions ) - return os.linesep.join( answer ) \ No newline at end of file + return os.linesep.join( answer ) Modified: pyplusplus_dev/pyplusplus/decl_wrappers/__init__.py =================================================================== --- pyplusplus_dev/pyplusplus/decl_wrappers/__init__.py 2006-09-13 09:24:37 UTC (rev 537) +++ pyplusplus_dev/pyplusplus/decl_wrappers/__init__.py 2006-09-13 11:08:13 UTC (rev 538) @@ -60,6 +60,7 @@ from pygccxml import declarations from call_policies import call_policy_t +from call_policies import default_call_policies_t from call_policies import default_call_policies from call_policies import compound_policy_t from call_policies import return_argument_t Modified: pyplusplus_dev/pyplusplus/decl_wrappers/call_policies.py =================================================================== --- pyplusplus_dev/pyplusplus/decl_wrappers/call_policies.py 2006-09-13 09:24:37 UTC (rev 537) +++ pyplusplus_dev/pyplusplus/decl_wrappers/call_policies.py 2006-09-13 11:08:13 UTC (rev 538) @@ -5,9 +5,9 @@ """ This modules contains definition of call policies classes. Call policies names -are same, that used in boost.python library. +are same, that used in boost.python library. -For every class that implements code creation of call policies, there is a +For every class that implements code creation of call policies, there is a convinience function. """ @@ -34,27 +34,35 @@ @type creation_policy: L{CREATION_POLICY} """ code = self._create_impl( function_creator ) - if creation_policy == CREATION_POLICY.AS_INSTANCE: + if code and creation_policy == CREATION_POLICY.AS_INSTANCE: code = code + '()' return code + def is_default( self ): + """Returns True is self is instance of L{default_call_policies_t} class""" + #Small hack that allows to write nicer code + return False + def _create_impl( self, function_creator ): raise NotImplementedError() - -class default_t(call_policy_t): + +class default_call_policies_t(call_policy_t): """implementation for ::boost::python::default_call_policies""" def __init__( self ): call_policy_t.__init__( self ) - + def _create_impl(self, function_creator ): return algorithm.create_identifier( function_creator, '::boost::python::default_call_policies' ) - + + def is_default( self ): + return True + def __str__(self): return 'default_call_policies' - + def default_call_policies(): """create ::boost::python::default_call_policies""" - return default_t() + return default_call_policies_t() class compound_policy_t( call_policy_t ): """base class for all call policies, except default one""" @@ -62,24 +70,26 @@ call_policy_t.__init__( self ) self._base = base if not base: - self._base = default_t() - + self._base = default_call_policies_t() + def _get_base_policy( self ): - return self._base + return self._base def _set_base_policy( self, new_policy ): self._base = new_policy base_policy = property( _get_base_policy, _set_base_policy - , doc="base call policy, by default is reference to L{default_t} call policy") + , doc="base call policy, by default is reference to L{default_call_policies_t} call policy") def _get_args(self, function_creator): return [] def _get_name(self, function_creator): raise NotImplementedError() - + def _create_impl( self, function_creator ): args = self._get_args(function_creator) - args.append( self._base.create( function_creator, CREATION_POLICY.AS_TEMPLATE_ARGUMENT ) ) + base_policy_code = self._base.create( function_creator, CREATION_POLICY.AS_TEMPLATE_ARGUMENT ) + if base_policy_code: + args.append( base_policy_code ) name = algorithm.create_identifier( function_creator, self._get_name(function_creator) ) return declarations.templates.join( name, args ) @@ -88,13 +98,13 @@ args = map( lambda text: text.replace( '::boost::python::', '' ) , self._get_args( None ) ) return declarations.templates.join( name, args ) - + class return_argument_t( compound_policy_t ): """implementation for ::boost::python::return_argument call policies""" def __init__( self, position=1, base=None): compound_policy_t.__init__( self, base ) self._position = position - + def _get_position( self ): return self._position def _set_position( self, new_position): @@ -106,7 +116,7 @@ return '::boost::python::return_self' else: return '::boost::python::return_arg' - + def _get_args(self, function_creator): if self.position == 1: return [] @@ -123,7 +133,7 @@ def __init__( self, position=1, base=None): compound_policy_t.__init__( self, base ) self._position = position - + def _get_position( self ): return self._position def _set_position( self, new_position): @@ -132,34 +142,34 @@ def _get_name(self, function_creator): return '::boost::python::return_internal_reference' - + def _get_args(self, function_creator): return [ str( self.position ) ] def return_internal_reference( arg_pos=1, base=None): return return_internal_reference_t( arg_pos, base ) - + class with_custodian_and_ward_t( compound_policy_t ): def __init__( self, custodian, ward, base=None): compound_policy_t.__init__( self, base ) self._custodian = custodian self._ward = ward - + def _get_custodian( self ): return self._custodian def _set_custodian( self, new_custodian): self._custodian = new_custodian custodian = property( _get_custodian, _set_custodian ) - + def _get_ward( self ): return self._ward def _set_ward( self, new_ward): self._ward = new_ward ward = property( _get_ward, _set_ward ) - + def _get_name(self, function_creator): return '::boost::python::with_custodian_and_ward' - + def _get_args(self, function_creator): return [ str( self.custodian ), str( self.ward ) ] @@ -172,7 +182,7 @@ def _get_name(self, function_creator): return '::boost::python::with_custodian_and_ward_postcall' - + def with_custodian_and_ward_postcall( custodian, ward, base=None): return with_custodian_and_ward_postcall_t( custodian, ward, base ) @@ -180,7 +190,7 @@ def __init__( self, result_converter_generator, base=None): compound_policy_t.__init__( self, base ) self._result_converter_generator = result_converter_generator - + def _get_result_converter_generator( self ): return self._result_converter_generator def _set_result_converter_generator( self, new_result_converter_generator): @@ -190,7 +200,7 @@ def _get_name(self, function_creator): return '::boost::python::return_value_policy' - + def _get_args(self, function_creator): if function_creator: rcg = algorithm.create_identifier( function_creator, self.result_converter_generator ) @@ -206,4 +216,4 @@ return_opaque_pointer = '::boost::python::return_opaque_pointer' def return_value_policy( result_converter_generator, base=None): - return return_value_policy_t( result_converter_generator, base ) \ No newline at end of file + return return_value_policy_t( result_converter_generator, base ) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <rom...@us...> - 2006-09-13 09:24:50
|
Revision: 537 http://svn.sourceforge.net/pygccxml/?rev=537&view=rev Author: roman_yakovenko Date: 2006-09-13 02:24:37 -0700 (Wed, 13 Sep 2006) Log Message: ----------- fixing "create_castinig_constructor" functionality. As it was suggested by David Abrahams, by default they will be not generated. Previous behavior is preserved. Modified Paths: -------------- pyplusplus_dev/pyplusplus/decl_wrappers/calldef_wrapper.py pyplusplus_dev/pyplusplus/module_builder/builder.py pyplusplus_dev/pyplusplus/module_creator/creator.py pyplusplus_dev/unittests/casting_tester.py Modified: pyplusplus_dev/pyplusplus/decl_wrappers/calldef_wrapper.py =================================================================== --- pyplusplus_dev/pyplusplus/decl_wrappers/calldef_wrapper.py 2006-09-13 07:32:06 UTC (rev 536) +++ pyplusplus_dev/pyplusplus/decl_wrappers/calldef_wrapper.py 2006-09-13 09:24:37 UTC (rev 537) @@ -216,6 +216,7 @@ declarations.constructor_t.__init__( self, *arguments, **keywords ) calldef_t.__init__( self ) self._body = '' + self._allow_implicit_conversion = False def _get_body(self): return self._body @@ -229,6 +230,33 @@ return 'Py++ does not exports compiler generated constructors' return '' + def does_define_implicit_conversion( self ): + """ returns true if the constructor can take part in implicit conversions. + + For more information see: + + * http://boost.org/libs/python/doc/v2/implicit.html#implicitly_convertible-spec + + * http://msdn2.microsoft.com/en-us/library/h1y7x448.aspx + """ + if self.parent.is_abstract: #user is not able to create an instance of the class + return False + if self.is_copy_constructor: + return False + if 1 != len( self.arguments ): + return False + if self.parent.find_out_member_access_type( self ) != declarations.ACCESS_TYPES.PUBLIC: + return False + return True + + def _get_allow_implicit_conversion(self): + return self._allow_implicit_conversion and self.does_define_implicit_conversion() + def _set_allow_implicit_conversion(self, allow_implicit_conversion): + self._allow_implicit_conversion = allow_implicit_conversion + allow_implicit_conversion = property( _get_allow_implicit_conversion, _set_allow_implicit_conversion + , doc="boolean, indicates whether Py++ should generate implicitly_convertible code or not" \ + "Default value is calculated from the constructor type" ) + class destructor_t( declarations.destructor_t, calldef_t ): """you may ignore this class for he time being. Modified: pyplusplus_dev/pyplusplus/module_builder/builder.py =================================================================== --- pyplusplus_dev/pyplusplus/module_builder/builder.py 2006-09-13 07:32:06 UTC (rev 536) +++ pyplusplus_dev/pyplusplus/module_builder/builder.py 2006-09-13 09:24:37 UTC (rev 537) @@ -7,6 +7,8 @@ import sys import time +import warnings + from pygccxml import parser from pygccxml import declarations as decls_package @@ -201,7 +203,7 @@ def build_code_creator( self , module_name , boost_python_ns_name='bp' - , create_castinig_constructor=True + , create_castinig_constructor=False , call_policies_resolver_=None , types_db=None , target_configuration=None @@ -224,10 +226,18 @@ and returns documentation string @type doc_extractor: callable or None """ + if create_castinig_constructor: + msg = os.linesep.join([ + "create_castinig_constructor argument is deprecated and should not be used." + , "If you still want Py++ to generate implicitly_convertible code, consider to use allow_implicit_conversion constructor property" + , "mb = module_builder_t(...)" + , "mb.constructors().allow_implicit_conversion = True"]) + warnings.warn(msg, DeprecationWarning, stacklevel=2) + self.global_ns.constructors().allow_implicit_conversion = True + creator = mcreator_package.creator_t( self.global_ns , module_name , boost_python_ns_name - , create_castinig_constructor , call_policies_resolver_ , types_db , target_configuration Modified: pyplusplus_dev/pyplusplus/module_creator/creator.py =================================================================== --- pyplusplus_dev/pyplusplus/module_creator/creator.py 2006-09-13 07:32:06 UTC (rev 536) +++ pyplusplus_dev/pyplusplus/module_creator/creator.py 2006-09-13 09:24:37 UTC (rev 537) @@ -64,7 +64,6 @@ , decls , module_name , boost_python_ns_name='bp' - , create_castinig_constructor=False , call_policies_resolver_=None , types_db=None , target_configuration=None @@ -75,7 +74,6 @@ @param decls: Declarations that should be exposed in the final module. @param module_name: The name of the final module. @param boost_python_ns_name: The alias for the boost::python namespace. - @param create_castinig_constructor: ...todo... @param call_policies_resolver_: Callable that takes one declaration (calldef_t) as input and returns a call policy object which should be used for this declaration. @param types_db: ...todo... @param target_configuration: A target configuration object can be used to customize the generated source code to a particular compiler or a particular version of Boost.Python. @@ -83,7 +81,6 @@ @type decls: list of declaration_t @type module_name: str @type boost_python_ns_name: str - @type create_castinig_constructor: bool @type call_policies_resolver_: callable @type types_db: L{types_database_t<types_database.types_database_t>} @type target_configuration: L{target_configuration_t<code_creators.target_configuration_t>} @@ -110,7 +107,6 @@ self.__extmodule = code_creators.module_t() self.__extmodule.add_system_header( "boost/python.hpp" ) self.__extmodule.adopt_creator( code_creators.include_t( header="boost/python.hpp" ) ) - self.__create_castinig_constructor = create_castinig_constructor if boost_python_ns_name: bp_ns_alias = code_creators.namespace_alias_t( alias=boost_python_ns_name , full_namespace_name='::boost::python' ) @@ -251,10 +247,6 @@ def _does_class_have_smth_to_export(self, exportable_members ): return bool( self._filter_decls( exportable_members ) ) - def _is_constructor_of_abstract_class( self, decl ): - assert isinstance( decl, declarations.constructor_t ) - return decl.parent.is_abstract - def _filter_decls( self, decls ): # Filter out artificial (compiler created) types unless they are classes # See: http://public.kitware.com/pipermail/gccxml/2004-October/000486.html @@ -604,10 +596,7 @@ if self.curr_decl.is_copy_constructor: return self.__types_db.update( self.curr_decl ) - if not self._is_constructor_of_abstract_class( self.curr_decl ) \ - and 1 == len( self.curr_decl.arguments ) \ - and self.__create_castinig_constructor \ - and self.curr_decl.access_type == ACCESS_TYPES.PUBLIC: + if self.curr_decl.allow_implicit_conversion: maker = code_creators.casting_constructor_t( constructor=self.curr_decl ) self.__module_body.adopt_creator( maker ) Modified: pyplusplus_dev/unittests/casting_tester.py =================================================================== --- pyplusplus_dev/unittests/casting_tester.py 2006-09-13 07:32:06 UTC (rev 536) +++ pyplusplus_dev/unittests/casting_tester.py 2006-09-13 09:24:37 UTC (rev 537) @@ -10,13 +10,16 @@ class tester_t(fundamental_tester_base.fundamental_tester_base_t): EXTENSION_NAME = 'casting' - + def __init__( self, *args ): - fundamental_tester_base.fundamental_tester_base_t.__init__( + fundamental_tester_base.fundamental_tester_base_t.__init__( self , tester_t.EXTENSION_NAME , *args ) - + + def customize( self, mb ): + mb.constructors().allow_implicit_conversion = True + def run_tests( self, module): x_inst = module.x() x_inst.value = 25 @@ -26,7 +29,7 @@ self.failUnless( 0 == module.x_value(False) ) def create_suite(): - suite = unittest.TestSuite() + suite = unittest.TestSuite() suite.addTest( unittest.makeSuite(tester_t)) return suite @@ -34,4 +37,4 @@ unittest.TextTestRunner(verbosity=2).run( create_suite() ) if __name__ == "__main__": - run_suite() \ No newline at end of file + run_suite() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <rom...@us...> - 2006-09-13 07:32:32
|
Revision: 536 http://svn.sourceforge.net/pygccxml/?rev=536&view=rev Author: roman_yakovenko Date: 2006-09-13 00:32:06 -0700 (Wed, 13 Sep 2006) Log Message: ----------- fixing "immutable" bug argument that have immutable type, should not be passed by value and not by reference Modified Paths: -------------- pyplusplus_dev/pyplusplus/code_creators/array_1_registrator.py pyplusplus_dev/pyplusplus/code_creators/calldef.py pyplusplus_dev/pyplusplus/code_creators/member_variable.py pyplusplus_dev/pyplusplus/decl_wrappers/__init__.py pyplusplus_dev/pyplusplus/decl_wrappers/indexing_suite1.py pyplusplus_dev/pyplusplus/decl_wrappers/variable_wrapper.py pyplusplus_dev/pyplusplus/module_creator/call_policies_resolver.py pyplusplus_dev/unittests/data/member_functions_to_be_exported.hpp pyplusplus_dev/unittests/member_functions_tester.py Added Paths: ----------- pyplusplus_dev/pyplusplus/decl_wrappers/python_traits.py Modified: pyplusplus_dev/pyplusplus/code_creators/array_1_registrator.py =================================================================== --- pyplusplus_dev/pyplusplus/code_creators/array_1_registrator.py 2006-09-11 19:25:08 UTC (rev 535) +++ pyplusplus_dev/pyplusplus/code_creators/array_1_registrator.py 2006-09-13 07:32:06 UTC (rev 536) @@ -9,6 +9,7 @@ import code_creator from pyplusplus import code_repository from pyplusplus.decl_wrappers import call_policies +from pyplusplus.decl_wrappers import python_traits from pygccxml import declarations class array_1_registrator_t( code_creator.code_creator_t ): @@ -41,7 +42,7 @@ def _guess_call_policies(self): item_type = declarations.array_item_type( self.array_type ) - if declarations.is_fundamental( item_type ) or declarations.is_enum( item_type ): + if python_traits.is_immutable( item_type ): return call_policies.default_call_policies() else: return call_policies.return_internal_reference() Modified: pyplusplus_dev/pyplusplus/code_creators/calldef.py =================================================================== --- pyplusplus_dev/pyplusplus/code_creators/calldef.py 2006-09-11 19:25:08 UTC (rev 535) +++ pyplusplus_dev/pyplusplus/code_creators/calldef.py 2006-09-13 07:32:06 UTC (rev 536) @@ -9,6 +9,7 @@ import declaration_based import class_declaration from pygccxml import declarations +from pyplusplus.decl_wrappers import python_traits import pyplusplus.function_transformers as function_transformers #virtual functions that returns const reference to something @@ -174,17 +175,19 @@ params = [] for index in range( len( self.declaration.arguments ) ): arg_type = declarations.remove_alias( self.declaration.arguments[index].type ) - arg_base_type = declarations.base_type( arg_type ) - if declarations.is_fundamental( arg_base_type ): + if python_traits.is_immutable( arg_type ): params.append( self.argument_name( index ) ) - elif declarations.is_reference( arg_type ) \ - and not declarations.is_const( arg_type ) \ - and not declarations.is_enum( arg_base_type ): - params.append( 'boost::ref(%s)' % self.argument_name( index ) ) + elif declarations.is_reference( arg_type ): + no_ref = declarations.remove_reference( arg_type ) + if python_traits.is_immutable( no_ref ): + #pass by value + params.append( self.argument_name( index ) ) + else: + #pass by ref + params.append( 'boost::ref(%s)' % self.argument_name( index ) ) elif declarations.is_pointer( arg_type ) \ and not declarations.is_pointer( arg_type.base ) \ - and not declarations.is_fundamental( arg_type.base ) \ - and not declarations.is_enum( arg_base_type ): + and not python_traits.is_immutable( arg_type.base ): params.append( 'boost::python::ptr(%s)' % self.argument_name( index ) ) else: params.append( self.argument_name( index ) ) @@ -443,7 +446,7 @@ class mem_fun_v_transformed_t( calldef_t ): """Creates code for (public) virtual member functions. """ - + def __init__( self, function, wrapper=None ): calldef_t.__init__( self, function=function, wrapper=wrapper ) self.default_function_type_alias = 'default_' + self.function_type_alias @@ -504,7 +507,7 @@ @type function: calldef_t """ calldef_wrapper_t.__init__( self, function=function ) - + # Stores the name of the variable that holds the override self._override_var = None @@ -593,11 +596,11 @@ if( %(override_var)s ) { $PRE_CALL - + ${RESULT_VAR_ASSIGNMENT}boost::python::call<$RESULT_TYPE>($INPUT_PARAMS); - + $POST_CALL - + $RETURN_STMT } else @@ -636,7 +639,7 @@ cls_wrapper = self._subst_manager.wrapper_func.declare_local("cls_wrapper", cls_wrapper_type); # The name of the 'self' variable (i.e. first argument) selfname = self._subst_manager.wrapper_func.arg_list[0].name - + body = """$DECLARATIONS $PRE_CALL @@ -668,7 +671,7 @@ "cls_wrapper" : cls_wrapper, "self" : selfname, "base_name" : self.base_name() } - + # function_call = declarations.call_invocation.join( self.declaration.name # , [ self.function_call_args() ] ) # body = self.wrapped_class_identifier() + '::' + function_call + ';' @@ -693,20 +696,20 @@ header = 'static $RET_TYPE %s( $ARG_LIST_DEF ) {'%self.default_name() header = self._subst_manager.subst_wrapper(header) - + answer = [ header ] answer.append( self.indent( self.create_default_body() ) ) answer.append( '}' ) return os.linesep.join( answer ) - + def _create_impl(self): # Create the substitution manager decl = self.declaration sm = function_transformers.substitution_manager_t(decl, transformers=decl.function_transformers) self._override_var = sm.virtual_func.declare_local(decl.alias+"_callable", "boost::python::override", default='this->get_override( "%s" )'%decl.alias) self._subst_manager = sm - + answer = [ self.create_function() ] answer.append( os.linesep ) answer.append( self.create_base_function() ) Modified: pyplusplus_dev/pyplusplus/code_creators/member_variable.py =================================================================== --- pyplusplus_dev/pyplusplus/code_creators/member_variable.py 2006-09-11 19:25:08 UTC (rev 535) +++ pyplusplus_dev/pyplusplus/code_creators/member_variable.py 2006-09-13 07:32:06 UTC (rev 536) @@ -8,6 +8,7 @@ import declaration_based from pyplusplus import code_repository from pyplusplus.decl_wrappers import call_policies +from pyplusplus.decl_wrappers import python_traits from pygccxml import declarations class member_variable_base_t( declaration_based.declaration_based_t ): @@ -508,7 +509,7 @@ def _get_exported_var_type( self ): type_ = declarations.remove_reference( self.declaration.type ) type_ = declarations.remove_const( type_ ) - if declarations.is_fundamental( type_ ) or declarations.is_enum( type_ ): + if python_traits.is_immutable( type_ ): return type_ else: return self.declaration.type @@ -533,10 +534,8 @@ def _get_has_setter( self ): if declarations.is_const( declarations.remove_reference( self.declaration.type ) ): return False - elif declarations.is_fundamental( self._get_exported_var_type() ): + elif python_traits.is_immutable( self._get_exported_var_type() ): return True - elif declarations.is_enum( self._get_exported_var_type() ): - return True else: pass Modified: pyplusplus_dev/pyplusplus/decl_wrappers/__init__.py =================================================================== --- pyplusplus_dev/pyplusplus/decl_wrappers/__init__.py 2006-09-11 19:25:08 UTC (rev 535) +++ pyplusplus_dev/pyplusplus/decl_wrappers/__init__.py 2006-09-13 07:32:06 UTC (rev 536) @@ -91,6 +91,8 @@ from doc_extractor import doc_extractor_i +import python_traits + class dwfactory_t( declarations.decl_factory_t ): """ declarations factory class Modified: pyplusplus_dev/pyplusplus/decl_wrappers/indexing_suite1.py =================================================================== --- pyplusplus_dev/pyplusplus/decl_wrappers/indexing_suite1.py 2006-09-11 19:25:08 UTC (rev 535) +++ pyplusplus_dev/pyplusplus/decl_wrappers/indexing_suite1.py 2006-09-13 07:32:06 UTC (rev 536) @@ -6,17 +6,11 @@ """defines interface for exposing STD containers, using current version of indexing suite""" from pygccxml import declarations - +import python_traits #NoProxy #By default indexed elements have Python reference semantics and are returned by #proxy. This can be disabled by supplying true in the NoProxy template parameter. -#When we want to disable is: -#1. We deal with immutable objects: -# 1. fundamental types -# 2. enum type -# 3. std::[w]string -# 4. std::complex -# 5. shared_ptr +#We want to disable NoProxy when we deal with immutable objects. class indexing_suite1_t( object ): """ @@ -43,15 +37,7 @@ def _get_no_proxy( self ): if self.__no_proxy is None: - element_type = self.element_type - if declarations.is_fundamental( element_type ) \ - or declarations.is_enum( element_type ) \ - or declarations.is_std_string( element_type ) \ - or declarations.is_std_wstring( element_type ) \ - or declarations.smart_pointer_traits.is_smart_pointer( element_type ): - self.__no_proxy = True - else: - self.__no_proxy = False + self.__no_proxy = python_traits.is_immutable( self.element_type ) return self.__no_proxy def _set_no_proxy( self, no_proxy ): Added: pyplusplus_dev/pyplusplus/decl_wrappers/python_traits.py =================================================================== --- pyplusplus_dev/pyplusplus/decl_wrappers/python_traits.py (rev 0) +++ pyplusplus_dev/pyplusplus/decl_wrappers/python_traits.py 2006-09-13 07:32:06 UTC (rev 536) @@ -0,0 +1,19 @@ +# Copyright 2004 Roman Yakovenko. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +"""defines few "type traits" functions related to C++ Python bindings""" + +from pygccxml import declarations + +def is_immutable( type_ ): + """returns True, if type_ represents Python immutable type""" + return declarations.is_fundamental( type_ ) \ + or declarations.is_enum( type_ ) \ + or declarations.is_std_string( type_ ) \ + or declarations.is_std_wstring( type_ ) \ + or declarations.smart_pointer_traits.is_smart_pointer( type_ ) + #todo is_complex, ... + + Modified: pyplusplus_dev/pyplusplus/decl_wrappers/variable_wrapper.py =================================================================== --- pyplusplus_dev/pyplusplus/decl_wrappers/variable_wrapper.py 2006-09-11 19:25:08 UTC (rev 535) +++ pyplusplus_dev/pyplusplus/decl_wrappers/variable_wrapper.py 2006-09-13 07:32:06 UTC (rev 536) @@ -5,8 +5,9 @@ """defines class that configure global and member variable exposing""" +import decl_wrapper from pygccxml import declarations -import decl_wrapper +from pyplusplus.decl_wrappers import python_traits class variable_t(decl_wrapper.decl_wrapper_t, declarations.variable_t): """defines a set of properties, that will instruct Py++ how to expose the variable""" @@ -50,8 +51,8 @@ if declarations.is_pointer( type_ ): if self.type_qualifiers.has_static: return "Py++ can not expose static pointer member variables. This could be changed in future." - if declarations.is_fundamental( type_.base ): - return "Py++ can not expose pointer to fundamental member variables. This could be changed in future." + if python_traits.is_immutable( type_.base ): + return "Py++ can not expose pointer to Python immutable member variables. This could be changed in future." units = declarations.decompose_type( type_ ) ptr2functions = filter( lambda unit: isinstance( unit, declarations.calldef_type_t ) Modified: pyplusplus_dev/pyplusplus/module_creator/call_policies_resolver.py =================================================================== --- pyplusplus_dev/pyplusplus/module_creator/call_policies_resolver.py 2006-09-11 19:25:08 UTC (rev 535) +++ pyplusplus_dev/pyplusplus/module_creator/call_policies_resolver.py 2006-09-13 07:32:06 UTC (rev 536) @@ -6,6 +6,7 @@ from pygccxml import declarations from pyplusplus import decl_wrappers from pyplusplus import code_creators +from pyplusplus.decl_wrappers import python_traits class resolver_t( object ): def __init__( self ): @@ -100,7 +101,7 @@ return_type = declarations.remove_cv( calldef.return_type ) if declarations.is_reference( return_type ): return_type = declarations.remove_reference( return_type ) - if declarations.is_fundamental( return_type ) or declarations.is_enum( return_type ): + if python_traits.is_immutable( return_type ): if declarations.is_const( calldef.return_type ): return decl_wrappers.return_value_policy( decl_wrappers.copy_const_reference ) else: @@ -123,7 +124,7 @@ no_ref = declarations.remove_reference( variable.type ) base_type = declarations.remove_const( no_ref ) - if declarations.is_fundamental( base_type ) or declarations.is_enum( base_type ): + if python_traits.is_immutable( base_type ): #the relevant code creator will generate code, that will return this member variable #by value return decl_wrappers.default_call_policies() Modified: pyplusplus_dev/unittests/data/member_functions_to_be_exported.hpp =================================================================== --- pyplusplus_dev/unittests/data/member_functions_to_be_exported.hpp 2006-09-11 19:25:08 UTC (rev 535) +++ pyplusplus_dev/unittests/data/member_functions_to_be_exported.hpp 2006-09-13 07:32:06 UTC (rev 536) @@ -1,161 +1,172 @@ -// Copyright 2004 Roman Yakovenko. -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#ifndef __member_functions_to_be_exported_hpp__ -#define __member_functions_to_be_exported_hpp__ - -namespace member_functions{ - -struct protected_mf_t{ -protected: - static int x(){ return 1;} -}; - -struct protected_base_t{ -protected: - int regular( int x ){ return x; } - int regular_overloaded( int x ){ return x * x; } - int regular_overloaded( int x, int y ){ return x * y; } - - int regular_const( int x ) const { return x; } - int regular_const_overloaded( int x ) const { return x * x; } - int regular_const_overloaded( int x, int y) const { return x * y; } - -//virtual - - virtual int virtual_( int x ){ return x; } - virtual int virtual_overloaded( int x ){ return x * x; } - virtual int virtual_overloaded( int x, int y ){ return x * y; } - - virtual int virtual_const( int x ) const { return x; } - virtual int virtual_const_overloaded( int x ) const { return x * x; } - virtual int virtual_const_overloaded( int x, int y ) const { return x * y; } - -//pure virtual - virtual int pure_virtual( int x ) = 0; - virtual int pure_virtual_overloaded( int x ) = 0; - virtual int pure_virtual_overloaded( int x, int y ) = 0; - - virtual int pure_virtual_const( int x ) const = 0; - virtual int pure_virtual_const_overloaded( int x ) const = 0; - virtual int pure_virtual_const_overloaded( int x, int y ) const = 0; -}; - -struct protected_public_derived_t : public protected_base_t{ - - virtual int pure_virtual( int x ) { return x;} - virtual int pure_virtual_overloaded( int x ) { return x * x; } - virtual int pure_virtual_overloaded( int x, int y ){ return x * y; } - - virtual int pure_virtual_const( int x ) const { return x; } - virtual int pure_virtual_const_overloaded( int x ) const { return x * x; } - virtual int pure_virtual_const_overloaded( int x, int y ) const { return x * y; } -}; - -struct protected_protected_derived_t : public protected_base_t{ - - virtual int pure_virtual( int x ) { return x;} - virtual int pure_virtual_overloaded( int x ) { return x * x; } - virtual int pure_virtual_overloaded( int x, int y ){ return x * y; } - - virtual int pure_virtual_const( int x ) const { return x; } - virtual int pure_virtual_const_overloaded( int x ) const { return x * x; } - virtual int pure_virtual_const_overloaded( int x, int y ) const { return x * y; } -}; - - -struct public_base_t{ -public: - int regular( int x ){ return x; } - int regular_overloaded( int x ){ return x * x; } - int regular_overloaded( int x, int y ){ return x * y; } - - int regular_const( int x ) const { return x; } - int regular_const_overloaded( int x ) const { return x * x; } - int regular_const_overloaded( int x, int y) const { return x * y; } - -//virtual - - virtual int virtual_( int x ){ return x; } - virtual int virtual_overloaded( int x ){ return x * x; } - virtual int virtual_overloaded( int x, int y ){ return x * y; } - - virtual int virtual_const( int x ) const { return x; } - virtual int virtual_const_overloaded( int x ) const { return x * x; } - virtual int virtual_const_overloaded( int x, int y ) const { return x * y; } - -//pure virtual - virtual int pure_virtual( int x ) = 0; - virtual int pure_virtual_overloaded( int x ) = 0; - virtual int pure_virtual_overloaded( int x, int y ) = 0; - - virtual int pure_virtual_const( int x ) const = 0; - virtual int pure_virtual_const_overloaded( int x ) const = 0; - virtual int pure_virtual_const_overloaded( int x, int y ) const = 0; -}; - -struct public_derived_t : public public_base_t{ - - virtual int pure_virtual( int x ) { return x;} - virtual int pure_virtual_overloaded( int x ) { return x * x; } - virtual int pure_virtual_overloaded( int x, int y ){ return x * y; } - - virtual int pure_virtual_const( int x ) const { return x; } - virtual int pure_virtual_const_overloaded( int x ) const { return x * x; } - virtual int pure_virtual_const_overloaded( int x, int y ) const { return x * y; } -}; - - -struct private_base_t{ - void remove_gcc_warning(){} -private: - int regular( int x ){ return x; } - int regular_overloaded( int x ){ return x * x; } - int regular_overloaded( int x, int y ){ return x * y; } - - int regular_const( int x ) const { return x; } - int regular_const_overloaded( int x ) const { return x * x; } - int regular_const_overloaded( int x, int y) const { return x * y; } - -//virtual - - virtual int virtual_( int x ){ return x; } - virtual int virtual_overloaded( int x ){ return x * x; } - virtual int virtual_overloaded( int x, int y ){ return x * y; } - - virtual int virtual_const( int x ) const { return x; } - virtual int virtual_const_overloaded( int x ) const { return x * x; } - virtual int virtual_const_overloaded( int x, int y ) const { return x * y; } - -//pure virtual - virtual int pure_virtual( int x ) = 0; - virtual int pure_virtual_overloaded( int x ) = 0; - virtual int pure_virtual_overloaded( int x, int y ) = 0; - - virtual int pure_virtual_const( int x ) const = 0; - virtual int pure_virtual_const_overloaded( int x ) const = 0; - virtual int pure_virtual_const_overloaded( int x, int y ) const = 0; -}; - -struct private_derived_t : public private_base_t{ - - virtual int pure_virtual( int x ) { return x;} - virtual int pure_virtual_overloaded( int x ) { return x * x; } - virtual int pure_virtual_overloaded( int x, int y ){ return x * y; } - - virtual int pure_virtual_const( int x ) const { return x; } - virtual int pure_virtual_const_overloaded( int x ) const { return x * x; } - virtual int pure_virtual_const_overloaded( int x, int y ) const { return x * y; } -}; +// Copyright 2004 Roman Yakovenko. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef __member_functions_to_be_exported_hpp__ +#define __member_functions_to_be_exported_hpp__ + +#include <string> + +namespace member_functions{ + +struct protected_mf_t{ +protected: + static int x(){ return 1;} +}; + +struct protected_base_t{ +protected: + int regular( int x ){ return x; } + int regular_overloaded( int x ){ return x * x; } + int regular_overloaded( int x, int y ){ return x * y; } + + int regular_const( int x ) const { return x; } + int regular_const_overloaded( int x ) const { return x * x; } + int regular_const_overloaded( int x, int y) const { return x * y; } + +//virtual + + virtual int virtual_( int x ){ return x; } + virtual int virtual_overloaded( int x ){ return x * x; } + virtual int virtual_overloaded( int x, int y ){ return x * y; } + + virtual int virtual_const( int x ) const { return x; } + virtual int virtual_const_overloaded( int x ) const { return x * x; } + virtual int virtual_const_overloaded( int x, int y ) const { return x * y; } + +//pure virtual + virtual int pure_virtual( int x ) = 0; + virtual int pure_virtual_overloaded( int x ) = 0; + virtual int pure_virtual_overloaded( int x, int y ) = 0; + + virtual int pure_virtual_const( int x ) const = 0; + virtual int pure_virtual_const_overloaded( int x ) const = 0; + virtual int pure_virtual_const_overloaded( int x, int y ) const = 0; +}; + +struct protected_public_derived_t : public protected_base_t{ + + virtual int pure_virtual( int x ) { return x;} + virtual int pure_virtual_overloaded( int x ) { return x * x; } + virtual int pure_virtual_overloaded( int x, int y ){ return x * y; } + + virtual int pure_virtual_const( int x ) const { return x; } + virtual int pure_virtual_const_overloaded( int x ) const { return x * x; } + virtual int pure_virtual_const_overloaded( int x, int y ) const { return x * y; } +}; + +struct protected_protected_derived_t : public protected_base_t{ + + virtual int pure_virtual( int x ) { return x;} + virtual int pure_virtual_overloaded( int x ) { return x * x; } + virtual int pure_virtual_overloaded( int x, int y ){ return x * y; } + + virtual int pure_virtual_const( int x ) const { return x; } + virtual int pure_virtual_const_overloaded( int x ) const { return x * x; } + virtual int pure_virtual_const_overloaded( int x, int y ) const { return x * y; } +}; + + +struct public_base_t{ +public: + int regular( int x ){ return x; } + int regular_overloaded( int x ){ return x * x; } + int regular_overloaded( int x, int y ){ return x * y; } + + int regular_const( int x ) const { return x; } + int regular_const_overloaded( int x ) const { return x * x; } + int regular_const_overloaded( int x, int y) const { return x * y; } + +//virtual + + virtual int virtual_( int x ){ return x; } + virtual int virtual_overloaded( int x ){ return x * x; } + virtual int virtual_overloaded( int x, int y ){ return x * y; } + + virtual int virtual_const( int x ) const { return x; } + virtual int virtual_const_overloaded( int x ) const { return x * x; } + virtual int virtual_const_overloaded( int x, int y ) const { return x * y; } + +//pure virtual + virtual int pure_virtual( int x ) = 0; + virtual int pure_virtual_overloaded( int x ) = 0; + virtual int pure_virtual_overloaded( int x, int y ) = 0; + + virtual int pure_virtual_const( int x ) const = 0; + virtual int pure_virtual_const_overloaded( int x ) const = 0; + virtual int pure_virtual_const_overloaded( int x, int y ) const = 0; +}; + +struct public_derived_t : public public_base_t{ + + virtual int pure_virtual( int x ) { return x;} + virtual int pure_virtual_overloaded( int x ) { return x * x; } + virtual int pure_virtual_overloaded( int x, int y ){ return x * y; } + + virtual int pure_virtual_const( int x ) const { return x; } + virtual int pure_virtual_const_overloaded( int x ) const { return x * x; } + virtual int pure_virtual_const_overloaded( int x, int y ) const { return x * y; } +}; + + +struct private_base_t{ + void remove_gcc_warning(){} +private: + int regular( int x ){ return x; } + int regular_overloaded( int x ){ return x * x; } + int regular_overloaded( int x, int y ){ return x * y; } + + int regular_const( int x ) const { return x; } + int regular_const_overloaded( int x ) const { return x * x; } + int regular_const_overloaded( int x, int y) const { return x * y; } + +//virtual + + virtual int virtual_( int x ){ return x; } + virtual int virtual_overloaded( int x ){ return x * x; } + virtual int virtual_overloaded( int x, int y ){ return x * y; } + + virtual int virtual_const( int x ) const { return x; } + virtual int virtual_const_overloaded( int x ) const { return x * x; } + virtual int virtual_const_overloaded( int x, int y ) const { return x * y; } + +//pure virtual + virtual int pure_virtual( int x ) = 0; + virtual int pure_virtual_overloaded( int x ) = 0; + virtual int pure_virtual_overloaded( int x, int y ) = 0; + + virtual int pure_virtual_const( int x ) const = 0; + virtual int pure_virtual_const_overloaded( int x ) const = 0; + virtual int pure_virtual_const_overloaded( int x, int y ) const = 0; +}; + +struct private_derived_t : public private_base_t{ + + virtual int pure_virtual( int x ) { return x;} + virtual int pure_virtual_overloaded( int x ) { return x * x; } + virtual int pure_virtual_overloaded( int x, int y ){ return x * y; } + + virtual int pure_virtual_const( int x ) const { return x; } + virtual int pure_virtual_const_overloaded( int x ) const { return x * x; } + virtual int pure_virtual_const_overloaded( int x, int y ) const { return x * y; } +}; + struct callable_t{ int operator()( int i, int j ) const { return i + j; } int operator()( int i, int j, int k ) const { return i + j + k; } -}; - -} - -#endif//__member_functions_to_be_exported_hpp__ - +}; + +struct immutable_by_ref_t{ + virtual std::string identity( std::string const & x ) = 0; + + static std::string + call_identity( immutable_by_ref_t& imm, std::string const & x ){ + return imm.identity( x ); + } +}; + +} + +#endif//__member_functions_to_be_exported_hpp__ + Modified: pyplusplus_dev/unittests/member_functions_tester.py =================================================================== --- pyplusplus_dev/unittests/member_functions_tester.py 2006-09-11 19:25:08 UTC (rev 535) +++ pyplusplus_dev/unittests/member_functions_tester.py 2006-09-13 07:32:06 UTC (rev 536) @@ -11,13 +11,13 @@ class tester_t(fundamental_tester_base.fundamental_tester_base_t): EXTENSION_NAME = 'member_functions' - + def __init__( self, *args ): - fundamental_tester_base.fundamental_tester_base_t.__init__( + fundamental_tester_base.fundamental_tester_base_t.__init__( self , tester_t.EXTENSION_NAME , *args ) - + def customize(self, mb ): names = [ 'protected_protected_derived_t' @@ -33,7 +33,17 @@ #will reporoduce bug mb.class_('callable_t').always_expose_using_scope = True mb.BOOST_PYTHON_MAX_ARITY = 1 - + + def create_py_immutable_by_ref( self, module ): + class py_immutable_by_ref( module.immutable_by_ref_t ): + def __init__( self ): + module.immutable_by_ref_t.__init__( self ) + + def identity( self, x ): + return x*2 + + return py_immutable_by_ref() + def create_test_class_inst(self, class_ ): class tester_impl_t( class_ ): def __init__(self): @@ -63,39 +73,39 @@ def _test_instance( self, inst, class_defined_in_cpp): self.failUnless( 23 == inst.regular( 23 ) ) - self.failUnless( 9 == inst.regular_overloaded( 3 ) ) - self.failUnless( 15 == inst.regular_overloaded( 3, 5 ) ) + self.failUnless( 9 == inst.regular_overloaded( 3 ) ) + self.failUnless( 15 == inst.regular_overloaded( 3, 5 ) ) self.failUnless( 23 == inst.regular_const( 23 ) ) - self.failUnless( 9 == inst.regular_const_overloaded( 3 ) ) - self.failUnless( 15 == inst.regular_const_overloaded( 3, 5 ) ) + self.failUnless( 9 == inst.regular_const_overloaded( 3 ) ) + self.failUnless( 15 == inst.regular_const_overloaded( 3, 5 ) ) self.failUnless( 23 == inst.virtual_( 23 ) ) - self.failUnless( 9 == inst.virtual_overloaded( 3 ) ) - self.failUnless( 15 == inst.virtual_overloaded( 3, 5 ) ) + self.failUnless( 9 == inst.virtual_overloaded( 3 ) ) + self.failUnless( 15 == inst.virtual_overloaded( 3, 5 ) ) self.failUnless( 23 == inst.virtual_const( 23 ) ) - self.failUnless( 9 == inst.virtual_const_overloaded( 3 ) ) - self.failUnless( 15 == inst.virtual_const_overloaded( 3, 5 ) ) - + self.failUnless( 9 == inst.virtual_const_overloaded( 3 ) ) + self.failUnless( 15 == inst.virtual_const_overloaded( 3, 5 ) ) + if class_defined_in_cpp: self.failUnless( 23 == inst.pure_virtual( 23 ) ) - self.failUnless( 9 == inst.pure_virtual_overloaded( 3 ) ) - self.failUnless( 15 == inst.pure_virtual_overloaded( 3, 5 ) ) - + self.failUnless( 9 == inst.pure_virtual_overloaded( 3 ) ) + self.failUnless( 15 == inst.pure_virtual_overloaded( 3, 5 ) ) + self.failUnless( 23 == inst.pure_virtual_const( 23 ) ) - self.failUnless( 9 == inst.pure_virtual_const_overloaded( 3 ) ) - self.failUnless( 15 == inst.pure_virtual_const_overloaded( 3, 5 ) ) + self.failUnless( 9 == inst.pure_virtual_const_overloaded( 3 ) ) + self.failUnless( 15 == inst.pure_virtual_const_overloaded( 3, 5 ) ) else: self.failUnless( 46 == inst.pure_virtual( 23 ) ) - self.failUnless( 6 == inst.pure_virtual_overloaded( 3 ) ) - self.failUnless( 8 == inst.pure_virtual_overloaded( 3, 5 ) ) - + self.failUnless( 6 == inst.pure_virtual_overloaded( 3 ) ) + self.failUnless( 8 == inst.pure_virtual_overloaded( 3, 5 ) ) + self.failUnless( 46 == inst.pure_virtual_const( 23 ) ) - self.failUnless( 6 == inst.pure_virtual_const_overloaded( 3 ) ) - self.failUnless( 8 == inst.pure_virtual_const_overloaded( 3, 5 ) ) - - def run_tests(self, module): + self.failUnless( 6 == inst.pure_virtual_const_overloaded( 3 ) ) + self.failUnless( 8 == inst.pure_virtual_const_overloaded( 3, 5 ) ) + + def run_tests(self, module): derived = module.protected_public_derived_t() self._test_instance( derived, True ) derived = module.protected_protected_derived_t() @@ -106,9 +116,13 @@ self._test_instance( derived, False ) derived = self.create_test_class_inst( module.public_base_t ) self._test_instance( derived, False ) - + + x = self.create_py_immutable_by_ref(module) + self.failUnless( x.identity( '11' ) == '1111' ) + self.failUnless( module.immutable_by_ref_t.call_identity(x, '11') == '1111' ) + def create_suite(): - suite = unittest.TestSuite() + suite = unittest.TestSuite() suite.addTest( unittest.makeSuite(tester_t)) return suite @@ -116,4 +130,4 @@ unittest.TextTestRunner(verbosity=2).run( create_suite() ) if __name__ == "__main__": - run_suite() \ No newline at end of file + run_suite() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mb...@us...> - 2006-09-11 19:25:19
|
Revision: 535 http://svn.sourceforge.net/pygccxml/?rev=535&view=rev Author: mbaas Date: 2006-09-11 12:25:08 -0700 (Mon, 11 Sep 2006) Log Message: ----------- Rolled back the previous commit. Modified Paths: -------------- pygccxml_dev/pygccxml/declarations/calldef.py Modified: pygccxml_dev/pygccxml/declarations/calldef.py =================================================================== --- pygccxml_dev/pygccxml/declarations/calldef.py 2006-09-11 15:56:45 UTC (rev 534) +++ pygccxml_dev/pygccxml/declarations/calldef.py 2006-09-11 19:25:08 UTC (rev 535) @@ -39,25 +39,9 @@ """ def __init__( self, name='', type=None, default_value=None ): - """Constructor. - - The type can either be a L{type_t} object or a string containing - a valid C++ type. In the latter case the string will be wrapped - inside an appropriate type_t object, so the L{type} property - will always be a type_t object. - - @param name: The name of the argument - @type name: str - @param type: The type of the argument - @type type: L{type_t} or str - @param default_value: The optional default value of the argument - @tyape default_value: str - """ object.__init__(self) self._name = name self._default_value = default_value - if not isinstance(type, cpptypes.type_t): - type = cpptypes.dummy_type_t(str(type)) self._type = type def __str__(self): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Roman Y. <rom...@gm...> - 2006-09-11 18:30:58
|
On 9/11/06, mb...@us... <mb...@us...> wrote: > Revision: 534 > http://svn.sourceforge.net/pygccxml/?rev=534&view=rev > Author: mbaas > Date: 2006-09-11 08:56:45 -0700 (Mon, 11 Sep 2006) > > Log Message: > ----------- > Added a doc string to the constructor of argument_t and, for additional convenience, allowed the 'type' argument to also be a string in addition to a type_t object. The constructor will automatically wrap the string inside the appropriate type_t object. > Matthias you broke the rule: pygccxml is stand-alone project. You should setup type of the argument outside of the class :-( -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |
From: <mb...@us...> - 2006-09-11 15:56:49
|
Revision: 534 http://svn.sourceforge.net/pygccxml/?rev=534&view=rev Author: mbaas Date: 2006-09-11 08:56:45 -0700 (Mon, 11 Sep 2006) Log Message: ----------- Added a doc string to the constructor of argument_t and, for additional convenience, allowed the 'type' argument to also be a string in addition to a type_t object. The constructor will automatically wrap the string inside the appropriate type_t object. Modified Paths: -------------- pygccxml_dev/pygccxml/declarations/calldef.py Modified: pygccxml_dev/pygccxml/declarations/calldef.py =================================================================== --- pygccxml_dev/pygccxml/declarations/calldef.py 2006-09-11 09:51:36 UTC (rev 533) +++ pygccxml_dev/pygccxml/declarations/calldef.py 2006-09-11 15:56:45 UTC (rev 534) @@ -39,9 +39,25 @@ """ def __init__( self, name='', type=None, default_value=None ): + """Constructor. + + The type can either be a L{type_t} object or a string containing + a valid C++ type. In the latter case the string will be wrapped + inside an appropriate type_t object, so the L{type} property + will always be a type_t object. + + @param name: The name of the argument + @type name: str + @param type: The type of the argument + @type type: L{type_t} or str + @param default_value: The optional default value of the argument + @tyape default_value: str + """ object.__init__(self) self._name = name self._default_value = default_value + if not isinstance(type, cpptypes.type_t): + type = cpptypes.dummy_type_t(str(type)) self._type = type def __str__(self): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <rom...@us...> - 2006-09-11 09:51:42
|
Revision: 533 http://svn.sourceforge.net/pygccxml/?rev=533&view=rev Author: roman_yakovenko Date: 2006-09-11 02:51:36 -0700 (Mon, 11 Sep 2006) Log Message: ----------- small fix to allow Visual-C++ 6.5 compiler to work Modified Paths: -------------- pyplusplus_dev/pyplusplus/code_repository/array_1.py Modified: pyplusplus_dev/pyplusplus/code_repository/array_1.py =================================================================== --- pyplusplus_dev/pyplusplus/code_repository/array_1.py 2006-09-07 12:47:12 UTC (rev 532) +++ pyplusplus_dev/pyplusplus/code_repository/array_1.py 2006-09-11 09:51:36 UTC (rev 533) @@ -26,9 +26,9 @@ //1 - dimension namespace pyplusplus{ namespace containers{ namespace static_sized{ -inline void +inline void raise_on_out_of_range( long unsigned int size, long unsigned int index ){ - if( index < 0 || size <= index ){ + if( size <= index ){ throw std::out_of_range("index out of range"); } } @@ -36,19 +36,20 @@ template< class TItemType, long unsigned int size > struct const_array_1_t{ + typedef BOOST_DEDUCED_TYPENAME boost::call_traits<const TItemType>::param_type reference_type; + const_array_1_t( TItemType const * const data ) : m_data( data ){ if( !data ){ throw std::runtime_error( "const_array_1_t: pointer to null has been recieved." ); } } - + long unsigned int len() const { return size; } - - typename boost::call_traits<const TItemType>::param_type - item_ref( long unsigned int index ) const{ + + reference_type item_ref( long unsigned int index ) const{ raise_on_out_of_range( size, index ); return m_data[index]; } @@ -62,6 +63,8 @@ template< class TItemType, long unsigned int size > struct array_1_t{ + typedef BOOST_DEDUCED_TYPENAME boost::call_traits<const TItemType>::param_type reference_type; + array_1_t( TItemType * data ) : m_data( data ){ if( !data ){ @@ -72,49 +75,47 @@ long unsigned int len() const { return size; } - - typename boost::call_traits<const TItemType>::param_type - item_ref( long unsigned int index ) const{ + + reference_type item_ref( long unsigned int index ) const{ raise_on_out_of_range( size, index ); return m_data[index]; } void - set_item( long unsigned int index - , typename boost::call_traits<const TItemType>::param_type new_value ){ + set_item( long unsigned int index, reference_type new_value ){ raise_on_out_of_range( size, index ); m_data[index] = new_value; } private: - TItemType* m_data; + TItemType* m_data; }; template< class TItemType, long unsigned int size, typename CallPolicies > void register_const_array_1(const char* name){ typedef const_array_1_t< TItemType, size > wrapper_t; - boost::python::class_< wrapper_t >( name, boost::python::no_init ) + boost::python::class_< wrapper_t >( name, boost::python::no_init ) .def( "__getitem__" , &wrapper_t::item_ref , ( boost::python::arg("index") ) - , CallPolicies() ) + , CallPolicies() ) .def( "__len__", &wrapper_t::len ); } template< class TItemType, long unsigned int size, typename CallPolicies > void register_array_1(const char* name){ typedef array_1_t< TItemType, size > wrapper_t; - boost::python::class_< wrapper_t >( name, boost::python::no_init ) + boost::python::class_< wrapper_t >( name, boost::python::no_init ) .def( "__getitem__" , &wrapper_t::item_ref , ( boost::python::arg("index") ) - , CallPolicies() ) + , CallPolicies() ) .def( "__setitem__" , &wrapper_t::set_item , ( boost::python::arg("index"), boost::python::arg("value") ) - , CallPolicies() ) + , CallPolicies() ) .def( "__len__", &wrapper_t::len ); } @@ -123,4 +124,4 @@ #endif//__array_1_pyplusplus_hpp__ -""" \ No newline at end of file +""" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mb...@us...> - 2006-09-07 12:47:17
|
Revision: 532 http://svn.sourceforge.net/pygccxml/?rev=532&view=rev Author: mbaas Date: 2006-09-07 05:47:12 -0700 (Thu, 07 Sep 2006) Log Message: ----------- Added tests for the output_array_t class Modified Paths: -------------- pyplusplus_dev/unittests/data/function_transformations_to_be_exported.hpp pyplusplus_dev/unittests/function_transformations_tester.py Modified: pyplusplus_dev/unittests/data/function_transformations_to_be_exported.hpp =================================================================== --- pyplusplus_dev/unittests/data/function_transformations_to_be_exported.hpp 2006-09-07 12:46:20 UTC (rev 531) +++ pyplusplus_dev/unittests/data/function_transformations_to_be_exported.hpp 2006-09-07 12:47:12 UTC (rev 532) @@ -45,6 +45,13 @@ return v[0]+v[1]+v[2]; } + // A method with a output array of fixed size + virtual void fixed_output_array(int v[3]) { + v[0] = 1; + v[1] = 2; + v[2] = 3; + } + unsigned int m_width; unsigned int m_height; @@ -69,6 +76,14 @@ return v; } +// This is used for calling img.fixed_output_array() on an instance passed +// in by Python. +int image_fixed_output_array( image_t& img) { + int v[3]; + img.fixed_output_array(v); + return v[0]+v[1]+v[2]; } +} + #endif//__function_transformations_to_be_exported_hpp__ Modified: pyplusplus_dev/unittests/function_transformations_tester.py =================================================================== --- pyplusplus_dev/unittests/function_transformations_tester.py 2006-09-07 12:46:20 UTC (rev 531) +++ pyplusplus_dev/unittests/function_transformations_tester.py 2006-09-07 12:47:12 UTC (rev 532) @@ -26,6 +26,7 @@ image.member_function( "get_size2" ).function_transformers.extend([output_t(1), output_t(2)]) image.member_function( "input_arg" ).function_transformers.extend([input_t(1)]) image.member_function( "fixed_input_array" ).function_transformers.extend([input_array_t(1,3)]) + image.member_function( "fixed_output_array" ).function_transformers.extend([output_array_t(1,3)]) mb.free_function("get_cpp_instance").call_policies = return_value_policy(reference_existing_object) mb.variable( "cpp_instance" ).exclude() mb.decls(lambda decl: decl.name[0]=="_").exclude() @@ -62,16 +63,31 @@ self.assertRaises(ValueError, lambda : img.fixed_input_array(1)) self.assertRaises(ValueError, lambda : img.fixed_input_array(None)) + # Check the fixed_output_array method + self.assertEqual(img.fixed_output_array(), [1,2,3]) + ####### Do the tests on a class derived in Python ######## class py_image1_t(module.image_t): def __init__(self, h, w): module.image_t.__init__(self, h, w) + self.fixed_output_array_mode = 0 # Override a virtual method def get_one_value(self): return self.m_height+1 + def fixed_output_array(self): + # Produce a correct return value + if self.fixed_output_array_mode==0: + return (2,5,7) + # Produce the wrong type + elif self.fixed_output_array_mode==1: + return 5 + # Produce a sequence with the wrong number of items + elif self.fixed_output_array_mode==2: + return (2,5) + pyimg1 = py_image1_t(3,7) # Check a method that returns two values by reference @@ -83,6 +99,13 @@ # Check if the Python class can also be passed back to C++ self.assertEqual(module.get_image_one_value(pyimg1), 4) + # Check if fixed_output_array() is correctly called from C++ + self.assertEqual(module.image_fixed_output_array(pyimg1), 14) + pyimg1.fixed_output_array_mode = 1 + self.assertRaises(ValueError, lambda : module.image_fixed_output_array(pyimg1)) + pyimg1.fixed_output_array_mode = 2 + self.assertRaises(ValueError, lambda : module.image_fixed_output_array(pyimg1)) + class py_image2_t(module.image_t): def __init__(self, h, w): module.image_t.__init__(self, h, w) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mb...@us...> - 2006-09-07 12:46:26
|
Revision: 531 http://svn.sourceforge.net/pygccxml/?rev=531&view=rev Author: mbaas Date: 2006-09-07 05:46:20 -0700 (Thu, 07 Sep 2006) Log Message: ----------- Committed the missing output_array_t policy Modified Paths: -------------- pyplusplus_dev/pyplusplus/function_transformers/arg_policies.py Modified: pyplusplus_dev/pyplusplus/function_transformers/arg_policies.py =================================================================== --- pyplusplus_dev/pyplusplus/function_transformers/arg_policies.py 2006-09-06 14:02:43 UTC (rev 530) +++ pyplusplus_dev/pyplusplus/function_transformers/arg_policies.py 2006-09-07 12:46:20 UTC (rev 531) @@ -7,8 +7,12 @@ """This module contains the standard argument policy objects. +The following policies are available: + - L{output_t} - L{input_t} + - L{input_array_t} + - L{output_array_t} """ from pygccxml import declarations @@ -124,7 +128,7 @@ def __init__(self, idx, size): """Constructor. - @param idx: Index of the argument that is an output value (the first arg has index 1). + @param idx: Index of the argument that is an input array (the first arg has index 1). @type idx: int @param size: The fixed size of the input array @type size: int @@ -202,3 +206,96 @@ res += " %s.append(%s[%s]);"%(self.pylist, self.argname, self.virtual_ivar) return res + +# output_array_t +class output_array_t: + """Handles an output array of a fixed size. + + void getVec3(double* v) -> v = getVec3() + # v will be a list with 3 floats + + TODO: Error handling (in the virtual function)! + + """ + + def __init__(self, idx, size): + """Constructor. + + @param idx: Index of the argument that is an output array (the first arg has index 1). + @type idx: int + @param size: The fixed size of the output array + @type size: int + """ + + self.idx = idx + self.size = size + + self.argname = None + self.basetype = None + self.pyval = None + self.cval = None + self.ivar = None + + def __str__(self): + return "OutputArray(%d,%d)"%(self.idx, self.size) + + def init_funcs(self, sm): + # Remove the original argument... + arg = sm.remove_arg(self.idx) + + if not (isinstance(arg.type, declarations.pointer_t) or + isinstance(arg.type, declarations.array_t)): + raise ValueError, "Argument %d (%s) must be a pointer."%(self.idx, arg.name) + + self.argname = arg.name + self.basetype = str(arg.type.base).replace("const", "").strip() + + # Wrapper: + + # Declare a variable that will hold the C array... + self.wrapper_cval = sm.wrapper_func.declare_local("c_"+self.argname, self.basetype, size=self.size) + # Declare a Python list which will receive the output... + self.wrapper_pyval = sm.wrapper_func.declare_local(self.argname, "boost::python::list") + # ...and add it to the result + sm.wrapper_func.result_exprs.append(arg.name) + + # Declare an int which is used for the loop + self.wrapper_ivar = sm.wrapper_func.declare_local("i", "int", default=0) + + sm.wrapper_func.input_params[self.idx-1] = self.wrapper_cval + + # Virtual: + + # Declare a variable that will receive the Python list + self.virtual_pyval = sm.virtual_func.declare_local("py_"+self.argname, "boost::python::object") + + # Declare an int which is used for the loop + self.virtual_ivar = sm.virtual_func.declare_local("i", "int", default=0) + + def wrapper_post_call(self, sm): + res = "" + res += "// Copy the sequence '%s' into '%s'...\n"%(self.wrapper_cval, self.wrapper_pyval) + res += "for(%s=0; %s<%d; %s++)\n"%(self.wrapper_ivar, self.wrapper_ivar, self.size, self.wrapper_ivar) + res += " %s.append(%s[%s]);"%(self.wrapper_pyval, self.wrapper_cval , self.wrapper_ivar) + return res + + def virtual_post_call(self, sm): + res = "" + res += "// Assert that the Python object corresponding to output\n" + res += "// argument '%s' is really a sequence.\n"%self.argname + res += "%s = %s;\n"%(self.virtual_pyval, sm.py_result_expr(self.argname)) + res += "if (!PySequence_Check(%s.ptr()))\n"%self.virtual_pyval + res += "{\n" + res += ' PyErr_SetString(PyExc_ValueError, "%s: sequence expected as return value for output array \'%s\'");\n'%(sm.decl.name, self.argname) + res += ' boost::python::throw_error_already_set();\n' + res += "}\n" + res += "// Assert that the sequence has the correct size\n" + res += "if (PySequence_Length(%s.ptr())!=%s)\n"%(self.virtual_pyval, self.size) + res += "{\n" + res += ' PyErr_SetString(PyExc_ValueError, "%s: sequence with %s values expected as return value for output array \'%s\'");\n'%(sm.decl.name, self.size, self.argname) + res += ' boost::python::throw_error_already_set();\n' + res += "}\n" + res += "// Copy the Python sequence into '%s'\n"%self.argname + res += "for(%s=0; %s<%d; %s++)\n"%(self.virtual_ivar, self.virtual_ivar, self.size, self.virtual_ivar) + res += " %s[%s] = boost::python::extract<%s>(%s[%s]);"%(self.argname, self.virtual_ivar, self.basetype, self.virtual_pyval, self.virtual_ivar) + return res This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mb...@us...> - 2006-09-06 14:02:51
|
Revision: 530 http://svn.sourceforge.net/pygccxml/?rev=530&view=rev Author: mbaas Date: 2006-09-06 07:02:43 -0700 (Wed, 06 Sep 2006) Log Message: ----------- Added more tests (which do work now). Modified Paths: -------------- pyplusplus_dev/unittests/data/function_transformations_to_be_exported.hpp pyplusplus_dev/unittests/function_transformations_tester.py Modified: pyplusplus_dev/unittests/data/function_transformations_to_be_exported.hpp =================================================================== --- pyplusplus_dev/unittests/data/function_transformations_to_be_exported.hpp 2006-09-06 14:01:52 UTC (rev 529) +++ pyplusplus_dev/unittests/data/function_transformations_to_be_exported.hpp 2006-09-06 14:02:43 UTC (rev 530) @@ -10,7 +10,7 @@ struct image_t{ - image_t( unsigned int& h, unsigned int& w ) + image_t( unsigned int h, unsigned int w ) : m_height( h ) , m_width( w ) {} @@ -22,16 +22,53 @@ w = m_width; } + // Return only one value + virtual void get_one_value(unsigned int& h) { + h = m_height; + } + + // Like get_size() but with a return type and an additional argument + // that has to be kept in the signature + virtual int get_size2( unsigned int& h, unsigned int& w, int noref=0 ){ + h = m_height; + w = m_width; + return noref; + } + + // A method with an input argument + virtual int input_arg(int& in){ + return in; + } + + // A method taking an input array of fixed size + virtual int fixed_input_array(int v[3]) { + return v[0]+v[1]+v[2]; + } + unsigned int m_width; unsigned int m_height; }; +// Provide an instance created in C++ (i.e. this is not a wrapper instance) +image_t cpp_instance(12,13); +image_t& get_cpp_instance() { + return cpp_instance; +} + inline void get_image_size( image_t& img, unsigned int& h, unsigned int& w ){ img.get_size( h, w ); } +// This is used for calling img.get_one_value() on an instance passed +// in by Python. +unsigned int get_image_one_value( image_t& img ) { + unsigned int v; + img.get_one_value(v); + return v; } +} + #endif//__function_transformations_to_be_exported_hpp__ Modified: pyplusplus_dev/unittests/function_transformations_tester.py =================================================================== --- pyplusplus_dev/unittests/function_transformations_tester.py 2006-09-06 14:01:52 UTC (rev 529) +++ pyplusplus_dev/unittests/function_transformations_tester.py 2006-09-06 14:02:43 UTC (rev 530) @@ -8,6 +8,7 @@ import unittest import fundamental_tester_base from pyplusplus.function_transformers.arg_policies import * +from pyplusplus.decl_wrappers import * class tester_t(fundamental_tester_base.fundamental_tester_base_t): EXTENSION_NAME = 'function_transformations' @@ -20,13 +21,99 @@ def customize( self, mb ): image = mb.class_( "image_t" ) - image.member_function( "get_size" ).function_transformers.extend([Output(1), Output(2)]) + image.member_function( "get_size" ).function_transformers.extend([output_t(1), output_t(2)]) + image.member_function( "get_one_value" ).function_transformers.extend([output_t(1)]) + image.member_function( "get_size2" ).function_transformers.extend([output_t(1), output_t(2)]) + image.member_function( "input_arg" ).function_transformers.extend([input_t(1)]) + image.member_function( "fixed_input_array" ).function_transformers.extend([input_array_t(1,3)]) + mb.free_function("get_cpp_instance").call_policies = return_value_policy(reference_existing_object) + mb.variable( "cpp_instance" ).exclude() + mb.decls(lambda decl: decl.name[0]=="_").exclude() def run_tests(self, module): + """Run the actual unit tests. + """ + + ####### Do the tests directly on the wrapper C++ class ######## + img = module.image_t( 2, 6) - h,w = img.get_size() - self.failUnless( h == 2 and w == 6 ) + # Check a method that returns two values by reference + self.assertEqual(img.get_size(), (2,6)) + + # Check a method that only returns one value by reference + self.assertEqual(img.get_one_value(), 2) + + # Check if the C++ class can also be passed back to C++ + self.assertEqual(module.get_image_one_value(img), 2) + + # Check get_size2() + self.assertEqual(img.get_size2(), (0,2,6)) + self.assertEqual(img.get_size2(1), (1,2,6)) + + # Check the input_arg method + self.assertEqual(img.input_arg(5), 5) + + # Check the fixed_input_array method + self.assertEqual(img.fixed_input_array([1,2,3]), 6) + self.assertEqual(img.fixed_input_array((1,2,3)), 6) + self.assertRaises(ValueError, lambda : img.fixed_input_array([1,2,3,4])) + self.assertRaises(ValueError, lambda : img.fixed_input_array([1,2])) + self.assertRaises(ValueError, lambda : img.fixed_input_array(1)) + self.assertRaises(ValueError, lambda : img.fixed_input_array(None)) + + ####### Do the tests on a class derived in Python ######## + + class py_image1_t(module.image_t): + def __init__(self, h, w): + module.image_t.__init__(self, h, w) + + # Override a virtual method + def get_one_value(self): + return self.m_height+1 + + pyimg1 = py_image1_t(3,7) + + # Check a method that returns two values by reference + self.assertEqual(pyimg1.get_size(), (3,7)) + + # Check a method that only returns one value by reference + self.assertEqual(pyimg1.get_one_value(), 4) + + # Check if the Python class can also be passed back to C++ + self.assertEqual(module.get_image_one_value(pyimg1), 4) + + class py_image2_t(module.image_t): + def __init__(self, h, w): + module.image_t.__init__(self, h, w) + + # Override a virtual method and invoke the inherited method + def get_one_value(self): + return module.image_t.get_one_value(self)+2 + + pyimg2 = py_image2_t(4,8) + + # Check the derived get_one_value() method + self.assertEqual(pyimg2.get_one_value(), 6) + + # Check if the Python class can also be passed back to C++ + self.assertEqual(module.get_image_one_value(pyimg2), 6) + + ####### Do the tests on a class instantiated in C++ ######## + + cppimg = module.get_cpp_instance() + + # Check a method that returns two values by reference + self.assertEqual(cppimg.get_size(), (12,13)) + + # Check a method that only returns one value by reference + self.assertEqual(cppimg.get_one_value(), 12) + + # Check if the C++ class can also be passed back to C++ + self.assertEqual(module.get_image_one_value(cppimg), 12) + + + def create_suite(): suite = unittest.TestSuite() suite.addTest( unittest.makeSuite(tester_t)) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mb...@us...> - 2006-09-06 14:01:56
|
Revision: 529 http://svn.sourceforge.net/pygccxml/?rev=529&view=rev Author: mbaas Date: 2006-09-06 07:01:52 -0700 (Wed, 06 Sep 2006) Log Message: ----------- Filled the *transformed*_t classes for public virtual member functions. Modified Paths: -------------- pyplusplus_dev/pyplusplus/code_creators/calldef.py Modified: pyplusplus_dev/pyplusplus/code_creators/calldef.py =================================================================== --- pyplusplus_dev/pyplusplus/code_creators/calldef.py 2006-09-06 13:59:47 UTC (rev 528) +++ pyplusplus_dev/pyplusplus/code_creators/calldef.py 2006-09-06 14:01:52 UTC (rev 529) @@ -9,6 +9,7 @@ import declaration_based import class_declaration from pygccxml import declarations +import pyplusplus.function_transformers as function_transformers #virtual functions that returns const reference to something #could not be overriden by Python. The reason is simple: @@ -440,6 +441,9 @@ return os.linesep.join( answer ) class mem_fun_v_transformed_t( calldef_t ): + """Creates code for (public) virtual member functions. + """ + def __init__( self, function, wrapper=None ): calldef_t.__init__( self, function=function, wrapper=wrapper ) self.default_function_type_alias = 'default_' + self.function_type_alias @@ -476,19 +480,64 @@ result.append( '(%s)(&%s)' % ( self.wrapper.function_type().decl_string, self.wrapper.default_full_name() ) ) else: - result.append( '&%s'% declarations.full_name( self.declaration ) ) if self.wrapper: - result.append( self.param_sep() ) result.append( '&%s' % self.wrapper.default_full_name() ) + else: + result.append( '&%s'% declarations.full_name( self.declaration ) ) +# result.append( '&%s'% declarations.full_name( self.declaration ) ) +# if self.wrapper: +# result.append( self.param_sep() ) +# result.append( '&%s' % self.wrapper.default_full_name() ) return ''.join( result ) class mem_fun_v_transformed_wrapper_t( calldef_wrapper_t ): + """Creates wrapper code for (public) virtual member functions. + + The generated code consists of two functions: the virtual function + and the 'default' function. + """ + def __init__( self, function ): + """Constructor. + + @param function: Function declaration + @type function: calldef_t + """ calldef_wrapper_t.__init__( self, function=function ) + + # Stores the name of the variable that holds the override + self._override_var = None + def default_name(self): + """Return the name of the 'default' function. + + @rtype: str + """ + return "default_" + self.declaration.alias + def default_full_name(self): + """Return the full name of the 'default' function. + + The returned name also includes the class name. + + @rtype: str + """ return self.parent.full_name + '::default_' + self.declaration.alias + def virtual_name(self): + """Return the name of the 'virtual' function. + + @rtype: str + """ + return self.declaration.name + + def base_name(self): + """Return the name of the 'base' function. + + @rtype: str + """ + return "base_" + self.declaration.name + def function_type(self): return declarations.member_function_type_t( return_type=self.declaration.return_type @@ -496,53 +545,135 @@ , arguments_types=map( lambda arg: arg.type, self.declaration.arguments ) , has_const=self.declaration.has_const ) - def create_declaration(self, name, has_virtual=True): - template = '%(virtual)s%(return_type)s %(name)s( %(args)s )%(constness)s %(throw)s' + def create_declaration(self, name, virtual=True): + """Create the function header. - virtual = 'virtual ' - if not has_virtual: - virtual = '' + This method is used for the virtual function (and the base_ function), + but not for the default function. + """ + template = '%(virtual)s$RET_TYPE %(name)s( $ARG_LIST_DEF )%(constness)s %(throw)s' + # Substitute the $-variables + template = self._subst_manager.subst_virtual(template) + + virtualspec = '' + if virtual: + virtualspec = 'virtual ' + constness = '' if self.declaration.has_const: constness = ' const ' return template % { - 'virtual' : virtual - , 'return_type' : self.declaration.return_type.decl_string + 'virtual' : virtualspec , 'name' : name - , 'args' : self.args_declaration() , 'constness' : constness , 'throw' : self.throw_specifier_code() } - def create_virtual_body(self): - template = [] - template.append( 'if( %(override)s func_%(alias)s = this->get_override( "%(alias)s" ) )' ) - template.append( self.indent('%(return_)sfunc_%(alias)s( %(args)s );') ) - template.append( 'else' ) - template.append( self.indent('%(return_)s%(wrapped_class)s::%(name)s( %(args)s );') ) - template = os.linesep.join( template ) + def create_base_body(self): + body = "%(return_)s%(wrapped_class)s::%(name)s( %(args)s );" return_ = '' if not declarations.is_void( self.declaration.return_type ): return_ = 'return ' - return template % { - 'override' : self.override_identifier() - , 'name' : self.declaration.name - , 'alias' : self.declaration.alias + return body % { + 'name' : self.declaration.name + , 'args' : self.function_call_args() , 'return_' : return_ - , 'args' : self.function_call_args() , 'wrapped_class' : self.wrapped_class_identifier() } + def create_virtual_body(self): + + body = """ +$DECLARATIONS + +if( %(override_var)s ) +{ + $PRE_CALL + + ${RESULT_VAR_ASSIGNMENT}boost::python::call<$RESULT_TYPE>($INPUT_PARAMS); + + $POST_CALL + + $RETURN_STMT +} +else +{ + %(inherited)s +} +""" + + vf = self._subst_manager.virtual_func + arg0 = "%s.ptr()"%self._override_var + if vf.INPUT_PARAMS=="": + vf.INPUT_PARAMS = arg0 + else: + vf.INPUT_PARAMS = arg0+", "+vf.INPUT_PARAMS + + # Replace the $-variables + body = self._subst_manager.subst_virtual(body) + +# template = [] +# template.append( 'if( %(override)s func_%(alias)s = this->get_override( "%(alias)s" ) )' ) +# template.append( self.indent('%(return_)sfunc_%(alias)s( %(args)s );') ) +# template.append( 'else' ) +# template.append( self.indent('%(return_)s%(wrapped_class)s::%(name)s( %(args)s );') ) +# template = os.linesep.join( template ) + + return body % { +# 'override' : self.override_identifier() + 'override_var' : self._override_var + , 'alias' : self.declaration.alias +# , 'func_var' : "func_"+self.declaration.alias + , 'inherited' : self.create_base_body() + } + def create_default_body(self): - function_call = declarations.call_invocation.join( self.declaration.name - , [ self.function_call_args() ] ) - body = self.wrapped_class_identifier() + '::' + function_call + ';' - if not declarations.is_void( self.declaration.return_type ): - body = 'return ' + body + cls_wrapper_type = self.parent.full_name + cls_wrapper = self._subst_manager.wrapper_func.declare_local("cls_wrapper", cls_wrapper_type); + # The name of the 'self' variable (i.e. first argument) + selfname = self._subst_manager.wrapper_func.arg_list[0].name + + body = """$DECLARATIONS + +$PRE_CALL + +%(cls_wrapper_type)s* %(cls_wrapper)s = dynamic_cast<%(cls_wrapper_type)s*>(&%(self)s); +if (%(cls_wrapper)s==0) +{ + // The following call is done on an instance created in C++, + // so it won't invoke Python code. + $RESULT_VAR_ASSIGNMENT$CALL_FUNC_NAME($INPUT_PARAMS); +} +else +{ + // The following call is done on an instance created in Python, + // i.e. a wrapper instance. This call might invoke Python code. + $RESULT_VAR_ASSIGNMENT%(cls_wrapper)s->%(base_name)s($INPUT_PARAMS); +} + +$POST_CALL + +$RETURN_STMT +""" + + # Replace the $-variables + body = self._subst_manager.subst_wrapper(body) + + # Replace the remaining parameters + body = body%{"cls_wrapper_type" : cls_wrapper_type, + "cls_wrapper" : cls_wrapper, + "self" : selfname, + "base_name" : self.base_name() } + +# function_call = declarations.call_invocation.join( self.declaration.name +# , [ self.function_call_args() ] ) +# body = self.wrapped_class_identifier() + '::' + function_call + ';' +# if not declarations.is_void( self.declaration.return_type ): +# body = 'return ' + body return body def create_function(self): @@ -551,18 +682,47 @@ answer.append( '}' ) return os.linesep.join( answer ) + def create_base_function( self ): + answer = [ self.create_declaration("base_"+self.declaration.name, False) + '{' ] + body = "%(return_)s%(wrapped_class)s::%(name)s( %(args)s );" + answer.append( self.indent( self.create_base_body() ) ) + answer.append( '}' ) + return os.linesep.join( answer ) + def create_default_function( self ): - answer = [ self.create_declaration('default_' + self.declaration.alias, False) + '{' ] + + header = 'static $RET_TYPE %s( $ARG_LIST_DEF ) {'%self.default_name() + header = self._subst_manager.subst_wrapper(header) + + answer = [ header ] answer.append( self.indent( self.create_default_body() ) ) answer.append( '}' ) return os.linesep.join( answer ) + def _create_impl(self): + # Create the substitution manager + decl = self.declaration + sm = function_transformers.substitution_manager_t(decl, transformers=decl.function_transformers) + self._override_var = sm.virtual_func.declare_local(decl.alias+"_callable", "boost::python::override", default='this->get_override( "%s" )'%decl.alias) + self._subst_manager = sm + answer = [ self.create_function() ] answer.append( os.linesep ) + answer.append( self.create_base_function() ) + answer.append( os.linesep ) answer.append( self.create_default_function() ) - return os.linesep.join( answer ) + answer = os.linesep.join( answer ) + # Replace the argument list of the declaration so that in the + # case that keywords are created, the correct arguments will be + # picked up (i.e. the modified argument list and not the original + # argument list) + self.declaration.arguments = self._subst_manager.wrapper_func.arg_list + + return answer + + class mem_fun_protected_t( calldef_t ): def __init__( self, function, wrapper ): calldef_t.__init__( self, function=function, wrapper=wrapper ) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mb...@us...> - 2006-09-06 13:59:51
|
Revision: 528 http://svn.sourceforge.net/pygccxml/?rev=528&view=rev Author: mbaas Date: 2006-09-06 06:59:47 -0700 (Wed, 06 Sep 2006) Log Message: ----------- Renamed the class Output to output_t to be consistent with the Py++ naming conventions. Added two new arg policies: input_t and input_array_t. Modified Paths: -------------- pyplusplus_dev/pyplusplus/function_transformers/arg_policies.py Modified: pyplusplus_dev/pyplusplus/function_transformers/arg_policies.py =================================================================== --- pyplusplus_dev/pyplusplus/function_transformers/arg_policies.py 2006-09-06 13:58:33 UTC (rev 527) +++ pyplusplus_dev/pyplusplus/function_transformers/arg_policies.py 2006-09-06 13:59:47 UTC (rev 528) @@ -5,13 +5,16 @@ # # Initial author: Matthias Baas -"""This module contains standard argument policy objects. +"""This module contains the standard argument policy objects. + + - L{output_t} + - L{input_t} """ from pygccxml import declarations -# Output -class Output: +# output_t +class output_t: """Handles a single output variable. The specified variable is removed from the argument list and is turned @@ -64,7 +67,138 @@ res = "// Extract the C++ value for output argument '%s' (index: %d)\n"%(arg.name, self.idx) if isinstance(arg.type, declarations.pointer_t): res += "*" - res += "%s = boost::python::extract<%s>(%s[%d]);"%(arg.name, arg.type.base, sm.virtual_func.result_var, sm.wrapper_func.result_exprs.index(self.local_var)) + res += "%s = boost::python::extract<%s>(%s);"%(arg.name, arg.type.base, sm.py_result_expr(self.local_var)) return res +# input_t +class input_t: + """Handles a single input variable. + + The reference on the specified variable is removed. + + void setValue(int& v) -> setValue(v) + """ + + def __init__(self, idx): + """Constructor. + + The specified argument must be a reference or a pointer. + + @param idx: Index of the argument that is an output value (the first arg has index 1). + @type idx: int + """ + self.idx = idx + + def __str__(self): + return "Input(%d)"%(self.idx) + + def init_funcs(self, sm): + # Remove the specified input argument from the wrapper function + arg = sm.remove_arg(self.idx) + + # Do some checks (the arg has to be a reference or a pointer) + reftype = arg.type + if not (isinstance(reftype, declarations.reference_t) or + isinstance(reftype, declarations.pointer_t)): + raise ValueError, 'Output variable %d ("%s") must be a reference or a pointer (got %s)'%(self.idx, arg.name, arg.type) + + # Create an equivalent argument that is not a reference type + noref_arg = declarations.argument_t(name=arg.name, type=arg.type.base, default_value=arg.default_value) + # Insert the noref argument + sm.insert_arg(self.idx, noref_arg, arg.name) + + +# input_array_t +class input_array_t: + """Handles an input array with fixed size. + + void setVec3(double* v) -> setVec3(object v) + # v must be a sequence of 3 floats + + + TODO: Error handling (in the wrapper function)! + + """ + + def __init__(self, idx, size): + """Constructor. + + @param idx: Index of the argument that is an output value (the first arg has index 1). + @type idx: int + @param size: The fixed size of the input array + @type size: int + """ + self.idx = idx + self.size = size + + self.argname = None + self.basetype = None + self.carray = None + self.wrapper_ivar = None + self.virtual_ivar = None + self.pylist = None + + def __str__(self): + return "InputArray(%d,%d)"%(self.idx, self.size) + + def init_funcs(self, sm): + + # Remove the original argument... + arg = sm.remove_arg(self.idx) + + if not (isinstance(arg.type, declarations.pointer_t) or + isinstance(arg.type, declarations.array_t)): + raise ValueError, "Argument %d (%s) must be a pointer."%(self.idx, arg.name) + + # Declare a variable that will hold the Python list + # (this will be the input of the Python call in the virtual function) + self.pylist = sm.virtual_func.declare_local("py_"+arg.name, "boost::python::list") + + # Replace the removed argument with a Python object. + newarg = declarations.argument_t(arg.name, "boost::python::object") + sm.insert_arg(self.idx, newarg, self.pylist) + + self.argname = arg.name + self.basetype = str(arg.type.base).replace("const", "").strip() + + # Declare a variable that will hold the C array... + self.carray = sm.wrapper_func.declare_local("c_"+arg.name, self.basetype, size=self.size) + # and an int which is used for the loop + self.wrapper_ivar = sm.wrapper_func.declare_local("i", "int", default=0) + # and another one in the virtual function + self.virtual_ivar = sm.virtual_func.declare_local("i", "int", default=0) + + # Replace the input parameter with the C array + sm.wrapper_func.input_params[self.idx-1] = self.carray + + + def wrapper_pre_call(self, sm): + """Wrapper function code. + """ + res = "" + res += "// Assert that '%s' is really a sequence...\n"%self.argname + res += "if (!PySequence_Check(%s.ptr()))\n"%self.argname + res += "{\n" + res += ' PyErr_SetString(PyExc_ValueError, "Argument %s: sequence expected");\n'%self.argname + res += ' boost::python::throw_error_already_set();\n' + res += "}\n" + res += "// Copy the sequence '%s' into '%s'...\n"%(self.argname, self.carray) + res += 'if (%s.attr("__len__")()!=%d)\n'%(self.argname, self.size) + res += '{\n' + res += ' PyErr_SetString(PyExc_ValueError, "Invalid sequence size (expected %d)");\n'%self.size + res += ' boost::python::throw_error_already_set();\n' + res += '}\n' + res += "for(%s=0; %s<%d; %s++)\n"%(self.wrapper_ivar, self.wrapper_ivar, self.size, self.wrapper_ivar) + res += " %s[%s] = boost::python::extract< %s >(%s[%s]);"%(self.carray, self.wrapper_ivar, self.basetype, self.argname , self.wrapper_ivar) + return res + + def virtual_pre_call(self, sm): + """Virtual function code. + """ + res = "" + res += "// Copy the array '%s' into list '%s'...\n"%(self.argname, self.pylist) + res += "for(%s=0; %s<%d; %s++)\n"%(self.virtual_ivar, self.virtual_ivar, self.size, self.virtual_ivar) + res += " %s.append(%s[%s]);"%(self.pylist, self.argname, self.virtual_ivar) + return res + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mb...@us...> - 2006-09-06 13:58:37
|
Revision: 527 http://svn.sourceforge.net/pygccxml/?rev=527&view=rev Author: mbaas Date: 2006-09-06 06:58:33 -0700 (Wed, 06 Sep 2006) Log Message: ----------- Added the method py_result_expr() + a couple of smaller additions/fixes Modified Paths: -------------- pyplusplus_dev/pyplusplus/function_transformers/substitution_manager.py Modified: pyplusplus_dev/pyplusplus/function_transformers/substitution_manager.py =================================================================== --- pyplusplus_dev/pyplusplus/function_transformers/substitution_manager.py 2006-09-06 13:57:07 UTC (rev 526) +++ pyplusplus_dev/pyplusplus/function_transformers/substitution_manager.py 2006-09-06 13:58:33 UTC (rev 527) @@ -126,6 +126,8 @@ - RESULT_VAR_ASSIGNMENT: "<varname> = " or empty + - RESULT_TYPE: The type of the result variable + - CALL_FUNC_NAME: The name of the function that should be invoked (self?). - INPUT_PARAMS: The values or variables that will be passed to $FUNC_NAME, @@ -154,7 +156,7 @@ @type virtual_func: L{code_manager_t} @group Methods called by the user of the class: append_code_block, subst_wrapper, subst_virtual, get_includes - @group Methods called by the arg policies: remove_arg, insert_arg, require_include + @group Methods called by the function transformers: remove_arg, insert_arg, py_result_expr, require_include @author: Matthias Baas """ @@ -195,7 +197,8 @@ ret_type = None else: ret_type = decl.return_type - self.wrapper_func.result_var = self.wrapper_func.declare_local("result", str(ret_type)) + self.wrapper_func.result_type = str(ret_type) + self.wrapper_func.result_var = self.wrapper_func.declare_local("result", self.wrapper_func.result_type) self.wrapper_func.result_exprs = [self.wrapper_func.result_var] self.virtual_func.ret_type = ret_type @@ -212,6 +215,11 @@ self.wrapper_func.CALL_FUNC_NAME = decl.name self.wrapper_func.input_params = map(lambda a: a.name, decl.arguments) + # The offset that is added to the index in insert_arg() + # This index is either 0 for free functions or 1 for member functions + # because the "self" argument is not a regular argument. + self._insert_arg_idx_offset = 0 + # Check if we're dealing with a member function... clsdecl = self._class_decl(decl) if clsdecl!=None: @@ -219,6 +227,7 @@ selfarg = declarations.argument_t(selfname, "%s&"%clsdecl.name) self.wrapper_func.arg_list.insert(0, selfarg) self.wrapper_func.CALL_FUNC_NAME = "%s.%s"%(selfname, self.wrapper_func.CALL_FUNC_NAME) + self._insert_arg_idx_offset = 1 # Argument index map # Original argument index ---> Input arg index (indices are 0-based!) @@ -258,7 +267,8 @@ # Create a variable that will hold the result of the Python call # inside the virtual function. if len(self.wrapper_func.result_exprs)>0: - self.virtual_func.result_var = self.virtual_func.declare_local("pyresult", "boost::python::object") + self.virtual_func.result_type = "boost::python::object" + self.virtual_func.result_var = self.virtual_func.declare_local("pyresult", self.virtual_func.result_type) # self.virtual_func.result_expr = self.virtual_func.result_var self.wrapper_func.init_variables() @@ -312,7 +322,7 @@ if idx is 0 and the function has no return type). You must not modify this object as it may still be in use on the virtual function. - @rtype: argument_t + @rtype: L{argument_t<pygccxml.declarations.calldef.argument_t>} """ if self._funcs_initialized: raise ValueError, "remove_arg() may only be called before function initialization." @@ -351,7 +361,7 @@ return arg # insert_arg - def insert_arg(self, idx, arg): + def insert_arg(self, idx, arg, inputexpr): """Insert a new argument into the argument list of the wrapper function. This function is supposed to be called by function transformer @@ -360,7 +370,9 @@ @param idx: New argument index (may be negative) @type idx: int @param arg: New argument object - @type arg: argument_t + @type arg: L{argument_t<pygccxml.declarations.calldef.argument_t>} + @param inputexpr: The expression that is used as input parameter for the Python function call inside the virtual function + @type inputexpr: str """ if self._funcs_initialized: raise ValueError, "insert_arg() may only be called before function initialization." @@ -369,15 +381,67 @@ else: if idx<0: idx += len(self.wrapper_func.arg_list)+2 + + idx += self._insert_arg_idx_offset self.wrapper_func.arg_list.insert(idx-1, arg) # What to insert? - self.virtual_func.input_params.insert(idx-1, "???") + self.virtual_func.input_params.insert(idx-1, inputexpr) # Adjust the argument index map for i in range(idx-1,len(self.argidxmap)): if self.argidxmap[i]!=None: self.argidxmap[i] += 1 + # py_result_expr + def py_result_expr(self, local_wrapper_var): + """Return a C++ expression that references one particular item of the result tuple in the virtual function. + + This method is supposed to be used in the virtual_post_call() method + of function transformers when the result object of the Python call + is required. It relieves the transformer from having to check whether + its value is the only output value or not (in the former case the + value is an arbitrary Python object, in the latter case it is always + a tuple). + + For example, if a function transformer allocates a variable and + adds it to the result expressions of the wrapper function (so that + the wrapper function returns the value of this variable) then + the corresponding virtual function has to receive this value + and convert it to a C++ value. Suppose the result of invoking + the Python function inside the virtual function is stored in + the variable "pyresult" (which is of type "object"). The transformer + object that has to access its output value has to distinguish + two cases: + + - Its output value was the only output, then it references the + output value simply with "pyresult". + - There are also other output values, then it references its + output value with "pyresult[n]" where n is the position of + the output variable in the result tuple. + + To relieve the transformer from the burden of having to perform + this test, py_result_expr() can be used which generates the + appropriate expression. + + @param local_wrapper_var: The name of the local variable inside the wrapper that is part of the result tuple + @type local_wrapper_var: str + @return: The C++ expression that references the result item + @rtype: str + """ + # Get the name of the result variable + pyresult = self.virtual_func.result_var + # Determine the index of the requested local wrapper variable + try: + idx = self.wrapper_func.result_exprs.index(local_wrapper_var) + except ValueError: + raise ValueError, "The local variable '%s' is not returned by the wrapper function." + + # Return the C++ expression + if len(self.wrapper_func.result_exprs)==1: + return pyresult + else: + return "%s[%d]"%(pyresult, idx) + # require_include def require_include(self, include, where=None): """Declare an include file that is required for the code to compile. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mb...@us...> - 2006-09-06 13:57:10
|
Revision: 526 http://svn.sourceforge.net/pygccxml/?rev=526&view=rev Author: mbaas Date: 2006-09-06 06:57:07 -0700 (Wed, 06 Sep 2006) Log Message: ----------- Documentation update (so that links to the substitution manager are created) Modified Paths: -------------- pyplusplus_dev/pyplusplus/function_transformers/function_transformer.py Modified: pyplusplus_dev/pyplusplus/function_transformers/function_transformer.py =================================================================== --- pyplusplus_dev/pyplusplus/function_transformers/function_transformer.py 2006-09-06 13:56:17 UTC (rev 525) +++ pyplusplus_dev/pyplusplus/function_transformers/function_transformer.py 2006-09-06 13:57:07 UTC (rev 526) @@ -37,7 +37,7 @@ of the C++ wrapper function or allocate local variables. @param sm: Substitution manager instance - @type sm: substitution_manager_t + @type sm: L{substitution_manager_t} """ pass @@ -47,7 +47,7 @@ The code from this method will be put into the wrapper function. @param sm: Substitution manager instance - @type sm: substitution_manager_t + @type sm: L{substitution_manager_t} @return: C++ code or None @rtype: str """ @@ -59,7 +59,7 @@ The code from this method will be put into the wrapper function. @param sm: Substitution manager instance - @type sm: substitution_manager_t + @type sm: L{substitution_manager_t} @return: C++ code or None @rtype: str """ @@ -74,7 +74,7 @@ <not used yet> @param sm: Substitution manager instance - @type sm: substitution_manager_t + @type sm: L{substitution_manager_t} @return: C++ code or None @rtype: str """ @@ -86,7 +86,7 @@ The code from this method will be put into the virtual function. @param sm: Substitution manager instance - @type sm: substitution_manager_t + @type sm: L{substitution_manager_t} @return: C++ code or None @rtype: str """ @@ -98,7 +98,7 @@ The code from this method will be put into the virtual function. @param sm: Substitution manager instance - @type sm: substitution_manager_t + @type sm: L{substitution_manager_t} @return: C++ code or None @rtype: str """ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mb...@us...> - 2006-09-06 13:56:26
|
Revision: 525 http://svn.sourceforge.net/pygccxml/?rev=525&view=rev Author: mbaas Date: 2006-09-06 06:56:17 -0700 (Wed, 06 Sep 2006) Log Message: ----------- Added a result_type attribute and RESULT_TYPE variable that contains the type of the result variable. Modified Paths: -------------- pyplusplus_dev/pyplusplus/function_transformers/code_manager.py Modified: pyplusplus_dev/pyplusplus/function_transformers/code_manager.py =================================================================== --- pyplusplus_dev/pyplusplus/function_transformers/code_manager.py 2006-09-06 13:55:04 UTC (rev 524) +++ pyplusplus_dev/pyplusplus/function_transformers/code_manager.py 2006-09-06 13:56:17 UTC (rev 525) @@ -40,6 +40,8 @@ @type input_params: list of str @ivar result_var: The name of the variable that will receive the result of the function call. If None, the return value is ignored. This attribute will be used for the variable RESULT_VAR_ASSIGNMENT. @type result_var: str + @ivar result_type: The type of the variable 'result_var' + @type result_type: str @ivar result_expr: A string containing the expression that will be put after the "return" statement. This expression is used for the variable RETURN_STMT. @type result_expr: str @@ -71,6 +73,9 @@ # function call. If None, the return value is ignored. self.result_var = None + # The type of 'result_var' + self.result_type = "void" + # A string containing the expression that will be put after # the "return" statement. self.result_expr = None @@ -180,6 +185,10 @@ if self.result_var!=None: self.RESULT_VAR_ASSIGNMENT = "%s = "%self.result_var + # RESULT_TYPE + if self.result_type!=None: + self.RESULT_TYPE = str(self.result_type) + # INPUT_PARAMS self.INPUT_PARAMS = ", ".join(self.input_params) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mb...@us...> - 2006-09-06 13:55:08
|
Revision: 524 http://svn.sourceforge.net/pygccxml/?rev=524&view=rev Author: mbaas Date: 2006-09-06 06:55:04 -0700 (Wed, 06 Sep 2006) Log Message: ----------- Allow optional curly braces around a variable name to separate a variable from subsequent text. (so far only on non-block variables, but block variables don't need this anyway) Modified Paths: -------------- pyplusplus_dev/pyplusplus/function_transformers/subst.py Modified: pyplusplus_dev/pyplusplus/function_transformers/subst.py =================================================================== --- pyplusplus_dev/pyplusplus/function_transformers/subst.py 2006-09-05 19:14:44 UTC (rev 523) +++ pyplusplus_dev/pyplusplus/function_transformers/subst.py 2006-09-06 13:55:04 UTC (rev 524) @@ -108,7 +108,7 @@ code = "\n".join(lines) # Replace the non-block variables... - varexpr = re.compile("\$[a-zA-Z_]+") + varexpr = re.compile("\$[a-zA-Z_]+|\$\{[a-zA-Z_]+\}") while 1: m = varexpr.search(code) if m==None: @@ -116,6 +116,8 @@ s = m.start() e = m.end() key = code[s+1:e] + if key[0]=="{": + key = key[1:-1] code = "%s%s%s"%(code[:s], getattr(self, key, ""), code[e:]) # Replace trailing blanks on each line... This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <rom...@us...> - 2006-09-05 19:14:51
|
Revision: 523 http://svn.sourceforge.net/pygccxml/?rev=523&view=rev Author: roman_yakovenko Date: 2006-09-05 12:14:44 -0700 (Tue, 05 Sep 2006) Log Message: ----------- adding ouput_arg example Modified Paths: -------------- pyplusplus_dev/docs/peps/function_transformation.rest Modified: pyplusplus_dev/docs/peps/function_transformation.rest =================================================================== --- pyplusplus_dev/docs/peps/function_transformation.rest 2006-09-05 12:33:56 UTC (rev 522) +++ pyplusplus_dev/docs/peps/function_transformation.rest 2006-09-05 19:14:44 UTC (rev 523) @@ -194,7 +194,38 @@ create or give a hint to the user what transformation could\\should be applied on the function. +------------------------------------- +output_arg transformation example +------------------------------------- +:: + class output_arg_t( transformer_t ): + def __init__( self, ordinal ): + self.ordinal = ordinal + + def check( self, decl ): + if len( decl.arguments ) <= self.ordinal: + return user message + type_ = decl.arguments[self.ordinal].type + if not reference to immutable type: + raise user message + + def signature_changes( self, decl ): + assert not self.check( decl ) + return [ remove_arg( self.ordinal ) + , add_var_to_return_value( decl.arguments[ self.ordinal ].name ] + + def apply( self, sm ): + if sm is wrapper around C++ function: + sm. add declaration of variable type = decl.arguments[ self.ordinal ].type + and name = decl.arguments[ self.ordinal ].type and initial value + sm. add variable to return expression. + else: #sm is a wrapper around Python function + sm. extract value from the tuple and assign it to the argument + + def output_arg( ordinal ): + return output_arg_t( ordinal ) + ----------------- Problems to solve ----------------- This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <rom...@us...> - 2006-09-05 12:34:08
|
Revision: 522 http://svn.sourceforge.net/pygccxml/?rev=522&view=rev Author: roman_yakovenko Date: 2006-09-05 05:33:56 -0700 (Tue, 05 Sep 2006) Log Message: ----------- function transformation design purpose Modified Paths: -------------- pyplusplus_dev/docs/peps/function_transformation.rest pyplusplus_dev/docs/peps/www_configuration.py Removed Paths: ------------- pyplusplus_dev/docs/peps/call_wrapper_policies.rest Deleted: pyplusplus_dev/docs/peps/call_wrapper_policies.rest =================================================================== --- pyplusplus_dev/docs/peps/call_wrapper_policies.rest 2006-09-04 10:09:55 UTC (rev 521) +++ pyplusplus_dev/docs/peps/call_wrapper_policies.rest 2006-09-05 12:33:56 UTC (rev 522) @@ -1,254 +0,0 @@ -===================== -call wrapper policies -===================== - -.. contents:: Table of contents - -------------------- -What is useful for? -------------------- -Not all C++ functions could be exposed to Python as is. For example, next function -could not be exposed: -:: - - void get_size( int& size ); - -In order to expose ``get_size`` function, an user need to create next wrapper: -:: - - int get_size_wrapper( ){ - int size(0); - get_size( size ); - return size; - } - -|cwp| will provide the user with simple and intuitive way to instruct -`Py++`_ to generate right wrapper. Also, it will be possible to create -a custom policies. - -This document describes what is *going to be implemented*. - --------- -Analysis --------- - -C++ function arguments usage ----------------------------- - -In C++ function argument can be used to: - -* to pass some data to function ( in ) - - there is no need to return variable from the function - -* to return some data from function ( out ) - - there is no need to force Python programmer to pass the variable as argument - to the function - -* both ( in/out ) - -Function-wrapper signature will be a little bit different in every case. - -Variable names --------------- -I think it should be possible to apply few |cwp| on a single function. -The main, (read unresolved) issue, is management of variable names within -function-wrapper. I see next problems, which we should solve, before proceeding -to implementation: - -1. To share variable name, between different pieces of code. - - Right now I think, that every |cwp| will have ``pre-call`` and ``post-call`` - code creators. This design will allow the user to mix few |cwp|'s within - single function-wrapper. - -2. To insure name uniqueness. - -3. To give meaningful name. - -I think that is it very easy to solve the problem, if I remove "readability" -requirement. - -Call policies -------------- -I don't have any solution to the next problem. -I am going to change a little an example, from `Boost.Python`_ tutorials: -http://www.boost.org/libs/python/doc/tutorial/doc/html/python/functions.html#python.call_policies -:: - - //C++ code - struct Y - { - X x; Z* z; - int z_value() { return z->value(); } - }; - - X& f(Y& y, Z* z, int& error) - { - y.z = z; - return y.x; - } - - //Boost.Python code - def("f", f, return_internal_reference<1, with_custodian_and_ward<1, 2> >() ); - -What is the difference? Function ``f`` now takes 3rd argument - ``int&``. This -function could not be called from `Python`_. (Hint: numbers are immutable -objects in `Python`_ ). So in order to expose function ``f`` to `Python`_, -an user need to create a wrapper. And now he has a problem: how to wrap the function? - -I see only one solution user have to change signature of function ``f``. -Now some speculations: - -1. May be it is possible with `Boost.Python`_ library to set call policies on the - part of the return value? - :: - - boost::tuple f_wrapper( Y& y, Z* z ){ - int error(0); - X& x = f( y, z, error ); - return boost::tuple<X&, int>( x, error ); - } - - def("f", f_wrapper, smart call policies that will work only on first element within the tuple ); - -2. May be it is possible to create Boost.Python ``object`` with life-time management - hint? - :: - - boost::python::tuple f_wrapper( Y& y, Z* z ){ - int error(0); - X& x = f( y, z, error ); - boost::python::object x_obj( x, x is internal reference of y ); - return boost::python::make_tuple( x_obj, error ); - } - -Anyway, I think we will just ignore the problem - software ( == Boost.Python ) -should not be perfect - it should work in most ( != all ) cases! - ------------- -Common |cwp| ------------- -Those names are not final and could( may be should ) be changed. - -immutable by reference ------------------------ -:: - - //function to be exported - something f( int& i, std::string& str ) - -I suppose this is very common use case. More over this use case `Py++`_ -can and will treat by its own - no user action is needed. The wrapper -generated by `Py++`_ will very similar to the next code: -:: - - void f_wrapper( const int& i, const std::string& str ){ - int i_out( i ); - std::string str_out( str ); - boost::python::object f_return = f( i_out, str_out ); - return boost::python::make_tuple( f_return, i, str ); - } - - -The only customization available for user is to setup argument type: -[in\|out\|in,out] - -array ------ -Arrays are a little bit different beasts. Python does not have arrays. -So, `Py++`_, should implement arrays convertion: from/to C++/Python. -This is not the only difference, consider next function: -:: - - void fill( char* buffer, int index ){ - buffer[ index ] = 'c'; - } - - -There are few ways to expose this function: -:: - - ??? fill_wrapper( boost::python:list buffer, index ){ - long buffer_size = boost::python::extract<long>( buffer.attr("__len__") ); - boost::scoped_array<char> buffer_( new char[ buffer_size ] ); - for( long i = 0; i < buffer_size; ++i ){ - buffer_[ i ] = boost::python::extract<char>( buffer[i] ); - } - fill( buffer_.get(), index ); - //Now the question: how to return buffer_ to the caller? - //by constructing new list? - boost::python::list return_; - for( long i = 0; i < buffer_size; ++i ){ - return_.insert( i, buffer_[i] ); - } - return return_; - //or by modifying the buffer argument? In this case `Py++`_ will - //delete all items from buffer and will copy into it items from buffer_ - //variable. - } - -Arrays size -^^^^^^^^^^^ -1. static array - size of array is known at compile time. -2. dynamic array - - + size of array is one of the function arguments - - + other ( will not be implemented in the first phase ) - - - size of array is some global/local variable - - - size of array is returned by invocation some function - - -status as exception -------------------- -There a lot of code, that returns success status and/or error description by -using one of the function arguments. It will be possible to instruct `Py++`_ -to create wrapper for those functions, that will throw exception. -:: - - bool do_smth( error_description& error_desc ); - - bool do_smth_wrapper(){ - error_description error_desc; - bool return_ = do_smth( error_desc ); - if( some user code that will check that error_desc contains error ){ - throw some user code that will construct an exception from the error_desc; - } - return return_; - } - -pythread safe -------------- -Why not :-)? See next FAQ: http://boost.org/libs/python/doc/v2/faq.html#threadsupport -So, how `Py++`_ can help? `Py++`_ can generate exception safe code, -that will acquire and release Python global interpreter lock. - -------- -Summary -------- - -It still not clear to me how it should be implemented. There are also some issues -with `Boost.Python`_ library before we can implement some policies. - -If you can help or have some nice idea, please share: -https://lists.sourceforge.net/lists/listinfo/pygccxml-development - - -.. _`Py++` : ./../pyplusplus.html -.. |cwp| replace:: *"call wrapper policies"* -.. _`Boost.Python`: http://www.boost.org/libs/python/doc/index.html -.. _`Python`: http://www.python.org -.. _`GCC-XML`: http://www.gccxml.org - -.. - Local Variables: - mode: indented-text - indent-tabs-mode: nil - sentence-end-double-space: t - fill-column: 70 - End: - Modified: pyplusplus_dev/docs/peps/function_transformation.rest =================================================================== --- pyplusplus_dev/docs/peps/function_transformation.rest 2006-09-04 10:09:55 UTC (rev 521) +++ pyplusplus_dev/docs/peps/function_transformation.rest 2006-09-05 12:33:56 UTC (rev 522) @@ -1,78 +1,209 @@ -===================== -call wrapper policies -===================== +======================== +Function transformation +======================== .. contents:: Table of contents ------------------- What is useful for? ------------------- -Not all C++ functions could be exposed to Python as is. For example, next function -could not be exposed: + +https://realityforge.vrsource.org/view/PyppApi/CodeInserter gives a nice introduction +and the problem description. Please read it. + +----------- +Terminology +----------- + +Lets say that we have a function ``f``: + :: - void get_size( int& size ); + f = R f( A0 a0, ..., AN an ) -In order to expose ``get_size`` function, an user need to create next wrapper: +``R`` and ``A*`` represent an arbitrary C++ types. What we want is to create +another function ``ft`` (transformed): + :: - int get_size_wrapper( ){ - int size(0); - get_size( size ); - return size; - } + ft = RT ft( AT0 at0, ..., ATM atm ) -|cwp| will provide the user with simple and intuitive way to instruct -`Py++`_ to generate right wrapper. Also, it will be possible to create -a custom policies. +such that will do an additional work before and after ``f`` call. -This document describes what is *going to be implemented*. +Definitions +----------- --------- -Analysis --------- +*Transformation* - process that defines how to create transformed function from the +original one. -C++ function arguments usage ----------------------------- +For example - ``make function argument to be return value``: +:: -In C++ function argument can be used to: + f = void get_last_error( int& error ); -* to pass some data to function ( in ) +:: - there is no need to return variable from the function + ft = int get_last_error(); -* to return some data from function ( out ) +The definition of ``ft`` could look like: +:: - there is no need to force Python programmer to pass the variable as argument - to the function + int get_last_error_transformed(){ + int error(0); + get_last_error( error ); + return error; + } -* both ( in/out ) +I modified ``f`` signature and added some code before and after ``f`` call. -Function-wrapper signature will be a little bit different in every case. +*Function transformation* - group of transformations that should be applied at once +on a function. -Variable names +For example a function could have two immutable arguments, passed by reference. +Function transformation aggregates two transformations. + +A user will be able to define few function transformations for a single function. + +----------------------- +Design & implementation +----------------------- + +In the previous paragraph I introduced two new concepts: "transformation" and +"function transformation". These concepts should be presented in the solution. + + +Transformation -------------- -I think it should be possible to apply few |cwp| on a single function. -The main, (read unresolved) issue, is management of variable names within -function-wrapper. I see next problems, which we should solve, before proceeding -to implementation: -1. To share variable name, between different pieces of code. +Transformation class has two responsibilities: - Right now I think, that every |cwp| will have ``pre-call`` and ``post-call`` - code creators. This design will allow the user to mix few |cwp|'s within - single function-wrapper. +1. to modify function signature: -2. To insure name uniqueness. + * remove argument + * change argument type + * join arguments + * change return type -3. To give meaningful name. +2. to implement the transformation -I think that is it very easy to solve the problem, if I remove "readability" -requirement. +It is important to distinct between the responsibilities. Function signature +defines "interface" for a lot of services provided by `Py++`_. While the second +one is "implementation details" and should be "hidden" from the rest of the world. +In an ideal world we would have 2 classes, one class - one responsibility. +In `Py++`_ it means that we would have ``transformation_t`` class: +:: + + class transformation_t( object ): + def __init__( self ): + pass + + def check( self, function ): + "checks whether the transformation could be applied on the function or not" + raise NotImplementedError() + + def signature_changes( self, function ): + "returns a list of changes that should be done on function signature" + raise NotImplementedError() + +The class logically belongs to the ``decl_wrappers`` package. The ``transformer_t`` +is the second class, which logically belongs to ``code_creators`` package: +:: + + class transformer_t( ast_visitor_t ): + def __init__( self, function, transformation ): + function is a reference to the declaration we want to apply transformation on + transformation is an instance of "concrete" transformation + + def apply( self, function_body_as_tree ): + "integrates transformation code to function body" + raise NotImplementedError() + +What is ``ast_visitor_t`` and ``function_body_as_tree``. In an ideal world +concrete instance of ``transformer_t`` class would work with some kind of AST +( Abstract Syntax Tree ). Thus transformer would travel on the tree and modify it. + +Get the job done! +----------------- + +The previously described solution will not work in our, `Py++`_ developers and +users, world. There are mainly two reasons: + +1. AST approach is tooooooo complex. We don't have time to develop an AST for + representing, even limited subset of C++ expressions. Users will not have + time to learn how to use it. + +2. Class separation approach will not work too. In order to introduce new + transformation, user will have to understand the whole design of the `Py++`_ + package. + +Matthias Baas provided a "real world" solution for both problems. At first I did +not understand it, but now I appreciate it very much. It does not meant that I +agree with the his implementation. As for me he did not stress enough the +concepts within the code and more over he mixed them in different classes. + +I am going to propose another solution, which will be based on existing code. +Small re-factoring is needed. I don't expect changes in the user code. + +Proposed class: +:: + + class transformer_t( object ): + "base class for all transformation classes" + def __init__( self ): + pass + + def check( self, function ): + "checks whether the transformation could be applied on the function or not" + raise NotImplementedError() + + def signature_changes( self, function ): + "returns a list of changes that should be done on function signature" + raise NotImplementedError() + + def apply( self, sm ): #sm is an instance of the substitution manager + "integrates transformation code into function transformation body" + raise NotImplementedError() + +Comments: + +1. ``substituion_manager_t`` class allows us to achieve same result as with AST. + he way it does it is pretty simple to explain and understand - string + substitution. + +2. ``transformer_t`` class allows user to introduce new transformations, without + understanding the whole `Py++`_ package. + +Function trasformation +~~~~~~~~~~~~~~~~~~~~~~ + +What is responcibility of the ``function_transformation_t`` class? + +1. To keep reference to transformations defined by the user. + +2. To apply every transformation on the function body. For this purpose this + class will keep instance of ``substituion_manager_t`` class. + +3. To provide interface for ``mem_fun_v_transformed_t`` and + ``mem_fun_v_transformed_wrapper_t`` code creators classes. + +4. [Nice to have]To check, whether the transformation defined by user is + applicable or not. + +Somewhere we should put "function transformation" factory. This factory will +create or give a hint to the user what transformation could\\should be applied +on the function. + + +----------------- +Problems to solve +----------------- + +I don't have any solution to the next problems. + Call policies ------------- -I don't have any solution to the next problem. + I am going to change a little an example, from `Boost.Python`_ tutorials: http://www.boost.org/libs/python/doc/tutorial/doc/html/python/functions.html#python.call_policies :: @@ -124,122 +255,7 @@ return boost::python::make_tuple( x_obj, error ); } -Anyway, I think we will just ignore the problem - software ( == Boost.Python ) -should not be perfect - it should work in most ( != all ) cases! - ------------- -Common |cwp| ------------- -Those names are not final and could( may be should ) be changed. - -immutable by reference ------------------------ -:: - - //function to be exported - something f( int& i, std::string& str ) - -I suppose this is very common use case. More over this use case `Py++`_ -can and will treat by its own - no user action is needed. The wrapper -generated by `Py++`_ will very similar to the next code: -:: - - void f_wrapper( const int& i, const std::string& str ){ - int i_out( i ); - std::string str_out( str ); - boost::python::object f_return = f( i_out, str_out ); - return boost::python::make_tuple( f_return, i, str ); - } - - -The only customization available for user is to setup argument type: -[in\|out\|in,out] - -array ------ -Arrays are a little bit different beasts. Python does not have arrays. -So, `Py++`_, should implement arrays convertion: from/to C++/Python. -This is not the only difference, consider next function: -:: - - void fill( char* buffer, int index ){ - buffer[ index ] = 'c'; - } - - -There are few ways to expose this function: -:: - - ??? fill_wrapper( boost::python:list buffer, index ){ - long buffer_size = boost::python::extract<long>( buffer.attr("__len__") ); - boost::scoped_array<char> buffer_( new char[ buffer_size ] ); - for( long i = 0; i < buffer_size; ++i ){ - buffer_[ i ] = boost::python::extract<char>( buffer[i] ); - } - fill( buffer_.get(), index ); - //Now the question: how to return buffer_ to the caller? - //by constructing new list? - boost::python::list return_; - for( long i = 0; i < buffer_size; ++i ){ - return_.insert( i, buffer_[i] ); - } - return return_; - //or by modifying the buffer argument? In this case `Py++`_ will - //delete all items from buffer and will copy into it items from buffer_ - //variable. - } - -Arrays size -^^^^^^^^^^^ -1. static array - size of array is known at compile time. -2. dynamic array - - + size of array is one of the function arguments - - + other ( will not be implemented in the first phase ) - - - size of array is some global/local variable - - - size of array is returned by invocation some function - - -status as exception -------------------- -There a lot of code, that returns success status and/or error description by -using one of the function arguments. It will be possible to instruct `Py++`_ -to create wrapper for those functions, that will throw exception. -:: - - bool do_smth( error_description& error_desc ); - - bool do_smth_wrapper(){ - error_description error_desc; - bool return_ = do_smth( error_desc ); - if( some user code that will check that error_desc contains error ){ - throw some user code that will construct an exception from the error_desc; - } - return return_; - } - -pythread safe -------------- -Why not :-)? See next FAQ: http://boost.org/libs/python/doc/v2/faq.html#threadsupport -So, how `Py++`_ can help? `Py++`_ can generate exception safe code, -that will acquire and release Python global interpreter lock. - -------- -Summary -------- - -It still not clear to me how it should be implemented. There are also some issues -with `Boost.Python`_ library before we can implement some policies. - -If you can help or have some nice idea, please share: -https://lists.sourceforge.net/lists/listinfo/pygccxml-development - - .. _`Py++` : ./../pyplusplus.html -.. |cwp| replace:: *"call wrapper policies"* .. _`Boost.Python`: http://www.boost.org/libs/python/doc/index.html .. _`Python`: http://www.python.org .. _`GCC-XML`: http://www.gccxml.org Modified: pyplusplus_dev/docs/peps/www_configuration.py =================================================================== --- pyplusplus_dev/docs/peps/www_configuration.py 2006-09-04 10:09:55 UTC (rev 521) +++ pyplusplus_dev/docs/peps/www_configuration.py 2006-09-05 12:33:56 UTC (rev 522) @@ -1,5 +1,5 @@ name = 'PEP index' main_html_file = 'peps_index.html' files_to_skip = ['dsl_challenge_introduction.rest'] -names = { 'call_wrapper_policies' : 'call wrapper policies' +names = { 'function_transformation' : 'function transformation' , 'dsl_challenge' : 'DSL challenge' } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <rom...@us...> - 2006-09-04 10:10:07
|
Revision: 521 http://svn.sourceforge.net/pygccxml/?rev=521&view=rev Author: roman_yakovenko Date: 2006-09-04 03:09:55 -0700 (Mon, 04 Sep 2006) Log Message: ----------- renaming the document Added Paths: ----------- pyplusplus_dev/docs/peps/function_transformation.rest Copied: pyplusplus_dev/docs/peps/function_transformation.rest (from rev 518, pyplusplus_dev/docs/peps/call_wrapper_policies.rest) =================================================================== --- pyplusplus_dev/docs/peps/function_transformation.rest (rev 0) +++ pyplusplus_dev/docs/peps/function_transformation.rest 2006-09-04 10:09:55 UTC (rev 521) @@ -0,0 +1,254 @@ +===================== +call wrapper policies +===================== + +.. contents:: Table of contents + +------------------- +What is useful for? +------------------- +Not all C++ functions could be exposed to Python as is. For example, next function +could not be exposed: +:: + + void get_size( int& size ); + +In order to expose ``get_size`` function, an user need to create next wrapper: +:: + + int get_size_wrapper( ){ + int size(0); + get_size( size ); + return size; + } + +|cwp| will provide the user with simple and intuitive way to instruct +`Py++`_ to generate right wrapper. Also, it will be possible to create +a custom policies. + +This document describes what is *going to be implemented*. + +-------- +Analysis +-------- + +C++ function arguments usage +---------------------------- + +In C++ function argument can be used to: + +* to pass some data to function ( in ) + + there is no need to return variable from the function + +* to return some data from function ( out ) + + there is no need to force Python programmer to pass the variable as argument + to the function + +* both ( in/out ) + +Function-wrapper signature will be a little bit different in every case. + +Variable names +-------------- +I think it should be possible to apply few |cwp| on a single function. +The main, (read unresolved) issue, is management of variable names within +function-wrapper. I see next problems, which we should solve, before proceeding +to implementation: + +1. To share variable name, between different pieces of code. + + Right now I think, that every |cwp| will have ``pre-call`` and ``post-call`` + code creators. This design will allow the user to mix few |cwp|'s within + single function-wrapper. + +2. To insure name uniqueness. + +3. To give meaningful name. + +I think that is it very easy to solve the problem, if I remove "readability" +requirement. + +Call policies +------------- +I don't have any solution to the next problem. +I am going to change a little an example, from `Boost.Python`_ tutorials: +http://www.boost.org/libs/python/doc/tutorial/doc/html/python/functions.html#python.call_policies +:: + + //C++ code + struct Y + { + X x; Z* z; + int z_value() { return z->value(); } + }; + + X& f(Y& y, Z* z, int& error) + { + y.z = z; + return y.x; + } + + //Boost.Python code + def("f", f, return_internal_reference<1, with_custodian_and_ward<1, 2> >() ); + +What is the difference? Function ``f`` now takes 3rd argument - ``int&``. This +function could not be called from `Python`_. (Hint: numbers are immutable +objects in `Python`_ ). So in order to expose function ``f`` to `Python`_, +an user need to create a wrapper. And now he has a problem: how to wrap the function? + +I see only one solution user have to change signature of function ``f``. +Now some speculations: + +1. May be it is possible with `Boost.Python`_ library to set call policies on the + part of the return value? + :: + + boost::tuple f_wrapper( Y& y, Z* z ){ + int error(0); + X& x = f( y, z, error ); + return boost::tuple<X&, int>( x, error ); + } + + def("f", f_wrapper, smart call policies that will work only on first element within the tuple ); + +2. May be it is possible to create Boost.Python ``object`` with life-time management + hint? + :: + + boost::python::tuple f_wrapper( Y& y, Z* z ){ + int error(0); + X& x = f( y, z, error ); + boost::python::object x_obj( x, x is internal reference of y ); + return boost::python::make_tuple( x_obj, error ); + } + +Anyway, I think we will just ignore the problem - software ( == Boost.Python ) +should not be perfect - it should work in most ( != all ) cases! + +------------ +Common |cwp| +------------ +Those names are not final and could( may be should ) be changed. + +immutable by reference +----------------------- +:: + + //function to be exported + something f( int& i, std::string& str ) + +I suppose this is very common use case. More over this use case `Py++`_ +can and will treat by its own - no user action is needed. The wrapper +generated by `Py++`_ will very similar to the next code: +:: + + void f_wrapper( const int& i, const std::string& str ){ + int i_out( i ); + std::string str_out( str ); + boost::python::object f_return = f( i_out, str_out ); + return boost::python::make_tuple( f_return, i, str ); + } + + +The only customization available for user is to setup argument type: +[in\|out\|in,out] + +array +----- +Arrays are a little bit different beasts. Python does not have arrays. +So, `Py++`_, should implement arrays convertion: from/to C++/Python. +This is not the only difference, consider next function: +:: + + void fill( char* buffer, int index ){ + buffer[ index ] = 'c'; + } + + +There are few ways to expose this function: +:: + + ??? fill_wrapper( boost::python:list buffer, index ){ + long buffer_size = boost::python::extract<long>( buffer.attr("__len__") ); + boost::scoped_array<char> buffer_( new char[ buffer_size ] ); + for( long i = 0; i < buffer_size; ++i ){ + buffer_[ i ] = boost::python::extract<char>( buffer[i] ); + } + fill( buffer_.get(), index ); + //Now the question: how to return buffer_ to the caller? + //by constructing new list? + boost::python::list return_; + for( long i = 0; i < buffer_size; ++i ){ + return_.insert( i, buffer_[i] ); + } + return return_; + //or by modifying the buffer argument? In this case `Py++`_ will + //delete all items from buffer and will copy into it items from buffer_ + //variable. + } + +Arrays size +^^^^^^^^^^^ +1. static array - size of array is known at compile time. +2. dynamic array + + + size of array is one of the function arguments + + + other ( will not be implemented in the first phase ) + + - size of array is some global/local variable + + - size of array is returned by invocation some function + + +status as exception +------------------- +There a lot of code, that returns success status and/or error description by +using one of the function arguments. It will be possible to instruct `Py++`_ +to create wrapper for those functions, that will throw exception. +:: + + bool do_smth( error_description& error_desc ); + + bool do_smth_wrapper(){ + error_description error_desc; + bool return_ = do_smth( error_desc ); + if( some user code that will check that error_desc contains error ){ + throw some user code that will construct an exception from the error_desc; + } + return return_; + } + +pythread safe +------------- +Why not :-)? See next FAQ: http://boost.org/libs/python/doc/v2/faq.html#threadsupport +So, how `Py++`_ can help? `Py++`_ can generate exception safe code, +that will acquire and release Python global interpreter lock. + +------- +Summary +------- + +It still not clear to me how it should be implemented. There are also some issues +with `Boost.Python`_ library before we can implement some policies. + +If you can help or have some nice idea, please share: +https://lists.sourceforge.net/lists/listinfo/pygccxml-development + + +.. _`Py++` : ./../pyplusplus.html +.. |cwp| replace:: *"call wrapper policies"* +.. _`Boost.Python`: http://www.boost.org/libs/python/doc/index.html +.. _`Python`: http://www.python.org +.. _`GCC-XML`: http://www.gccxml.org + +.. + Local Variables: + mode: indented-text + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + End: + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mb...@us...> - 2006-09-04 09:51:11
|
Revision: 520 http://svn.sourceforge.net/pygccxml/?rev=520&view=rev Author: mbaas Date: 2006-09-04 02:51:08 -0700 (Mon, 04 Sep 2006) Log Message: ----------- Ignore *.pyc files Property Changed: ---------------- pyplusplus_dev/pyplusplus/function_transformers/ Property changes on: pyplusplus_dev/pyplusplus/function_transformers ___________________________________________________________________ Name: svn:ignore + *.pyc This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mb...@us...> - 2006-09-04 09:50:39
|
Revision: 519 http://svn.sourceforge.net/pygccxml/?rev=519&view=rev Author: mbaas Date: 2006-09-04 02:50:33 -0700 (Mon, 04 Sep 2006) Log Message: ----------- Renamed attributes and variables so that individual words are separated by underscores. Modified Paths: -------------- pyplusplus_dev/pyplusplus/function_transformers/arg_policies.py pyplusplus_dev/pyplusplus/function_transformers/code_manager.py pyplusplus_dev/pyplusplus/function_transformers/substitution_manager.py Modified: pyplusplus_dev/pyplusplus/function_transformers/arg_policies.py =================================================================== --- pyplusplus_dev/pyplusplus/function_transformers/arg_policies.py 2006-09-04 08:16:39 UTC (rev 518) +++ pyplusplus_dev/pyplusplus/function_transformers/arg_policies.py 2006-09-04 09:50:33 UTC (rev 519) @@ -29,7 +29,7 @@ @type idx: int """ self.idx = idx - self.localvar = "<not initialized>" + self.local_var = "<not initialized>" def __str__(self): return "Output(%d)"%(self.idx) @@ -46,25 +46,25 @@ raise ValueError, 'Output variable %d ("%s") must be a reference or a pointer (got %s)'%(self.idx, arg.name, arg.type) # Declare a local variable that will receive the output value - self.localvar = sm.wrapperfunc.declare_local(arg.name, str(reftype.base)) + self.local_var = sm.wrapper_func.declare_local(arg.name, str(reftype.base)) # Append the output to the result tuple - sm.wrapperfunc.resultexprs.append(self.localvar) + sm.wrapper_func.result_exprs.append(self.local_var) # Replace the expression in the C++ function call if isinstance(reftype, declarations.pointer_t): - sm.wrapperfunc.inputparams[self.idx-1] = "&%s"%self.localvar + sm.wrapper_func.input_params[self.idx-1] = "&%s"%self.local_var else: - sm.wrapperfunc.inputparams[self.idx-1] = self.localvar + sm.wrapper_func.input_params[self.idx-1] = self.local_var def virtual_post_call(self, sm): """Extract the C++ value after the call to the Python function. """ - arg = sm.virtualfunc.arglist[self.idx-1] + arg = sm.virtual_func.arg_list[self.idx-1] res = "// Extract the C++ value for output argument '%s' (index: %d)\n"%(arg.name, self.idx) if isinstance(arg.type, declarations.pointer_t): res += "*" - res += "%s = boost::python::extract<%s>(%s[%d]);"%(arg.name, arg.type.base, sm.virtualfunc.resultvar, sm.wrapperfunc.resultexprs.index(self.localvar)) + res += "%s = boost::python::extract<%s>(%s[%d]);"%(arg.name, arg.type.base, sm.virtual_func.result_var, sm.wrapper_func.result_exprs.index(self.local_var)) return res Modified: pyplusplus_dev/pyplusplus/function_transformers/code_manager.py =================================================================== --- pyplusplus_dev/pyplusplus/function_transformers/code_manager.py 2006-09-04 08:16:39 UTC (rev 518) +++ pyplusplus_dev/pyplusplus/function_transformers/code_manager.py 2006-09-04 09:50:33 UTC (rev 519) @@ -22,26 +22,26 @@ A code block can declare a local variable using L{declare_local()} and it can manipulate one of the attributes that are used to initialize the final variables (see the documentation of the - instance variables below). The final variables (such as RETTYPE, - FUNCNAME, ARGLIST, etc.) are stored as regular attributes of the + instance variables below). The final variables (such as RET_TYPE, + FUNC_NAME, ARG_LIST, etc.) are stored as regular attributes of the object. The functionality to perform a text substitution (using the substitution() method) is inherited from the class L{subst_t}. - @ivar classname: The name of the class of which the generated function is a member. A value of None or an empty string is used for free functions. This attribute is used for creating the CLASSSPEC variable. - @type classname: str - @ivar rettype: Return type. The value may be any object where str(obj) is valid C++ code. The value None corresponds to void. This will be the value of the variable RETTYPE. - @type rettype: str - @ivar arglist: The argument list. The items are pygccxml argument_t objects. This list will appear in the variables ARGLIST, ARGLISTDEF and ARGLISTTYPES. - @type arglist: list of argument_t - @ivar inputparams: A list of strings that contain the input parameter for the function call. This list is used for the INPUTPARAMS variable. - @type inputparams: list of str - @ivar resultvar: The name of the variable that will receive the result of the function call. If None, the return value is ignored. This attribute will be used for the variable RESULTVARASSIGNMENT. - @type resultvar: str - @ivar resultexpr: A string containing the expression that will be put after the "return" statement. This expression is used for the variable RETURNSTMT. - @type resultexpr: str + @ivar class_name: The name of the class of which the generated function is a member. A value of None or an empty string is used for free functions. This attribute is used for creating the CLASS_SPEC variable. + @type class_name: str + @ivar ret_type: Return type. The value may be any object where str(obj) is valid C++ code. The value None corresponds to void. This will be the value of the variable RET_TYPE. + @type ret_type: str + @ivar arg_list: The argument list. The items are pygccxml argument_t objects. This list will appear in the variables ARG_LIST, ARG_LIST_DEF and ARG_LIST_TYPES. + @type arg_list: list of argument_t + @ivar input_params: A list of strings that contain the input parameter for the function call. This list is used for the INPUT_PARAMS variable. + @type input_params: list of str + @ivar result_var: The name of the variable that will receive the result of the function call. If None, the return value is ignored. This attribute will be used for the variable RESULT_VAR_ASSIGNMENT. + @type result_var: str + @ivar result_expr: A string containing the expression that will be put after the "return" statement. This expression is used for the variable RETURN_STMT. + @type result_expr: str @author: Matthias Baas """ @@ -50,30 +50,30 @@ """Constructor. """ subst_t.__init__(self, blockvars=["DECLARATIONS", - "PRECALL", - "POSTCALL"]) + "PRE_CALL", + "POST_CALL"]) # The name of the class of which the generated function is a member # (pass None or an empty string if the function is a free function) - self.classname = None + self.class_name = None # Return type (the value may be any object where str(obj) is valid # C++ code. The value None corresponds to "void"). - self.rettype = None + self.ret_type = None # The argument list. The items are argument_t objects. - self.arglist = [] + self.arg_list = [] # A list of strings that contain the input parameter for the # function call - self.inputparams = [] + self.input_params = [] # The name of the variable that will receive the result of the # function call. If None, the return value is ignored. - self.resultvar = None + self.result_var = None # A string containing the expression that will be put after # the "return" statement. - self.resultexpr = None + self.result_expr = None # Key:Variable name / Value:(type,size,default) self._declared_vars = {} @@ -110,7 +110,7 @@ """ if name in self._declared_vars: return True - if filter(lambda a: a.name==name, self.arglist): + if filter(lambda a: a.name==name, self.arg_list): return True return False @@ -140,29 +140,29 @@ attributes. """ - # CLASSSPEC - if (self.classname in [None, ""]): - self.CLASSSPEC = "" + # CLASS_SPEC + if (self.class_name in [None, ""]): + self.CLASS_SPEC = "" else: - self.CLASSSPEC = "%s::"%self.classname + self.CLASS_SPEC = "%s::"%self.class_name - # RETTYPE - if self.rettype==None: - self.RETTYPE = "void" + # RET_TYPE + if self.ret_type==None: + self.RET_TYPE = "void" else: - self.RETTYPE = str(self.rettype) + self.RET_TYPE = str(self.ret_type) - # ARGLISTDEF - args = map(lambda a: str(a), self.arglist) - self.ARGLISTDEF = ", ".join(args) + # ARG_LIST_DEF + args = map(lambda a: str(a), self.arg_list) + self.ARG_LIST_DEF = ", ".join(args) - # ARGLIST + # ARG_LIST args = map(lambda s: s.split("=")[0], args) - self.ARGLIST = ", ".join(args) + self.ARG_LIST = ", ".join(args) - # ARGLISTTYPES - args = map(lambda a: str(a.type), self.arglist) - self.ARGLISTTYPES = ", ".join(args) + # ARG_LIST_TYPES + args = map(lambda a: str(a.type), self.arg_list) + self.ARG_LIST_TYPES = ", ".join(args) # Create the declaration block -> DECLARATIONS vardecls = [] @@ -176,16 +176,16 @@ vardecls.append(vd+";") self.DECLARATIONS = "\n".join(vardecls) - # RESULTVARASSIGNMENT - if self.resultvar!=None: - self.RESULTVARASSIGNMENT = "%s = "%self.resultvar + # RESULT_VAR_ASSIGNMENT + if self.result_var!=None: + self.RESULT_VAR_ASSIGNMENT = "%s = "%self.result_var - # INPUTPARAMS - self.INPUTPARAMS = ", ".join(self.inputparams) + # INPUT_PARAMS + self.INPUT_PARAMS = ", ".join(self.input_params) - # RETURNSTMT - if self.resultexpr!=None: - self.RETURNSTMT = "return %s;"%self.resultexpr + # RETURN_STMT + if self.result_expr!=None: + self.RETURN_STMT = "return %s;"%self.result_expr # _make_name_unique def _make_name_unique(self, name): @@ -212,12 +212,12 @@ """The CodeManager class for the wrapper function. In contrast to a regular C++ function a Python function can return - several values, so this class provides the extra attribute "resultexprs" + several values, so this class provides the extra attribute "result_exprs" which is a list of individual expressions. Apart from that this class is identical to L{code_manager_t}. - @ivar resultexprs: Similar to resultexpr but this list variable can contain more than just one result. The items can be either strings containing the variable names (or expressions) that should be returned or it can be an argument_t object (usually from the argument list of the virtual function) whose name attribute will be used. This attribute only exists on the code manager for the wrapper function (the virtual function cannot return several values, use resultexpr instead). - @type resultexprs: list of str or argument_t + @ivar result_exprs: Similar to result_expr but this list variable can contain more than just one result. The items can be either strings containing the variable names (or expressions) that should be returned or it can be an argument_t object (usually from the argument list of the virtual function) whose name attribute will be used. This attribute only exists on the code manager for the wrapper function (the virtual function cannot return several values, use result_expr instead). + @type result_exprs: list of str or argument_t """ def __init__(self): @@ -225,41 +225,41 @@ """ code_manager_t.__init__(self) - # Similar to resultexpr but now there can be more than just one result + # Similar to result_expr but now there can be more than just one result # The items can be either strings containing the variable names (or # expressions) that should be returned or it can be an argument_t # object (usually from the argument list of the virtual function) # whose name attribute will be used. - self.resultexprs = [] + self.result_exprs = [] def init_variables(self): """Initialize the substitution variables. """ - # Prepare the variables for RETTYPE and RETURNSTMT... + # Prepare the variables for RET_TYPE and RETURN_STMT... # Convert all items into strings - resultexprs = [] - for re in self.resultexprs: + result_exprs = [] + for re in self.result_exprs: # String? if isinstance(re, types.StringTypes): - resultexprs.append(re) + result_exprs.append(re) # argument_t else: - resultexprs.append(re.name) + result_exprs.append(re.name) # No output values? - if len(resultexprs)==0: - self.rettype = None - self.resultexpr = None + if len(result_exprs)==0: + self.ret_type = None + self.result_expr = None # Exactly one output value? - elif len(resultexprs)==1: - self.rettype = "boost::python::object" - self.resultexpr = "boost::python::object(%s)"%resultexprs[0] + elif len(result_exprs)==1: + self.ret_type = "boost::python::object" + self.result_expr = "boost::python::object(%s)"%result_exprs[0] # More than one output value... else: - self.rettype = "boost::python::object" - self.resultexpr = "boost::python::make_tuple(%s)"%(", ".join(resultexprs)) + self.ret_type = "boost::python::object" + self.result_expr = "boost::python::make_tuple(%s)"%(", ".join(result_exprs)) # Invoke the inherited method that sets the actual variables code_manager_t.init_variables(self) Modified: pyplusplus_dev/pyplusplus/function_transformers/substitution_manager.py =================================================================== --- pyplusplus_dev/pyplusplus/function_transformers/substitution_manager.py 2006-09-04 08:16:39 UTC (rev 518) +++ pyplusplus_dev/pyplusplus/function_transformers/substitution_manager.py 2006-09-04 09:50:33 UTC (rev 519) @@ -29,17 +29,17 @@ entire wrapper function. Such a template string may look like this:: - $RETTYPE $CLASSSPEC$FUNCNAME($ARGLIST) + $RET_TYPE $CLASS_SPEC$FUNC_NAME($ARG_LIST) { $DECLARATIONS - $PRECALL + $PRE_CALL - $RESULTVARASSIGNMENT$CALLFUNCNAME($INPUTPARAMS); + $RESULT_VAR_ASSIGNMENT$CALL_FUNC_NAME($INPUT_PARAMS); - $POSTCALL + $POST_CALL - $RETURNSTMT + $RETURN_STMT } Any part of the function that is not fixed, i.e. that can be @@ -65,17 +65,17 @@ In this example, the individual variables have the following values: - - RETTYPE = C{boost::python::object} - - CLASSSPEC = C{Spam_wrapper::} - - FUNCNAME = C{foo_wrapper} - - ARGLIST = C{Spam& self, int mode} + - RET_TYPE = C{boost::python::object} + - CLASS_SPEC = C{Spam_wrapper::} + - FUNC_NAME = C{foo_wrapper} + - ARG_LIST = C{Spam& self, int mode} - DECLARATIONS = C{int result;\\nint w;\\nint h;} - - PRECALL = <empty> - - RESULTVARASSIGNMENT = C{result =} - - CALLFUNCNAME = C{self.foo} - - INPUTPARAMS = C{w, &h, mode} - - POSTCALL = <empty> - - RETURNSTMT = C{return boost::python::make_tuple(result, w, h);} + - PRE_CALL = <empty> + - RESULT_VAR_ASSIGNMENT = C{result =} + - CALL_FUNC_NAME = C{self.foo} + - INPUT_PARAMS = C{w, &h, mode} + - POST_CALL = <empty> + - RETURN_STMT = C{return boost::python::make_tuple(result, w, h);} Modifying the variables @@ -84,11 +84,11 @@ In addition to the actual user of the class (who wants to do text substitutions), the class is also used by the arg policies (code blocks) to modify the variables. - There are two attributes L{wrapperfunc} and L{virtualfunc} that are + There are two attributes L{wrapper_func} and L{virtual_func} that are used to modify either the wrapper or the virtual function. If the signature of the wrapper needs modification this should be done via the methods L{remove_arg()} and L{insert_arg()} and not via the - wrapperfunc or virtualfunc attributes because this affects the + wrapper_func or virtual_func attributes because this affects the virtual function as well (because the virtual function makes a call to the Python function). @@ -96,21 +96,21 @@ ========= - - RETTYPE: The return type (e.g. "void", "int", "boost::python::object") + - RET_TYPE: The return type (e.g. "void", "int", "boost::python::object") - - CLASSSPEC: "<classname>::" or empty + - CLASS_SPEC: "<classname>::" or empty - - FUNCNAME: The name of the wrapper or virtual function. + - FUNC_NAME: The name of the wrapper or virtual function. - - ARGLIST: The parameters for $FUNCNAME (including self if required) + - ARG_LIST: The parameters for $FUNC_NAME (including self if required) - - ARGLISTDEF: Like ARGLIST, but including default values (if there are any) + - ARG_LIST_DEF: Like ARG_LIST, but including default values (if there are any) - - ARGLISTTYPES: Like ARGLIST but the variable names are left out and only the types are listed (this can identify a particular signature). + - ARG_LIST_TYPES: Like ARG_LIST but the variable names are left out and only the types are listed (this can identify a particular signature). - DECLARATIONS: The declaration block - - PRECALL:: + - PRE_CALL:: +--------------------------+ | [try {] | @@ -124,14 +124,14 @@ | Pre-call code block n | +--------------------------+ - - RESULTVARASSIGNMENT: "<varname> = " or empty + - RESULT_VAR_ASSIGNMENT: "<varname> = " or empty - - CALLFUNCNAME: The name of the function that should be invoked (self?). + - CALL_FUNC_NAME: The name of the function that should be invoked (self?). - - INPUTPARAMS: The values or variables that will be passed to $FUNCNAME, + - INPUT_PARAMS: The values or variables that will be passed to $FUNC_NAME, e.g. "a, b" or "0.5, 1.5" etc - - POSTCALL:: + - POST_CALL:: +--------------------------+ | Post-call code block n | @@ -145,13 +145,13 @@ | [} catch(...) {...}] | +--------------------------+ - - RETURNSTMT: "return <varname>" or "return boost::python::make_tuple(...)" + - RETURN_STMT: "return <varname>" or "return boost::python::make_tuple(...)" - @ivar wrapperfunc: The L{code manager<code_manager_t>} object that manages the wrapper function. This is used by the arg policies to modify the wrapper function. - @type wrapperfunc: L{wrapper_code_manager_t} - @ivar virtualfunc: The L{code manager<code_manager_t>} object that manages the virtual function. This is used by the arg policies to modify the virtual function. - @type virtualfunc: L{code_manager_t} + @ivar wrapper_func: The L{code manager<code_manager_t>} object that manages the wrapper function. This is used by the arg policies to modify the wrapper function. + @type wrapper_func: L{wrapper_code_manager_t} + @ivar virtual_func: The L{code manager<code_manager_t>} object that manages the virtual function. This is used by the arg policies to modify the virtual function. + @type virtual_func: L{code_manager_t} @group Methods called by the user of the class: append_code_block, subst_wrapper, subst_virtual, get_includes @group Methods called by the arg policies: remove_arg, insert_arg, require_include @@ -159,21 +159,21 @@ @author: Matthias Baas """ - def __init__(self, decl, wrapperclass=None, transformers=None): + def __init__(self, decl, wrapper_class=None, transformers=None): """Constructor. @param decl: calldef declaration @type decl: calldef_t - @param wrapperclass: The name of the class the generated function should belong to (or None if the generated function should be a free function) - @type wrapperclass: str + @param wrapper_class: The name of the class the generated function should belong to (or None if the generated function should be a free function) + @type wrapper_class: str @param transformers: Function transformer objects @type transformers: list of function_transformer_t """ # Code manager for the virtual function - self.virtualfunc = code_manager_t() + self.virtual_func = code_manager_t() # Code manager for the wrapper function - self.wrapperfunc = wrapper_code_manager_t() + self.wrapper_func = wrapper_code_manager_t() # The declaration that represents the original C++ function self.decl = decl @@ -183,7 +183,7 @@ transformers = [] self.transformers = transformers - self.wrapperclass = wrapperclass + self.wrapper_class = wrapper_class # A list of required include files self._virtual_includes = [] @@ -192,33 +192,33 @@ # Initialize the code managers... if str(decl.return_type)=="void": - rettype = None + ret_type = None else: - rettype = decl.return_type - self.wrapperfunc.resultvar = self.wrapperfunc.declare_local("result", str(rettype)) - self.wrapperfunc.resultexprs = [self.wrapperfunc.resultvar] + ret_type = decl.return_type + self.wrapper_func.result_var = self.wrapper_func.declare_local("result", str(ret_type)) + self.wrapper_func.result_exprs = [self.wrapper_func.result_var] - self.virtualfunc.rettype = rettype - self.virtualfunc.arglist = decl.arguments[:] - self.virtualfunc.classname = wrapperclass - self.virtualfunc.FUNCNAME = decl.name - self.virtualfunc.CALLFUNCNAME = decl.name - self.virtualfunc.inputparams = map(lambda a: a.name, decl.arguments) + self.virtual_func.ret_type = ret_type + self.virtual_func.arg_list = decl.arguments[:] + self.virtual_func.class_name = wrapper_class + self.virtual_func.FUNC_NAME = decl.name + self.virtual_func.CALL_FUNC_NAME = decl.name + self.virtual_func.input_params = map(lambda a: a.name, decl.arguments) - self.wrapperfunc.rettype = rettype - self.wrapperfunc.arglist = decl.arguments[:] - self.wrapperfunc.classname = wrapperclass - self.wrapperfunc.FUNCNAME = "%s_wrapper"%decl.alias - self.wrapperfunc.CALLFUNCNAME = decl.name - self.wrapperfunc.inputparams = map(lambda a: a.name, decl.arguments) + self.wrapper_func.ret_type = ret_type + self.wrapper_func.arg_list = decl.arguments[:] + self.wrapper_func.class_name = wrapper_class + self.wrapper_func.FUNC_NAME = "%s_wrapper"%decl.alias + self.wrapper_func.CALL_FUNC_NAME = decl.name + self.wrapper_func.input_params = map(lambda a: a.name, decl.arguments) # Check if we're dealing with a member function... - clsdecl = self._classDecl(decl) + clsdecl = self._class_decl(decl) if clsdecl!=None: - selfname = self.wrapperfunc._make_name_unique("self") + selfname = self.wrapper_func._make_name_unique("self") selfarg = declarations.argument_t(selfname, "%s&"%clsdecl.name) - self.wrapperfunc.arglist.insert(0, selfarg) - self.wrapperfunc.CALLFUNCNAME = "%s.%s"%(selfname, self.wrapperfunc.CALLFUNCNAME) + self.wrapper_func.arg_list.insert(0, selfarg) + self.wrapper_func.CALL_FUNC_NAME = "%s.%s"%(selfname, self.wrapper_func.CALL_FUNC_NAME) # Argument index map # Original argument index ---> Input arg index (indices are 0-based!) @@ -257,12 +257,12 @@ # Create a variable that will hold the result of the Python call # inside the virtual function. - if len(self.wrapperfunc.resultexprs)>0: - self.virtualfunc.resultvar = self.virtualfunc.declare_local("pyresult", "boost::python::object") -# self.virtualfunc.resultexpr = self.virtualfunc.resultvar + if len(self.wrapper_func.result_exprs)>0: + self.virtual_func.result_var = self.virtual_func.declare_local("pyresult", "boost::python::object") +# self.virtual_func.result_expr = self.virtual_func.result_var - self.wrapperfunc.init_variables() - self.virtualfunc.init_variables() + self.wrapper_func.init_variables() + self.virtual_func.init_variables() self._funcs_initialized = True @@ -273,27 +273,27 @@ src = map(lambda cb: getattr(cb, "wrapper_pre_call", defmeth)(self), transformers) src = filter(lambda x: x!=None, src) precall = "\n\n".join(src) - self.wrapperfunc.PRECALL = precall + self.wrapper_func.PRE_CALL = precall # Create the wrapper function post-call block... src = map(lambda cb: getattr(cb, "wrapper_post_call", defmeth)(self), transformers) src = filter(lambda x: x!=None, src) src.reverse() postcall = "\n\n".join(src) - self.wrapperfunc.POSTCALL = postcall + self.wrapper_func.POST_CALL = postcall # Create the virtual function pre-call block... src = map(lambda cb: getattr(cb, "virtual_pre_call", defmeth)(self), transformers) src = filter(lambda x: x!=None, src) precall = "\n\n".join(src) - self.virtualfunc.PRECALL = precall + self.virtual_func.PRE_CALL = precall # Create the virtual function post-call block... src = map(lambda cb: getattr(cb, "virtual_post_call", defmeth)(self), transformers) src = filter(lambda x: x!=None, src) src.reverse() postcall = "\n\n".join(src) - self.virtualfunc.POSTCALL = postcall + self.virtual_func.POST_CALL = postcall # remove_arg @@ -317,23 +317,23 @@ if self._funcs_initialized: raise ValueError, "remove_arg() may only be called before function initialization." if idx<0: - idx += len(self.virtualfunc.arglist)+1 - if idx>=len(self.virtualfunc.arglist)+1: + idx += len(self.virtual_func.arg_list)+1 + if idx>=len(self.virtual_func.arg_list)+1: raise IndexError, "Index (%d) out of range."%idx # Remove original return type? if idx==0: - if id(self.wrapperfunc.rettype)==id(self.wrapperfunc.rettype): - self.wrapperfunc.rettype = None + if id(self.wrapper_func.ret_type)==id(self.wrapper_func.ret_type): + self.wrapper_func.ret_type = None else: raise ValueError, 'Argument %d not found on the wrapper function'%(idx) # Remove argument... else: # Get the original argument... - arg = self.virtualfunc.arglist[idx-1] + arg = self.virtual_func.arg_list[idx-1] # ...and remove it from the wrapper try: - self.wrapperfunc.arglist.remove(arg) + self.wrapper_func.arg_list.remove(arg) except ValueError: raise ValueError, 'Argument %d ("%s") not found on the wrapper function'%(idx, arg.name) @@ -342,7 +342,7 @@ paramidx = self.argidxmap[idx-1] if paramidx==None: raise ValueError, "Argument was already removed" - del self.virtualfunc.inputparams[paramidx] + del self.virtual_func.input_params[paramidx] self.argidxmap[idx-1] = None for i in range(idx,len(self.argidxmap)): if self.argidxmap[i]!=None: @@ -368,11 +368,11 @@ pass else: if idx<0: - idx += len(self.wrapperfunc.arglist)+2 - self.wrapperfunc.arglist.insert(idx-1, arg) + idx += len(self.wrapper_func.arg_list)+2 + self.wrapper_func.arg_list.insert(idx-1, arg) # What to insert? - self.virtualfunc.inputparams.insert(idx-1, "???") + self.virtual_func.input_params.insert(idx-1, "???") # Adjust the argument index map for i in range(idx-1,len(self.argidxmap)): if self.argidxmap[i]!=None: @@ -447,7 +447,7 @@ """ if not self._funcs_initialized: self.init_funcs() - return self.virtualfunc.substitute(template) + return self.virtual_func.substitute(template) # subst_wrapper def subst_wrapper(self, template): @@ -458,10 +458,10 @@ """ if not self._funcs_initialized: self.init_funcs() - return self.wrapperfunc.substitute(template) + return self.wrapper_func.substitute(template) - # _classDecl - def _classDecl(self, decl): + # _class_decl + def _class_decl(self, decl): """Return the class declaration that belongs to a member declaration. """ while decl.parent!=None: @@ -482,22 +482,22 @@ def __init__(self): function_transformer_t.__init__(self) - self.resultvar = "<not initialized>" + self.result_var = "<not initialized>" def __str__(self): return "ReturnVirtualResult()"%(self.idx) def init_funcs(self, sm): - if sm.virtualfunc.rettype==None: + if sm.virtual_func.ret_type==None: return # Declare the local variable that will hold the return value # for the virtual function - self.resultvar = sm.virtualfunc.declare_local("result", sm.virtualfunc.rettype) + self.result_var = sm.virtual_func.declare_local("result", sm.virtual_func.ret_type) # Replace the result expression if there is still the default # result expression (which will not work anyway) - if sm.virtualfunc.resultexpr==sm.virtualfunc.resultvar: - sm.virtualfunc.resultexpr = self.resultvar + if sm.virtual_func.result_expr==sm.virtual_func.result_var: + sm.virtual_func.result_expr = self.result_var def virtual_post_call(self, sm): # Search the result tuple of the wrapper function for the return @@ -505,12 +505,12 @@ # from the Python result tuple, converted to C++ and returned from # the virtual function. If it does not exist, do nothing. try: - resultidx = sm.wrapperfunc.resultexprs.index(sm.wrapperfunc.resultvar) + resultidx = sm.wrapper_func.result_exprs.index(sm.wrapper_func.result_var) except ValueError: return res = "// Extract the C++ return value\n" - res += "%s = boost::python::extract<%s>(%s[%d]);"%(self.resultvar, sm.virtualfunc.rettype, sm.virtualfunc.resultvar, resultidx) + res += "%s = boost::python::extract<%s>(%s[%d]);"%(self.result_var, sm.virtual_func.ret_type, sm.virtual_func.result_var, resultidx) return res @@ -532,19 +532,19 @@ spam = root[0].class_("Spam") foo = spam.member_function("foo") - wm = substitution_manager_t(foo, transformers=[Output(1), Output(2)], wrapperclass="Spam_wrapper") + wm = substitution_manager_t(foo, transformers=[Output(1), Output(2)], wrapper_class="Spam_wrapper") - template = '''$RETTYPE $CLASSSPEC$FUNCNAME($ARGLIST) + template = '''$RET_TYPE $CLASS_SPEC$FUNC_NAME($ARG_LIST) { $DECLARATIONS - $PRECALL + $PRE_CALL - $RESULTVARASSIGNMENT$CALLFUNCNAME($INPUTPARAMS); + $RESULT_VAR_ASSIGNMENT$CALL_FUNC_NAME($INPUT_PARAMS); - $POSTCALL + $POST_CALL - $RETURNSTMT + $RETURN_STMT } ''' print wm.subst_virtual(template) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mb...@us...> - 2006-09-04 08:16:45
|
Revision: 518 http://svn.sourceforge.net/pygccxml/?rev=518&view=rev Author: mbaas Date: 2006-09-04 01:16:39 -0700 (Mon, 04 Sep 2006) Log Message: ----------- Update the func transformer test so that func transformers are actually used. :) But as of now the test won't pass anyway because the func transformers feature is still work in progress. Modified Paths: -------------- pyplusplus_dev/unittests/data/function_transformations_to_be_exported.hpp pyplusplus_dev/unittests/function_transformations_tester.py Modified: pyplusplus_dev/unittests/data/function_transformations_to_be_exported.hpp =================================================================== --- pyplusplus_dev/unittests/data/function_transformations_to_be_exported.hpp 2006-09-04 07:03:18 UTC (rev 517) +++ pyplusplus_dev/unittests/data/function_transformations_to_be_exported.hpp 2006-09-04 08:16:39 UTC (rev 518) @@ -15,7 +15,9 @@ , m_width( w ) {} - void get_size( unsigned int& h, unsigned int& w ){ + // Made the method 'virtual' for now because func transformers + // are currently only taken into account on virtual functions. + virtual void get_size( unsigned int& h, unsigned int& w ){ h = m_height; w = m_width; } Modified: pyplusplus_dev/unittests/function_transformations_tester.py =================================================================== --- pyplusplus_dev/unittests/function_transformations_tester.py 2006-09-04 07:03:18 UTC (rev 517) +++ pyplusplus_dev/unittests/function_transformations_tester.py 2006-09-04 08:16:39 UTC (rev 518) @@ -7,6 +7,7 @@ import sys import unittest import fundamental_tester_base +from pyplusplus.function_transformers.arg_policies import * class tester_t(fundamental_tester_base.fundamental_tester_base_t): EXTENSION_NAME = 'function_transformations' @@ -19,7 +20,7 @@ def customize( self, mb ): image = mb.class_( "image_t" ) - pass + image.member_function( "get_size" ).function_transformers.extend([Output(1), Output(2)]) def run_tests(self, module): img = module.image_t( 2, 6) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <rom...@us...> - 2006-09-04 07:03:26
|
Revision: 517 http://svn.sourceforge.net/pygccxml/?rev=517&view=rev Author: roman_yakovenko Date: 2006-09-04 00:03:18 -0700 (Mon, 04 Sep 2006) Log Message: ----------- splittingsmall refactoring before introducing "function transformation" functionality Modified Paths: -------------- pyplusplus_dev/pyplusplus/code_creators/__init__.py pyplusplus_dev/pyplusplus/decl_wrappers/calldef_wrapper.py Modified: pyplusplus_dev/pyplusplus/code_creators/__init__.py =================================================================== --- pyplusplus_dev/pyplusplus/code_creators/__init__.py 2006-09-04 06:49:35 UTC (rev 516) +++ pyplusplus_dev/pyplusplus/code_creators/__init__.py 2006-09-04 07:03:18 UTC (rev 517) @@ -137,9 +137,13 @@ fwrapper_cls = mem_fun_pv_wrapper_t maker_cls = mem_fun_pv_t else: - if decl.overridable: - fwrapper_cls = mem_fun_v_wrapper_t - maker_cls = mem_fun_v_t + if decl.function_transformers: + fwrapper_cls = mem_fun_v_transformed_wrapper_t + maker_cls = mem_fun_v_transformed_t + else: + if decl.overridable: + fwrapper_cls = mem_fun_v_wrapper_t + maker_cls = mem_fun_v_t elif access_level == ACCESS_TYPES.PROTECTED: if decl.virtuality == VIRTUALITY_TYPES.NOT_VIRTUAL: if decl.has_static: Modified: pyplusplus_dev/pyplusplus/decl_wrappers/calldef_wrapper.py =================================================================== --- pyplusplus_dev/pyplusplus/decl_wrappers/calldef_wrapper.py 2006-09-04 06:49:35 UTC (rev 516) +++ pyplusplus_dev/pyplusplus/decl_wrappers/calldef_wrapper.py 2006-09-04 07:03:18 UTC (rev 517) @@ -28,7 +28,7 @@ self._use_default_arguments = True self._create_with_signature = False self._overridable = None - self._function_transformers = [] + self._function_transformers = None def get_call_policies(self): return self._call_policies @@ -121,12 +121,16 @@ Returns a reference to the internal list (which may be modified). """ + if None is self._function_transformers: + #TODO: for trivial cases get_size( int&, int& ) Py++ should guess + #function transformers + self._function_transformers = [] return self._function_transformers - + def _set_function_transformers(self, function_transformers): """Set method for property 'function_transformers'.""" self._function_transformers = function_transformers - + function_transformers = property( _get_function_transformers, _set_function_transformers, doc = """A list of function transformer objects that should be applied to the generated C++ code (default: []). The returned list is the internal list (not a copy) which may be modified. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |