From 888393c652d2418af419d0b59cd005d7a7cd3705 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Sat, 24 Mar 2012 21:07:49 +0000 Subject: [PATCH] Merge Python function support into function.c [SVN r77518] --- src/engine/builtins.c | 27 +-- src/engine/compile.c | 395 +----------------------------------------- src/engine/function.c | 367 ++++++++++++++++++++++++++++++++++++--- src/engine/function.h | 6 + src/engine/rules.c | 8 - src/engine/rules.h | 3 - 6 files changed, 353 insertions(+), 453 deletions(-) diff --git a/src/engine/builtins.c b/src/engine/builtins.c index 55933ade3..38a091066 100644 --- a/src/engine/builtins.c +++ b/src/engine/builtins.c @@ -1841,12 +1841,7 @@ LIST * builtin_python_import_rule( FRAME * frame, int flags ) 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 @@ PyObject * bjam_import_rule( PyObject * self, PyObject * args ) 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; diff --git a/src/engine/compile.c b/src/engine/compile.c index 4bfb15025..cb08e24c9 100644 --- a/src/engine/compile.c +++ b/src/engine/compile.c @@ -115,391 +115,6 @@ void frame_free( FRAME* frame ) } -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 @@ evaluate_rule( 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 @@ evaluate_rule( 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 ); } diff --git a/src/engine/function.c b/src/engine/function.c index 4556580f9..171b4f651 100644 --- a/src/engine/function.c +++ b/src/engine/function.c @@ -166,6 +166,21 @@ typedef struct _jam_function } 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 @@ void function_location( FUNCTION * function_, OBJECT * * file, int * line ) *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 @@ FUNCTION * function_compile_actions( const char * actions, OBJECT * file, int li 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 @@ FUNCTION * function_unbind_variables( FUNCTION * f ) 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 @@ FUNCTION * function_bind_variables( FUNCTION * f, module_t * module, int * count { 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 @@ void function_free( FUNCTION * function_ ) 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 @@ void function_run_actions( FUNCTION * function, FRAME * frame, STACK * s, string 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 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) 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 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) 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 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) } } + +#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 ); diff --git a/src/engine/function.h b/src/engine/function.h index d643b7ba0..64f26b3cf 100644 --- a/src/engine/function.h +++ b/src/engine/function.h @@ -37,4 +37,10 @@ FUNCTION * function_unbind_variables( FUNCTION * f ); void function_done( void ); +#ifdef HAVE_PYTHON + +FUNCTION * function_python( PyObject * function, PyObject * bjam_signature ); + +#endif + #endif diff --git a/src/engine/rules.c b/src/engine/rules.c index 63b1e1071..8ee034720 100644 --- a/src/engine/rules.c +++ b/src/engine/rules.c @@ -89,9 +89,6 @@ static RULE * enter_rule( OBJECT * rulename, module_t * target_module ) r->arguments = 0; r->exported = 0; r->module = target_module; -#ifdef HAVE_PYTHON - r->python_function = 0; -#endif } return r; } @@ -134,11 +131,6 @@ void rule_free( RULE * r ) 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 } diff --git a/src/engine/rules.h b/src/engine/rules.h index 45794380f..74cc4873b 100644 --- a/src/engine/rules.h +++ b/src/engine/rules.h @@ -90,9 +90,6 @@ struct _rule * the global module and be automatically * imported into other modules */ -#ifdef HAVE_PYTHON - PyObject * python_function; -#endif }; /* ACTIONS - a chain of ACTIONs. */