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);
     7.1 --- a/seqlualib.h	Wed Aug 20 01:59:55 2014 +0200
     7.2 +++ b/seqlualib.h	Wed Aug 20 04:24:08 2014 +0200
     7.3 @@ -3,6 +3,8 @@
     7.4  
     7.5  typedef struct {
     7.6    lua_State *L;
     7.7 +  int idx;
     7.8 +  int callargidx;
     7.9    int itertype;
    7.10    lua_Integer i;
    7.11  } seqlua_Iterator;

Impressum / About Us