[plt-scheme] Reusing the argv parameter in C extension primitives
Hi,
To allow this Scheme code:
(spy-apply some-py-function pyobj1 pyobj2 ...)
I had a C primitive that looked like this:
Scheme_Object* spy_apply(const char* name, int argc, Scheme_Object* argv[])
{
Scheme_Object* scheme_pyfn = argv[0];
PyObject* fnobj = PY(scheme_pyfn);
PyObject* args = PyTuple_New(argc - 1);
PyObject* result;
int i;
for ( i = 1; i < argc; i++ )
{
PyObject* arg = PY(argv[i]);
PyTuple_SetItem(args, i - 1, arg);
}
result = PyObject_CallObject(fnobj, args);
return SCM( result );
}
where the two functions SCM(py) and PY(scm) wrap/unwrap PyObjects
around SCHEME_CPTRP objects.
Some python function objects, though, are actually wrappers around
Scheme procedures, and PyObject_CallObject will call this function for
them:
PyObject* PySchemeFunction_Call(PyObject* self, PyObject* argsTuple,
PyObject* ignored)
{
PySchemeFunctionObject* fn = (PySchemeFunctionObject*) self;
Scheme_Object* argv[1024];
Scheme_Object* result;
int argc = PyTuple_GET_SIZE(argsTuple);
int i;
for ( i = 0; i < argc; i++ )
{
PyObject* arg = PyTuple_GET_ITEM(argsTuple, i);
argv[i] = SCM(arg);
}
result = _scheme_apply(fn->proc, argc, argv);
return PY(result);
}
I thought that translating the argv array into a Python tuple and then
back into another argv array was sort of wasteful, so I tried to edit
spy_apply:
Scheme_Object* spy_apply(const char* name, int argc, Scheme_Object* argv[])
{
Scheme_Object* scheme_pyfn = argv[0];
PyObject* fnobj = PY(scheme_pyfn);
if (fnobj->ob_type == &PySchemeFunction_Type)
return _scheme_apply(((PySchemeFunctionObject*)fnobj)->proc,
argc - 1, argv + 1);
....
}
But if the Scheme procedure used call/cc then my code would end up
jumping to random places. Should I always make a copy of argv instead
of reusing it in another scheme_apply? If so, can I keep a single
static argv array for that purpose, like this?
static Scheme_Object* spy_apply_argv[1024];
Scheme_Object* scheme_initialize(Scheme_Env* ns)
{
scheme_register_extension_global(&spy_apply_argv, sizeof(spy_apply_argv));
...
}
Scheme_Object* spy_apply(const char* name, int argc, Scheme_Object* argv[])
{
Scheme_Object* scheme_pyfn = argv[0];
PyObject* fnobj = PY(scheme_pyfn);
if (fnobj->ob_type == &PySchemeFunction_Type)
{
Scheme_Object* res;
int i = 0, argcc = argc - 1;
// maybe use memcpy here instead
for ( ; i < argcc; i++ )
spy_apply_argv[i] = argv[i + 1];
return _scheme_apply(((PySchemeFunctionObject*)fnobj)->proc,
argcc, spy_apply_argv);
}
...
}
Daniel