[pygccxml-commit] SF.net SVN: pygccxml: [761] pyplusplus_dev_ft/pyplusplus
Brought to you by:
mbaas,
roman_yakovenko
From: <rom...@us...> - 2006-11-28 14:01:53
|
Revision: 761 http://svn.sourceforge.net/pygccxml/?rev=761&view=rev Author: roman_yakovenko Date: 2006-11-28 06:01:48 -0800 (Tue, 28 Nov 2006) Log Message: ----------- initial implementation of transformers for virtual functions Modified Paths: -------------- pyplusplus_dev_ft/pyplusplus/code_repository/convenience.py pyplusplus_dev_ft/pyplusplus/function_transformers/__init__.py pyplusplus_dev_ft/pyplusplus/function_transformers/transformers.py Removed Paths: ------------- pyplusplus_dev_ft/pyplusplus/function_transformers/code_manager.py pyplusplus_dev_ft/pyplusplus/function_transformers/substitution_manager.py Modified: pyplusplus_dev_ft/pyplusplus/code_repository/convenience.py =================================================================== --- pyplusplus_dev_ft/pyplusplus/code_repository/convenience.py 2006-11-28 08:27:48 UTC (rev 760) +++ pyplusplus_dev_ft/pyplusplus/code_repository/convenience.py 2006-11-28 14:01:48 UTC (rev 761) @@ -135,6 +135,16 @@ return array_inserter_t<T>( array, size ); } +inline boost::python::object +get_out_argument( boost::python::object result, const char* arg_name ){ + if( PySequence_Check( result.ptr() ) ){ + return boost::python::getattr( result, arg_name ); + } + else{ + return result; + } +} + } /*pyplusplus*/ } /*convenience*/ namespace pyplus_conv = pyplusplus::convenience; Modified: pyplusplus_dev_ft/pyplusplus/function_transformers/__init__.py =================================================================== --- pyplusplus_dev_ft/pyplusplus/function_transformers/__init__.py 2006-11-28 08:27:48 UTC (rev 760) +++ pyplusplus_dev_ft/pyplusplus/function_transformers/__init__.py 2006-11-28 14:01:48 UTC (rev 761) @@ -16,7 +16,6 @@ """ -from substitution_manager import substitution_manager_t from transformer import transformer_t import transformers from function_transformation import function_transformation_t @@ -44,4 +43,4 @@ def output_array( *args, **keywd ): def creator( function ): return transformers.output_array_t( function, *args, **keywd ) - return creator \ No newline at end of file + return creator Deleted: pyplusplus_dev_ft/pyplusplus/function_transformers/code_manager.py =================================================================== --- pyplusplus_dev_ft/pyplusplus/function_transformers/code_manager.py 2006-11-28 08:27:48 UTC (rev 760) +++ pyplusplus_dev_ft/pyplusplus/function_transformers/code_manager.py 2006-11-28 14:01:48 UTC (rev 761) @@ -1,254 +0,0 @@ -# Copyright 2006 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) -# -# Initial author: Matthias Baas - -"""This module contains the L{code_manager_t} and L{wrapper_code_manager_t} classes. -""" - -import os -import types -import string - -# code_manager_t -class code_manager_t: - """This class manages pieces of source code for a C++ function. - - The class mainly provides the interface for the code blocks to - manipulate a function and stores the actual substitution variables. - Each function has its own code manager instance. - - A code block can declare a local variable using L{declare_variable()} - 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 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 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 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. - @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 - @ivar exception_handler_exit: The C++ code that is executed at the end of the main exception handler (default: "throw;"). - @type exception_handler_exit: str - - @author: Matthias Baas - """ - - def __init__(self): - """Constructor.""" - # 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.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.ret_type = None - # The argument list. The items are argument_t objects. - self.arg_list = [] - - # A list of strings that contain the input parameter for the - # function call - 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.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 - - # The C++ code that is executed at the end of the main - # exception handler. - self.exception_handler_exit = "throw;" - - # Key:Variable name / Value:(type,size,default) - self._declared_vars = {} - - def substitute( self, template_code ): - tmpl = string.Template(template_code) - return tmpl.safe_substitute(self.__dict__) - - # declare_variable - def declare_variable(self, name, type, initialize_expr=''): - """Declare a local variable and return its final name. - - @param name: The desired variable name - @type name: str - @param type: The type of the variable (must be valid C++ code) - @type type: str - @param size: The array length or None - @type size: int - @param default: The default value (must be valid C++ code) or None - @type default: str - @return: The assigned variable name (which is guaranteed to be unique) - @rtype: str - """ - name = self._make_name_unique(name) - self._declared_vars[name] = (type, initialize_expr) - return name - - def init_variables(self): - """Initialize the substitution variables. - - Based on the (lowercase) attributes, the final (uppercase) - variables are created. Those variables are regular string - attributes. - """ - - # CLASS_SPEC - if (self.class_name in [None, ""]): - self.CLASS_SPEC = "" - else: - self.CLASS_SPEC = "%s::"%self.class_name - - # RET_TYPE - if self.ret_type==None: - self.RET_TYPE = "void" - else: - self.RET_TYPE = str(self.ret_type) - - # ARG_LIST_DEF - args = map(lambda a: str(a), self.arg_list) - self.ARG_LIST_DEF = ", ".join(args) - - # ARG_LIST - args = map(lambda s: s.split("=")[0], args) - self.ARG_LIST = ", ".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 = [] - for name, (type, initialize_expr) in self._declared_vars.iteritems(): - tmpl = "%(type)s %(name)s%(initialize_expr)s;" - vardecls.append( tmpl % { 'type' : type - , 'name' : name - , 'initialize_expr' : initialize_expr } ) - self.DECLARATIONS = os.linesep.join(vardecls) - - # RESULT_VAR_ASSIGNMENT - if self.result_var!=None: - self.RESULT_VAR_ASSIGNMENT = "%s = "%self.result_var - else: - self.RESULT_VAR_ASSIGNMENT = "" - - # RESULT_TYPE - if self.result_type!=None: - self.RESULT_TYPE = str(self.result_type) - else: - self.RESULT_TYPE = "" - - # INPUT_PARAMS - self.INPUT_PARAMS = ", ".join(self.input_params) - - # RETURN_STMT - if self.result_expr!=None: - self.RETURN_STMT = "return %s;"%self.result_expr - else: - self.RETURN_STMT = "" - - # EXCEPTION_HANDLER_EXIT - if self.exception_handler_exit!=None: - self.EXCEPTION_HANDLER_EXIT = self.exception_handler_exit - else: - self.EXCEPTION_HANDLER_EXIT = "" - - # _make_name_unique - def _make_name_unique(self, name): - """Make a variable name unique so that there's no clash with other names. - - @param name: The variable name that should be unique - @type name: str - @return: A unique name based on the input name - @rtype: str - """ - n = 2 - newname = name - while 1: - if not self._declared_vars.has_key( newname ): - return newname - newname = "%s_%d"%(name, n) - n += 1 - -# wrapper_code_manager_t -class wrapper_code_manager_t(code_manager_t): - """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 "result_exprs" - 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 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): - """Constructor. - """ - code_manager_t.__init__(self) - - # 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.result_exprs = [] - - def init_variables(self): - """Initialize the substitution variables. - """ - - # Prepare the variables for RET_TYPE and RETURN_STMT... - - # Convert all items into strings - result_exprs = [] - for re in self.result_exprs: - # String? - if isinstance(re, types.StringTypes): - result_exprs.append(re) - # argument_t - else: - result_exprs.append(re.name) - - if self.result_expr==None: - # No output values? - if len(result_exprs)==0: - self.ret_type = None - self.result_expr = None - # Exactly one output value? - 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.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) - - Deleted: pyplusplus_dev_ft/pyplusplus/function_transformers/substitution_manager.py =================================================================== --- pyplusplus_dev_ft/pyplusplus/function_transformers/substitution_manager.py 2006-11-28 08:27:48 UTC (rev 760) +++ pyplusplus_dev_ft/pyplusplus/function_transformers/substitution_manager.py 2006-11-28 14:01:48 UTC (rev 761) @@ -1,511 +0,0 @@ -# Copyright 2006 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) -# -# Initial author: Matthias Baas - -"""This module contains the L{substitution_manager_t} class. -""" - -import os -from pygccxml import declarations -from code_manager import code_manager_t, wrapper_code_manager_t -from transformer import transformer_t -from transformer import return_ - -# substitution_manager_t -class substitution_manager_t: - """Helper class for creating C++ source code for wrapper functions. - - The class does not create the entire function source code itself - but it maintains the individual parts that can be composed by the - user of the class. Those individual parts are stored inside - variables which can be used to perform text substitutions. - - Doing substitutions - =================== - - Here is an example that demonstrates the usage of the class. The - user creates a template string that contains the layout of the - entire wrapper function. Such a template string may look like - this:: - - $RET_TYPE $CLASS_SPEC$FUNC_NAME($ARG_LIST) - { - $DECLARATIONS - - $PRE_CALL - - $RESULT_VAR_ASSIGNMENT$CALL_FUNC_NAME($INPUT_PARAMS); - - $POST_CALL - - $RETURN_STMT - } - - Any part of the function that is not fixed, i.e. that can be - modified by argument policies, is specified via a variable. The - substitution manager can now be used to substitute the variables with - their actual value. There are actually two sets of identical - variables, one for the wrapper function and one for the virtual - function. You choose a set either by using the L{subst_wrapper()} or - L{subst_virtual()} method for doing the substitution. For example, - performing a "wrapper" substitution on the above template string - might result in the following code:: - - boost::python::object Spam_wrapper::foo_wrapper(Spam& self, int mode) - { - int result; - int w; - int h; - - result = self.foo(w, &h, mode); - - return boost::python::make_tuple(result, w, h); - } - - In this example, the individual variables have the following values: - - - 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;} - - 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 - ======================= - - 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{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 - 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). - - Variables - ========= - - - - RET_TYPE: The return type (e.g. "void", "int", "boost::python::object") - - - CLASS_SPEC: "<classname>::" or empty - - - FUNC_NAME: The name of the wrapper or virtual function. - - - ARG_LIST: The parameters for $FUNC_NAME (including self if required) - - - ARG_LIST_DEF: Like ARG_LIST, but including default values (if there are any) - - - 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 - - - PRE_CALL:: - - +--------------------------+ - | [try {] | - +--------------------------+ - | Pre-call code block 1 | - +--------------------------+ - | Pre-call code block 2 | - +--------------------------+ - | ... | - +--------------------------+ - | Pre-call code block n | - +--------------------------+ - - - 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, - e.g. "a, b" or "0.5, 1.5" etc - - - POST_CALL:: - - +--------------------------+ - | Post-call code block n | - +--------------------------+ - | ... | - +--------------------------+ - | Post-call code block 2 | - +--------------------------+ - | Post-call code block 1 | - +--------------------------+ - | [} catch(...) {...}] | - +--------------------------+ - - - CLEANUP: The cleanup code blocks of all function transformers. - - - RETURN_STMT: "return <varname>" or "return boost::python::make_tuple(...)" - - - EXCEPTION_HANDLER_EXIT: The C++ code that is executed at the end of the main exception handler (default: "throw;") - - - @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 - @group Methods called by the function transformers: remove_arg, insert_arg, py_result_expr - - @author: Matthias Baas - """ - - def __init__(self, decl, wrapper_class=None, transformers=None): - """Constructor. - - @param decl: calldef declaration - @type decl: calldef_t - @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 transformer_t - """ - #prevent recursive import - from pyplusplus import decl_wrappers - # Code manager for the virtual function - self.virtual_func = code_manager_t() - # Code manager for the wrapper function - self.wrapper_func = wrapper_code_manager_t() - - # The declaration that represents the original C++ function - self.decl = decl - - # The function transformers - if transformers==None: - transformers = [] - self.transformers = transformers - - self.wrapper_class = wrapper_class - - # Initialize the code managers... - - 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 arg: decl_wrappers.python_traits.call_traits( arg.type ) % arg.name - , decl.arguments ) - - 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(declarations.type_traits.remove_reference(ret_type)) - self.wrapper_func.result_var = self.wrapper_func.declare_variable("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. - self._insert_arg_idx_offset = 0 - - # Check if we're dealing with a member function... - if isinstance( decl.parent, declarations.class_t ): - if decl.has_static: - self.wrapper_func.CALL_FUNC_NAME \ - = "%s::%s" % (declarations.full_name(decl.parent), self.wrapper_func.CALL_FUNC_NAME) - else: - selfname = self.wrapper_func._make_name_unique("self") - selfarg = declarations.argument_t(selfname, declarations.dummy_type_t("%s&"%declarations.full_name(decl.parent))) - 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!) - # Initial state is the identity: f(x) = x - # The argument index map represents a function that maps the argument - # index of the original C++ function to the index of the corresponding - # parameter in the input parameter list for the Python call. - self.argidxmap = range(len(decl.arguments)) - - - # Flag that is set after the functions were initialized - self._funcs_initialized = False - - # init_funcs - def init_funcs(self): - """Initialize the virtual function and the wrapper function. - - After this method has been called, the substitution variables - are ready for usage. - - It is not necessary to call this method manually, it is - automatically called at the time a substitution is requested. - """ - - # Append the default return_virtual_result_t code modifier - transformers = self.transformers+[return_virtual_result_t(self.decl)] - - for cb in transformers: - if hasattr(cb, "init_funcs"): - cb.init_funcs(self) - - # 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_type = "boost::python::object" - self.virtual_func.result_var = self.virtual_func.declare_variable("pyresult", self.virtual_func.result_type) - - self.wrapper_func.init_variables() - self.virtual_func.init_variables() - - self._funcs_initialized = True - - block_sep = os.linesep * 2 - # Create the wrapper function pre-call block... - tmp = filter(None, map(lambda cb: cb.wrapper_pre_call(self), transformers) ) - self.wrapper_func.PRE_CALL = block_sep.join( tmp ) - - # Create the wrapper function post-call block... - tmp = filter(None, map(lambda cb: cb.wrapper_post_call(self), transformers) ) - self.wrapper_func.POST_CALL = block_sep.join( tmp ) - - # Create the wrapper function cleanup block... - tmp = filter(None, map(lambda cb: cb.wrapper_cleanup(self), transformers) ) - self.wrapper_func.CLEANUP = block_sep.join( tmp ) - - # Create the virtual function pre-call block... - tmp = filter(None, map(lambda cb: cb.virtual_pre_call(self), transformers) ) - self.virtual_func.PRE_CALL = block_sep.join( tmp ) - - # Create the virtual function post-call block... - tmp = filter(None, map(lambda cb: cb.virtual_post_call(self), transformers) ) - self.virtual_func.POST_CALL = block_sep.join( tmp ) - - # Create the virtual function cleanup block... - tmp = filter(None, map(lambda cb: cb.virtual_cleanup(self), transformers) ) - self.virtual_func.CLEANUP = block_sep.join( tmp ) - - # remove_arg - def remove_arg(self, idx): - """Remove an argument from the wrapper function. - - This function can also be used to remove the original return value - (idx=0). - - The function is supposed to be called by function transformer - objects. - - @param idx: Argument index of the original function (may be negative) - @type idx: int - @returns: Returns the argument_t object that was removed (or None - 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: L{argument_t<pygccxml.declarations.calldef.argument_t>} - """ - if self._funcs_initialized: - raise ValueError, "remove_arg() may only be called before function initialization." - if idx<0: - 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.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... - else: - # Get the original argument... - arg = self.virtual_func.arg_list[idx-1] - # ...and remove it from the wrapper - try: - self.wrapper_func.arg_list.remove(arg) - except ValueError: - 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. - paramidx = self.argidxmap[idx-1] - if paramidx==None: - raise ValueError, "Argument was already removed" - 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: - self.argidxmap[i] -= 1 - - return arg - - - # insert_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 - objects. - - @param idx: New argument index (may be negative) - @type idx: int - @param arg: New argument object - @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." - if idx==0: - pass - 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, 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) - - # subst_virtual - def subst_virtual(self, template): - """Perform a text substitution using the "virtual" variable set. - - @return: Returns the input string that has all variables substituted. - @rtype: str - """ - if not self._funcs_initialized: - self.init_funcs() - return self.virtual_func.substitute(template) - - # subst_wrapper - def subst_wrapper(self, template): - """Perform a text substitution using the "wrapper" variable set. - - @return: Returns the input string that has all variables substituted. - @rtype: str - """ - if not self._funcs_initialized: - self.init_funcs() - return self.wrapper_func.substitute(template) - - - -# return_virtual_result_t -class return_virtual_result_t(transformer_t): - """Extract and return the result value of the virtual function. - - This is an internal code block object that is automatically appended - to the list of code blocks inside the substitution_manager_t class. - """ - - def __init__(self, function): - transformer_t.__init__(self, function) - self.result_var = "<not initialized>" - - def __str__(self): - return "ReturnVirtualResult()"%(self.idx) - - def init_funcs(self, sm): - if sm.virtual_func.ret_type==None: - return - - # Declare the local variable that will hold the return value - # for the virtual function - self.result_var = sm.virtual_func.declare_variable("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.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 - # value of the C++ function call. If the value exists it is extracted - # from the Python result tuple, converted to C++ and returned from - # the virtual function. If it does not exist, do nothing. - try: - resexpr = sm.py_result_expr(self.result_var) - except ValueError: - return - - res = "// Extract the C++ return value\n" - res += "%s = boost::python::extract<%s>(%s);"%(self.result_var, sm.virtual_func.ret_type, resexpr) - return res Modified: pyplusplus_dev_ft/pyplusplus/function_transformers/transformers.py =================================================================== --- pyplusplus_dev_ft/pyplusplus/function_transformers/transformers.py 2006-11-28 08:27:48 UTC (rev 760) +++ pyplusplus_dev_ft/pyplusplus/function_transformers/transformers.py 2006-11-28 14:01:48 UTC (rev 761) @@ -68,6 +68,11 @@ def __str__(self): return "output(%d)"%(self.arg_index) + def required_headers( self ): + """Returns list of header files that transformer generated code depends on.""" + return [ code_repository.convenience.file_name ] + + def __configure_non_virtual( self, controller ): #removing arg from the function wrapper definition controller.remove_wrapper_arg( self.arg.name ) @@ -88,6 +93,12 @@ assert isinstance( controller, controllers.virtual_mem_fun_controller_t ) #removing arg from the function wrapper definition controller.remove_py_arg( self.arg_index ) + tmpl = string.Template( + '$name = boost::python::extract< $type >( pyplus_conv::get_out_argument( $py_result, "$name" ) );' ) + store_py_result_in_arg = tmpl.substitute( name=self.arg.name + , type=self.arg.type.decl_string + , py_result=controller.py_result_variable.name ) + controller.add_py_post_call_code( store_py_result_in_arg ) # input_t @@ -128,6 +139,11 @@ def configure_free_fun(self, controller ): self.__configure_non_virtual( controller ) + def configure_virtual_mem_fun( self, controller ): + pass #according to boost.python documentation, it will create a copy of + #the object by itself + + # inout_t class inout_t(transformer.transformer_t): """Handles a single input/output variable. @@ -166,6 +182,14 @@ def configure_free_fun(self, controller ): self.__configure_non_virtual( controller ) + def configure_virtual_mem_fun( self, controller ): + assert isinstance( controller, controllers.virtual_mem_fun_controller_t ) + tmpl = string.Template( + '$name = boost::python::extract< $type >( pyplus_conv::get_out_argument( $py_result, "$name" ) );' ) + store_py_result_in_arg = tmpl.substitute( name=self.arg.name + , type=self.arg.type.decl_string + , py_result=controller.py_result_variable.name ) + controller.add_py_post_call_code( store_py_result_in_arg ) class input_array_t(transformer.transformer_t): """Handles an input array with fixed size. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |