From 72a0c82fcd03be7ba0a7626c8afab5907d668471 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 19 Jul 2010 13:20:51 +0000 Subject: [PATCH] Implemented a mechanism for parameter translation from bjam to python signatures. This allows to expose the same interface to Jamfiles as before, e.g. rule toolset.flags ( rule variable condition * : values * ) and use natural interface in the Python side, where, 'rule', 'variable', 'condition' and 'values' are parameters, and the first two of them will get string, not list of strings. [SVN r64158] --- src/build/feature.py | 3 +- src/build/project.py | 6 ++-- src/build/toolset.py | 6 ++-- src/engine/src/builtins.c | 28 +++++++++++++++++-- src/engine/src/compile.c | 59 ++++++++++++++++++++++++++++++--------- src/engine/src/lists.c | 34 ++++++++++++++++++++++ src/engine/src/lists.h | 11 ++++++++ src/engine/src/rules.c | 1 + src/engine/src/rules.h | 1 + src/util/__init__.py | 8 ++++++ 10 files changed, 136 insertions(+), 21 deletions(-) diff --git a/src/build/feature.py b/src/build/feature.py index 33a054478..061bb178d 100644 --- a/src/build/feature.py +++ b/src/build/feature.py @@ -14,7 +14,7 @@ import re -from b2.util import set, utility +from b2.util import set, utility, bjam_signature from b2.util.utility import add_grist, get_grist, ungrist, replace_grist, to_seq from b2.exceptions import * @@ -83,6 +83,7 @@ def enumerate (): # FIXME: prepare-test/finish-test? +@bjam_signature((["name"], ["values", "*"], ["attributes", "*"])) def feature (name, values, attributes = []): """ Declares a new feature with the given name, values, and attributes. name: the feature name diff --git a/src/build/project.py b/src/build/project.py index 2d2a83074..0f42e500a 100644 --- a/src/build/project.py +++ b/src/build/project.py @@ -978,7 +978,6 @@ attribute is allowed only for top-level 'project' invocations""") "Tool module '%s' does not define the 'init' method" % toolset[0]) m.init(*args) - def import_(self, name, names_to_import=None, local_names=None): name = name[0] @@ -991,7 +990,10 @@ attribute is allowed only for top-level 'project' invocations""") for f in m.__dict__: v = m.__dict__[f] if callable(v): - bjam.import_rule(jamfile_module, name + "." + f, v) + if hasattr(v, "bjam_signature"): + bjam.import_rule(jamfile_module, name + "." + f, v, v.bjam_signature) + else: + bjam.import_rule(jamfile_module, name + "." + f, v) if names_to_import: if not local_names: diff --git a/src/build/toolset.py b/src/build/toolset.py index af2486a5a..f952c3f6a 100644 --- a/src/build/toolset.py +++ b/src/build/toolset.py @@ -12,7 +12,7 @@ import feature, property, generators, property_set from b2.util.utility import * -from b2.util import set +from b2.util import set, bjam_signature __re_split_last_segment = re.compile (r'^(.+)\.([^\.])*') __re_two_ampersands = re.compile ('(&&)') @@ -87,7 +87,9 @@ def normalize_condition (property_sets): # FIXME push-checking-for-flags-module .... # FIXME: investigate existing uses of 'hack-hack' parameter # in jam code. - + +@bjam_signature((["rule_or_module", "variable_name", "condition", "*"], + ["values", "*"])) def flags (rule_or_module, variable_name, condition, values = []): """ Specifies the flags (variables) that must be set on targets under certain conditions, described by arguments. diff --git a/src/engine/src/builtins.c b/src/engine/src/builtins.c index 83bb1a2c4..2170af40e 100644 --- a/src/engine/src/builtins.c +++ b/src/engine/src/builtins.c @@ -1902,8 +1902,12 @@ PyObject* bjam_call( PyObject * self, PyObject * args ) /* - * Accepts three arguments: module name, rule name and Python callable. Creates - * a bjam rule with the specified name in the specified module, which will + * Accepts four arguments: + * - module name + * - rule name, + * - Python callable. + * - (optional) bjam language function signature. + * Creates a bjam rule with the specified name in the specified module, which will * invoke the Python callable. */ @@ -1912,10 +1916,12 @@ PyObject * bjam_import_rule( PyObject * self, PyObject * args ) char * module; char * rule; PyObject * func; + PyObject * bjam_signature = NULL; module_t * m; RULE * r; - if ( !PyArg_ParseTuple( args, "ssO:import_rule", &module, &rule, &func ) ) + if ( !PyArg_ParseTuple( args, "ssO|O:import_rule", + &module, &rule, &func, &bjam_signature ) ) return NULL; if ( !PyCallable_Check( func ) ) @@ -1932,6 +1938,22 @@ PyObject * bjam_import_rule( PyObject * self, PyObject * args ) 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; + } Py_INCREF( Py_None ); return Py_None; diff --git a/src/engine/src/compile.c b/src/engine/src/compile.c index 02f508bd6..a07e0d818 100644 --- a/src/engine/src/compile.c +++ b/src/engine/src/compile.c @@ -707,6 +707,7 @@ collect_arguments( RULE* rule, FRAME* frame ) LIST* value = 0; char modifier; LIST* arg_name = formal; /* hold the argument name for type checking */ + int multiple = 0; /* Stop now if a variable number of arguments are specified */ if ( name[0] == '*' && name[1] == 0 ) @@ -722,6 +723,7 @@ collect_arguments( RULE* rule, FRAME* frame ) case '+': case '*': value = list_copy( 0, actual ); + multiple = 1; actual = 0; /* skip an extra element for the modifier */ formal = formal->next; @@ -738,7 +740,8 @@ collect_arguments( RULE* rule, FRAME* frame ) } } - locals = addsettings( locals, VAR_SET, name, value ); + locals = addsettings(locals, VAR_SET, name, value); + locals->multiple = multiple; type_check( type_name, value, frame, rule, arg_name ); type_name = 0; } @@ -764,28 +767,58 @@ static LIST* call_python_function(RULE* r, FRAME* frame) { LIST * result = 0; - PyObject * arguments = PyTuple_New( frame->args->count ); + PyObject * arguments = 0; + PyObject * kw = NULL; int i ; PyObject * py_result; - for ( i = 0; i < frame->args->count; ++i ) + if (r->arguments) { - PyObject * arg = PyList_New(0); - LIST* l = lol_get( frame->args, i); + SETTINGS * args; - for ( ; l; l = l->next ) + arguments = PyTuple_New(0); + kw = PyDict_New(); + + for (args = collect_arguments(r, frame); args; args = args->next) { - PyObject * v = PyString_FromString(l->string); - PyList_Append( arg, v ); - Py_DECREF(v); + PyObject *key = PyString_FromString(args->symbol); + PyObject *value = 0; + if (args->multiple) + value = list_to_python(args->value); + else { + if (args->value) + value = PyString_FromString(args->value->string); + } + + 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); + + for ( ; l; l = l->next ) + { + PyObject * v = PyString_FromString(l->string); + PyList_Append( arg, v ); + Py_DECREF(v); + } + /* Steals reference to 'arg' */ + PyTuple_SetItem( arguments, i, arg ); } - /* Steals reference to 'arg' */ - PyTuple_SetItem( arguments, i, arg ); } frame_before_python_call = frame; - py_result = PyObject_CallObject( r->python_function, arguments ); - Py_DECREF( arguments ); + py_result = PyObject_Call( r->python_function, arguments, kw ); + Py_DECREF(arguments); + Py_XDECREF(kw); if ( py_result != NULL ) { if ( PyList_Check( py_result ) ) diff --git a/src/engine/src/lists.c b/src/engine/src/lists.c index df0eff4d5..ebabb63e9 100644 --- a/src/engine/src/lists.c +++ b/src/engine/src/lists.c @@ -303,3 +303,37 @@ void lol_print( LOL * lol ) list_print( lol->list[ i ] ); } } + +#ifdef HAVE_PYTHON + +PyObject *list_to_python(LIST *l) +{ + PyObject *result = PyList_New(0); + + for (; l; l = l->next) + { + PyObject* s = PyString_FromString(l->string); + PyList_Append(result, s); + Py_DECREF(s); + } + + return result; +} + +LIST *list_from_python(PyObject *l) +{ + LIST * result = 0; + + Py_ssize_t i, n; + n = PySequence_Size(l); + for (i = 0; i < n; ++i) + { + PyObject *v = PySequence_GetItem(l, i); + result = list_new (result, newstr (PyString_AsString(v))); + Py_DECREF(v); + } + + return result; +} + +#endif diff --git a/src/engine/src/lists.h b/src/engine/src/lists.h index ef5292397..1dc598274 100644 --- a/src/engine/src/lists.h +++ b/src/engine/src/lists.h @@ -45,6 +45,10 @@ #ifndef LISTS_DWA20011022_H # define LISTS_DWA20011022_H +#ifdef HAVE_PYTHON +#include +#endif + /* * LIST - list of strings */ @@ -93,5 +97,12 @@ LIST * lol_get( LOL *lol, int i ); void lol_print( LOL *lol ); void lol_build( LOL* lol, char** elements ); +#ifdef HAVE_PYTHON + +PyObject *list_to_python(LIST *l); +LIST *list_from_python(PyObject *l); + +#endif + #endif diff --git a/src/engine/src/rules.c b/src/engine/src/rules.c index 3d1a3a86e..a0be1d340 100644 --- a/src/engine/src/rules.c +++ b/src/engine/src/rules.c @@ -421,6 +421,7 @@ SETTINGS * addsettings( SETTINGS * head, int flag, char * symbol, LIST * value ) v->symbol = newstr( symbol ); v->value = value; v->next = head; + v->multiple = 0; head = v; } else if ( flag == VAR_APPEND ) diff --git a/src/engine/src/rules.h b/src/engine/src/rules.h index 78e056202..806a1469c 100644 --- a/src/engine/src/rules.h +++ b/src/engine/src/rules.h @@ -119,6 +119,7 @@ struct _settings SETTINGS * next; char * symbol; /* symbol name for var_set() */ LIST * value; /* symbol value for var_set() */ + int multiple; }; /* TARGETS - a chain of TARGETs. */ diff --git a/src/util/__init__.py b/src/util/__init__.py index e69de29bb..e64c0fc5e 100644 --- a/src/util/__init__.py +++ b/src/util/__init__.py @@ -0,0 +1,8 @@ + +def bjam_signature(s): + + def wrap(f): + f.bjam_signature = s + return f + + return wrap