seqlua
changeset 8:144f0bddee2b
Pass value as argument to __call metamethod
author | jbe |
---|---|
date | Wed Aug 20 04:24:08 2014 +0200 (2014-08-20) |
parents | 2cb22d01fdd0 |
children | 564320bb2862 |
files | Makefile README seqlua.c seqlua_c_example.c seqlua_c_example_test.lua seqlualib.c seqlualib.h |
line diff
1.1 --- a/Makefile Wed Aug 20 01:59:55 2014 +0200 1.2 +++ b/Makefile Wed Aug 20 04:24:08 2014 +0200 1.3 @@ -8,13 +8,13 @@ 1.4 seqlualib.o: seqlualib.c seqlualib.h 1.5 cc -O2 -c -fpic -I $(LUA_INCLUDE) -o seqlualib.o seqlualib.c 1.6 1.7 -seqlua.so: seqlua.o seqlualib.o 1.8 - ld -shared -o seqlua.so seqlua.o seqlualib.o 1.9 +seqlua.so: seqlua.o 1.10 + ld -shared -o seqlua.so seqlua.o 1.11 1.12 seqlua.o: seqlua.c seqlualib.h 1.13 cc -O2 -c -fpic -I $(LUA_INCLUDE) -o seqlua.o seqlua.c 1.14 1.15 -seqlua_c_example.so: seqlua_c_example.o seqlua.o 1.16 +seqlua_c_example.so: seqlua_c_example.o seqlualib.o 1.17 ld -shared -o seqlua_c_example.so seqlua_c_example.o seqlualib.o 1.18 1.19 seqlua_c_example.o: seqlua_c_example.c seqlualib.h
2.1 --- a/README Wed Aug 20 01:59:55 2014 +0200 2.2 +++ b/README Wed Aug 20 04:24:08 2014 +0200 2.3 @@ -35,12 +35,12 @@ 2.4 -- 2 b 2.5 -- 3 c 2.6 2.7 - function alphabet() 2.8 + function alphabet(from, to) 2.9 local letter = nil 2.10 return function() 2.11 if letter == nil then 2.12 - letter = "a" 2.13 - elseif letter == "z" then 2.14 + letter = from 2.15 + elseif letter == to then 2.16 return nil 2.17 else 2.18 letter = string.char(string.byte(letter) + 1) 2.19 @@ -49,7 +49,7 @@ 2.20 end 2.21 end 2.22 2.23 - f = alphabet() 2.24 + f = alphabet("a", "z") 2.25 2.26 for i, v in ipairs(f) do 2.27 print(i, v) 2.28 @@ -62,6 +62,21 @@ 2.29 -- 25 y 2.30 -- 26 z 2.31 2.32 + c = setmetatable( 2.33 + { iter = alphabet("a", "f") }, 2.34 + { __call = function(t) return t.iter() end } 2.35 + ) 2.36 + 2.37 + for i, v in ipairs(c) do 2.38 + print(i, v) 2.39 + end 2.40 + -- prints: 2.41 + -- 1 a 2.42 + -- 2 b 2.43 + -- 3 c 2.44 + -- 4 e 2.45 + -- 5 f 2.46 + 2.47 set = {apple = true, banana = true} 2.48 for i, k, v in ipairs(pairs(set)) do 2.49 print(i, k, v) 2.50 @@ -145,9 +160,3 @@ 2.51 value is replaced by a closure calling the ``__call`` metamethod. 2.52 2.53 2.54 -TODO 2.55 ----- 2.56 - 2.57 -* pass the original value to the ``__call`` metamethod as first argument 2.58 - 2.59 -
3.1 --- a/seqlua.c Wed Aug 20 01:59:55 2014 +0200 3.2 +++ b/seqlua.c Wed Aug 20 04:24:08 2014 +0200 3.3 @@ -1,6 +1,12 @@ 3.4 #include <lua.h> 3.5 #include <lauxlib.h> 3.6 -#include "seqlualib.h" 3.7 + 3.8 +static int seqlua_aux_call(lua_State *L) { 3.9 + lua_pushvalue(L, lua_upvalueindex(1)); 3.10 + lua_pushvalue(L, lua_upvalueindex(2)); 3.11 + lua_call(L, 1, 1); 3.12 + return 1; 3.13 +} 3.14 3.15 static int seqlua_ipairsaux_raw(lua_State *L) { 3.16 lua_Integer i; 3.17 @@ -35,7 +41,7 @@ 3.18 } 3.19 } 3.20 3.21 -static int seqlua_ipairsaux_funcclosure(lua_State *L) { 3.22 +static int seqlua_ipairsaux_triplet(lua_State *L) { 3.23 lua_Integer i = lua_tointeger(L, lua_upvalueindex(4)) + 1; 3.24 lua_settop(L, 0); 3.25 lua_pushinteger(L, i); 3.26 @@ -57,18 +63,22 @@ 3.27 } 3.28 3.29 static int seqlua_ipairs(lua_State *L) { 3.30 - if (luaL_getmetafield(L, 1, "__call")) { 3.31 - if (lua_type(L, -1) != LUA_TFUNCTION) luaL_error(L, "__call is not a function"); 3.32 - lua_replace(L, 1); 3.33 - } 3.34 + luaL_checkany(L, 1); // provides better error message 3.35 if (lua_type(L, 1) == LUA_TFUNCTION) { 3.36 + seqlua_ipairs_function: 3.37 if (!lua_isnoneornil(L, 2) || !lua_isnoneornil(L, 3)) { 3.38 lua_settop(L, 3); 3.39 lua_pushinteger(L, 0); 3.40 - lua_pushcclosure(L, seqlua_ipairsaux_funcclosure, 4); 3.41 + lua_pushcclosure(L, seqlua_ipairsaux_triplet, 4); 3.42 return 1; 3.43 } 3.44 lua_pushcfunction(L, seqlua_ipairsaux_func); 3.45 + } else if (luaL_getmetafield(L, 1, "__call")) { 3.46 + if (lua_type(L, -1) != LUA_TFUNCTION) luaL_error(L, "__call is not a function"); 3.47 + lua_pushvalue(L, 1); 3.48 + lua_pushcclosure(L, seqlua_aux_call, 2); 3.49 + lua_replace(L, 1); 3.50 + goto seqlua_ipairs_function; 3.51 } else if (luaL_getmetafield(L, 1, "__index")) { 3.52 lua_pushcfunction(L, seqlua_ipairsaux_meta); 3.53 } else { 3.54 @@ -80,7 +90,26 @@ 3.55 return 3; 3.56 } 3.57 3.58 -static int seqlua_iteratoraux(lua_State *L) { 3.59 +static int seqlua_iteratoraux_raw(lua_State *L) { 3.60 + lua_Integer i = lua_tointeger(L, lua_upvalueindex(2)) + 1; 3.61 + lua_rawgeti(L, lua_upvalueindex(1), i); 3.62 + if (lua_isnil(L, -1)) return 1; 3.63 + lua_pushinteger(L, i); 3.64 + lua_replace(L, lua_upvalueindex(2)); 3.65 + return 1; 3.66 +} 3.67 + 3.68 +static int seqlua_iteratoraux_meta(lua_State *L) { 3.69 + lua_Integer i = lua_tointeger(L, lua_upvalueindex(2)) + 1; 3.70 + lua_pushinteger(L, i); 3.71 + lua_gettable(L, lua_upvalueindex(1)); 3.72 + if (lua_isnil(L, -1)) return 1; 3.73 + lua_pushinteger(L, i); 3.74 + lua_replace(L, lua_upvalueindex(2)); 3.75 + return 1; 3.76 +} 3.77 + 3.78 +static int seqlua_iteratoraux_triplet(lua_State *L) { 3.79 lua_settop(L, 0); 3.80 lua_pushvalue(L, lua_upvalueindex(1)); 3.81 lua_pushvalue(L, lua_upvalueindex(2)); 3.82 @@ -95,21 +124,31 @@ 3.83 return lua_gettop(L); 3.84 } 3.85 3.86 -static int seqlua_iterator(lua_State *L) { 3.87 - if (luaL_getmetafield(L, 1, "__call")) { 3.88 - if (lua_type(L, -1) != LUA_TFUNCTION) luaL_error(L, "__call is not a function"); 3.89 - lua_replace(L, 1); 3.90 - } 3.91 +int seqlua_iterator(lua_State *L) { 3.92 + luaL_checkany(L, 1); // provides better error message 3.93 + lua_settop(L, 3); 3.94 if (lua_type(L, 1) == LUA_TFUNCTION) { 3.95 - if (lua_isnoneornil(L, 2) && lua_isnoneornil(L, 3)) { 3.96 + seqlua_iterator_function: 3.97 + if (lua_isnil(L, 2) && lua_isnil(L, 3)) { 3.98 lua_settop(L, 1); 3.99 } else { 3.100 - lua_settop(L, 3); 3.101 - lua_pushcclosure(L, seqlua_iteratoraux, 3); 3.102 + lua_pushcclosure(L, seqlua_iteratoraux_triplet, 3); 3.103 } 3.104 + } else if (luaL_getmetafield(L, 1, "__call")) { 3.105 + if (lua_type(L, -1) != LUA_TFUNCTION) luaL_error(L, "__call is not a function"); 3.106 + lua_pushvalue(L, 1); 3.107 + lua_pushcclosure(L, seqlua_aux_call, 2); 3.108 + lua_replace(L, 1); 3.109 + goto seqlua_iterator_function; 3.110 + } else if (luaL_getmetafield(L, 1, "__index")) { 3.111 + lua_pushvalue(L, 1); 3.112 + lua_pushinteger(L, 0); 3.113 + lua_pushcclosure(L, seqlua_iteratoraux_raw, 2); 3.114 } else { 3.115 - seqlua_iterclosure(L, 1); 3.116 - lua_settop(L, 1); 3.117 + luaL_checktype(L, 1, LUA_TTABLE); 3.118 + lua_pushvalue(L, 1); 3.119 + lua_pushinteger(L, 0); 3.120 + lua_pushcclosure(L, seqlua_iteratoraux_meta, 2); 3.121 } 3.122 return 1; 3.123 }
4.1 --- a/seqlua_c_example.c Wed Aug 20 01:59:55 2014 +0200 4.2 +++ b/seqlua_c_example.c Wed Aug 20 04:24:08 2014 +0200 4.3 @@ -8,14 +8,29 @@ 4.4 seqlua_iterloop(L, &iter, 1) { 4.5 if (seqlua_itercount(&iter) > 1) fputs(",", stdout); 4.6 fputs(luaL_tolstring(L, -1, NULL), stdout); 4.7 - lua_pop(L, 1); 4.8 + lua_pop(L, 1); // pop value that luaL_tolstring pushed onto stack 4.9 } 4.10 fputs("\n", stdout); 4.11 return 0; 4.12 } 4.13 4.14 +static int seqlua_c_example_printthree(lua_State *L) { 4.15 + int i; 4.16 + seqlua_iterclosure(L, 1); 4.17 + for (i=0; i<3; i++) { 4.18 + lua_pushvalue(L, 1); 4.19 + lua_call(L, 0, 1); 4.20 + fputs(luaL_tolstring(L, -1, NULL), stdout); 4.21 + lua_pop(L, 1); // pop value that luaL_tolstring pushed onto stack 4.22 + fputs("\n", stdout); 4.23 + } 4.24 + return 0; 4.25 +} 4.26 + 4.27 int luaopen_seqlua_c_example(lua_State *L) { 4.28 lua_pushcfunction(L, seqlua_c_example_printcsv); 4.29 lua_setglobal(L, "printcsv"); 4.30 + lua_pushcfunction(L, seqlua_c_example_printthree); 4.31 + lua_setglobal(L, "printthree"); 4.32 return 0; 4.33 }
5.1 --- a/seqlua_c_example_test.lua Wed Aug 20 01:59:55 2014 +0200 5.2 +++ b/seqlua_c_example_test.lua Wed Aug 20 04:24:08 2014 +0200 5.3 @@ -22,3 +22,15 @@ 5.4 -- prints: 5.5 -- 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 5.6 5.7 +printthree(alphabet()) 5.8 +-- prints: 5.9 +-- a 5.10 +-- b 5.11 +-- c 5.12 + 5.13 +printthree(setmetatable({v="x"}, {__call=function(t) return t.v end})) 5.14 +-- prints: 5.15 +-- x 5.16 +-- x 5.17 +-- x 5.18 +
6.1 --- a/seqlualib.c Wed Aug 20 01:59:55 2014 +0200 6.2 +++ b/seqlualib.c Wed Aug 20 04:24:08 2014 +0200 6.3 @@ -2,28 +2,33 @@ 6.4 #include <lauxlib.h> 6.5 #include "seqlualib.h" 6.6 6.7 -#define SEQLUA_ITERTYPE_FUNC 1 6.8 -#define SEQLUA_ITERTYPE_META 2 6.9 -#define SEQLUA_ITERTYPE_RAW 3 6.10 +#define SEQLUA_ITERTYPE_CALL 1 6.11 +#define SEQLUA_ITERTYPE_FUNC 2 6.12 +#define SEQLUA_ITERTYPE_META 3 6.13 +#define SEQLUA_ITERTYPE_RAW 4 6.14 6.15 void seqlua_iterinit(lua_State *L, seqlua_Iterator *iter, int idx) { 6.16 luaL_checkany(L, idx); // provides better error message 6.17 iter->L = L; 6.18 if (luaL_getmetafield(L, idx, "__call")) { 6.19 if (lua_type(L, -1) != LUA_TFUNCTION) luaL_error(L, "__call is not a function"); 6.20 - iter->itertype = SEQLUA_ITERTYPE_FUNC; 6.21 + iter->idx = lua_gettop(L); 6.22 + iter->callargidx = idx; 6.23 + iter->itertype = SEQLUA_ITERTYPE_CALL; 6.24 } else if (lua_type(L, idx) == LUA_TFUNCTION) { 6.25 - lua_pushvalue(L, idx); 6.26 + lua_pushnil(L); // dummy value 6.27 + iter->idx = idx; 6.28 iter->itertype = SEQLUA_ITERTYPE_FUNC; 6.29 } else { 6.30 + iter->idx = idx; 6.31 if (luaL_getmetafield(L, idx, "__index")) { 6.32 - lua_pop(L, 1); 6.33 iter->itertype = SEQLUA_ITERTYPE_META; 6.34 + // leave __index as dummy value 6.35 } else { 6.36 + lua_pushnil(L); // dummy value 6.37 luaL_checktype(L, idx, LUA_TTABLE); 6.38 iter->itertype = SEQLUA_ITERTYPE_RAW; 6.39 } 6.40 - lua_pushvalue(L, idx); 6.41 } 6.42 iter->i = 0; 6.43 } 6.44 @@ -32,19 +37,25 @@ 6.45 lua_State *L = iter->L; 6.46 lua_Integer i = ++iter->i; 6.47 switch (iter->itertype) { 6.48 + case SEQLUA_ITERTYPE_CALL: 6.49 + lua_pushvalue(L, iter->idx); 6.50 + lua_pushvalue(L, iter->callargidx); 6.51 + lua_call(L, 1, 1); 6.52 + break; 6.53 case SEQLUA_ITERTYPE_FUNC: 6.54 - lua_pushvalue(L, -1); 6.55 + lua_pushvalue(L, iter->idx); 6.56 lua_call(L, 0, 1); 6.57 break; 6.58 case SEQLUA_ITERTYPE_META: 6.59 lua_pushinteger(L, i); 6.60 - lua_gettable(L, -2); 6.61 + lua_gettable(L, iter->idx); 6.62 break; 6.63 case SEQLUA_ITERTYPE_RAW: 6.64 - lua_rawgeti(L, -1, i); 6.65 + lua_rawgeti(L, iter->idx, i); 6.66 + break; 6.67 } 6.68 if (lua_isnil(L, -1)) { 6.69 - lua_pop(L, 2); 6.70 + lua_pop(L, 2); // remove nil and dummy value 6.71 return 0; 6.72 } 6.73 return 1; 6.74 @@ -69,11 +80,21 @@ 6.75 return 1; 6.76 } 6.77 6.78 +static int seqlua_iterclosureaux_call(lua_State *L) { 6.79 + lua_pushvalue(L, lua_upvalueindex(1)); 6.80 + lua_pushvalue(L, lua_upvalueindex(2)); 6.81 + lua_call(L, 1, 1); 6.82 + return 1; 6.83 +} 6.84 + 6.85 void seqlua_iterclosure(lua_State *L, int idx) { 6.86 + luaL_checkany(L, idx); // provides better error message 6.87 if (lua_type(L, idx) == LUA_TFUNCTION) { 6.88 // do nothing 6.89 } else if (luaL_getmetafield(L, idx, "__call")) { 6.90 if (lua_type(L, -1) != LUA_TFUNCTION) luaL_error(L, "__call is not a function"); 6.91 + lua_pushvalue(L, idx); 6.92 + lua_pushcclosure(L, seqlua_iterclosureaux_call, 2); 6.93 lua_replace(L, idx); 6.94 } else if (luaL_getmetafield(L, idx, "__index")) { 6.95 lua_pop(L, 1);