lua-users home
lua-l archive

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


On Mon, Jun 15, 2009 at 6:14 AM, John Hind wrote:
>On Mon, Jun 15, 2009 at 4:59 AM, Juris Kalnins wrote:
>> There is lua_lessthan and lua_equal that mirror '<' and '=='.
>> Is there any comparable way to execute from C API other
>> operators too?
>>
>...there does not seem to be a match for the arithmetic
> operations or for __le.... It would be useful (if only for orthogonality)
> to have API functions for the arithmetic operations also!

I too came across this omission when writing lua2c [1], which
translates Lua source to C code consisting of Lua C API calls.  The
workaround I ended up doing was to code generate the equivalent
functions if the operations occurred in the Lua code.  For example,
look at the output for bisect.c (based on bisect.lua) on the web page
[1].  I would prefer if Lua defined these functions itself, as that
would remove boilerplate from the lua2c output.

  [1] http://lua-users.org/wiki/LuaToCee

The code templates used are copied at the bottom of this message.
Since the binary arithmetic functions are quite similar, it might be
better to implement them all as a single function that does a lookup
on the operation.  That would result in three new C API functions:
lua_lessequal, lua_binop, and lua_unop.  You might even merge
lua_equal, lua_lessthan and lua_lessequal into lua_binop, but the
comparison functions always return a Boolean, which one usually
prefers returned directly in C rather than pushed onto the Lua stack.
BTW, the "warning" below is merely documenting the fact that an
assumption is being made about the implemented value of
LUA_REGISTRYINDEX that might not be explicit in the Lua Reference
Manual.

-----

/* __add metamethod handler.
 * warning: assumes indices in range LUA_REGISTRYINDEX < x < 0 are relative. */
static void lc_add(lua_State * L, int idxa, int idxb) {
  if (lua_isnumber(L,idxa) && lua_isnumber(L,idxb)) {
    lua_pushnumber(L,lua_tonumber(L,idxa) + lua_tonumber(L,idxb));
  }
  else {
    if (luaL_getmetafield(L,idxa,"__add")||luaL_getmetafield(L,idxb,"__add")) {
      lua_pushvalue(L,idxa < 0 && idxa > LUA_REGISTRYINDEX ? idxa-1 : idxa);
      lua_pushvalue(L,idxb < 0 && idxb > LUA_REGISTRYINDEX ? idxb-2 : idxb);
      lua_call(L,2,1);
    }
    else {
      luaL_error(L, "attempt to perform arithmetic");
    }
  }
}
/* ... and similarly for the other binary operations ... */


/* __le metamethod handler.
 * warning: assumes indices in range LUA_REGISTRYINDEX < x < 0 are relative. */
static int lc_le(lua_State * L, int idxa, int idxb) {
  if (lua_type(L,idxa) == LUA_TNUMBER && lua_type(L,idxb) == LUA_TNUMBER) {
    return lua_tonumber(L,idxa) <= lua_tonumber(L,idxb);
  }
  else if (lua_type(L,idxa) == LUA_TSTRING && lua_type(L,idxb) == LUA_TSTRING) {
    /* result similar to lvm.c l_strcmp */
    return lua_lessthan(L,idxa,idxb) || lua_rawequal(L,idxa,idxb);
  }
  else if (luaL_getmetafield(L,idxa,"__le")||luaL_getmetafield(L,idxb,"__le")) {
    lua_pushvalue(L,idxa < 0 && idxa > LUA_REGISTRYINDEX ? idxa-1 : idxa);
    lua_pushvalue(L,idxb < 0 && idxb > LUA_REGISTRYINDEX ? idxb-2 : idxb);
    lua_call(L,2,1);
    const int result = lua_toboolean(L,-1);
    lua_pop(L,1);
    return result;
  }
  else if (luaL_getmetafield(L,idxa,"__lt")||luaL_getmetafield(L,idxb,"__lt")) {
    lua_pushvalue(L,idxb < 0 && idxb > LUA_REGISTRYINDEX ? idxb-1 : idxb);
    lua_pushvalue(L,idxa < 0 && idxa > LUA_REGISTRYINDEX ? idxa-2 : idxa);
    lua_call(L,2,1);
    const int result = ! lua_toboolean(L,-1);
    lua_pop(L,1);
    return result;
  }
  else {
    return luaL_error(L, "attempt to compare");
  }
}


/* __unm metamethod handler.
 * warning: assumes indices in range LUA_REGISTRYINDEX < x < 0 are relative. */
static void lc_unm(lua_State * L, int idxa) {
  if (lua_isnumber(L,idxa)) {
    lua_pushnumber(L,- lua_tonumber(L, idxa));
  }
  else {
    if (luaL_getmetafield(L,idxa,"__unm")) {
      lua_pushvalue(L,idxa < 0 && idxa > LUA_REGISTRYINDEX ? idxa-1 : idxa);
      lua_call(L,1,1);
    }
    else {
      luaL_error(L, "attempt to perform arithmetic");
    }
  }
}