lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


One thing I have recently implemented for lua in C is automatic parameter
list creation.  I know there are those who will find this horrifically
inelegant, but here goes.

The idea is that when a dynamic library of subroutines is loaded, or
some interface is loaded (e.g. IDL) then instead of having to generate
code manually to bind each C function or interface call to the desired
subroutine, we automatically build a parameter list on the fly and
push it on to the stack.  By casting the desired function to a generic
function call type, we can pass our bag of parameters to the function
and have them interpreted as the normal arguments to the function.
Using this scheme, we could load in a dynamic link library on the fly
and with just a string or table to specify its parameters, generate
a function call to it.


Here's an example:

int mycfunction(int val, char *stuff)
{
  printf("value=%d stuff=%s\n", val, stuff);
  return val+1;
}

Then to bind this to lua we would do

x=lua_newtag();           /* sets up generic function interception tag */
lua_pushCclosure(bindingfunc, 0);
lua_settagmethod(x, "function");

lua_createtable();       /* create a table with two elements */
lua_Object tb = lua_pop();
lua_pushobject(tb);
lua_settag(x);
lua_pushobject(tb);
lua_pushnumber(1.0);
lua_pushCclosure(mycfunction, 0);  /* first element is pointer to real function */
lua_settable();
lua_pushobject(tb);
lua_pushnumber(2.0);
lua_pushstring("iis");    /* two element list, returns integer, one integer, one string */
lua_settable();
lua_pushobject(tb);
lua_setglobal("mycfunction");

Then to actually implement the generic function call creator

typedef long (genericcall)(char parmlist[256]);
 
void bindingfunc(void)    /* tag method */
{
  char parmlist[256];
  char *tr = parmlist;
  int argno, retval;
 
  lua_Object tb = lua_getparam(1);
  genericcall gf;
  char *parmtypes;

  lua_pushobject(tb);     /* gets the c function and parameters */
  lua_pushnumber(1.0);
  gf = (genericcall)(lua_getcfunction(lua_gettable());
  lua_pushobject(tb);
  lua_pushnumber(2.0);
  parmtypes = lua_getstring(lua_gettable());
  for(argno=1;argno<strlen(parmtypes);argno++) {
    switch (parmtypes[argno])
    case 'i':
       *((int *)tr)++ = (int)luaL_check_number(argno+1);
       break;
    case 's':
       *((char **)tr)++ = luaL_check_string(argno+1);
       break;
  }
  retval = gf(parmlist);
  switch (parmtypes[0]) {
    case 'i':
       lua_pushnumber(retval);
       break;
    case 's':
       lua_pushstring((char *)retval);
       break;
  }
}

The first part defines a new tag for intercepted external function calls.
The next part creates a table with the first element as the function that
we wish to call, and the second element as the parameters in a string 
(though another table might be better, I used a string for brevity here).
Then when the table is called like a function, the tag method is invoked,
and the parameters are automatically read and a parameter list is created.
Because the function is casted to an array, it is actually passed a char
array, but it interprets it as its parameters.

I have actually implemented this and it seems to work great.  I am trying
to figure out how to also do C++ method calls the same way, since
essentially they are the same as a function call except with the first
parameter as "this".  I am not exactly sure how to deal with virtual
functions, but perhaps the casting can handle that.

This works for C functions OK, perhaps someone can think of a way to do
this for methods.  This would help eliminate the need for wrapper functions
and the tedious creation of them.

Dan Marks
dmarks@uiuc.edu