Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r77518 - trunk/tools/build/v2/engine
From: steven_at_[hidden]
Date: 2012-03-24 17:07:50


Author: steven_watanabe
Date: 2012-03-24 17:07:49 EDT (Sat, 24 Mar 2012)
New Revision: 77518
URL: http://svn.boost.org/trac/boost/changeset/77518

Log:
Merge Python function support into function.c
Text files modified:
   trunk/tools/build/v2/engine/builtins.c | 27 --
   trunk/tools/build/v2/engine/compile.c | 395 ---------------------------------------
   trunk/tools/build/v2/engine/function.c | 367 ++++++++++++++++++++++++++++++++++--
   trunk/tools/build/v2/engine/function.h | 6
   trunk/tools/build/v2/engine/rules.c | 8
   trunk/tools/build/v2/engine/rules.h | 3
   6 files changed, 353 insertions(+), 453 deletions(-)

Modified: trunk/tools/build/v2/engine/builtins.c
==============================================================================
--- trunk/tools/build/v2/engine/builtins.c (original)
+++ trunk/tools/build/v2/engine/builtins.c 2012-03-24 17:07:49 EDT (Sat, 24 Mar 2012)
@@ -1841,12 +1841,7 @@
         if ( pFunc && PyCallable_Check( pFunc ) )
         {
             module_t * m = bindmodule( jam_module );
- RULE * r = bindrule( jam_rule, m );
-
- /* Make pFunc owned. */
- Py_INCREF( pFunc );
-
- r->python_function = pFunc;
+ new_rule_body( m, jam_rule, 0, function_python( pFunc, 0 ), 0 );
         }
         else
         {
@@ -2014,25 +2009,7 @@
     object_free( rule_name );
 
     /* Make pFunc owned. */
- Py_INCREF( func );
-
- r->python_function = func;
- r->arguments = 0;
-
- if (bjam_signature)
- {
- argument_list * arg_list = args_new();
- Py_ssize_t i;
-
- Py_ssize_t s = PySequence_Size (bjam_signature);
- for (i = 0; i < s; ++i)
- {
- PyObject* v = PySequence_GetItem (bjam_signature, i);
- lol_add(arg_list->data, list_from_python (v));
- Py_DECREF(v);
- }
- r->arguments = arg_list;
- }
+ r->procedure = function_python( func, bjam_signature );
 
     Py_INCREF( Py_None );
     return Py_None;

Modified: trunk/tools/build/v2/engine/compile.c
==============================================================================
--- trunk/tools/build/v2/engine/compile.c (original)
+++ trunk/tools/build/v2/engine/compile.c 2012-03-24 17:07:49 EDT (Sat, 24 Mar 2012)
@@ -115,391 +115,6 @@
 }
 
 
