diff --git a/pt.lua b/pt.lua index 6eea391..821634f 100755 --- a/pt.lua +++ b/pt.lua @@ -44,10 +44,12 @@ function pt.__call(pt, args) 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.noncanon = args.noncanon or false self.indent = args.indent or ' ' self.queued = {} self.cache = {} - self:inner('__root__', t, '') + self.canonicalized = {} + self:inner('__root', t, '') return self.seen end @@ -55,7 +57,12 @@ function pt:write(...) self.writer(...) end -function pt.safekey(k) +function pt:safecanon(k) + local s = tostring(k) + return s:gsub('[^%w_]', '_') +end + +function pt:safekey(k) if type(k) == 'table' then return 't'..getaddr(k) end @@ -64,7 +71,7 @@ function pt.safekey(k) return s:find('[^%w_]') and ('%q'):format(s) or s end -function pt.safeval(v, indentation, indent) +function pt:safeval(v, indentation) if type(v) == 'function' then return 'f'..getaddr(v) end @@ -74,7 +81,7 @@ function pt.safeval(v, indentation, indent) end -- TODO: move newline/indentation handling to another function? if s:find('[\r\n]') then - s = ('\n'..s):gsub('[\r\n]', '\n'..indentation..indent) + s = ('\n'..s):gsub('[\r\n]', '\n'..indentation..self.indent) end --local safe = ('%q'):format(s) --return s == safe:sub(2, -2) and s or safe @@ -85,34 +92,45 @@ end function pt:inner(k, v, indentation) if type(v) ~= 'table' then if self.skeleton then return end - self:write(indentation, pt.safekey(k), ': ') - self:write(pt.safeval(v, indentation, self.indent), '\n') + self:write(indentation, self:safekey(k), ': ') + self:write(self:safeval(v, indentation), '\n') return end local addr = getaddr(v) - self:write(indentation, pt.safekey(k)) + self:write(indentation, self:safekey(k)) + + local canon + if not self.noncanon and type(k) ~= 'table' then + canon = self.canonicalized[addr] + if canon == nil then + canon = self:safecanon(k)..'_t'..addr + self.canonicalized[addr] = canon + end + else + canon = 't'..addr + end if #indentation > self.depth or self.skipped[addr] then --self.skipped[addr] = true -- TODO: extra logics - self:write(': #t', addr, '\n') + self:write(': #', canon, '\n') return end if self.seen[addr] or self.queued[addr] then - self:write(': *t', addr, self.seen_elsewhere[addr] and ' #\n' or '\n') + self:write(': *', canon, self.seen_elsewhere[addr] and ' #\n' or '\n') return end self.seen[addr] = true - self:write(': &t', addr, '\n') + self:write(': &', canon, '\n') self:outer(v, indentation..self.indent) end function pt:outer_old(t, indentation) if type(t) ~= "table" then - local s = pt.safeval(t, indentation, self.indent) + local s = self:safeval(t, indentation) self:write(indentation, s, '\n') return end @@ -151,7 +169,7 @@ end function pt:outer(t, indentation) if type(t) ~= "table" then - local s = pt.safeval(t, indentation, self.indent) + local s = self:safeval(t, indentation) self:write(indentation, s, '\n') return end