seaofvoices / darklua

A command line tool that transforms Lua code
https://darklua.com/
MIT License
71 stars 9 forks source link

A rule for removing (converting) generalized iteration #203

Open sircfenner opened 2 months ago

sircfenner commented 2 months ago

See https://github.com/seaofvoices/darklua/issues/202 for motivation.

An implementation I have done in the past converts the following:

for x, y, z in input do
    print(x, y, z)
end

into:

local _iterator = input
local _invariant, _control
if type(input) == "table" then
    local _mt = getmetatable(input)
    if type(_mt) == "table" and type(_mt.__iter) == "function" then
        _iterator, _invariant, _control = _mt.__iter(input)
    else
        _iterator, _invariant, _control = pairs(input) -- !
    end
end
for x, y, z in _iterator, _invariant, _control do
    print(x, y, z)
end

This may not be 100% correct but could be a good starting point.

As it can't be determined statically whether the subject of iteration is (1) a plain table, (2) an iterator function, or (3) a table with an __iter metamethod defined, it is necessary to insert a runtime check.

Notes:

  1. Using pairs(input) does not necessarily conform to the order of Luau generic iteration (for example, consecutive array indices starting from 1 go first)
  2. Doesn't handle iterating over userdata (with __iter defined), which is supported by Luau
  3. There may also be issues with accessing __iter if __metatable is set