lua-users home
lua-l archive

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



How about this one, which creates record types with named fields?
(I guess it is my competitive spirit :) )

And dangerously close to implementing ADTs; only lacking pattern matching. hmmm....

#include <lua.h>
#include <lauxlib.h>

/* constructor = record(typename, field...)
     rec = constructor(val...)
     val = rec(field)
     val... = rec(field...)
     allvals = rec()
     typename = rec(nil)
*/

static int aux_record(lua_State *L) {
  int m = lua_gettop(L);
  int n = lua_pushupvalues(L);
  if (m == 0) {
    return n - 1;   /* return all the values */
  } else {
    int i = 1;
    ++m;
    for (; i < m; ++i) {
      int field;
      if (lua_isnil(L, i)) {  /* get the typename */
        lua_pushvalue(L, m);
        lua_gettable(L, m);
      } else {
        lua_pushvalue(L, i);
        lua_gettable(L, m);
        if (!lua_isnil(L, -1)) {
          field = (int)lua_tonumber(L, -1);
          lua_pop(L, 1);
          lua_pushvalue(L, m + field);
        }
      }
      lua_replace(L, i);
    }
        --m;
    lua_settop(L, m);
    return m;
  }
}

static int aux_factory(lua_State *L) {
  int nfields = (int)lua_tonumber(L, lua_upvalueindex(2));
  lua_settop(L, nfields - 1);  /* cavalierly discard extra values */
  lua_pushvalue(L, lua_upvalueindex(1));
  lua_insert(L, 1);
  lua_pushcclosure(L, aux_record, nfields);
  return 1;
}
       
/* create a record type by generating its constructor from a list of field names;
   the first argument is the name of the record type itself
 */
static int l_recordFactory(lua_State *L) {
  int n = lua_gettop(L);
  int i;
  luaL_checkstring(L, 1);
  luaL_argcheck(L, n <= LUA_MINSTACK, n, "too many fields");
         /* Actually, the limit could be quite a bit bigger) */
  luaL_argcheck(L, n > 1, n, "need at least one field");
  luaL_checkstack(L, 3, "This should never happen");
  lua_newtable(L);
  lua_pushvalue(L, -1); /* The table itself is the key for the typename */
  lua_pushvalue(L, 1);
  lua_settable(L, -3);
  lua_replace(L, 1);
  for (i = n; i > 1; ) {
    luaL_checkstring(L, -1);  /* strictly optional, why shouldn't they be arbitrary types */
    lua_pushnumber(L, (lua_Number)--i);
    lua_settable(L, 1);
  }
  lua_pushnumber(L, (lua_Number)n);
  lua_pushcclosure(L, aux_factory, 2);
  return 1;
}

int luaopen_record(lua_State *L) {
  lua_pushliteral(L, "record");
  lua_pushcclosure(L, l_recordFactory, 0);
  lua_settable(L, LUA_GLOBALSINDEX);
  return 0;
}

-------------------

Lua 5.0.2-rici  Copyright (C) 1994-2003 Tecgraf, PUC-Rio
> cons = record("cons", "cdr", "car")
> null = cons()
> =null()
nil     nil
> a = cons(null, 24)
> b = cons(a, 37)
> =b()
function: 0x6049b0      37
> =b(nil)
cons
> =a()
function: 0x604910      24
> =a 'car'
24
> =a(nil)
list
> =a("car", "cdr")
24      function: 0x604910