lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Mon, May 24, 2010 at 4:09 PM, M Joonas Pihlaja
<jpihlaja@cc.helsinki.fi> wrote:
> This particular generic-for proposal doesn't work for basic iterators
> which follow the current iterator protocol.  For example, it would try
> to run pairs() on the function "next" if we were to give it this:
>
> for k,v in next, sometable do
>        print(k,v)
> end
>
> In lua 5.1 that's equivalent to "for k,v in pairs(sometable) do
> print(k,v) end".
>

I wrote a function that implements the algorithm in pure Lua. The
function body comes first, so all of the arguments from iterator
factories like pairs() will be sent as parameters, but beyond that it
seems to work perfectly.

----
function meta_for(...)
  local params = {...}
  local body = table.remove(params, 1)

  local object = table.remove(params, 1)
  local obj_meta = debug.getmetatable(object)

  if type(object) == "number" and
      not obj_meta or (obj_meta and not obj_meta.__iter) then
    local var   = tonumber(object)
    local limit = tonumber(params[1])
    local step  = tonumber(params[2])

    for i=var,limit,step do
      body(i)
    end
  else
    local f, s, var
    if obj_meta and obj_meta.__iter then
      f, s, var = obj_meta.__iter(object, params)
    elseif type(object) == "table" then
      f, s, var = pairs(object, params)
    else
      f, s, var = object, params[1], params[2]
    end

    while true do
      local results = {f(s, var)}
      var = results[1]
      if var == nil then break end
      body(unpack(results))
    end
  end
end
----

Usage:
meta_for(function(k, v)
  print(k, v)
end, {1, 1, 2, 3, 5})

--[[
Equivalent to
for k,v in {1, 1, 2, 3, 5} do
  print(k, v)
end
--]]

Output:
1 1
2 1
3 2
4 3
5 5

Numeric works too: meta_for(function(i) print(i) end, 100, 10, -5)

As a slightly interesting point, you can do this, too:

function range(min, max)
  return min, max, 1
end
meta_for(function(i) print(i) end, range(1, 10))


> The key point is that the _compiler_ can't know in advance whether
> you're going to give numbers some wacky __iter metamethod before you
> actually run the loop, so you're going to have to check for __iter on
> numbers every time you begin a loop, just like in your pseudocode
> above.  By the time the interpreter wants to run your loop it's too
> late to do any optimisation.

I don't really know enough about the Lua bytecode compiler to comment
further, sorry

~Jonathan