[lua] push list values with __index metamethod to lookup string/nil keys in key-value lists

personal/stbuehler/wip
Stefan Bühler 9 years ago
parent 9f9fe72d97
commit ad687636e9
  1. 69
      src/main/core_lua.c
  2. 64
      src/main/value_lua.c

@ -246,6 +246,75 @@ static int li_lua_path_simplify(lua_State *L) {
return 1;
}
/* not used right now: using __index metamethod instead to lookup on demand. also not tested yet. */
#if 0
/* should convert a [(key,value)] list to a table t[key] = value;
* a nil key marks the default entry.
* returns (t, default_entry)
* requires unique keys
*/
static int li_lua_kvl_to_table(lua_State *L) {
int resTable, defValue;
gboolean haveDefault = FALSE;
if (!lua_istable(L, 1)) return 0;
lua_newtable(L);
resTable = lua_top(L);
lua_pushnil();
defValue = lua_top(L);
lua_pushnil(L); /* start iterating with "no key" */
while (0 != lua_next(L, 1)) {
gboolean nil_key = FALSE;
/* key at -2 and value at -1 */
/* only lists (numeric keys) with tuples ("tables") as entries */
if (LUA_TNUMBER != lua_type(L, -2) || !lua_istable(L, -1)) return 0;
lua_pushnil(L);
while (0 != lua_next(L, -2)) {
if (LUA_TNUMBER != lua_type(L, -2)) return 0; /* not a tuple */
lua_Number n = lua_tonumber(L, -2);
if (n == 1) { /* key from (k,v) pair */
switch (lua_type(L, -1)) {
case LUA_TNIL:
nil_key = TRUE;
break;
case LUA_TSTRING:
break;
default:
return 0; /* wrong key type */
}
} else if (n != 2) return 0; /* not a (k,v) pair */
lua_pop(L, 1);
}
if (!nil_key) {
lua_rawgeti(L, -1, 1);
lua_gettable(L, resTable);
if (!lua_isnil(L, -1)) return 0; /* duplicate key */
lua_pop(L, 1);
lua_rawgeti(L, -1, 1);
lua_rawgeti(L, -2, 2);
lua_settable(L, resTable);
} else if (haveDefault) {
return 0; /* duplicate default */
} else {
lua_rawgeti(L, -1, 2);
lua_replace(L, defValue);
}
lua_pop(L, 1); /* pop value for next iteration */
}
return 2;
}
#endif
static void lua_push_constants(lua_State *L, int ndx) {
lua_pushinteger(L, LI_HANDLER_GO_ON);
lua_setfield(L, ndx, "HANDLER_GO_ON");

@ -4,6 +4,67 @@
#include <lighttpd/actions_lua.h>
#include <lighttpd/core_lua.h>
#include <lauxlib.h>
#define LUA_KVLIST_VALUE "li KeyValue list (string, liValue*)"
static int lua_kvlist_index(lua_State *L) {
guint len, i;
gboolean nil_key;
switch (lua_type(L, 2)) {
case LUA_TNUMBER:
lua_rawget(L, 1);
return 1;
case LUA_TSTRING:
nil_key = FALSE;
break;
case LUA_TNIL:
nil_key = TRUE;
break;
default:
goto fail;
}
if (LUA_TTABLE != lua_type(L, 1)) goto fail;
len = lua_objlen(L, 1);
for (i = len; i >= 1; lua_pop(L, 1), --i) {
lua_rawgeti(L, 1, i);
if (LUA_TTABLE != lua_type(L, -1)) continue;
if (2 != lua_objlen(L, -1)) continue;
lua_rawgeti(L, -1, 1);
switch (lua_type(L, -1)) {
case LUA_TSTRING:
if (nil_key) break;
if (!lua_equal(L, -1, 2)) break;
lua_rawgeti(L, -1, 2);
return 1;
case LUA_TNIL:
if (!nil_key) break;
lua_rawgeti(L, -1, 2);
return 1;
default:
break;
}
lua_pop(L, 1);
}
fail:
lua_pushnil(L);
return 1;
}
static void lua_push_kvlist_metatable(lua_State *L) {
if (luaL_newmetatable(L, LUA_KVLIST_VALUE)) {
lua_pushcclosure(L, lua_kvlist_index, 0);
lua_setfield(L, -2, "__index");
}
}
static liValue* li_value_from_lua_table(liServer *srv, lua_State *L, int ndx) {
liValue *val = NULL, *sub_option;
GArray *list = NULL;
@ -182,6 +243,9 @@ int li_lua_push_value(lua_State *L, liValue *value) {
li_lua_push_value(L, subval);
lua_rawseti(L, -2, i);
}
/* kvlist lookup for string/nil keys */
lua_push_kvlist_metatable(L);
lua_setmetatable(L, -2);
} break;
case LI_VALUE_HASH: {
GHashTableIter it;

Loading…
Cancel
Save