seqlua

changeset 23:29792283522f

Removed iterator(...) function; ipairs doesn't accept iterator triplets anymore
author jbe
date Thu Aug 21 20:01:52 2014 +0200 (2014-08-21)
parents 50c6388d4963
children 28d472cc7a9b
files README seqlua.c seqlua_c_example.c seqlua_c_example_test.lua seqlua_ipairs_example.lua seqlualib.c
line diff
     1.1 --- a/README	Thu Aug 21 13:04:45 2014 +0200
     1.2 +++ b/README	Thu Aug 21 20:01:52 2014 +0200
     1.3 @@ -3,12 +3,8 @@
     1.4  
     1.5  This is an experimental package to extend Lua in the following manner:
     1.6  
     1.7 -* allow ipairs(...) to accept tables as well as functions or iterator triplets,
     1.8 -* provide a function iterator(...) that returns single functions unmodified,
     1.9 -  but converts
    1.10 -    * iterator triplets into closures, and
    1.11 -    * tables into a function closure that iterates over the elements,
    1.12 -* provide the auxiliary C functions and macros to simplify iterating over both
    1.13 +* allow ipairs(...) to accept tables as well as functions
    1.14 +* provide auxiliary C functions and macros to simplify iterating over both
    1.15    tables and iterator functions with the same statement.
    1.16  
    1.17  This library completely ignores the ``__ipairs`` metamethod (as it is
    1.18 @@ -50,9 +46,7 @@
    1.19        end
    1.20      end
    1.21  
    1.22 -    f = alphabet("a", "z")
    1.23 -
    1.24 -    for i, v in ipairs(f) do
    1.25 +    for i, v in ipairs(alphabet()) do
    1.26        print(i, v)
    1.27      end
    1.28      -- prints:
    1.29 @@ -63,50 +57,33 @@
    1.30      --  25  y
    1.31      --  26  z
    1.32  
    1.33 -    set = {apple = true, banana = true}
    1.34 -    for i, k, v in ipairs(pairs(set)) do
    1.35 -      print(i, k, v)
    1.36 +    function filter(f, seq)
    1.37 +      return coroutine.wrap(function()
    1.38 +        for i, v in ipairs(seq) do f(v) end
    1.39 +      end)
    1.40      end
    1.41 -    -- prints:
    1.42 -    --  1   banana  true
    1.43 -    --  2   apple   true
    1.44 -    -- (order of "apple" and "banana" may vary)
    1.45 -
    1.46 -More examples for invoking the ``ipairs(...)`` function can be found in the
    1.47 -file ``seqlua_ipairs_example.lua``.
    1.48  
    1.49 -The function ``iterator(...)`` may be used to convert any table, any function,
    1.50 -or any iterator triplet into a single function (possibly creating a closure):
    1.51 -
    1.52 -    require "seqlua"
    1.53 -
    1.54 -    function filter_strings(...)
    1.55 -      nextvalue = iterator(...)
    1.56 -      return function()
    1.57 -        local value
    1.58 -        repeat
    1.59 -          value = nextvalue()
    1.60 -        until value == nil or type(value) == "string"
    1.61 -        return value
    1.62 +    function filterfunc(v)
    1.63 +      local type_v = type(v)
    1.64 +      if type_v == "string" then
    1.65 +        coroutine.yield(v)
    1.66 +      elseif type_v == "number" then
    1.67 +        for i = 1, v do
    1.68 +          coroutine.yield(true)
    1.69 +        end
    1.70        end
    1.71      end
    1.72  
    1.73 -    for i, v in ipairs(filter_strings{"Hello", true, "World"}) do
    1.74 -      print(i, v)
    1.75 -    end
    1.76 -    -- prints:
    1.77 -    --  1   Hello
    1.78 -    --  2   World
    1.79 -
    1.80 -    tbl = {apple = true, banana = true, [1] = "array entry"}
    1.81 -    for v in filter_strings(pairs(tbl)) do
    1.82 +    for v in filter(filterfunc, {"a", "b", 3, "c"}) do
    1.83        print(v)
    1.84      end
    1.85      -- prints:
    1.86 -    --   banana
    1.87 -    --   apple
    1.88 -    -- (order may vary)
    1.89 -
    1.90 +    --  a
    1.91 +    --  b
    1.92 +    --  true
    1.93 +    --  true
    1.94 +    --  true
    1.95 +    --  c
    1.96  
    1.97  
    1.98  C part of the library
    1.99 @@ -121,8 +98,8 @@
   1.100          lua_pop((L), 1) \
   1.101        )
   1.102  
   1.103 -This macro allows iteration over either tables or iterator functions (but not
   1.104 -iterator triplets) as the following example function demonstrates:
   1.105 +This macro allows iteration over either tables or iterator functions as the
   1.106 +following example function demonstrates:
   1.107  
   1.108      int printcsv(lua_State *L) {
   1.109        seqlua_Iterator iter;
   1.110 @@ -141,20 +118,4 @@
   1.111      printcsv(assert(io.open("testfile")):lines())
   1.112      -- prints: line1,line2,... of "testfile"
   1.113  
   1.114 -Additionally, ``seqlualib`` includes a function ``seqlua_iterclosure(L, idx)``,
   1.115 -which converts a table at a given stack index into a function closure (stored
   1.116 -on the same stack index) that iterates over the elements of the table. If the
   1.117 -value at the given stack index is already a function (or if it is callable
   1.118 -through a ``__call`` metamethod), then ``seqlua_iterclosure(L, idx)`` leaves
   1.119 -the value at ``idx`` unchanged.
   1.120  
   1.121 -
   1.122 -TODO
   1.123 -----
   1.124 -
   1.125 -Accepting iterator triplets doesn't work, because even if a single function
   1.126 -is passed to ipairs, that function still might expect to get the previous
   1.127 -iteration value as second argument. Therefore, accepting iterator triplets
   1.128 -as argument to ipairs should be removed.
   1.129 -
   1.130 -
     2.1 --- a/seqlua.c	Thu Aug 21 13:04:45 2014 +0200
     2.2 +++ b/seqlua.c	Thu Aug 21 20:01:52 2014 +0200
     2.3 @@ -33,41 +33,13 @@
     2.4    }
     2.5  }
     2.6  
     2.7 -static int seqlua_ipairsaux_triplet(lua_State *L) {
     2.8 -  lua_Integer i = lua_tointeger(L, lua_upvalueindex(4)) + 1;
     2.9 -  lua_settop(L, 0);
    2.10 -  lua_pushinteger(L, i);
    2.11 -  lua_replace(L, lua_upvalueindex(4));
    2.12 -  lua_pushinteger(L, i);
    2.13 -  lua_pushvalue(L, lua_upvalueindex(1));
    2.14 -  lua_pushvalue(L, lua_upvalueindex(2));
    2.15 -  lua_pushvalue(L, lua_upvalueindex(3));
    2.16 -  lua_call(L, 2, LUA_MULTRET);
    2.17 -  if (lua_isnoneornil(L, 2)) {
    2.18 -    lua_settop(L, 0);
    2.19 -    lua_pushnil(L);
    2.20 -    return 1;
    2.21 -  } else {
    2.22 -    lua_pushvalue(L, 2);
    2.23 -    lua_replace(L, lua_upvalueindex(3));
    2.24 -    return lua_gettop(L);
    2.25 -  }
    2.26 -}
    2.27 -
    2.28  static int seqlua_ipairs(lua_State *L) {
    2.29    luaL_checkany(L, 1);  // provides better error message
    2.30 -  if (lua_type(L, 1) == LUA_TFUNCTION) {
    2.31 -    seqlua_ipairs_function:
    2.32 -    if (!lua_isnoneornil(L, 2) || !lua_isnoneornil(L, 3)) {
    2.33 -      lua_settop(L, 3);
    2.34 -      lua_pushinteger(L, 0);
    2.35 -      lua_pushcclosure(L, seqlua_ipairsaux_triplet, 4);
    2.36 -      return 1;
    2.37 -    }
    2.38 +  if (
    2.39 +    lua_type(L, 1) == LUA_TFUNCTION ||
    2.40 +    (luaL_getmetafield(L, 1, "__call") && (lua_pop(L, 1), 1))
    2.41 +  ) {
    2.42      lua_pushcfunction(L, seqlua_ipairsaux_func);
    2.43 -  } else if (luaL_getmetafield(L, 1, "__call")) {
    2.44 -    lua_pop(L, 1);
    2.45 -    goto seqlua_ipairs_function;
    2.46    } else if (luaL_getmetafield(L, 1, "__index")) {
    2.47      lua_pushcfunction(L, seqlua_ipairsaux_meta);
    2.48    } else {
    2.49 @@ -79,70 +51,8 @@
    2.50    return 3;
    2.51  }
    2.52  
    2.53 -static int seqlua_iteratoraux_raw(lua_State *L) {
    2.54 -  lua_Integer i = lua_tointeger(L, lua_upvalueindex(2)) + 1;
    2.55 -  lua_rawgeti(L, lua_upvalueindex(1), i);
    2.56 -  if (lua_isnil(L, -1)) return 1;
    2.57 -  lua_pushinteger(L, i);
    2.58 -  lua_replace(L, lua_upvalueindex(2));
    2.59 -  return 1;
    2.60 -}
    2.61 -
    2.62 -static int seqlua_iteratoraux_meta(lua_State *L) {
    2.63 -  lua_Integer i = lua_tointeger(L, lua_upvalueindex(2)) + 1;
    2.64 -  lua_pushinteger(L, i);
    2.65 -  lua_gettable(L, lua_upvalueindex(1));
    2.66 -  if (lua_isnil(L, -1)) return 1;
    2.67 -  lua_pushinteger(L, i);
    2.68 -  lua_replace(L, lua_upvalueindex(2));
    2.69 -  return 1;
    2.70 -}
    2.71 -
    2.72 -static int seqlua_iteratoraux_triplet(lua_State *L) {
    2.73 -  lua_settop(L, 0);
    2.74 -  lua_pushvalue(L, lua_upvalueindex(1));
    2.75 -  lua_pushvalue(L, lua_upvalueindex(2));
    2.76 -  lua_pushvalue(L, lua_upvalueindex(3));
    2.77 -  lua_call(L, 2, LUA_MULTRET);
    2.78 -  if (lua_isnoneornil(L, 1)) {
    2.79 -    lua_settop(L, 1);
    2.80 -    return 1;
    2.81 -  }
    2.82 -  lua_pushvalue(L, 1);
    2.83 -  lua_replace(L, lua_upvalueindex(3));
    2.84 -  return lua_gettop(L);
    2.85 -}
    2.86 -
    2.87 -int seqlua_iterator(lua_State *L) {
    2.88 -  luaL_checkany(L, 1);  // provides better error message
    2.89 -  lua_settop(L, 3);
    2.90 -  if (lua_type(L, 1) == LUA_TFUNCTION) {
    2.91 -    seqlua_iterator_function:
    2.92 -    if (lua_isnil(L, 2) && lua_isnil(L, 3)) {
    2.93 -      lua_settop(L, 1);
    2.94 -    } else {
    2.95 -      lua_pushcclosure(L, seqlua_iteratoraux_triplet, 3);
    2.96 -    }
    2.97 -  } else if (luaL_getmetafield(L, 1, "__call")) {
    2.98 -    lua_pop(L, 1);
    2.99 -    goto seqlua_iterator_function;
   2.100 -  } else if (luaL_getmetafield(L, 1, "__index")) {
   2.101 -    lua_pushvalue(L, 1);
   2.102 -    lua_pushinteger(L, 0);
   2.103 -    lua_pushcclosure(L, seqlua_iteratoraux_meta, 2);
   2.104 -  } else {
   2.105 -    luaL_checktype(L, 1, LUA_TTABLE);
   2.106 -    lua_pushvalue(L, 1);
   2.107 -    lua_pushinteger(L, 0);
   2.108 -    lua_pushcclosure(L, seqlua_iteratoraux_raw, 2);
   2.109 -  }
   2.110 -  return 1;
   2.111 -}
   2.112 -
   2.113  int luaopen_seqlua(lua_State *L) {
   2.114    lua_pushcfunction(L, seqlua_ipairs);
   2.115    lua_setglobal(L, "ipairs");
   2.116 -  lua_pushcfunction(L, seqlua_iterator);
   2.117 -  lua_setglobal(L, "iterator");
   2.118    return 1;
   2.119  }
     3.1 --- a/seqlua_c_example.c	Thu Aug 21 13:04:45 2014 +0200
     3.2 +++ b/seqlua_c_example.c	Thu Aug 21 20:01:52 2014 +0200
     3.3 @@ -14,23 +14,8 @@
     3.4    return 0;
     3.5  }
     3.6  
     3.7 -static int seqlua_c_example_printthree(lua_State *L) {
     3.8 -  int i;
     3.9 -  seqlua_iterclosure(L, 1);
    3.10 -  for (i=0; i<3; i++) {
    3.11 -    lua_pushvalue(L, 1);
    3.12 -    lua_call(L, 0, 1);
    3.13 -    fputs(luaL_tolstring(L, -1, NULL), stdout);
    3.14 -    lua_pop(L, 1);  // pop value that luaL_tolstring pushed onto stack
    3.15 -    fputs("\n", stdout);
    3.16 -  }
    3.17 -  return 0;
    3.18 -}
    3.19 -
    3.20  int luaopen_seqlua_c_example(lua_State *L) {
    3.21    lua_pushcfunction(L, seqlua_c_example_printcsv);
    3.22    lua_setglobal(L, "printcsv");
    3.23 -  lua_pushcfunction(L, seqlua_c_example_printthree);
    3.24 -  lua_setglobal(L, "printthree");
    3.25    return 0;
    3.26  }
     4.1 --- a/seqlua_c_example_test.lua	Thu Aug 21 13:04:45 2014 +0200
     4.2 +++ b/seqlua_c_example_test.lua	Thu Aug 21 20:01:52 2014 +0200
     4.3 @@ -22,15 +22,3 @@
     4.4  -- prints:
     4.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
     4.6  
     4.7 -printthree(alphabet())
     4.8 --- prints:
     4.9 ---  a
    4.10 ---  b
    4.11 ---  c
    4.12 -
    4.13 -printthree(setmetatable({v="x"}, {__call=function(t) return t.v end}))
    4.14 --- prints:
    4.15 ---  x
    4.16 ---  x
    4.17 ---  x
    4.18 -
     5.1 --- a/seqlua_ipairs_example.lua	Thu Aug 21 13:04:45 2014 +0200
     5.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.3 @@ -1,110 +0,0 @@
     5.4 -require "seqlua"
     5.5 -
     5.6 -t = {"a", "b", "c"}
     5.7 -
     5.8 -for i, v in ipairs(t) do
     5.9 -  print(i, v)
    5.10 -end
    5.11 --- prints:
    5.12 ---  1   a
    5.13 ---  2   b
    5.14 ---  3   c
    5.15 -
    5.16 -function alphabet(from, to)
    5.17 -  local letter = nil
    5.18 -  return function()
    5.19 -    if letter == nil then
    5.20 -      letter = from
    5.21 -    elseif letter == to then
    5.22 -      return nil
    5.23 -    else
    5.24 -      letter = string.char(string.byte(letter) + 1)
    5.25 -    end
    5.26 -    return letter
    5.27 -  end
    5.28 -end
    5.29 -
    5.30 -f = alphabet("a", "z")
    5.31 -
    5.32 -for i, v in ipairs(f) do
    5.33 -  print(i, v)
    5.34 -end
    5.35 --- prints:
    5.36 ---  1   a
    5.37 ---  2   b
    5.38 ---  3   c
    5.39 ---  ...
    5.40 ---  25  y
    5.41 ---  26  z
    5.42 -
    5.43 -c = setmetatable(
    5.44 -  { iter = alphabet("a", "f") },
    5.45 -  { __call = function(t) return t.iter() end }
    5.46 -)
    5.47 -
    5.48 -for i, v in ipairs(c) do
    5.49 -  print(i, v)
    5.50 -end
    5.51 --- prints:
    5.52 ---  1   a
    5.53 ---  2   b
    5.54 ---  3   c
    5.55 ---  4   d
    5.56 ---  5   e
    5.57 ---  6   f
    5.58 -
    5.59 -g = coroutine.wrap(function()
    5.60 -  coroutine.yield("Alice")
    5.61 -  coroutine.yield("Bob")
    5.62 -  for i = 1, 3 do
    5.63 -    coroutine.yield("Person #" .. tostring(i))
    5.64 -  end
    5.65 -end)
    5.66 -
    5.67 -for i, v in ipairs(g) do
    5.68 -  print(i, v)
    5.69 -end
    5.70 --- prints:
    5.71 ---  1   Alice
    5.72 ---  2   Bob
    5.73 ---  3   Person #1
    5.74 ---  4   Person #2
    5.75 ---  5   Person #3
    5.76 -
    5.77 -function filter(f, iter, iter_s, iter_i)
    5.78 -  return coroutine.wrap(function()
    5.79 -    for i, v in ipairs(iter, iter_s, iter_i) do f(v) end
    5.80 -  end)
    5.81 -end
    5.82 -
    5.83 -function filterfunc(v)
    5.84 -  local type_v = type(v)
    5.85 -  if type_v == "string" then
    5.86 -    coroutine.yield(v)
    5.87 -  elseif type_v == "number" then
    5.88 -    for i = 1, v do
    5.89 -      coroutine.yield(true)
    5.90 -    end
    5.91 -  end
    5.92 -end
    5.93 -
    5.94 -for v in filter(filterfunc, {"a", "b", 3, "c"}) do
    5.95 -  print(v)
    5.96 -end
    5.97 --- prints:
    5.98 ---  a
    5.99 ---  b
   5.100 ---  true
   5.101 ---  true
   5.102 ---  true
   5.103 ---  c
   5.104 -
   5.105 -set = {apple = true, banana = true}
   5.106 -for i, k, v in ipairs(pairs(set)) do
   5.107 -  print(i, k, v)
   5.108 -end
   5.109 --- prints:
   5.110 ---  1   banana  true
   5.111 ---  2   apple   true
   5.112 --- (order of "apple" and "banana" may vary)
   5.113 -
     6.1 --- a/seqlualib.c	Thu Aug 21 13:04:45 2014 +0200
     6.2 +++ b/seqlualib.c	Thu Aug 21 20:01:52 2014 +0200
     6.3 @@ -10,13 +10,12 @@
     6.4    luaL_checkany(L, idx);  // provides better error message
     6.5    iter->L = L;
     6.6    iter->idx = idx;
     6.7 -  if (lua_type(L, idx) == LUA_TFUNCTION) {
     6.8 +  if (
     6.9 +    lua_type(L, idx) == LUA_TFUNCTION ||
    6.10 +    (luaL_getmetafield(L, idx, "__call") && (lua_pop(L, 1), 1))
    6.11 +  ) {
    6.12      iter->itertype = SEQLUA_ITERTYPE_FUNC;
    6.13 -  } else if (luaL_getmetafield(L, idx, "__call")) {
    6.14 -    lua_pop(L, 1);
    6.15 -    iter->itertype = SEQLUA_ITERTYPE_FUNC;
    6.16 -  } else if (luaL_getmetafield(L, idx, "__index")) {
    6.17 -    lua_pop(L, 1);
    6.18 +  } else if (luaL_getmetafield(L, idx, "__index") && (lua_pop(L, 1), 1)) {
    6.19      iter->itertype = SEQLUA_ITERTYPE_META;
    6.20    } else {
    6.21      luaL_checktype(L, idx, LUA_TTABLE);
    6.22 @@ -48,43 +47,3 @@
    6.23    return 1;
    6.24  }
    6.25  
    6.26 -static int seqlua_iterclosureaux_raw(lua_State *L) {
    6.27 -  lua_Integer i = lua_tointeger(L, lua_upvalueindex(2)) + 1;
    6.28 -  lua_rawgeti(L, lua_upvalueindex(1), i);
    6.29 -  if (lua_isnil(L, -1)) return 1;
    6.30 -  lua_pushinteger(L, i);
    6.31 -  lua_replace(L, lua_upvalueindex(2));
    6.32 -  return 1;
    6.33 -}
    6.34 -
    6.35 -static int seqlua_iterclosureaux_meta(lua_State *L) {
    6.36 -  lua_Integer i = lua_tointeger(L, lua_upvalueindex(2)) + 1;
    6.37 -  lua_pushinteger(L, i);
    6.38 -  lua_gettable(L, lua_upvalueindex(1));
    6.39 -  if (lua_isnil(L, -1)) return 1;
    6.40 -  lua_pushinteger(L, i);
    6.41 -  lua_replace(L, lua_upvalueindex(2));
    6.42 -  return 1;
    6.43 -}
    6.44 -
    6.45 -void seqlua_iterclosure(lua_State *L, int idx) {
    6.46 -  luaL_checkany(L, idx);  // provides better error message
    6.47 -  if (lua_type(L, idx) == LUA_TFUNCTION) {
    6.48 -    // do nothing
    6.49 -  } else if (luaL_getmetafield(L, idx, "__call")) {
    6.50 -    lua_pop(L, 1);
    6.51 -  } else if (luaL_getmetafield(L, idx, "__index")) {
    6.52 -    lua_pop(L, 1);
    6.53 -    lua_pushvalue(L, idx);
    6.54 -    lua_pushinteger(L, 0);
    6.55 -    lua_pushcclosure(L, seqlua_iterclosureaux_meta, 2);
    6.56 -    lua_replace(L, idx);
    6.57 -  } else {
    6.58 -    luaL_checktype(L, idx, LUA_TTABLE);
    6.59 -    lua_pushvalue(L, idx);
    6.60 -    lua_pushinteger(L, 0);
    6.61 -    lua_pushcclosure(L, seqlua_iterclosureaux_raw, 2);
    6.62 -    lua_replace(L, idx);
    6.63 -  }
    6.64 -}
    6.65 -

Impressum / About Us