Fixed incorrect sref name used for tables within table keys

`insref` argument of `val2str` explicitly sets name to use for a value
within the self reference section when it is seen again.

It's necessary to provide it for table keys, as they can only be
referenced through the `iname` storage table. For values sref name
can be calculated based on sref of the parent table and the key.

When serializing normal values (key is not a table or another special type),
`insref` was passed as is to the recursive `val2str` call. This is incorrect
when `insref` is actually present (i.e. parent table is a table key
or a value for a table key), the values should get their own sref names
instead of the parent name. Passing `nil` instead is enough to fix this.

Fixes #28, closes #30.
This commit is contained in:
Peter Melnichenko 2018-04-19 13:13:53 +03:00 committed by Paul Kulchenko
parent aedfe52d49
commit ecf3b48c83
2 changed files with 13 additions and 1 deletions

View File

@ -89,7 +89,7 @@ local function s(t, opts)
local path = seen[t]..'['..tostring(seen[key] or globals[key] or gensym(key))..']' local path = seen[t]..'['..tostring(seen[key] or globals[key] or gensym(key))..']'
sref[#sref] = path..space..'='..space..tostring(seen[value] or val2str(value,nil,indent,path)) sref[#sref] = path..space..'='..space..tostring(seen[value] or val2str(value,nil,indent,path))
else else
out[#out+1] = val2str(value,key,indent,insref,seen[t],plainindex,level+1) out[#out+1] = val2str(value,key,indent,nil,seen[t],plainindex,level+1)
if maxlen then if maxlen then
maxlen = maxlen - #out[#out] maxlen = maxlen - #out[#out]
if maxlen < 0 then break end if maxlen < 0 then break end

View File

@ -163,6 +163,18 @@ do
assert(_a[t1].rec1 == _a[t1], "circular reference in self-reference section 2: failed") assert(_a[t1].rec1 == _a[t1], "circular reference in self-reference section 2: failed")
end end
-- test circular reference with the table first seen as a value in a table key
do
local a = {}
local table1 = {}
a[{table1}] = table1
local _a = assert(loadstring(serpent.dump(a, {sparse = false, nocode = true})))()
local t1 = next(_a)
assert(t1[1], "circular reference with the table first seen as a value in a table key 1: failed")
assert(t1[1] == _a[t1], "circular reference with the table first seen as a value in a table key 2: failed")
end
-- test userdata with __tostring method that returns type starting with digits -- test userdata with __tostring method that returns type starting with digits
if _VERSION == 'Lua 5.1' then if _VERSION == 'Lua 5.1' then
local userdata = newproxy(true) local userdata = newproxy(true)