diff --git a/extra.lua b/extra.lua index c0aa538..fb5982b 100755 --- a/extra.lua +++ b/extra.lua @@ -1,3 +1,10 @@ +local insert = table.insert +local pairs = pairs +local rawget = rawget +local sort = table.sort +local tostring = tostring +local type = type + local function strpad(num, count, pad) num = tostring(num) return (pad:rep(count)..num):sub(#num) @@ -18,9 +25,9 @@ end local function order_keys(t) local oi = {} for key in pairs(t) do - table.insert(oi, key) + insert(oi, key) end - table.sort(oi, mixed_sorter) + sort(oi, mixed_sorter) return oi end @@ -33,7 +40,7 @@ local function opairs(t, cache) return function() i = i + 1 local key = oi[i] - if key then return key, t[key] end + if key ~= nil then return key, t[key] end end end diff --git a/pt.lua b/pt.lua index 6fe9ef9..6eea391 100755 --- a/pt.lua +++ b/pt.lua @@ -25,8 +25,8 @@ local function copy(t) -- shallow copy if type(t) ~= 'table' then return end local new = {} - for key, value in pairs(t) do - new[key] = value + for k,v in pairs(t) do + new[k] = v end return new end @@ -43,7 +43,10 @@ function pt.__call(pt, args) self.depth = args.depth or 16 self.writer = args.writer or io.write self.skeleton = args.skeleton or false + self.outer = args.alt_order and self.outer_old or self.outer + self.indent = args.indent or ' ' self.queued = {} + self.cache = {} self:inner('__root__', t, '') return self.seen end @@ -61,7 +64,7 @@ function pt.safekey(k) return s:find('[^%w_]') and ('%q'):format(s) or s end -function pt.safeval(v, indent) +function pt.safeval(v, indentation, indent) if type(v) == 'function' then return 'f'..getaddr(v) end @@ -69,25 +72,28 @@ function pt.safeval(v, indent) if type(v) == 'number' then return s end - s = s:find('[\r\n]') and ('\n'..s):gsub('[\r\n]', '\n'..indent..' ') or s + -- TODO: move newline/indentation handling to another function? + if s:find('[\r\n]') then + s = ('\n'..s):gsub('[\r\n]', '\n'..indentation..indent) + end --local safe = ('%q'):format(s) --return s == safe:sub(2, -2) and s or safe -- TODO: finish matching valid characters return s:find('[^%w_()[]{}.]') and ('%q'):format(s) or s end -function pt:inner(k, v, indent) +function pt:inner(k, v, indentation) if type(v) ~= 'table' then if self.skeleton then return end - self:write(indent, pt.safekey(k), ': ') - self:write(pt.safeval(v, indent), '\n') + self:write(indentation, pt.safekey(k), ': ') + self:write(pt.safeval(v, indentation, self.indent), '\n') return end local addr = getaddr(v) - self:write(indent, pt.safekey(k)) + self:write(indentation, pt.safekey(k)) - if #indent > self.depth or self.skipped[addr] then + if #indentation > self.depth or self.skipped[addr] then --self.skipped[addr] = true -- TODO: extra logics self:write(': #t', addr, '\n') return @@ -101,12 +107,13 @@ function pt:inner(k, v, indent) self.seen[addr] = true self:write(': &t', addr, '\n') - self:outer(v, indent..' ') + self:outer(v, indentation..self.indent) end -function pt:outer(t, indent) +function pt:outer_old(t, indentation) if type(t) ~= "table" then - self:write(indent, pt.safeval(t, indent), '\n') + local s = pt.safeval(t, indentation, self.indent) + self:write(indentation, s, '\n') return end @@ -116,29 +123,62 @@ function pt:outer(t, indent) for k,v in opairs(t) do if type(v) == 'table' then local addr = getaddr(v) - if not self.queued[addr] and not self.seen[addr] and not self.skipped[addr] then + if not (self.queued[addr] or self.seen[addr] or self.skipped[addr]) then self.queued[addr] = true ours[k] = v else not_ours[k] = v end else - self:inner(k, v, indent) + self:inner(k, v, indentation) end end for k,v in opairs(not_ours) do - self:inner(k, v, indent) + self:inner(k, v, indentation) end for k,v in opairs(ours) do self.queued[getaddr(v)] = nil - self:inner(k, v, indent) + self:inner(k, v, indentation) end local mt = getmetatable(t) if mt ~= nil then - self:inner('__metatable', mt, indent) + self:inner('__metatable', mt, indentation) + end +end + +function pt:outer(t, indentation) + if type(t) ~= "table" then + local s = pt.safeval(t, indentation, self.indent) + self:write(indentation, s, '\n') + return + end + + local ours = {} + + for k,v in opairs(t, self.cache) do + if type(v) == 'table' then + local addr = getaddr(v) + if not (self.queued[addr] or self.seen[addr] or self.skipped[addr]) then + self.queued[addr] = true + ours[k] = addr + end + end + end + + local mt = getmetatable(t) + if mt ~= nil then + self:inner('__metatable', mt, indentation) + end + + for k,v in opairs(t, self.cache) do + local addr = ours[k] + if addr then + self.queued[addr] = nil + end + self:inner(k, v, indentation) end end diff --git a/run.lua b/run.lua index 5468bcf..63f3c00 100755 --- a/run.lua +++ b/run.lua @@ -2,21 +2,22 @@ local pt = require('pt') t = { - A = { + A = 'hello', + B = { a = 'beep', b = 'boop', c = 'burp', }, - B = { + C = { a = 'nude', b = 'dude', c = 'lewd', }, - C = 'hello', + D = 'goodbye', } -t.A.d = t.B -t.B.d = t.A -t.D = t +t.B.d = t.C +t.C.d = t.B +t.E = t function dump(t, fn, seen) if t == nil then return end