$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
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. */