-static void argument_error( const char * message, RULE * rule, FRAME * frame, OBJECT * arg )
-{
- LOL * actual = frame->args;
- assert( rule->procedure != 0 );
- backtrace_line( frame->prev );
- printf( "*** argument error\n* rule %s ( ", frame->rulename );
- lol_print( rule->arguments->data );
- printf( " )\n* called with: ( " );
- lol_print( actual );
- printf( " )\n* %s %s\n", message, arg ? object_str ( arg ) : "" );
- function_location( rule->procedure, &frame->file, &frame->line );
- print_source_line( frame );
- printf( "see definition of rule '%s' being called\n", object_str( rule->name ) );
- backtrace( frame->prev );
- exit( 1 );
-}
-
-
-/* Define delimiters for type check elements in argument lists (and return type
- * specifications, eventually).
- */
-# define TYPE_OPEN_DELIM '['
-# define TYPE_CLOSE_DELIM ']'
-
-/*
- * is_type_name() - true iff the given string represents a type check
- * specification.
- */
-
-int is_type_name( const char * s )
-{
- return ( s[ 0 ] == TYPE_OPEN_DELIM ) &&
- ( s[ strlen( s ) - 1 ] == TYPE_CLOSE_DELIM );
-}
-
-
-/*
- * arg_modifier - if the next element of formal is a single character, return
- * that; return 0 otherwise. Used to extract "*+?" modifiers * from argument
- * lists.
- */
-
-static char arg_modifier( LISTITER iter, LISTITER end )
-{
- iter = list_next( iter );
- if ( iter != end )
- {
- const char * next = object_str( list_item( iter ) );
- if ( next && ( next[ 0 ] != 0 ) && ( next[ 1 ] == 0 ) )
- return next[ 0 ];
- }
- return 0;
-}
-
-
-/*
- * type_check() - checks that each element of values satisfies the requirements
- * of type_name.
- *
- * caller - the frame of the rule calling the rule whose arguments are
- * being checked
- *
- * called - the rule being called
- *
- * arg_name - a list element containing the name of the argument being
- * checked
- */
-
-static void type_check_range
-(
- OBJECT * type_name,
- LISTITER iter,
- LISTITER end,
- FRAME * caller,
- RULE * called,
- OBJECT * arg_name
-)
-{
- static module_t * typecheck = 0;
-
- /* If nothing to check, bail now. */
- if ( iter == end || !type_name )
- return;
-
- if ( !typecheck )
- {
- typecheck = bindmodule( constant_typecheck );
- }
-
- /* If the checking rule can not be found, also bail. */
- if ( !typecheck->rules || !hash_find( typecheck->rules, type_name ) )
- return;
-
- for ( ; iter != end; iter = list_next( iter ) )
- {
- LIST *error;
- FRAME frame[1];
- frame_init( frame );
- frame->module = typecheck;
- frame->prev = caller;
- frame->prev_user = caller->module->user_module ? caller : caller->prev_user;
-
- /* Prepare the argument list */
- lol_add( frame->args, list_new( L0, object_copy( list_item( iter ) ) ) );
- error = evaluate_rule( type_name, frame );
-
- if ( !list_empty( error ) )
- argument_error( object_str( list_front( error ) ), called, caller, arg_name );
-
- frame_free( frame );
- }
-}
-
-static void type_check
-(
- OBJECT * type_name,
- LIST * values,
- FRAME * caller,
- RULE * called,
- OBJECT * arg_name
-)
-{
- type_check_range( type_name, list_begin( values ), list_end( values ), caller, called, arg_name );
-}
-
-
-/*
- * collect_arguments() - local argument checking and collection
- */
-static SETTINGS *
-collect_arguments( RULE* rule, FRAME* frame )
-{
- SETTINGS *locals = 0;
-
- LOL * all_actual = frame->args;
- LOL * all_formal = rule->arguments ? rule->arguments->data : 0;
- if ( all_formal ) /* Nothing to set; nothing to check */
- {
- int max = all_formal->count > all_actual->count
- ? all_formal->count
- : all_actual->count;
-
- int n;
- for ( n = 0; n < max ; ++n )
- {
- LIST *actual = lol_get( all_actual, n );
- OBJECT * type_name = 0;
-
- LIST *formal;
- LISTITER formal_iter, formal_end;
- LISTITER actual_iter = list_begin( actual ), actual_end = list_end( actual );
- for ( formal = lol_get( all_formal, n ),
- formal_iter = list_begin( formal ), formal_end = list_end( formal );
- formal_iter != formal_end; formal_iter = list_next( formal_iter ) )
- {
- OBJECT * name = list_item( formal_iter );
-
- if ( is_type_name( object_str( name ) ) )
- {
- if ( type_name )
- argument_error( "missing argument name before type name:", rule, frame, name );
-
- if ( list_next( formal_iter ) == formal_end )
- argument_error( "missing argument name after type name:", rule, frame, name );
-
- type_name = name;
- }
- else
- {
- LIST* value = L0;
- char modifier;
- OBJECT* arg_name = list_item( formal_iter ); /* hold the argument name for type checking */
- int multiple = 0;
-
- /* Stop now if a variable number of arguments are specified */
- if ( object_str( name )[0] == '*' && object_str( name )[1] == 0 )
- return locals;
-
- modifier = arg_modifier( formal_iter, formal_end );
-
- if ( actual_iter == actual_end && modifier != '?' && modifier != '*' )
- argument_error( "missing argument", rule, frame, name );
-
- switch ( modifier )
- {
- case '+':
- case '*':
- value = list_copy_range( actual, actual_iter, actual_end );
- multiple = 1;
- actual_iter = actual_end;
- /* skip an extra element for the modifier */
- formal_iter = list_next( formal_iter );
- break;
- case '?':
- /* skip an extra element for the modifier */
- formal_iter = list_next( formal_iter );
- /* fall through */
- default:
- if ( actual_iter != actual_end ) /* in case actual is missing */
- {
- value = list_new( L0, object_copy( list_item( actual_iter ) ) );
- actual_iter = list_next( actual_iter );
- }
- }
-
- locals = addsettings(locals, VAR_SET, name, value);
- locals->multiple = multiple;
- type_check( type_name, value, frame, rule, arg_name );
- type_name = 0;
- }
- }
-
- if ( actual_iter != actual_end )
- {
- argument_error( "extra argument", rule, frame, list_item( actual_iter ) );
- }
- }
- }
- return locals;
-}
-
-RULE *
-enter_rule( char *rulename, module_t *target_module );
-
-#ifdef HAVE_PYTHON
-
-static int python_instance_number = 0;
-
-
-/* Given a Python object, return a string to use in Jam
- code instead of said object.
- If the object is string, use the string value
- If the object implemenets __jam_repr__ method, use that.
- Otherwise return 0. */
-OBJECT *python_to_string(PyObject* value)
-{
- if (PyString_Check(value))
- {
- return object_new(PyString_AsString(value));
- }
- else
- {
- /* See if this is an instance that defines special __jam_repr__
- method. */
- if (PyInstance_Check(value)
- && PyObject_HasAttrString(value, "__jam_repr__"))
- {
- PyObject* repr = PyObject_GetAttrString(value, "__jam_repr__");
- if (repr)
- {
- PyObject* arguments2 = PyTuple_New(0);
- PyObject* value2 = PyObject_Call(repr, arguments2, 0);
- Py_DECREF(repr);
- Py_DECREF(arguments2);
- if (PyString_Check(value2))
- {
- return object_new(PyString_AsString(value2));
- }
- Py_DECREF(value2);
- }
- }
- return 0;
- }
-}
-
-static LIST*
-call_python_function(RULE* r, FRAME* frame)
-{
- LIST * result = 0;
- PyObject * arguments = 0;
- PyObject * kw = NULL;
- int i ;
- PyObject * py_result;
- FRAME * prev_frame_before_python_call;
-
- if (r->arguments)
- {
- SETTINGS * args;
-
- arguments = PyTuple_New(0);
- kw = PyDict_New();
-
- for (args = collect_arguments(r, frame); args; args = args->next)
- {
- PyObject *key = PyString_FromString(object_str(args->symbol));
- PyObject *value = 0;
- if (args->multiple)
- value = list_to_python(args->value);
- else {
- if (!list_empty(args->value))
- value = PyString_FromString(object_str(list_front(args->value)));
- }
-
- if (value)
- PyDict_SetItem(kw, key, value);
- Py_DECREF(key);
- Py_XDECREF(value);
- }
- }
- else
- {
- arguments = PyTuple_New( frame->args->count );
- for ( i = 0; i < frame->args->count; ++i )
- {
- PyObject * arg = PyList_New(0);
- LIST* l = lol_get( frame->args, i);
- LISTITER iter = list_begin( l ), end = list_end( l );
-
- for ( ; iter != end; iter = list_next( iter ) )
- {
- PyObject * v = PyString_FromString(object_str(list_item(iter)));
- PyList_Append( arg, v );
- Py_DECREF(v);
- }
- /* Steals reference to 'arg' */
- PyTuple_SetItem( arguments, i, arg );
- }
- }
-
- prev_frame_before_python_call = frame_before_python_call;
- frame_before_python_call = frame;
- py_result = PyObject_Call( r->python_function, arguments, kw );
- frame_before_python_call = prev_frame_before_python_call;
- Py_DECREF(arguments);
- Py_XDECREF(kw);
- if ( py_result != NULL )
- {
- if ( PyList_Check( py_result ) )
- {
- int size = PyList_Size( py_result );
- int i;
- for ( i = 0; i < size; ++i )
- {
- PyObject * item = PyList_GetItem( py_result, i );
- OBJECT *s = python_to_string (item);
- if (!s) {
- fprintf( stderr, "Non-string object returned by Python call.\n" );
- } else {
- result = list_new (result, s);
- }
- }
- }
- else if ( py_result == Py_None )
- {
- result = L0;
- }
- else
- {
- OBJECT *s = python_to_string(py_result);
- if (s)
- result = list_new(L0, s);
- else
- /* We have tried all we could. Return empty list. There are
- cases, e.g. feature.feature function that should return
- value for the benefit of Python code and which also can be
- called by Jam code, where no sensible value can be
- returned. We cannot even emit a warning, since there will
- be a pile of them. */
- result = L0;
- }
-
- Py_DECREF( py_result );
- }
- else
- {
- PyErr_Print();
- fprintf(stderr,"Call failed\n");
- }
-
- return result;
-}
-
-
-module_t * python_module()
-{
- static module_t * python = 0;
- if ( !python )
- python = bindmodule(constant_python);
- return python;
-}
-
-#endif
-
-LIST * function_run_with_args( FUNCTION * function_, FRAME * frame, STACK * s );
-
 /*
  * evaluate_rule() - execute a rule invocation.
  */
@@ -516,14 +131,6 @@
 
     rule = bindrule( rulename, frame->module );
 
-#ifdef HAVE_PYTHON
- if ( rule->python_function )
- {
- frame->module = python_module();
- return call_python_function( rule, frame );
- }
-#endif
-
     if ( DEBUG_COMPILE )
     {
         /* Try hard to indicate in which module the rule is going to execute. */
@@ -654,7 +261,7 @@
         FUNCTION * function = rule->procedure;
 
         function_refer( function );
- result = function_run_with_args( function, frame, stack_global() );
+ result = function_run( function, frame, stack_global() );
         function_free( function );
     }
 

Modified: trunk/tools/build/v2/engine/function.c
==============================================================================
--- trunk/tools/build/v2/engine/function.c (original)
+++ trunk/tools/build/v2/engine/function.c 2012-03-24 17:07:49 EDT (Sat, 24 Mar 2012)
@@ -166,6 +166,21 @@
 } JAM_FUNCTION;
 
 
+#ifdef HAVE_PYTHON
+
+#define FUNCTION_PYTHON 2
+
+typedef struct _python_function
+{
+ FUNCTION base;
+ PyObject * python_function;
+} PYTHON_FUNCTION;
+
+static LIST * call_python_function( PYTHON_FUNCTION * function, FRAME * frame );
+
+#endif
+
+
 struct _stack
 {
     void * data;
@@ -2516,9 +2531,17 @@
         *file = constant_builtin;
         *line = -1;
     }
+#ifdef HAVE_PYTHON
+ if ( function_->type == FUNCTION_PYTHON )
+ {
+ *file = constant_builtin;
+ *line = -1;
+ }
+#endif
     else
     {
         JAM_FUNCTION * function = (JAM_FUNCTION *)function_;
+ assert( function_->type == FUNCTION_JAM );
         *file = function->file;
         *line = function->line;
     }
@@ -2570,9 +2593,26 @@
     return (FUNCTION *)result;
 }
 
-int is_type_name( const char * s );
 static void argument_list_print( struct arg_list * args, int num_args );
 
+
+/* Define delimiters for type check elements in argument lists (and return type
+ * specifications, eventually).
+ */
+# define TYPE_OPEN_DELIM '['
+# define TYPE_CLOSE_DELIM ']'
+
+/*
+ * is_type_name() - true iff the given string represents a type check
+ * specification.
+ */
+
+int is_type_name( const char * s )
+{
+ return ( s[ 0 ] == TYPE_OPEN_DELIM ) &&
+ ( s[ strlen( s ) - 1 ] == TYPE_CLOSE_DELIM );
+}
+
 static void argument_error( const char * message, FUNCTION * procedure, FRAME * frame, OBJECT * arg )
 {
     LOL * actual = frame->args;
@@ -3122,8 +3162,15 @@
         else
             return (FUNCTION *)func;
     }
+#ifdef HAVE_PYTHON
+ else if ( f->type == FUNCTION_PYTHON )
+ {
+ return f;
+ }
+#endif
     else
     {
+ assert( f->type == FUNCTION_BUILTIN );
         return f;
     }
 }
@@ -3134,12 +3181,19 @@
     {
         return f;
     }
+#ifdef HAVE_PYTHON
+ else if ( f->type == FUNCTION_PYTHON )
+ {
+ return f;
+ }
+#endif
     else
     {
         JAM_FUNCTION * func = (JAM_FUNCTION *)f;
         JAM_FUNCTION * new_func = BJAM_MALLOC( sizeof( JAM_FUNCTION ) );
         instruction * code;
         int i;
+ assert( f->type == FUNCTION_JAM );
         memcpy( new_func, func, sizeof( JAM_FUNCTION ) );
         new_func->base.reference_count = 1;
         new_func->base.formal_arguments = argument_list_bind_variables( f->formal_arguments, f->num_formal_arguments, module, counter );
@@ -3250,8 +3304,17 @@
             object_free( func->file );
         }
     }
+#ifdef HAVE_PYTHON
+ else if ( function_->type == FUNCTION_PYTHON )
+ {
+ PYTHON_FUNCTION * func = (PYTHON_FUNCTION *)function_;
+ Py_DECREF( func->python_function );
+ if ( function_->rulename ) object_free( function_->rulename );
+ }
+#endif
     else
     {
+ assert( function_->type == FUNCTION_BUILTIN );
         if ( function_->rulename ) object_free( function_->rulename );
     }
 
@@ -3286,28 +3349,6 @@
     stack_deallocate( s, sizeof( string * ) );
 }
 
