Code:
1 traverse = {} 2 function traverse:new(tname) 3 local o = {} 4 o.names = {} 5 o.queue = {} 6 o.cur = { 7 tbl = nil, 8 path = nil, 9 state = nil, 10 } 11 12 local mt = {} 13 function mt:__call(tn) 14 return o:iter(tn) 15 end 16 mt.__index = self 17 setmetatable(o, mt) 18 19 if tname then 20 o:enqueue(tname) 21 end 22 return o 23 end 24 function traverse:next() 25 local v 26 local names, queue, cur = self.names, self.queue, self.cur 27 28 local function _poptbl() 29 if cur.tbl then 30 names[cur.tbl] = nil 31 end 32 cur.tbl = table.remove(queue, 1) 33 cur.path = names[cur.tbl] 34 cur.state = nil 35 end 36 37 repeat 38 -- Find something to return to the user... 39 if not cur.state then 40 -- Pop a new table off the stack 41 _poptbl() 42 if not cur.tbl then 43 -- No more tables to process 44 return nil 45 end 46 end 47 cur.state,v = next(cur.tbl, cur.state) 48 until cur.state 49 50 if type(v) == "table" then 51 local path = cur.path.."."..cur.state 52 names[v] = path 53 table.insert(queue, v) 54 end 55 return cur.path,cur.tbl,cur.state,v 56 end 57 function traverse:iter(tname) 58 if tname then 59 self:enqueue(tname) 60 end 61 return function(...) return self:next(unpack(arg)) end, nil, nil 62 end 63 function traverse:enqueue(tname) 64 local v = _G[tname] 65 table.insert(self.queue, v) 66 self.names[v] = tname 67 end 68 function traverse:reset() 69 self.names = {} 70 self.queue = {} 71 end 72 local traverse_mt = { 73 __call = function(self, tname) 74 if tname then 75 return self:new(tname):iter() 76 else 77 return self:new() 78 end 79 end 80 } 81 setmetatable(traverse, traverse_mt)
Example Usage:
1 foo = {a={},b={},c={"bar"},d={e={},f={"moo"}},1,2,3,4,5} 2 bar = {"alpha", "beta", "theta", omega = {}} 3 4 local mytraverser = traverse() 5 mytraverser:enqueue("bar") 6 mytraverser:enqueue("foo") 7 for p,t,k,v in mytraverser() do 8 --for p,t,k,v in traverse('foo') do 9 print(string.format("%s[%s] = %s",tostring(p),tostring(k),tostring(v))) 10 end
Output from Example Usage:
1 bar[1] = alpha 2 bar[2] = beta 3 bar[3] = theta 4 bar[omega] = table: 0x510650 5 foo[1] = 1 6 foo[2] = 2 7 foo[3] = 3 8 foo[4] = 4 9 foo[5] = 5 10 foo[a] = table: 0x5102d0 11 foo[c] = table: 0x510370 12 foo[b] = table: 0x510320 13 foo[d] = table: 0x5103c0 14 foo.c[1] = bar 15 foo.d[e] = table: 0x5104c0 16 foo.d[f] = table: 0x510510 17 foo.d.f[1] = moo