[pygccxml-commit] SF.net SVN: pygccxml: [545] pyplusplus_dev/pyplusplus
Brought to you by:
mbaas,
roman_yakovenko
From: <mb...@us...> - 2006-09-14 13:07:11
|
Revision: 545 http://svn.sourceforge.net/pygccxml/?rev=545&view=rev Author: mbaas Date: 2006-09-14 06:06:59 -0700 (Thu, 14 Sep 2006) Log Message: ----------- Committed the current snapshot of the function transformers. This is still work in progress and there are things missing, but it is sort of a milestone (at least for me) because I could use this version successfully for the Maya bindings where it could replace the arg policy feature from pypp_api. In this version, support for function transformers on non-virtual member functions has been implemented. Public (non-pure) virtual methods should now take the transformers into account in all cases (in the previous version it could happen that they were ignored). New policy class for in/out variables. Moved the transformed code creators to calldef_transformed.py (calldef.py is already big enough) so that the chance for conclicts on updates is reduced. Modified Paths: -------------- pyplusplus_dev/pyplusplus/code_creators/__init__.py pyplusplus_dev/pyplusplus/code_creators/calldef.py pyplusplus_dev/pyplusplus/function_transformers/arg_policies.py pyplusplus_dev/pyplusplus/function_transformers/code_manager.py pyplusplus_dev/pyplusplus/function_transformers/substitution_manager.py pyplusplus_dev/pyplusplus/module_creator/creator.py pyplusplus_dev/pyplusplus/module_creator/creators_wizard.py Added Paths: ----------- pyplusplus_dev/pyplusplus/code_creators/calldef_transformed.py Modified: pyplusplus_dev/pyplusplus/code_creators/__init__.py =================================================================== --- pyplusplus_dev/pyplusplus/code_creators/__init__.py 2006-09-14 13:01:56 UTC (rev 544) +++ pyplusplus_dev/pyplusplus/code_creators/__init__.py 2006-09-14 13:06:59 UTC (rev 545) @@ -74,8 +74,10 @@ from calldef import copy_constructor_wrapper_t from calldef import null_constructor_wrapper_t -from calldef import mem_fun_v_transformed_t -from calldef import mem_fun_v_transformed_wrapper_t +from calldef_transformed import mem_fun_transformed_t +from calldef_transformed import mem_fun_transformed_wrapper_t +from calldef_transformed import mem_fun_v_transformed_t +from calldef_transformed import mem_fun_v_transformed_wrapper_t from global_variable import global_variable_base_t from global_variable import global_variable_t Modified: pyplusplus_dev/pyplusplus/code_creators/calldef.py =================================================================== --- pyplusplus_dev/pyplusplus/code_creators/calldef.py 2006-09-14 13:01:56 UTC (rev 544) +++ pyplusplus_dev/pyplusplus/code_creators/calldef.py 2006-09-14 13:06:59 UTC (rev 545) @@ -10,7 +10,6 @@ import class_declaration from pygccxml import declarations from pyplusplus import decl_wrappers -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: @@ -234,6 +233,7 @@ else: return '&%s' % declarations.full_name( self.declaration ) + class mem_fun_t( calldef_t ): def __init__( self, function ): calldef_t.__init__( self, function=function ) @@ -446,289 +446,7 @@ answer.append( self.create_default_function() ) 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 - - def create_function_type_alias_code( self, exported_class_alias=None ): - result = [] - - ftype = self.declaration.function_type() - result.append( 'typedef %s;' % ftype.create_typedef( self.function_type_alias, exported_class_alias ) ) - if self.wrapper: - result.append( os.linesep ) - ftype = self.wrapper.function_type() - result.append( 'typedef %s;' % ftype.create_typedef( self.default_function_type_alias ) ) - return ''.join( result ) - - def create_doc(self): - return None - - def create_function_ref_code(self, use_function_alias=False): - result = [] - if use_function_alias: - result.append( '%s(&%s)' - % ( self.function_type_alias, declarations.full_name( self.declaration ) ) ) - if self.wrapper: - result.append( self.param_sep() ) - result.append( '%s(&%s)' - % ( self.default_function_type_alias, self.wrapper.default_full_name() ) ) - elif self.declaration.create_with_signature: - result.append( '(%s)(&%s)' - % ( self.declaration.function_type().decl_string - , declarations.full_name( self.declaration ) ) ) - if self.wrapper: - result.append( self.param_sep() ) - result.append( '(%s)(&%s)' - % ( self.wrapper.function_type().decl_string, self.wrapper.default_full_name() ) ) - else: - if self.wrapper: - 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 - , class_inst=declarations.dummy_type_t( self.parent.full_name ) - , arguments_types=map( lambda arg: arg.type, self.declaration.arguments ) - , has_const=self.declaration.has_const ) - - def create_declaration(self, name, virtual=True): - """Create the function header. - - 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' : virtualspec - , 'name' : name - , 'constness' : constness - , 'throw' : self.throw_specifier_code() - } - - 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 body % { - 'name' : self.declaration.name - , 'args' : self.function_call_args() - , 'return_' : return_ - , '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): - 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): - answer = [ self.create_declaration(self.declaration.name) + '{' ] - answer.append( self.indent( self.create_virtual_body() ) ) - 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 ): - - 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() ) - 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 ) Added: pyplusplus_dev/pyplusplus/code_creators/calldef_transformed.py =================================================================== --- pyplusplus_dev/pyplusplus/code_creators/calldef_transformed.py (rev 0) +++ pyplusplus_dev/pyplusplus/code_creators/calldef_transformed.py 2006-09-14 13:06:59 UTC (rev 545) @@ -0,0 +1,496 @@ +# 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) + +import os +#import algorithm +#import code_creator +#import class_declaration +from pygccxml import declarations +from calldef import calldef_t, calldef_wrapper_t +import pyplusplus.function_transformers as function_transformers + +###################################################################### + +class mem_fun_transformed_t( calldef_t ): + """Creates code for public non-virtual member functions. + """ + + def __init__( self, function, wrapper=None ): + calldef_t.__init__( self, function=function, wrapper=wrapper ) + + def create_function_type_alias_code( self, exported_class_alias=None ): + if self.wrapper==None: + ftype = self.declaration.function_type() + else: + ftype = self.wrapper.function_type() + res = 'typedef %s;' % ftype.create_typedef( self.function_type_alias, exported_class_alias ) + return res + + def create_function_ref_code(self, use_function_alias=False): + if self.wrapper: + full_name = self.wrapper.full_name() + else: + full_name = declarations.full_name( self.declaration ) + + if use_function_alias: + return '%s( &%s )' \ + % ( self.function_type_alias, full_name ) + elif self.declaration.create_with_signature: + if self.wrapper: + func_type = self.wrapper.function_type() + else: + func_type = self.declaration.function_type().decl_string + return '(%s)( &%s )' \ + % ( func_type, full_name ) + else: + return '&%s' % full_name + + +class mem_fun_transformed_wrapper_t( calldef_wrapper_t ): + """Creates wrapper code for (public) non-virtual member functions. + + The generated function is either used as a static member inside the + wrapper class (when self.parent is not None) or as a free function + (when self.parent is None). + """ + + def __init__( self, function ): + """Constructor. + + @param function: Function declaration + @type function: calldef_t + """ + calldef_wrapper_t.__init__( self, function=function ) + +# def is_free_function(self): +# """Return True if the generated function is a free function. +# +# @rtype: bool +# """ +# return self.parent==None + + def function_type(self): + """Return the type of the wrapper function. + + @rtype: type_t + """ + template = '$RET_TYPE' + rettype = self._subst_manager.subst_wrapper(template) + rettype = declarations.dummy_type_t(rettype) + + return declarations.free_function_type_t( + return_type=rettype + , arguments_types=map( lambda arg: arg.type, self.declaration.arguments ) ) + + + def full_name(self): + """Return the full name of the wrapper function. + + The returned name also includes the class name (if there is any). + + @rtype: str + """ + if self.parent==None: + return '_py_' + self.declaration.alias + else: + return self.parent.full_name + '::_py_' + self.declaration.alias + + def create_sig_id(self): + """Create an ID string that identifies a signature. + + @rtype: str + """ + template = '%s($ARG_LIST_TYPES)'%self.declaration.alias + return self._subst_manager.subst_wrapper(template) + + def create_declaration(self, name): + """Create the function header. + """ + template = 'static $RET_TYPE %(name)s( $ARG_LIST_DEF ) %(throw)s' + + # Substitute the $-variables + template = self._subst_manager.subst_wrapper(template) + + return template % { + 'name' : "_py_"+name + , 'throw' : self.throw_specifier_code() + } + + def create_body(self): + + body = """ +$DECLARATIONS + +$PRE_CALL + +$RESULT_VAR_ASSIGNMENT$CALL_FUNC_NAME($INPUT_PARAMS); + +$POST_CALL + +$RETURN_STMT +""" + + # Replace the $-variables + body = self._subst_manager.subst_wrapper(body) + + return body + + def create_function(self): +# sig_id = self.create_sig_id() + # ...check sig here... + + answer = [70*"/"] + answer.append("// Transformed wrapper function for:") + answer.append("// %s"%self.declaration) + answer.append(70*"/") + answer.append( self.create_declaration(self.declaration.alias) + '{') + answer.append( self.indent( self.create_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._subst_manager = sm + + answer = self.create_function() + + # 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_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 + + def create_function_type_alias_code( self, exported_class_alias=None ): + if self.wrapper==None: + ftype = self.declaration.function_type() + else: + ftype = self.wrapper.function_type() + + result = [] + result.append( 'typedef %s;' % ftype.create_typedef( self.function_type_alias, exported_class_alias ) ) + return ''.join( result ) + + def create_doc(self): + return None + + def create_function_ref_code(self, use_function_alias=False): + if self.wrapper: + full_name = self.wrapper.default_full_name() + else: + full_name = declarations.full_name( self.declaration ) + + result = [] + if use_function_alias: + result.append( '%s(&%s)' + % ( self.function_type_alias, full_name ) ) + elif self.declaration.create_with_signature: + if self.wrapper: + func_type = self.wrapper.function_type() + else: + func_type = self.declaration.function_type().decl_string + result.append( '(%s)(&%s)' + % ( func_type, full_name ) ) + else: + result.append( '&%s' % 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): + template = '$RET_TYPE' + rettype = self._subst_manager.subst_wrapper(template) + rettype = declarations.dummy_type_t(rettype) + + return declarations.free_function_type_t( + return_type=rettype + , arguments_types=map( lambda arg: arg.type, self.declaration.arguments ) ) + + return declarations.member_function_type_t( + return_type=self.declaration.return_type + , class_inst=declarations.dummy_type_t( self.parent.full_name ) + , arguments_types=map( lambda arg: arg.type, self.declaration.arguments ) + , has_const=self.declaration.has_const ) + + def create_declaration(self, name, virtual=True): + """Create the function header. + + 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' : virtualspec + , 'name' : name + , 'constness' : constness + , 'throw' : self.throw_specifier_code() + } + + 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 body % { + 'name' : self.declaration.name + , 'args' : self.function_call_args() + , 'return_' : return_ + , 'wrapped_class' : self.wrapped_class_identifier() + } + + def create_virtual_body(self): + + thread_safe = False + + if thread_safe: + # Todo: Properly allocate "gstate" + body = """ +PyGILState_STATE gstate; +gstate = PyGILState_Ensure(); + +$DECLARATIONS + +PyGILState_Release(gstate); + +if( %(override_var)s ) +{ + gstate = PyGILState_Ensure(); + + try { + $PRE_CALL + + ${RESULT_VAR_ASSIGNMENT}boost::python::call<$RESULT_TYPE>($INPUT_PARAMS); + + $POST_CALL + } + catch(...) + { + if (PyErr_Occurred()) + { + PyErr_Print(); + } + PyGILState_Release(gstate); + throw; + } + PyGILState_Release(gstate); + $RETURN_STMT +} +else +{ + %(inherited)s +} +""" + + if not thread_safe: + 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): + 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*>(boost::addressof(%(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): + answer = [ self.create_declaration(self.declaration.name) + '{' ] + answer.append( self.indent( self.create_virtual_body() ) ) + 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 ): + + 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() ) + 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 + Property changes on: pyplusplus_dev/pyplusplus/code_creators/calldef_transformed.py ___________________________________________________________________ Name: svn:eol-style + native Modified: pyplusplus_dev/pyplusplus/function_transformers/arg_policies.py =================================================================== --- pyplusplus_dev/pyplusplus/function_transformers/arg_policies.py 2006-09-14 13:01:56 UTC (rev 544) +++ pyplusplus_dev/pyplusplus/function_transformers/arg_policies.py 2006-09-14 13:06:59 UTC (rev 545) @@ -11,6 +11,7 @@ - L{output_t} - L{input_t} + - L{inout_t} - L{input_array_t} - L{output_array_t} """ @@ -105,14 +106,73 @@ 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) + raise ValueError, 'Input 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) +# inout_t +class inout_t: + """Handles a single input/output variable. + void foo(int& v) -> v = foo(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 in/out value (the first arg has index 1). + @type idx: int + """ + self.idx = idx + self.local_var = "<not initialized>" + + def __str__(self): + return "InOut(%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, 'InOut 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) + + # Use the input arg to also store the output + self.local_var = noref_arg.name + # Append the output to the result tuple + sm.wrapper_func.result_exprs.append(self.local_var) + + # Replace the expression in the C++ function call + if isinstance(reftype, declarations.pointer_t): + sm.wrapper_func.input_params[self.idx-1] = "&%s"%self.local_var + else: + 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.virtual_func.arg_list[self.idx-1] + res = "// Extract the C++ value for in/out argument '%s' (index: %d)\n"%(arg.name, self.idx) + if isinstance(arg.type, declarations.pointer_t): + res += "*" + res += "%s = boost::python::extract<%s>(%s);"%(arg.name, arg.type.base, sm.py_result_expr(self.local_var)) + return res + + + # input_array_t class input_array_t: """Handles an input array with fixed size. @@ -160,7 +220,7 @@ 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") + newarg = declarations.argument_t(arg.name, declarations.dummy_type_t("boost::python::object")) sm.insert_arg(self.idx, newarg, self.pylist) self.argname = arg.name Modified: pyplusplus_dev/pyplusplus/function_transformers/code_manager.py =================================================================== --- pyplusplus_dev/pyplusplus/function_transformers/code_manager.py 2006-09-14 13:01:56 UTC (rev 544) +++ pyplusplus_dev/pyplusplus/function_transformers/code_manager.py 2006-09-14 13:06:59 UTC (rev 545) @@ -35,7 +35,7 @@ @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 + @type arg_list: list of L{argument_t<pygccxml.declarations.calldef.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. @@ -225,8 +225,8 @@ which is a list of individual expressions. Apart from that this class is identical to L{code_manager_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 + @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 L{argument_t<pygccxml.declarations.calldef.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 L{argument_t<pygccxml.declarations.calldef.argument_t>} """ def __init__(self): Modified: pyplusplus_dev/pyplusplus/function_transformers/substitution_manager.py =================================================================== --- pyplusplus_dev/pyplusplus/function_transformers/substitution_manager.py 2006-09-14 13:01:56 UTC (rev 544) +++ pyplusplus_dev/pyplusplus/function_transformers/substitution_manager.py 2006-09-14 13:06:59 UTC (rev 545) @@ -192,29 +192,31 @@ self._wrapper_includes = [] # Initialize the code managers... - - if str(decl.return_type)=="void": - ret_type = None - else: - ret_type = decl.return_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 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.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) + if str(decl.return_type)=="void": + ret_type = None + else: + ret_type = decl.return_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 + + self.wrapper_func.ret_type = ret_type + # 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. @@ -224,7 +226,7 @@ clsdecl = self._class_decl(decl) if clsdecl!=None: selfname = self.wrapper_func._make_name_unique("self") - selfarg = declarations.argument_t(selfname, "%s&"%clsdecl.name) + selfarg = declarations.argument_t(selfname, declarations.dummy_type_t("%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 @@ -256,6 +258,8 @@ It is not necessary to call this method manually, it is automatically called at the time a substitution is requested. """ +# print "Transforming:",self.decl +# print " using transformers:", ", ".join(map(lambda x: str(x), self.transformers)) # Append the default return_virtual_result_t code modifier transformers = self.transformers+[return_virtual_result_t()] @@ -335,6 +339,7 @@ if idx==0: if id(self.wrapper_func.ret_type)==id(self.wrapper_func.ret_type): self.wrapper_func.ret_type = None + self.wrapper_func.result_exprs.remove(self.wrapper_func.result_var) else: raise ValueError, 'Argument %d not found on the wrapper function'%(idx) # Remove argument... @@ -345,7 +350,9 @@ try: self.wrapper_func.arg_list.remove(arg) except ValueError: - raise ValueError, 'Argument %d ("%s") not found on the wrapper function'%(idx, arg.name) + msg = str(self.decl)+"\n" + msg += 'Argument %d ("%s") not found on the wrapper function'%(idx, arg.name) + raise ValueError, msg # Remove the input parameter on the Python call in the # virtual function. Modified: pyplusplus_dev/pyplusplus/module_creator/creator.py =================================================================== --- pyplusplus_dev/pyplusplus/module_creator/creator.py 2006-09-14 13:01:56 UTC (rev 544) +++ pyplusplus_dev/pyplusplus/module_creator/creator.py 2006-09-14 13:06:59 UTC (rev 545) @@ -546,6 +546,19 @@ maker = maker_cls( function=self.curr_decl ) self.curr_code_creator.adopt_creator( maker ) + # Are we dealing with transformed non-virtual member functions? + if maker_cls==code_creators.mem_fun_transformed_t: + # Create the code creator that generates the function source code + mftw = code_creators.mem_fun_transformed_wrapper_t(self.curr_decl) + # and add it either to the wrapper class or just to the declaration + # area of the cpp file + if self.curr_code_creator.wrapper is None: + self.curr_code_creator.associated_decl_creators.append(mftw) + else: + self.curr_code_creator.wrapper.adopt_creator(mftw) + # Set the wrapper so that the registration code will refer to it + maker.wrapper = mftw + if self.curr_decl.has_static: #static_method should be created only once. found = filter( lambda creator: isinstance( creator, code_creators.static_method_t ) Modified: pyplusplus_dev/pyplusplus/module_creator/creators_wizard.py =================================================================== --- pyplusplus_dev/pyplusplus/module_creator/creators_wizard.py 2006-09-14 13:01:56 UTC (rev 544) +++ pyplusplus_dev/pyplusplus/module_creator/creators_wizard.py 2006-09-14 13:06:59 UTC (rev 545) @@ -22,7 +22,10 @@ access_level = decl.parent.find_out_member_access_type( decl ) if access_level == ACCESS_TYPES.PUBLIC: if decl.virtuality == VIRTUALITY_TYPES.NOT_VIRTUAL: - maker_cls = code_creators.mem_fun_t + if decl.function_transformers: + maker_cls = code_creators.mem_fun_transformed_t + else: + maker_cls = code_creators.mem_fun_t elif decl.virtuality == VIRTUALITY_TYPES.PURE_VIRTUAL: fwrapper_cls = code_creators.mem_fun_pv_wrapper_t maker_cls = code_creators.mem_fun_pv_t This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |