# HG changeset patch # User jbe # Date 1408501448 -7200 # Node ID 144f0bddee2b5063762eb807c50fec5e2ecf2354 # Parent 2cb22d01fdd0449747711e259ef5ace69c24286d Pass value as argument to __call metamethod diff -r 2cb22d01fdd0 -r 144f0bddee2b Makefile --- a/Makefile Wed Aug 20 01:59:55 2014 +0200 +++ b/Makefile Wed Aug 20 04:24:08 2014 +0200 @@ -8,13 +8,13 @@ seqlualib.o: seqlualib.c seqlualib.h cc -O2 -c -fpic -I $(LUA_INCLUDE) -o seqlualib.o seqlualib.c -seqlua.so: seqlua.o seqlualib.o - ld -shared -o seqlua.so seqlua.o seqlualib.o +seqlua.so: seqlua.o + ld -shared -o seqlua.so seqlua.o seqlua.o: seqlua.c seqlualib.h cc -O2 -c -fpic -I $(LUA_INCLUDE) -o seqlua.o seqlua.c -seqlua_c_example.so: seqlua_c_example.o seqlua.o +seqlua_c_example.so: seqlua_c_example.o seqlualib.o ld -shared -o seqlua_c_example.so seqlua_c_example.o seqlualib.o seqlua_c_example.o: seqlua_c_example.c seqlualib.h diff -r 2cb22d01fdd0 -r 144f0bddee2b README --- a/README Wed Aug 20 01:59:55 2014 +0200 +++ b/README Wed Aug 20 04:24:08 2014 +0200 @@ -35,12 +35,12 @@ -- 2 b -- 3 c - function alphabet() + function alphabet(from, to) local letter = nil return function() if letter == nil then - letter = "a" - elseif letter == "z" then + letter = from + elseif letter == to then return nil else letter = string.char(string.byte(letter) + 1) @@ -49,7 +49,7 @@ end end - f = alphabet() + f = alphabet("a", "z") for i, v in ipairs(f) do print(i, v) @@ -62,6 +62,21 @@ -- 25 y -- 26 z + c = setmetatable( + { iter = alphabet("a", "f") }, + { __call = function(t) return t.iter() end } + ) + + for i, v in ipairs(c) do + print(i, v) + end + -- prints: + -- 1 a + -- 2 b + -- 3 c + -- 4 e + -- 5 f + set = {apple = true, banana = true} for i, k, v in ipairs(pairs(set)) do print(i, k, v) @@ -145,9 +160,3 @@ value is replaced by a closure calling the ``__call`` metamethod. -TODO ----- - -* pass the original value to the ``__call`` metamethod as first argument - - diff -r 2cb22d01fdd0 -r 144f0bddee2b seqlua.c --- a/seqlua.c Wed Aug 20 01:59:55 2014 +0200 +++ b/seqlua.c Wed Aug 20 04:24:08 2014 +0200 @@ -1,6 +1,12 @@ #include #include -#include "seqlualib.h" + +static int seqlua_aux_call(lua_State *L) { + lua_pushvalue(L, lua_upvalueindex(1)); + lua_pushvalue(L, lua_upvalueindex(2)); + lua_call(L, 1, 1); + return 1; +} static int seqlua_ipairsaux_raw(lua_State *L) { lua_Integer i; @@ -35,7 +41,7 @@ } } -static int seqlua_ipairsaux_funcclosure(lua_State *L) { +static int seqlua_ipairsaux_triplet(lua_State *L) { lua_Integer i = lua_tointeger(L, lua_upvalueindex(4)) + 1; lua_settop(L, 0); lua_pushinteger(L, i); @@ -57,18 +63,22 @@ } static int seqlua_ipairs(lua_State *L) { - if (luaL_getmetafield(L, 1, "__call")) { - if (lua_type(L, -1) != LUA_TFUNCTION) luaL_error(L, "__call is not a function"); - lua_replace(L, 1); - } + luaL_checkany(L, 1); // provides better error message if (lua_type(L, 1) == LUA_TFUNCTION) { + seqlua_ipairs_function: if (!lua_isnoneornil(L, 2) || !lua_isnoneornil(L, 3)) { lua_settop(L, 3); lua_pushinteger(L, 0); - lua_pushcclosure(L, seqlua_ipairsaux_funcclosure, 4); + lua_pushcclosure(L, seqlua_ipairsaux_triplet, 4); return 1; } lua_pushcfunction(L, seqlua_ipairsaux_func); + } else if (luaL_getmetafield(L, 1, "__call")) { + if (lua_type(L, -1) != LUA_TFUNCTION) luaL_error(L, "__call is not a function"); + lua_pushvalue(L, 1); + lua_pushcclosure(L, seqlua_aux_call, 2); + lua_replace(L, 1); + goto seqlua_ipairs_function; } else if (luaL_getmetafield(L, 1, "__index")) { lua_pushcfunction(L, seqlua_ipairsaux_meta); } else { @@ -80,7 +90,26 @@ return 3; } -static int seqlua_iteratoraux(lua_State *L) { +static int seqlua_iteratoraux_raw(lua_State *L) { + lua_Integer i = lua_tointeger(L, lua_upvalueindex(2)) + 1; + lua_rawgeti(L, lua_upvalueindex(1), i); + if (lua_isnil(L, -1)) return 1; + lua_pushinteger(L, i); + lua_replace(L, lua_upvalueindex(2)); + return 1; +} + +static int seqlua_iteratoraux_meta(lua_State *L) { + lua_Integer i = lua_tointeger(L, lua_upvalueindex(2)) + 1; + lua_pushinteger(L, i); + lua_gettable(L, lua_upvalueindex(1)); + if (lua_isnil(L, -1)) return 1; + lua_pushinteger(L, i); + lua_replace(L, lua_upvalueindex(2)); + return 1; +} + +static int seqlua_iteratoraux_triplet(lua_State *L) { lua_settop(L, 0); lua_pushvalue(L, lua_upvalueindex(1)); lua_pushvalue(L, lua_upvalueindex(2)); @@ -95,21 +124,31 @@ return lua_gettop(L); } -static int seqlua_iterator(lua_State *L) { - if (luaL_getmetafield(L, 1, "__call")) { - if (lua_type(L, -1) != LUA_TFUNCTION) luaL_error(L, "__call is not a function"); - lua_replace(L, 1); - } +int seqlua_iterator(lua_State *L) { + luaL_checkany(L, 1); // provides better error message + lua_settop(L, 3); if (lua_type(L, 1) == LUA_TFUNCTION) { - if (lua_isnoneornil(L, 2) && lua_isnoneornil(L, 3)) { + seqlua_iterator_function: + if (lua_isnil(L, 2) && lua_isnil(L, 3)) { lua_settop(L, 1); } else { - lua_settop(L, 3); - lua_pushcclosure(L, seqlua_iteratoraux, 3); + lua_pushcclosure(L, seqlua_iteratoraux_triplet, 3); } + } else if (luaL_getmetafield(L, 1, "__call")) { + if (lua_type(L, -1) != LUA_TFUNCTION) luaL_error(L, "__call is not a function"); + lua_pushvalue(L, 1); + lua_pushcclosure(L, seqlua_aux_call, 2); + lua_replace(L, 1); + goto seqlua_iterator_function; + } else if (luaL_getmetafield(L, 1, "__index")) { + lua_pushvalue(L, 1); + lua_pushinteger(L, 0); + lua_pushcclosure(L, seqlua_iteratoraux_raw, 2); } else { - seqlua_iterclosure(L, 1); - lua_settop(L, 1); + luaL_checktype(L, 1, LUA_TTABLE); + lua_pushvalue(L, 1); + lua_pushinteger(L, 0); + lua_pushcclosure(L, seqlua_iteratoraux_meta, 2); } return 1; } diff -r 2cb22d01fdd0 -r 144f0bddee2b seqlua_c_example.c --- a/seqlua_c_example.c Wed Aug 20 01:59:55 2014 +0200 +++ b/seqlua_c_example.c Wed Aug 20 04:24:08 2014 +0200 @@ -8,14 +8,29 @@ seqlua_iterloop(L, &iter, 1) { if (seqlua_itercount(&iter) > 1) fputs(",", stdout); fputs(luaL_tolstring(L, -1, NULL), stdout); - lua_pop(L, 1); + lua_pop(L, 1); // pop value that luaL_tolstring pushed onto stack } fputs("\n", stdout); return 0; } +static int seqlua_c_example_printthree(lua_State *L) { + int i; + seqlua_iterclosure(L, 1); + for (i=0; i<3; i++) { + lua_pushvalue(L, 1); + lua_call(L, 0, 1); + fputs(luaL_tolstring(L, -1, NULL), stdout); + lua_pop(L, 1); // pop value that luaL_tolstring pushed onto stack + fputs("\n", stdout); + } + return 0; +} + int luaopen_seqlua_c_example(lua_State *L) { lua_pushcfunction(L, seqlua_c_example_printcsv); lua_setglobal(L, "printcsv"); + lua_pushcfunction(L, seqlua_c_example_printthree); + lua_setglobal(L, "printthree"); return 0; } diff -r 2cb22d01fdd0 -r 144f0bddee2b seqlua_c_example_test.lua --- a/seqlua_c_example_test.lua Wed Aug 20 01:59:55 2014 +0200 +++ b/seqlua_c_example_test.lua Wed Aug 20 04:24:08 2014 +0200 @@ -22,3 +22,15 @@ -- prints: -- a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z +printthree(alphabet()) +-- prints: +-- a +-- b +-- c + +printthree(setmetatable({v="x"}, {__call=function(t) return t.v end})) +-- prints: +-- x +-- x +-- x + diff -r 2cb22d01fdd0 -r 144f0bddee2b seqlualib.c --- a/seqlualib.c Wed Aug 20 01:59:55 2014 +0200 +++ b/seqlualib.c Wed Aug 20 04:24:08 2014 +0200 @@ -2,28 +2,33 @@ #include #include "seqlualib.h" -#define SEQLUA_ITERTYPE_FUNC 1 -#define SEQLUA_ITERTYPE_META 2 -#define SEQLUA_ITERTYPE_RAW 3 +#define SEQLUA_ITERTYPE_CALL 1 +#define SEQLUA_ITERTYPE_FUNC 2 +#define SEQLUA_ITERTYPE_META 3 +#define SEQLUA_ITERTYPE_RAW 4 void seqlua_iterinit(lua_State *L, seqlua_Iterator *iter, int idx) { luaL_checkany(L, idx); // provides better error message iter->L = L; if (luaL_getmetafield(L, idx, "__call")) { if (lua_type(L, -1) != LUA_TFUNCTION) luaL_error(L, "__call is not a function"); - iter->itertype = SEQLUA_ITERTYPE_FUNC; + iter->idx = lua_gettop(L); + iter->callargidx = idx; + iter->itertype = SEQLUA_ITERTYPE_CALL; } else if (lua_type(L, idx) == LUA_TFUNCTION) { - lua_pushvalue(L, idx); + lua_pushnil(L); // dummy value + iter->idx = idx; iter->itertype = SEQLUA_ITERTYPE_FUNC; } else { + iter->idx = idx; if (luaL_getmetafield(L, idx, "__index")) { - lua_pop(L, 1); iter->itertype = SEQLUA_ITERTYPE_META; + // leave __index as dummy value } else { + lua_pushnil(L); // dummy value luaL_checktype(L, idx, LUA_TTABLE); iter->itertype = SEQLUA_ITERTYPE_RAW; } - lua_pushvalue(L, idx); } iter->i = 0; } @@ -32,19 +37,25 @@ lua_State *L = iter->L; lua_Integer i = ++iter->i; switch (iter->itertype) { + case SEQLUA_ITERTYPE_CALL: + lua_pushvalue(L, iter->idx); + lua_pushvalue(L, iter->callargidx); + lua_call(L, 1, 1); + break; case SEQLUA_ITERTYPE_FUNC: - lua_pushvalue(L, -1); + lua_pushvalue(L, iter->idx); lua_call(L, 0, 1); break; case SEQLUA_ITERTYPE_META: lua_pushinteger(L, i); - lua_gettable(L, -2); + lua_gettable(L, iter->idx); break; case SEQLUA_ITERTYPE_RAW: - lua_rawgeti(L, -1, i); + lua_rawgeti(L, iter->idx, i); + break; } if (lua_isnil(L, -1)) { - lua_pop(L, 2); + lua_pop(L, 2); // remove nil and dummy value return 0; } return 1; @@ -69,11 +80,21 @@ return 1; } +static int seqlua_iterclosureaux_call(lua_State *L) { + lua_pushvalue(L, lua_upvalueindex(1)); + lua_pushvalue(L, lua_upvalueindex(2)); + lua_call(L, 1, 1); + return 1; +} + void seqlua_iterclosure(lua_State *L, int idx) { + luaL_checkany(L, idx); // provides better error message if (lua_type(L, idx) == LUA_TFUNCTION) { // do nothing } else if (luaL_getmetafield(L, idx, "__call")) { if (lua_type(L, -1) != LUA_TFUNCTION) luaL_error(L, "__call is not a function"); + lua_pushvalue(L, idx); + lua_pushcclosure(L, seqlua_iterclosureaux_call, 2); lua_replace(L, idx); } else if (luaL_getmetafield(L, idx, "__index")) { lua_pop(L, 1); diff -r 2cb22d01fdd0 -r 144f0bddee2b seqlualib.h --- a/seqlualib.h Wed Aug 20 01:59:55 2014 +0200 +++ b/seqlualib.h Wed Aug 20 04:24:08 2014 +0200 @@ -3,6 +3,8 @@ typedef struct { lua_State *L; + int idx; + int callargidx; int itertype; lua_Integer i; } seqlua_Iterator;