Fixed key sorting and removed addresses from names of temp variables for a more stable output.

This commit is contained in:
Paul Kulchenko 2012-06-13 10:21:44 -07:00
parent 75c34f67f3
commit 428061f498
3 changed files with 22 additions and 7 deletions

View File

@ -127,6 +127,12 @@ See LICENSE file.
## History ## History
Jun 13 2012 v0.13
- Added maxlevel option.
- Fixed key sorting such that `true` and `'true'` are always sorted in
the same order (for a more stable output).
- Removed addresses from names of temporary variables (for stable output).
Jun 12 2012 v0.12 Jun 12 2012 v0.12
- Added options to configure serialization process. - Added options to configure serialization process.
- Added 'goto' to the list of keywords for Lua 5.2. - Added 'goto' to the list of keywords for Lua 5.2.

View File

@ -1,4 +1,4 @@
local n, v = "serpent", 0.12 -- (C) 2012 Paul Kulchenko; MIT License local n, v = "serpent", 0.13 -- (C) 2012 Paul Kulchenko; MIT License
local c, d = "Paul Kulchenko", "Serializer and pretty printer of Lua data types" local c, d = "Paul Kulchenko", "Serializer and pretty printer of Lua data types"
local snum = {[tostring(1/0)]='1/0 --[[math.huge]]',[tostring(-1/0)]='-1/0 --[[-math.huge]]',[tostring(0/0)]='0/0'} local snum = {[tostring(1/0)]='1/0 --[[math.huge]]',[tostring(-1/0)]='-1/0 --[[-math.huge]]',[tostring(0/0)]='0/0'}
local badtype = {thread = true, userdata = true} local badtype = {thread = true, userdata = true}
@ -14,8 +14,9 @@ local function s(t, opts)
local name, indent, fatal = opts.name, opts.indent, opts.fatal local name, indent, fatal = opts.name, opts.indent, opts.fatal
local sparse, custom, huge = opts.sparse, opts.custom, not opts.nohuge local sparse, custom, huge = opts.sparse, opts.custom, not opts.nohuge
local space, maxl = (opts.compact and '' or ' '), (opts.maxlevel or math.huge) local space, maxl = (opts.compact and '' or ' '), (opts.maxlevel or math.huge)
local seen, sref = {}, {} local seen, sref, syms, symn = {}, {}, {}, 0
local function gensym(val) return tostring(val):gsub("[^%w]","") end local function gensym(val) return tostring(val):gsub("[^%w]",""):gsub("(%d%w+)",
function(s) if not syms[s] then symn = symn+1; syms[s] = symn end return syms[s] end) end
local function safestr(s) return type(s) == "number" and (huge and snum[tostring(s)] or s) local function safestr(s) return type(s) == "number" and (huge and snum[tostring(s)] or s)
or type(s) ~= "string" and tostring(s) -- escape NEWLINE/010 and EOF/026 or type(s) ~= "string" and tostring(s) -- escape NEWLINE/010 and EOF/026
or ("%q"):format(s):gsub("\010","n"):gsub("\026","\\026") end or ("%q"):format(s):gsub("\010","n"):gsub("\026","\\026") end
@ -26,14 +27,13 @@ local function s(t, opts)
local n = name == nil and '' or name local n = name == nil and '' or name
local plain = type(n) == "string" and n:match("^[%l%u_][%w_]*$") and not keyword[n] local plain = type(n) == "string" and n:match("^[%l%u_][%w_]*$") and not keyword[n]
local safe = plain and n or '['..safestr(n)..']' local safe = plain and n or '['..safestr(n)..']'
return (path or '')..(plain and path and '.' or '')..safe, safe return (path or '')..(plain and path and '.' or '')..safe, safe end
end
local function alphanumsort(o, n) local function alphanumsort(o, n)
local maxn = tonumber(n) or 12 local maxn = tonumber(n) or 12
local function padnum(d) return ("%0"..maxn.."d"):format(d) end local function padnum(d) return ("%0"..maxn.."d"):format(d) end
table.sort(o, function(a,b) table.sort(o, function(a,b)
return tostring(a):gsub("%d+",padnum) < tostring(b):gsub("%d+",padnum) end) return tostring(a):gsub("%d+",padnum)..type(a)
end < tostring(b):gsub("%d+",padnum)..type(b) end) end
local function val2str(t, name, indent, path, plainindex, level) local function val2str(t, name, indent, path, plainindex, level)
local ttype, level = type(t), (level or 0) local ttype, level = type(t), (level or 0)
local spath, sname = safename(path, name) local spath, sname = safename(path, name)

View File

@ -52,3 +52,12 @@ assert(_a.list[4] == 'f', "specific table element preserves its value: failed")
_a = loadstring(serpent.dump(a, {sparse = false, nocode = true}))() _a = loadstring(serpent.dump(a, {sparse = false, nocode = true}))()
assert(pcall(function() _a.z() end) == false, "nocode replaces functions with dummy errors: failed") assert(pcall(function() _a.z() end) == false, "nocode replaces functions with dummy errors: failed")
assert(#(_a.list) == #(a.list), "size of array part stays the same: failed") assert(#(_a.list) == #(a.list), "size of array part stays the same: failed")
local diffable = {sortkeys = true, comment = false, nocode = true, indent = ' '}
assert(serpent.block(a, diffable) == serpent.block(_a, diffable),
"block(a) == block(copy_of_a): failed")
-- test maxlevel
_a = loadstring(serpent.dump(a, {sparse = false, nocode = true, maxlevel = 1}))()
assert(#(_a.list) == 0, "nested table 1 is empty with maxlevel=1: failed")
assert(#(_a[true]) == 0, "nested table 2 is empty with maxlevel=1: failed")