-LIST * function_run_with_args( FUNCTION * function_, FRAME * frame, STACK * s )
-{
- LIST * result;
- if ( function_->type == FUNCTION_BUILTIN )
- {
- BUILTIN_FUNCTION * f = (BUILTIN_FUNCTION *)function_;
- if ( function_->formal_arguments )
- argument_list_check( function_->formal_arguments, function_->num_formal_arguments, function_, frame );
- return f->func( frame, f->flags );
- }
-
- if ( function_->formal_arguments )
- argument_list_push( function_->formal_arguments, function_->num_formal_arguments, function_, frame, s );
-
- result = function_run( function_, frame, s );
-
- if ( function_->formal_arguments )
- argument_list_pop( function_->formal_arguments, function_->num_formal_arguments, frame, s );
-
- return result;
-}
-
 /*
  * WARNING: The instruction set is tuned for Jam and
  * is not really generic. Be especially careful about
@@ -3326,9 +3367,26 @@
     if ( function_->type == FUNCTION_BUILTIN )
     {
         BUILTIN_FUNCTION * f = (BUILTIN_FUNCTION *)function_;
+ if ( function_->formal_arguments )
+ argument_list_check( function_->formal_arguments, function_->num_formal_arguments, function_, frame );
         return f->func( frame, f->flags );
     }
 
+#ifdef HAVE_PYTHON
+
+ else if ( function_->type == FUNCTION_PYTHON )
+ {
+ PYTHON_FUNCTION * f = (PYTHON_FUNCTION *)function_;
+ return call_python_function( f, frame );
+ }
+
+#endif
+
+ assert( function_->type == FUNCTION_JAM );
+
+ if ( function_->formal_arguments )
+ argument_list_push( function_->formal_arguments, function_->num_formal_arguments, function_, frame, s );
+
     function = (JAM_FUNCTION *)function_;
     code = function->code;
     for ( ; ; )
@@ -3590,6 +3648,8 @@
 
         case INSTR_RETURN:
         {
+ if ( function_->formal_arguments )
+ argument_list_pop( function_->formal_arguments, function_->num_formal_arguments, frame, s );
 #ifndef NDEBUG
     
             if ( !( saved_stack == s->data ) )
@@ -4208,6 +4268,267 @@
     }
 }
 
+
+#ifdef HAVE_PYTHON
+
+static struct arg_list * arg_list_compile_python( PyObject * bjam_signature, int * num_arguments )
+{
+ if ( bjam_signature )
+ {
+ struct argument_list_compiler c[ 1 ];
+ struct arg_list * result;
+ Py_ssize_t s, i, j, inner;
+ argument_list_compiler_init( c );
+
+ s = PySequence_Size( bjam_signature );
+ for ( i = 0; i < s; ++i )
+ {
+ struct argument_compiler arg_comp[ 1 ];
+ struct arg_list arg;
+ PyObject * v = PySequence_GetItem( bjam_signature, i );
+ argument_compiler_init( arg_comp );
+
+ inner = PySequence_Size( v );
+ for ( j = 0; j < inner; ++j )
+ {
+ PyObject * x = PySequence_GetItem( v, j );
+ argument_compiler_add( arg_comp, object_new( PyString_AsString( x ) ), constant_builtin, -1 );
+ }
+
+ arg = arg_compile_impl( arg_comp, constant_builtin, -1 );
+ dynamic_array_push( c->args, arg );
+ argument_compiler_free( arg_comp );
+ Py_DECREF( v );
+ }
+
+ *num_arguments = c->args->size;
+ result = BJAM_MALLOC( c->args->size * sizeof( struct arg_list ) );
+ memcpy( result, c->args->data, c->args->size * sizeof( struct arg_list ) );
+ argument_list_compiler_free( c );
+ return result;
+ }
+ else
+ {
+ *num_arguments = 0;
+ return 0;
+ }
+}
+
+FUNCTION * function_python( PyObject * function, PyObject * bjam_signature )
+{
+ PYTHON_FUNCTION * result = BJAM_MALLOC( sizeof( PYTHON_FUNCTION ) );
+
+ result->base.type = FUNCTION_PYTHON;
+ result->base.reference_count = 1;
+ result->base.rulename = 0;
+ result->base.formal_arguments = arg_list_compile_python( bjam_signature, &result->base.num_formal_arguments );
+ Py_INCREF( function );
+ result->python_function = function;
+
+ return (FUNCTION *)result;
+}
+
+static void argument_list_to_python( struct arg_list * formal, int formal_count, FUNCTION * function, FRAME * frame, PyObject * kw )
+{
+ LOL * all_actual = frame->args;
+ int i, j;
+
+ for ( i = 0; i < formal_count; ++i )
+ {
+ LIST *actual = lol_get( all_actual, i );
+ LISTITER actual_iter = list_begin( actual ), actual_end = list_end( actual );
+ for ( j = 0; j < formal[i].size; ++j )
+ {
+ struct argument * formal_arg = &formal[i].args[j];
+ PyObject * value;
+ LIST * l;
+
+ switch ( formal_arg->flags )
+ {
+ case ARG_ONE:
+ if ( actual_iter == actual_end )
+ argument_error( "missing argument", function, frame, formal_arg->arg_name );
+ type_check_range( formal_arg->type_name, actual_iter, list_next( actual_iter ), frame, function, formal_arg->arg_name );
+ value = PyString_FromString( object_str( list_item( actual_iter) ) );
+ actual_iter = list_next( actual_iter );
+ break;
+ case ARG_OPTIONAL:
+ if ( actual_iter == actual_end )
+ value = 0;
+ else
+ {
+ type_check_range( formal_arg->type_name, actual_iter, list_next( actual_iter ), frame, function, formal_arg->arg_name );
+ value = PyString_FromString( object_str( list_item( actual_iter) ) );
+ actual_iter = list_next( actual_iter );
+ }
+ break;
+ case ARG_PLUS:
+ if ( actual_iter == actual_end )
+ argument_error( "missing argument", function, frame, formal_arg->arg_name );
+ /* fallthrough */
+ case ARG_STAR:
+ type_check_range( formal_arg->type_name, actual_iter, actual_end, frame, function, formal_arg->arg_name );
+ l = list_copy_range( actual, actual_iter, actual_end );
+ value = list_to_python( l );
+ list_free( l );
+ actual_iter = actual_end;
+ break;
+ case ARG_VARIADIC:
+ return;
+ }
+
+ if (value)
+ {
+ PyObject * key = PyString_FromString( object_str( formal_arg->arg_name ) );
+ PyDict_SetItem( kw, key, value );
+ Py_DECREF( key );
+ Py_DECREF( value );
+ }
+ }
+
+ if ( actual_iter != actual_end )
+ {
+ argument_error( "extra argument", function, frame, list_item( actual_iter ) );
+ }
+ }
+
+ for ( ; i < all_actual->count; ++i )
+ {
+ LIST * actual = lol_get( all_actual, i );
+ if ( !list_empty( actual ) )
+ {
+ argument_error( "extra argument", function, frame, list_front( actual ) );
+ }
+ }
+}
+
+/* Given a Python object, return a string to use in Jam
+ code instead of said object.
+ If the object is string, use the string value
+ If the object implemenets __jam_repr__ method, use that.
+ Otherwise return 0. */
+OBJECT * python_to_string( PyObject * value )
+{
+ if ( PyString_Check( value ) )
+ {
+ return object_new( PyString_AsString( value ) );
+ }
+ else
+ {
+ /* See if this is an instance that defines special __jam_repr__
+ method. */
+ if ( PyInstance_Check( value )
+ && PyObject_HasAttrString( value, "__jam_repr__" ) )
+ {
+ PyObject* repr = PyObject_GetAttrString( value, "__jam_repr__" );
+ if ( repr )
+ {
+ PyObject * arguments2 = PyTuple_New( 0 );
+ PyObject * value2 = PyObject_Call( repr, arguments2, 0 );
+ Py_DECREF( repr );
+ Py_DECREF( arguments2 );
+ if ( PyString_Check( value2 ) )
+ {
+ return object_new( PyString_AsString( value2 ) );
+ }
+ Py_DECREF( value2 );
+ }
+ }
+ return 0;
+ }
+}
+
+static module_t * python_module()
+{
+ static module_t * python = 0;
+ if ( !python )
+ python = bindmodule(constant_python);
+ return python;
+}
+
+static LIST * call_python_function( PYTHON_FUNCTION * function, FRAME * frame )
+{
+ LIST * result = 0;
+ PyObject * arguments = 0;
+ PyObject * kw = NULL;
+ int i ;
+ PyObject * py_result;
+ FRAME * prev_frame_before_python_call;
+
+ if ( function->base.formal_arguments )
+ {
+ arguments = PyTuple_New(0);
+ kw = PyDict_New();
+
+ argument_list_to_python( function->base.formal_arguments, function->base.num_formal_arguments, &function->base, frame, kw );
+ }
+ else
+ {
+ arguments = PyTuple_New( frame->args->count );
+ for ( i = 0; i < frame->args->count; ++i )
+ {
+ PyTuple_SetItem( arguments, i, list_to_python( lol_get( frame->args, i ) ) );
+ }
+ }
+
+ frame->module = python_module();
+
+ prev_frame_before_python_call = frame_before_python_call;
+ frame_before_python_call = frame;
+ py_result = PyObject_Call( function->python_function, arguments, kw );
+ frame_before_python_call = prev_frame_before_python_call;
+ Py_DECREF( arguments );
+ Py_XDECREF( kw );
+ if ( py_result != NULL )
+ {
+ if ( PyList_Check( py_result ) )
+ {
+ int size = PyList_Size( py_result );
+ int i;
+ for ( i = 0; i < size; ++i )
+ {
+ PyObject * item = PyList_GetItem( py_result, i );
+ OBJECT *s = python_to_string( item );
+ if ( !s ) {
+ fprintf( stderr, "Non-string object returned by Python call.\n" );
+ } else {
+ result = list_new( result, s );
+ }
+ }
+ }
+ else if ( py_result == Py_None )
+ {
+ result = L0;
+ }
+ else
+ {
+ OBJECT *s = python_to_string( py_result );
+ if (s)
+ result = list_new( L0, s );
+ else
+ /* We have tried all we could. Return empty list. There are
+ cases, e.g. feature.feature function that should return
+ value for the benefit of Python code and which also can be
+ called by Jam code, where no sensible value can be
+ returned. We cannot even emit a warning, since there will
+ be a pile of them. */
+ result = L0;
+ }
+
+ Py_DECREF( py_result );
+ }
+ else
+ {
+ PyErr_Print();
+ fprintf( stderr,"Call failed\n" );
+ }
+
+ return result;
+}
+
+#endif
+
+
 void function_done( void )
 {
     BJAM_FREE( stack );

Modified: trunk/tools/build/v2/engine/function.h
==============================================================================
--- trunk/tools/build/v2/engine/function.h (original)
+++ trunk/tools/build/v2/engine/function.h 2012-03-24 17:07:49 EDT (Sat, 24 Mar 2012)
@@ -37,4 +37,10 @@
 
 void function_done( void );
 
+#ifdef HAVE_PYTHON
+
+FUNCTION * function_python( PyObject * function, PyObject * bjam_signature );
+
+#endif
+
 #endif

Modified: trunk/tools/build/v2/engine/rules.c
==============================================================================
--- trunk/tools/build/v2/engine/rules.c (original)
+++ trunk/tools/build/v2/engine/rules.c 2012-03-24 17:07:49 EDT (Sat, 24 Mar 2012)
@@ -89,9 +89,6 @@
         r->arguments = 0;
         r->exported = 0;
         r->module = target_module;
-#ifdef HAVE_PYTHON
- r->python_function = 0;
-#endif
     }
     return r;
 }
@@ -134,11 +131,6 @@
     if ( r->actions )
         actions_free( r->actions );
     r->actions = 0;
-#ifdef HAVE_PYTHON
- if ( r->python_function )
- Py_DECREF( r->python_function );
- r->python_function = 0;
-#endif
 }
 
 

Modified: trunk/tools/build/v2/engine/rules.h
==============================================================================
--- trunk/tools/build/v2/engine/rules.h (original)
+++ trunk/tools/build/v2/engine/rules.h 2012-03-24 17:07:49 EDT (Sat, 24 Mar 2012)
@@ -90,9 +90,6 @@
                                  * the global module and be automatically
                                  * imported into other modules
                                  */
-#ifdef HAVE_PYTHON
- PyObject * python_function;
-#endif
 };
 
 /* ACTIONS - a chain of ACTIONs. */


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk